/* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * SPDX-License-Identifier: Apache-2.0 * ============LICENSE_END========================================================= */ package org.openecomp.sdc.be.components.impl; import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.QUOTE; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DESCRIPTION; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.IMPLEMENTATION; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.NOTIFICATIONS; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.REQUIRED; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.STATUS; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.TYPE; import fj.data.Either; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.collections.MapUtils; import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * Handles interface definition TOSCA conversions */ @Component("interfaceDefinitionHandler") public class InterfaceDefinitionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceDefinitionHandler.class); private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic; public InterfaceDefinitionHandler(final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic) { this.interfaceOperationBusinessLogic = interfaceOperationBusinessLogic; } /** * Creates an interface definition based on a TOSCA map representing an interface definition. * * @param interfaceDefinitionToscaMap the TOSCA interface definition structure * @return an interface definition representation */ public InterfaceDefinition create(final Map interfaceDefinitionToscaMap) { final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); if (interfaceDefinitionToscaMap.containsKey(TYPE.getElementName())) { final Object typeObj = interfaceDefinitionToscaMap.get(TYPE.getElementName()); if (!(typeObj instanceof String)) { throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML); } final String type = (String) typeObj; interfaceDefinition.setType(type); interfaceDefinition.setUniqueId(type.toLowerCase()); } final Map inputDefinitionMap = handleInputs(interfaceDefinitionToscaMap); if (!inputDefinitionMap.isEmpty()) { final Map collect = inputDefinitionMap.entrySet().stream(). collect(Collectors.toMap(Entry::getKey, value -> new InputDataDefinition(value.getValue()))); interfaceDefinition.setInputs(collect); } final Map operationMap; if (interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName()) || interfaceDefinitionToscaMap .containsKey(NOTIFICATIONS.getElementName())) { operationMap = handleOperations(interfaceDefinitionToscaMap); //TODO handle notifications } else { operationMap = handleLegacyOperations(interfaceDefinitionToscaMap); } if (!operationMap.isEmpty()) { validateOperations(interfaceDefinition.getType(), operationMap); interfaceDefinition.setOperations(operationMap); } return interfaceDefinition; } private void validateOperations(final String interfaceType, final Map operationMap) { if (MapUtils.isEmpty(operationMap)) { return; } Either, ResponseFormat> interfaceDefinitionMapEither = interfaceOperationBusinessLogic.getAllInterfaceLifecycleTypes(); if (interfaceDefinitionMapEither.isRight() || MapUtils.isEmpty(interfaceDefinitionMapEither.left().value())) { throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType); } final Map interfaceDefinitionMap = interfaceDefinitionMapEither.left().value(); final Optional interfaceDefinitionOptional = interfaceDefinitionMap.entrySet().stream() .filter(interfaceDefinitionEntry -> interfaceDefinitionEntry.getKey().equalsIgnoreCase(interfaceType)) .map(Entry::getValue).findFirst(); if (interfaceDefinitionOptional.isEmpty()) { throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType); } final InterfaceDefinition interfaceDefinition = interfaceDefinitionOptional.get(); operationMap.keySet().forEach(operation1 -> { if (!interfaceDefinition.hasOperation(operation1)) { throw new ByActionStatusComponentException(ActionStatus.INTERFACE_OPERATION_NOT_DEFINED, operation1, interfaceType); } }); } private Map handleOperations( final Map interfaceDefinitionToscaMap) { if (!interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName())) { return Collections.emptyMap(); } final Map operationMap = (Map) interfaceDefinitionToscaMap.get(OPERATIONS.getElementName()); return operationMap.entrySet().stream() .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map) interfaceEntry.getValue())) .collect( Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition)); } private Map handleLegacyOperations( final Map interfaceDefinitionToscaMap) { final List notALegacyOperationEntry = Arrays .asList(OPERATIONS.getElementName(), TYPE.getElementName(), INPUTS.getElementName(), NOTIFICATIONS.getElementName()); return interfaceDefinitionToscaMap.entrySet().stream() .filter(interfaceEntry -> !notALegacyOperationEntry.contains(interfaceEntry.getKey())) .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map) interfaceEntry.getValue())) .collect( Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition)); } private OperationDataDefinition createOperation(final String operationName, final Map operationDefinitionMap) { final OperationDataDefinition operation = new OperationDataDefinition(); operation.setName(operationName); handleOperationImplementation(operationDefinitionMap).ifPresent(operation::setImplementation); if (operationDefinitionMap.containsKey(INPUTS.getElementName())) { final Map interfaceInputs = (Map) operationDefinitionMap.get(INPUTS.getElementName()); operation.setInputs(handleInterfaceOperationInputs(interfaceInputs)); } return operation; } private ListDataDefinition handleInterfaceOperationInputs( final Map interfaceInputs) { final ListDataDefinition inputs = new ListDataDefinition<>(); for (final Entry interfaceInput : interfaceInputs.entrySet()) { final OperationInputDefinition operationInput = new OperationInputDefinition(); operationInput.setName(interfaceInput.getKey()); if (interfaceInput.getValue() instanceof Map) { final LinkedHashMap inputPropertyValue = (LinkedHashMap) interfaceInput.getValue(); LOGGER.info("createModuleInterface: i interfaceInput.getKey() {}, {} , {} ", interfaceInput.getKey(), inputPropertyValue.keySet(), inputPropertyValue.values()); if (inputPropertyValue.get(TYPE.getElementName()) != null) { operationInput.setType(inputPropertyValue.get(TYPE.getElementName()).toString()); } if (inputPropertyValue.get(DESCRIPTION.getElementName()) != null) { operationInput.setDescription(inputPropertyValue.get(DESCRIPTION.getElementName()).toString()); } if (inputPropertyValue.get(REQUIRED.getElementName()) != null) { operationInput.setRequired( Boolean.getBoolean(inputPropertyValue.get(REQUIRED.getElementName()).toString())); } if (inputPropertyValue.get(DEFAULT.getElementName()) != null) { operationInput.setToscaDefaultValue(inputPropertyValue.get(DEFAULT.getElementName()).toString()); } if (inputPropertyValue.get(STATUS.getElementName()) != null) { operationInput.setStatus(inputPropertyValue.get(STATUS.getElementName()).toString()); } } else if (interfaceInput.getValue() instanceof String) { final String value = (String) interfaceInput.getValue(); operationInput.setDefaultValue(value); operationInput.setToscaDefaultValue(value); operationInput.setValue(value); } inputs.add(operationInput); } return inputs; } private Optional handleOperationImplementation( final Map operationDefinitionMap) { if (!operationDefinitionMap.containsKey(IMPLEMENTATION.getElementName())) { return Optional.empty(); } final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); final String artifactName = (String) operationDefinitionMap.get(IMPLEMENTATION.getElementName()); if (OperationArtifactUtil.artifactNameIsALiteralValue(artifactName)) { artifactDataDefinition.setArtifactName(artifactName); } else { artifactDataDefinition.setArtifactName(QUOTE + artifactName + QUOTE); } return Optional.of(artifactDataDefinition); } private Map handleInputs(final Map interfaceDefinitionToscaMap) { if (!interfaceDefinitionToscaMap.containsKey(INPUTS.getElementName())) { return Collections.emptyMap(); } final Either, ResultStatusEnum> inputMapEither = ImportUtils.getInputs(interfaceDefinitionToscaMap); if (inputMapEither.isRight()) { return Collections.emptyMap(); } return inputMapEither.left().value(); } }