From 51411acd1d4b06fc9bbc40338a27dd061dba425f Mon Sep 17 00:00:00 2001 From: Toshimichi Fukuda Date: Thu, 18 Apr 2019 21:38:46 +0900 Subject: Change to enable SDC list type input Change-Id: Ic3a9c6e714a5afd22b58bf2cb066932b1ec2a5c0 Issue-ID: SDC-2046 Signed-off-by: Toshimichi Fukuda Signed-off-by: Satoshi Fujii Signed-off-by: Ayumu Ueha --- .../be/components/impl/DataTypeBusinessLogic.java | 138 +++++++++ .../be/components/impl/InputsBusinessLogic.java | 322 +++++++++++++++++---- .../ComponentInstanceInputPropertyDeclarator.java | 10 + .../ComponentInstancePropertyDeclarator.java | 9 + .../property/ComponentPropertyDeclarator.java | 69 ++++- .../property/DefaultPropertyDeclarator.java | 77 ++++- .../property/GroupPropertyDeclarator.java | 7 + .../property/PolicyPropertyDeclarator.java | 7 + .../property/PropertyDeclarationOrchestrator.java | 44 +++ .../be/components/property/PropertyDeclarator.java | 17 ++ ...omponentInstancePropertyToPolicyDeclarator.java | 5 + .../ComponentPropertyToPolicyDeclarator.java | 7 +- .../openecomp/sdc/be/servlets/InputsServlet.java | 219 ++++++++++++++ .../openecomp/sdc/be/tosca/PropertyConvertor.java | 42 +-- .../openecomp/sdc/be/tosca/ToscaExportHandler.java | 61 +++- .../sdc/be/tosca/model/ToscaDataType.java | 126 ++++++++ .../sdc/be/tosca/model/ToscaTemplate.java | 17 ++ 17 files changed, 1064 insertions(+), 113 deletions(-) create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DataTypeBusinessLogic.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaDataType.java (limited to 'catalog-be/src/main/java') diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DataTypeBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DataTypeBusinessLogic.java new file mode 100644 index 0000000000..e020876b3b --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/DataTypeBusinessLogic.java @@ -0,0 +1,138 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 Fujitsu Limited. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.components.impl; + +import fj.data.Either; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@org.springframework.stereotype.Component("dataTypeBusinessLogic") +public class DataTypeBusinessLogic extends BaseBusinessLogic { + + /** + * Get a list of data types that the Component has. + * + * @param componentId Unique ID of the Component + * @return list of data types + */ + public Either, StorageOperationStatus> getPrivateDataTypes(String componentId) { + ComponentParametersView filter = new ComponentParametersView(); + filter.disableAll(); + filter.setIgnoreDataType(false); + + // Get Component object + Either componentResult = + toscaOperationFacade.getToscaElement(componentId, filter); + if (componentResult.isRight()) { + return Either.right(componentResult.right().value()); + } + Component component = componentResult.left().value(); + + List dataTypesToReturn = component.getDataTypes(); + if (dataTypesToReturn == null) { + // this means there is no DATA_TYPES graph vertex. + // in this case, returns empty list. + dataTypesToReturn = new ArrayList<>(); + } + + return Either.left(dataTypesToReturn); + } + + /** + * Get a data type in a Component + * + * @param componentId Unique ID of the Component + * @param dataTypeName Data type name + * @return found data type + */ + public Either getPrivateDataType(String componentId, String dataTypeName) { + Either, StorageOperationStatus> dataTypesResult = this.getPrivateDataTypes(componentId); + if (dataTypesResult.isRight()) { + return Either.right(dataTypesResult.right().value()); + } + List dataTypes = dataTypesResult.left().value(); + Optional findResult = dataTypes.stream().filter(e -> e.getName().equals(dataTypeName)).findAny(); + if (!findResult.isPresent()) { + return Either.right(StorageOperationStatus.NOT_FOUND); + } + return Either.left(findResult.get()); + } + + /** + * Delete a data type from the Component. + * + * @param componentId Unique ID of the Component + * @param dataTypeName Data type name to be deleted + * @return deleted data type + */ + public Either deletePrivateDataType(String componentId, String dataTypeName) { + ComponentParametersView filter = new ComponentParametersView(); + filter.disableAll(); + filter.setIgnoreDataType(false); + + // Get Component object + Either componentResult = + toscaOperationFacade.getToscaElement(componentId, filter); + if (componentResult.isRight()) { + // not exists + return Either.right(componentResult.right().value()); + } + + return deletePrivateDataType(componentResult.left().value(), dataTypeName); + } + + /** + * Delete a data type from the Component. + * + * @param component Component object which has data types. + * needs to be fetched with componentParametersView.setIgnoreDataType(false) + * @param dataTypeName Data type name to be deleted + * @return deleted data type + */ + public Either deletePrivateDataType(Component component, String dataTypeName) { + // check the specified data type exists + List dataTypes = component.getDataTypes(); + if (CollectionUtils.isEmpty(dataTypes)) { + return Either.right(StorageOperationStatus.NOT_FOUND); + } + Optional dataTypeResult = + dataTypes.stream().filter(e -> e.getName().equals(dataTypeName)).findFirst(); + if (!dataTypeResult.isPresent()) { + return Either.right(StorageOperationStatus.NOT_FOUND); + } + + // delete it + StorageOperationStatus deleteResult = toscaOperationFacade.deleteDataTypeOfComponent(component, dataTypeName); + if (deleteResult != StorageOperationStatus.OK) { + return Either.right(deleteResult); + } + + // return deleted data type if ok + return Either.left(dataTypeResult.get()); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java index 214b5df4e1..a98694626f 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java @@ -22,7 +22,9 @@ package org.openecomp.sdc.be.components.impl; import fj.data.Either; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -31,6 +33,10 @@ import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.builder.ReflectionToStringBuilder; +import org.openecomp.sdc.be.components.impl.exceptions.ComponentException; import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator; import org.openecomp.sdc.be.components.validation.ComponentValidations; import org.openecomp.sdc.be.dao.api.ActionStatus; @@ -42,14 +48,18 @@ import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; import org.openecomp.sdc.be.model.ComponentInstInputsMap; +import org.openecomp.sdc.be.model.ComponentInstListInput; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstancePropInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; import org.openecomp.sdc.common.log.wrappers.Logger; @@ -73,6 +83,9 @@ public class InputsBusinessLogic extends BaseBusinessLogic { private PropertyDeclarationOrchestrator propertyDeclarationOrchestrator; @Inject private ComponentInstanceBusinessLogic componentInstanceBusinessLogic; + @Inject + private DataTypeBusinessLogic dataTypeBusinessLogic; + /** * associate inputs to a given component with paging * @@ -280,7 +293,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } //Validate value and Constraint of input - Either constraintValidatorResponse = validateInputValueConstraint(component, inputs); + Either constraintValidatorResponse = validateInputValueConstraint(inputs); if (constraintValidatorResponse.isRight()) { log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value()); @@ -339,8 +352,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } } - private Either validateInputValueConstraint( - org.openecomp.sdc.be.model.Component component, List inputs) { + private Either validateInputValueConstraint(List inputs) { PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = PropertyValueConstraintValidationUtil.getInstance(); List inputDefinitions = new ArrayList<>(); @@ -408,46 +420,107 @@ public class InputsBusinessLogic extends BaseBusinessLogic { try { validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false); - ComponentParametersView componentParametersView = new ComponentParametersView(); - componentParametersView.disableAll(); - componentParametersView.setIgnoreInputs(false); - componentParametersView.setIgnoreComponentInstancesInputs(false); - componentParametersView.setIgnoreComponentInstances(false); - componentParametersView.setIgnoreComponentInstancesProperties(false); - componentParametersView.setIgnorePolicies(false); - componentParametersView.setIgnoreGroups(false); - componentParametersView.setIgnoreUsers(false); + component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp); - Either validateComponent = validateComponentExists(componentId, componentType, componentParametersView); + result = propertyDeclarationOrchestrator.declarePropertiesToInputs(component, componentInstInputsMapUi) + .left() + .bind(inputsToCreate -> prepareInputsForCreation(userId, componentId, inputsToCreate)) + .right() + .map(componentsUtils::getResponseFormat); - if (validateComponent.isRight()) { - result = Either.right(validateComponent.right().value()); - return result; - } - component = validateComponent.left().value(); + return result; - if (shouldLockComp) { - Either lockComponent = lockComponent(component, CREATE_INPUT); - if (lockComponent.isRight()) { - result = Either.right(lockComponent.right().value()); - return result; + } catch (ComponentException e) { + log.error("#createMultipleInputs: Exception thrown: ", e); + result = Either.right(e.getResponseFormat()); + return result; + } finally { + + if (!inTransaction) { + if (result == null || result.isRight()) { + log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP); + titanDao.rollback(); + } else { + log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP); + titanDao.commit(); } } + // unlock resource + if (shouldLockComp && component != null) { + graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); + } - Either canWork = validateCanWorkOnComponent(component, userId); - if (canWork.isRight()) { - result = Either.right(canWork.right().value()); - return result; + } + } + + /** + * Creates a list input with a data type which has properties specified. + * + * @param userId User ID + * @param componentId Component ID + * @param componentType Component type + * @param componentListInput Properties to be declared and input to be created + * @param shouldLockComp true if the component should be locked + * @param inTransaction true if already in transaction + */ + public Either, ResponseFormat> createListInput(String userId, String componentId, + ComponentTypeEnum componentType, ComponentInstListInput componentListInput, boolean shouldLockComp, + boolean inTransaction) { + + Either, ResponseFormat> result = null; + org.openecomp.sdc.be.model.Component component = null; + + log.trace("#createListInput: enter"); + + try { + /* check if user exists */ + validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false); + + component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp); + + InputDefinition listInput = componentListInput.getListInput(); + DataTypeDefinition dataType = + prepareDataTypeForListInput(componentListInput.getComponentInstInputsMap(), listInput); + Map dataTypesMap = new HashMap<>(); + dataTypesMap.put(dataType.getName(), dataType); + if (log.isDebugEnabled()) { + log.debug("#createListInput: dataTypesMap={}", ReflectionToStringBuilder.toString(dataTypesMap)); } - result = propertyDeclarationOrchestrator.declarePropertiesToInputs(component, componentInstInputsMapUi) - .left() - .bind(inputsToCreate -> prepareInputsForCreation(userId, componentId, inputsToCreate)) - .right() - .map(componentsUtils::getResponseFormat); + Either, StorageOperationStatus> dataTypeResult = + toscaOperationFacade.addDataTypesToComponent(dataTypesMap, componentId); + if (dataTypeResult.isRight()) { + log.debug("#createListInput: DataType creation failed."); + throw new ComponentException(componentsUtils.getResponseFormat(dataTypeResult.right().value())); + } + + // create list input + listInput.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, listInput.getName())); + listInput.setInstanceUniqueId( + propertyDeclarationOrchestrator.getPropOwnerId(componentListInput.getComponentInstInputsMap())); + listInput.setIsDeclaredListInput(true); + Map listInputMap = new HashMap<>(); + listInputMap.put(listInput.getName(), listInput); + result = createListInputsInGraph(listInputMap, dataTypesMap, component); + if (result.isRight()) { + log.debug("#createListInput: createListInputsInGraph failed."); + throw new ComponentException(result.right().value()); + } + + // update properties + result = propertyDeclarationOrchestrator + .declarePropertiesToListInput(component, componentListInput.getComponentInstInputsMap(), listInput) + .right().map(err -> componentsUtils.getResponseFormat(err)) + .left().map(Arrays::asList); + + log.trace("#createListInput: leave"); return result; + } catch (ComponentException e) { + log.error("#createListInput: Exception thrown", e); + result = Either.right(e.getResponseFormat()); + return result; } finally { if (!inTransaction) { @@ -463,8 +536,65 @@ public class InputsBusinessLogic extends BaseBusinessLogic { if (shouldLockComp && component != null) { graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); } + } + } + private ComponentParametersView getBaseComponentParametersView() { + ComponentParametersView componentParametersView = new ComponentParametersView(); + componentParametersView.disableAll(); + componentParametersView.setIgnoreInputs(false); + componentParametersView.setIgnoreComponentInstances(false); + componentParametersView.setIgnoreComponentInstancesInputs(false); + componentParametersView.setIgnoreComponentInstancesProperties(false); + componentParametersView.setIgnorePolicies(false); + componentParametersView.setIgnoreGroups(false); + componentParametersView.setIgnoreUsers(false); + return componentParametersView; + } + + private org.openecomp.sdc.be.model.Component getAndValidateComponentForCreate( + String userId, String componentId, ComponentTypeEnum componentType, boolean shouldLockComp + ) { + + ComponentParametersView componentParametersView = getBaseComponentParametersView(); + + Either componentEither = + // get Component Object + validateComponentExists(componentId, componentType, componentParametersView) + .left().bind(component -> { + if (shouldLockComp) { + // lock the component + return lockComponent(component, CREATE_INPUT).left().map(result -> component); + } + return Either.left(component); + }).left().bind(component -> validateCanWorkOnComponent(component, userId).left().map(result -> component)); + if (componentEither.isRight()) { + throw new ComponentException(componentEither.right().value()); + } + return componentEither.left().value(); + } + + private DataTypeDefinition prepareDataTypeForListInput(ComponentInstInputsMap inputsMap, InputDefinition input) { + // Confirm if type is list + if (StringUtils.isEmpty(input.getType()) || !input.getType().equals(ToscaPropertyType.LIST.getType())) { + log.debug("#prepareDataTypeForListInput: Type of input is not list."); + throw new ComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE)); } + + // Confirm schema type is not empty + String desiredTypeName = input.getSchemaType(); + if (StringUtils.isEmpty(desiredTypeName)) { + log.debug("#prepareDataTypeForListInput: Schema type of list input is empty."); + throw new ComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE)); + } + + DataTypeDefinition dataType = new DataTypeDefinition(); + List propInputs = inputsMap.resolvePropertiesToDeclare().getRight(); + dataType.setName(desiredTypeName); + dataType.setDerivedFromName(ToscaPropertyType.Root.getType()); + // Copy properties from inputsMap + dataType.setProperties(propInputs.stream().map(PropertyDefinition::new).collect(Collectors.toList())); + return dataType; } private Either, StorageOperationStatus> prepareInputsForCreation(String userId, String cmptId, List inputsToCreate) { @@ -519,6 +649,42 @@ public class InputsBusinessLogic extends BaseBusinessLogic { return Either.left(associateInputsEither.left().value()); } + private Either, ResponseFormat> createListInputsInGraph(Map inputs, + Map privateDataTypes, org.openecomp.sdc.be.model.Component component) { + + log.trace("#createListInputsInGraph: enter"); + Either, ResponseFormat> allDataTypes = getAllDataTypes( + applicationDataTypeCache); + if (allDataTypes.isRight()) { + return Either.right(allDataTypes.right().value()); + } + + Map dataTypes = allDataTypes.left().value(); + dataTypes.putAll(privateDataTypes); + + for (Map.Entry inputDefinition : inputs.entrySet()) { + String inputName = inputDefinition.getKey(); + inputDefinition.getValue().setName(inputName); + + Either preparedInputEither = + prepareAndValidateInputBeforeCreate(inputDefinition.getValue(), dataTypes); + if (preparedInputEither.isRight()) { + return Either.right(preparedInputEither.right().value()); + } + } + + Either, StorageOperationStatus> addInputsEither = toscaOperationFacade + .addInputsToComponent(inputs, component.getUniqueId()); + if (addInputsEither.isRight()) { + log.debug("#createListInputsInGraph: Failed to create inputs under component {}. Status is {}", + component.getUniqueId(), addInputsEither.right().value()); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(addInputsEither.right().value()))); + } + log.trace("#createListInputsInGraph: leave"); + return Either.left(addInputsEither.left().value()); + } + /** * Delete input from service * @@ -536,21 +702,16 @@ public class InputsBusinessLogic extends BaseBusinessLogic { validateUserExists(userId, "Delete input", true); - ComponentParametersView componentParametersView = new ComponentParametersView(); - componentParametersView.disableAll(); - componentParametersView.setIgnoreInputs(false); - componentParametersView.setIgnoreComponentInstances(false); - componentParametersView.setIgnoreComponentInstancesInputs(false); - componentParametersView.setIgnoreComponentInstancesProperties(false); - componentParametersView.setIgnorePolicies(false); - componentParametersView.setIgnoreGroups(false); - componentParametersView.setIgnoreUsers(false); + ComponentParametersView componentParametersView = getBaseComponentParametersView(); componentParametersView.setIgnoreInterfaces(false); + componentParametersView.setIgnoreDataType(false); componentParametersView.setIgnoreProperties(false); - Either componentEither = toscaOperationFacade.getToscaElement(componentId, componentParametersView); + Either componentEither = + toscaOperationFacade.getToscaElement(componentId, componentParametersView); if (componentEither.isRight()) { - deleteEither = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentEither.right().value()))); + deleteEither = Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(componentEither.right().value()))); return deleteEither; } org.openecomp.sdc.be.model.Component component = componentEither.left().value(); @@ -562,13 +723,15 @@ public class InputsBusinessLogic extends BaseBusinessLogic { // Get the input findAny(); if (!optionalInput.isPresent()) { - return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUT_IS_NOT_CHILD_OF_COMPONENT, inputId, componentId)); + return Either.right( + componentsUtils.getResponseFormat(ActionStatus.INPUT_IS_NOT_CHILD_OF_COMPONENT, inputId, componentId)); } InputDefinition inputForDelete = optionalInput.get(); // Lock component - Either lockResultEither = lockComponent(componentId, component, "deleteInput"); + Either lockResultEither = + lockComponent(componentId, component, "deleteInput"); if (lockResultEither.isRight()) { ResponseFormat responseFormat = lockResultEither.right().value(); deleteEither = Either.right(responseFormat); @@ -577,18 +740,29 @@ public class InputsBusinessLogic extends BaseBusinessLogic { // Delete input operations try { - StorageOperationStatus status = toscaOperationFacade.deleteInputOfResource(component, inputForDelete.getName()); + StorageOperationStatus status = + toscaOperationFacade.deleteInputOfResource(component, inputForDelete.getName()); if (status != StorageOperationStatus.OK) { log.debug("Component id: {} delete input id: {} failed", componentId, inputId); - deleteEither = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status), component.getName())); + deleteEither = Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(status), component.getName())); + return deleteEither; + } + + if (BooleanUtils.isTrue(inputForDelete.getIsDeclaredListInput())){ + deleteEither = deleteListInput(componentId, inputId, component, inputForDelete, status); return deleteEither; } - StorageOperationStatus storageOperationStatus = propertyDeclarationOrchestrator.unDeclarePropertiesAsInputs(component, inputForDelete); + + StorageOperationStatus storageOperationStatus = + propertyDeclarationOrchestrator.unDeclarePropertiesAsInputs(component, inputForDelete); if (storageOperationStatus != StorageOperationStatus.OK) { log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId); - deleteEither = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status), component.getName())); + deleteEither = Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(status), component.getName())); return deleteEither; } + deleteEither = Either.left(inputForDelete); return deleteEither; } finally { @@ -603,8 +777,31 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } } - private Either prepareAndValidateInputBeforeCreate(InputDefinition newInputDefinition, Map dataTypes) { + private Either deleteListInput(String componentId, String inputId, + org.openecomp.sdc.be.model.Component component, + InputDefinition inputForDelete, StorageOperationStatus status) { + // the input is created by 'Declare List'. + // need to 1. undeclare properties, 2. delete input, 3. delete private data type + + StorageOperationStatus storageOperationStatus = + propertyDeclarationOrchestrator.unDeclarePropertiesAsListInputs(component, inputForDelete); + if (storageOperationStatus != StorageOperationStatus.OK) { + log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(status), component.getName())); + } + Either deleteResult = + dataTypeBusinessLogic.deletePrivateDataType(component, inputForDelete.getSchemaType()); + if (deleteResult.isRight()) { + log.debug("Component id: {} delete datatype name: {} failed", componentId, inputForDelete.getSchemaType()); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(deleteResult.right().value()), component.getName())); + } + log.trace("deleteInput: deletePrivateDataType (OK)"); + return Either.left(inputForDelete); + } + private Either prepareAndValidateInputBeforeCreate(InputDefinition newInputDefinition, Map dataTypes) { // validate input default values Either defaultValuesValidation = validatePropertyDefaultValue(newInputDefinition, dataTypes); @@ -613,24 +810,22 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } // convert property ToscaPropertyType type = getType(newInputDefinition.getType()); - if (type != null) { + if (type != null && newInputDefinition != null) { PropertyValueConverter converter = type.getConverter(); // get inner type + SchemaDefinition schema = newInputDefinition.getSchema(); String innerType = null; - if (newInputDefinition != null) { - SchemaDefinition schema = newInputDefinition.getSchema(); - if (schema != null) { - PropertyDataDefinition prop = schema.getProperty(); - if (prop != null) { - innerType = prop.getType(); - } - } - String convertedValue; - if (newInputDefinition.getDefaultValue() != null) { - convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, dataTypes); - newInputDefinition.setDefaultValue(convertedValue); + if (schema != null) { + PropertyDataDefinition prop = schema.getProperty(); + if (prop != null) { + innerType = prop.getType(); } } + String convertedValue; + if (newInputDefinition.getDefaultValue() != null) { + convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, dataTypes); + newInputDefinition.setDefaultValue(convertedValue); + } } return Either.left(newInputDefinition); } @@ -696,5 +891,4 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } - } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstanceInputPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstanceInputPropertyDeclarator.java index faeca88d60..d7b366e0a8 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstanceInputPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstanceInputPropertyDeclarator.java @@ -78,6 +78,16 @@ public class ComponentInstanceInputPropertyDeclarator extends DefaultPropertyDec return toscaOperationFacade.updateComponentInstanceInputs(component, componentInstanceInputsByInputId.get(0).getComponentInstanceId(), componentInstanceInputsByInputId); } + @Override + public StorageOperationStatus unDeclarePropertiesAsListInputs(Component component, InputDefinition input) { + List componentInstanceInputsByInputId = componentInstanceBusinessLogic.getComponentInstanceInputsByInputId(component, input.getUniqueId()); + if (isEmpty(componentInstanceInputsByInputId)) { + return StorageOperationStatus.OK; + } + componentInstanceInputsByInputId.forEach(cmptInstanceInput -> prepareValueBeforeDelete(input, cmptInstanceInput, cmptInstanceInput.getPath())); + return toscaOperationFacade.updateComponentInstanceInputs(component, componentInstanceInputsByInputId.get(0).getComponentInstanceId(), componentInstanceInputsByInputId); + } + @Override InputDefinition createInputFromProperty(String componentId, ComponentInstance propertiesOwner, String inputName, ComponentInstancePropInput propInput, PropertyDataDefinition prop) { InputDefinition inputFromProperty = super.createInputFromProperty(componentId, propertiesOwner, inputName, propInput, prop); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstancePropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstancePropertyDeclarator.java index c716e24440..973e5985f9 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstancePropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentInstancePropertyDeclarator.java @@ -70,4 +70,13 @@ public class ComponentInstancePropertyDeclarator extends DefaultPropertyDeclarat return toscaOperationFacade.updateComponentInstanceProperties(component, componentInstancePropertiesDeclaredAsInput.get(0).getComponentInstanceId(), componentInstancePropertiesDeclaredAsInput); } + @Override + public StorageOperationStatus unDeclarePropertiesAsListInputs(Component component, InputDefinition input) { + List componentInstancePropertiesDeclaredAsInput = componentInstanceBusinessLogic.getComponentInstancePropertiesByInputId(component, input.getUniqueId()); + if (CollectionUtils.isEmpty(componentInstancePropertiesDeclaredAsInput)) { + return StorageOperationStatus.OK; + } + componentInstancePropertiesDeclaredAsInput.forEach(cmptInstanceProperty -> prepareValueBeforeDelete(input, cmptInstanceProperty, cmptInstanceProperty.getPath())); + return toscaOperationFacade.updateComponentInstanceProperties(component, componentInstancePropertiesDeclaredAsInput.get(0).getComponentInstanceId(), componentInstancePropertiesDeclaredAsInput); + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentPropertyDeclarator.java index d382499172..ae76dadbf0 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentPropertyDeclarator.java @@ -110,6 +110,40 @@ public class ComponentPropertyDeclarator extends DefaultPropertyDeclarator> propertyToUpdateCandidate = + getDeclaredPropertiesByInputId(component, input.getUniqueId()); + + if(propertyToUpdateCandidate.isPresent()) { + List propertiesToUpdate = propertyToUpdateCandidate.get(); + if (!propertiesToUpdate.isEmpty()) { + return unDeclareInputs(component, input, propertiesToUpdate); + } + } + + return StorageOperationStatus.OK; + } + + private StorageOperationStatus unDeclareInputs(Component component, + InputDefinition input, + List propertiesToUpdate) { + for (PropertyDefinition propertyToUpdate : propertiesToUpdate) { + StorageOperationStatus storageOperationStatus = unDeclareInput(component, input, propertyToUpdate); + if (StorageOperationStatus.OK != storageOperationStatus) { + return storageOperationStatus; + } + } + return StorageOperationStatus.OK; + } + private StorageOperationStatus unDeclareInput(Component component, InputDefinition input, PropertyDefinition propertyToUpdate) { @@ -124,9 +158,34 @@ public class ComponentPropertyDeclarator extends DefaultPropertyDeclarator getDeclaredPropertyByInputId(Component component, + private Optional getDeclaredPropertyByInputId(Component component, String inputId) { + List properties = component.getProperties(); + + if (CollectionUtils.isEmpty(properties)) { + return Optional.empty(); + } + + for (PropertyDefinition propertyDefinition : properties) { + List getInputValues = propertyDefinition.getGetInputValues(); + if (CollectionUtils.isEmpty(getInputValues)) { + continue; + } + + Optional getInputCandidate = + getInputValues.stream().filter(getInput -> getInput.getInputId().equals(inputId)).findAny(); + + if (getInputCandidate.isPresent()) { + return Optional.of(propertyDefinition); + } + } + + return Optional.empty(); + } + + private Optional> getDeclaredPropertiesByInputId(Component component, String inputId) { List properties = component.getProperties(); + List propertiesToUpdate = new ArrayList<>(); if(CollectionUtils.isEmpty(properties)) { return Optional.empty(); @@ -139,14 +198,14 @@ public class ComponentPropertyDeclarator extends DefaultPropertyDeclarator getInputCandidate = - getInputValues.stream().filter(getInput -> getInput.getInputId().equals(inputId)) - .findAny(); + getInputValues.stream().filter(getInput -> getInput.getInputId().equals(inputId)) + .findAny(); if(getInputCandidate.isPresent()) { - return Optional.of(propertyDefinition); + propertiesToUpdate.add(propertyDefinition); } } - return Optional.empty(); + return Optional.of(propertiesToUpdate); } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java index 02b261b132..46c1c009bc 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java @@ -11,12 +11,14 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Arrays; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; import org.json.simple.JSONObject; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition; @@ -45,6 +47,7 @@ public abstract class DefaultPropertyDeclarator declarePropertiesAsPolicies(component, propertyOwner, propsToDeclare)) .orElse(Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId))); + } + @Override + public Either declarePropertiesAsListInput(Component component, String propertiesOwnerId, List propsToDeclare, InputDefinition input) { + log.debug("#declarePropertiesAsListInput - declaring properties as inputs for component {} from properties owner {}", component.getUniqueId(), propertiesOwnerId); + Optional propertyOwner = resolvePropertiesOwner(component, propertiesOwnerId); + if (propertyOwner.isPresent()) { + return declarePropertiesAsListInput(component, propertyOwner.get(), propsToDeclare, input); + } else { + return Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId)); + } } public StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policy) { @@ -130,12 +143,12 @@ public abstract class DefaultPropertyDeclarator()); @@ -155,6 +168,39 @@ public abstract class DefaultPropertyDeclarator declarePropertiesAsListInput(Component component, PROPERTYOWNER propertiesOwner, List propsToDeclare, InputDefinition input) { + List declaredProperties = new ArrayList<>(); + for (ComponentInstancePropInput propInput : propsToDeclare) { + if (StringUtils.isNotEmpty(propInput.getPropertiesName()) && propInput.getInput() != null) { + // sub-property in complex type is checked on UI. currently not supported. + log.debug("skip propInput (propertiesName={}) currently not supported.", propInput.getPropertiesName()); + continue; + } + PROPERTYTYPE declaredProperty = createDeclaredProperty(propInput); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put(GET_INPUT, Arrays.asList(input.getName(), GET_INPUT_INDEX, propInput.getName())); + declaredProperty.setValue(jsonObject.toJSONString()); + + GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition(); + getInputValueDataDefinition.setInputId(input.getUniqueId()); + getInputValueDataDefinition.setInputName(input.getName()); + List getInputValues = declaredProperty.getGetInputValues(); + if (getInputValues == null) { + getInputValues = new ArrayList<>(); + declaredProperty.setGetInputValues(getInputValues); + } + getInputValues.add(getInputValueDataDefinition); + + if (!declaredProperties.contains(declaredProperty)) { + // Add property to the list if not contain in declareProperties. + declaredProperties.add(declaredProperty); + } + } + return updatePropertiesValues(component, propertiesOwner.getUniqueId(), declaredProperties) + .left().map(x -> input); + } + private PropertiesDeclarationData createInputsAndOverridePropertiesValues(String componentId, PROPERTYOWNER propertiesOwner, List propsToDeclare) { List declaredProperties = new ArrayList<>(); List createdInputs = propsToDeclare.stream() @@ -182,6 +228,7 @@ public abstract class DefaultPropertyDeclarator()); } @@ -453,6 +499,9 @@ public abstract class DefaultPropertyDeclarator subMap = (Map)value; resetInputName(subMap, inputName); + } else if (value instanceof List && ((List) value).contains(inputName) && key.equals(GET_INPUT)) { + value = ""; + lhm1.remove(key); } else { continue; } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/GroupPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/GroupPropertyDeclarator.java index 46ca85c585..f9ef479ab0 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/GroupPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/GroupPropertyDeclarator.java @@ -89,6 +89,13 @@ public class GroupPropertyDeclarator extends DefaultPropertyDeclarator unDeclareGroupProperties(component, inputForDelete, groupProperties)) + .orElse(StorageOperationStatus.OK); + } + private StorageOperationStatus unDeclareGroupProperties(Component container, InputDefinition input, GroupProperties groupProperties) { String groupId = groupProperties.getGroupId(); List propsDeclaredAsInput = groupProperties.getProperties(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PolicyPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PolicyPropertyDeclarator.java index f7f4a75be1..17059104ff 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PolicyPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PolicyPropertyDeclarator.java @@ -87,6 +87,13 @@ public class PolicyPropertyDeclarator extends DefaultPropertyDeclarator unDeclarePolicyProperties(component, inputForDelete, policyProperties)) + .orElse(StorageOperationStatus.OK); + } + private StorageOperationStatus unDeclarePolicyProperties(Component container, InputDefinition input, PolicyProperties policyProperties) { String policyId = policyProperties.getPolicyId(); List propsDeclaredAsInput = policyProperties.getProperties(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java index 3a32559dda..a6c752d689 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java @@ -58,6 +58,20 @@ public class PropertyDeclarationOrchestrator { return propertyDeclarator.declarePropertiesAsPolicies(component, propsToDeclare.getLeft(), propsToDeclare.getRight()); } + /** + * + * @param component + * @param componentInstInputsMap + * @param input + * @return + */ + public Either declarePropertiesToListInput(Component component, ComponentInstInputsMap componentInstInputsMap, InputDefinition input) { + PropertyDeclarator propertyDeclarator = getPropertyDeclarator(componentInstInputsMap); + Pair> propsToDeclare = componentInstInputsMap.resolvePropertiesToDeclare(); + log.debug("#declarePropertiesToInputs: componentId={}, propOwnerId={}", component.getUniqueId(), propsToDeclare.getLeft()); + return propertyDeclarator.declarePropertiesAsListInput(component, propsToDeclare.getLeft(), propsToDeclare.getRight(), input); + } + public StorageOperationStatus unDeclarePropertiesAsInputs(Component component, InputDefinition inputToDelete) { log.debug("#unDeclarePropertiesAsInputs - removing input declaration for input {} on component {}", inputToDelete.getName(), component.getUniqueId()); for (PropertyDeclarator propertyDeclarator : propertyDeclaratorsToInput) { @@ -70,6 +84,36 @@ public class PropertyDeclarationOrchestrator { return StorageOperationStatus.OK; } + /** + * Un declare properties declared as list type input + * + * @param component + * @param inputToDelete + * @return + */ + public StorageOperationStatus unDeclarePropertiesAsListInputs(Component component, InputDefinition inputToDelete) { + log.debug("#unDeclarePropertiesAsListInputs - removing input declaration for input {} on component {}", inputToDelete.getName(), component.getUniqueId()); + for (PropertyDeclarator propertyDeclarator : propertyDeclaratorsToInput) { + StorageOperationStatus storageOperationStatus = propertyDeclarator.unDeclarePropertiesAsListInputs(component, inputToDelete); + if (StorageOperationStatus.OK != storageOperationStatus) { + log.debug("#unDeclarePropertiesAsListInputs - failed to remove input declaration for input {} on component {}. reason {}", inputToDelete.getName(), component.getUniqueId(), storageOperationStatus); + return storageOperationStatus; + } + } + return StorageOperationStatus.OK; + + } + + /** + * Get properties owner id + * + * @param componentInstInputsMap + * @return + */ + public String getPropOwnerId(ComponentInstInputsMap componentInstInputsMap) { + Pair> propsToDeclare = componentInstInputsMap.resolvePropertiesToDeclare(); + return propsToDeclare.getLeft(); + } public StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policyToDelete) { log.debug("#unDeclarePropertiesAsInputs - removing policy declaration for input {} on component {}", policyToDelete diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarator.java index c0f76288b2..b8b6c6eb62 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarator.java @@ -44,4 +44,21 @@ public interface PropertyDeclarator { */ StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policy); + /** + * Updates given list of properties to get values from the specified "list input" with get_input function. + * This function does NOT create "list input", it needs to be created separately. + * @param component the container + * @param propertiesOwnerId the id of the owner of the properties to declare (e.g ComponentInstance, Policy, Group etc) + * @param propsToDeclare the list of properties that are being declared as inputs + * @param input the input from which properties get values + * @return the input same as passed one at 4th argument + */ + Either declarePropertiesAsListInput(Component component, String propertiesOwnerId, List propsToDeclare, InputDefinition input); + + /** + * Un declare properties declared as list type input + * @param component the container of the input to be deleted + * @param input the input to be deleted + */ + StorageOperationStatus unDeclarePropertiesAsListInputs(Component component, InputDefinition input); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentInstancePropertyToPolicyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentInstancePropertyToPolicyDeclarator.java index bbbdf6f105..2726f67342 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentInstancePropertyToPolicyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentInstancePropertyToPolicyDeclarator.java @@ -64,6 +64,11 @@ public class ComponentInstancePropertyToPolicyDeclarator extends return StorageOperationStatus.OK; } + @Override + public StorageOperationStatus unDeclarePropertiesAsListInputs(Component component, InputDefinition input) { + return StorageOperationStatus.OK; + } + @Override public StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policy) { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentPropertyToPolicyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentPropertyToPolicyDeclarator.java index 1d73786938..6bd09c1622 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentPropertyToPolicyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/propertytopolicydeclarators/ComponentPropertyToPolicyDeclarator.java @@ -64,10 +64,15 @@ public class ComponentPropertyToPolicyDeclarator extends DefaultPropertyDeclarat return StorageOperationStatus.OK; } + @Override + public StorageOperationStatus unDeclarePropertiesAsListInputs(Component component, InputDefinition input) { + // no need for implementation since we are in a policy scenario + return StorageOperationStatus.OK; + } + @Override public void addPropertiesListToInput(PropertyDataDefinition declaredProp, InputDefinition input) { // no need for implementation since we are in a policy scenario - return; } @Override diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java index 7da6533570..9f77c5150a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java @@ -44,10 +44,15 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.openecomp.sdc.be.components.impl.DataTypeBusinessLogic; import org.openecomp.sdc.be.components.impl.InputsBusinessLogic; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.datatypes.enums.DeclarationTypeEnum; import org.openecomp.sdc.be.model.ComponentInstInputsMap; import org.openecomp.sdc.be.model.ComponentInstanceInput; @@ -55,10 +60,13 @@ import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.ComponentInstListInput; +import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.web.context.WebApplicationContext; @Loggable(prepend = true, value = Loggable.DEBUG, trim = false) @Api(value = "Input Catalog", description = "Input Servlet") @@ -256,6 +264,14 @@ public class InputsServlet extends AbstractValidationsServlet { } } + private Either parseToComponentInstanceMap(String serviceJson, User user) { + return getComponentsUtils().convertJsonToObjectUsingObjectMapper(serviceJson, user, ComponentInstInputsMap.class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.SERVICE); + } + + private Either parseToComponentInstListInput(String json, User user) { + return getComponentsUtils().convertJsonToObjectUsingObjectMapper(json, user, ComponentInstListInput.class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.SERVICE); + } + @POST @Path("/{componentType}/{componentId}/create/inputs") @ApiOperation(value = "Create inputs on service", httpMethod = "POST", notes = "Return inputs list", response = Resource.class) @@ -268,6 +284,71 @@ public class InputsServlet extends AbstractValidationsServlet { } + /** + * Creates a "list input" and updates given list of properties to get value from the input. + * also a data type which has same properties is created. + * the data type will be the entry_schema of the list input. + * @param componentType the container type (service, resource, ...) + * @param componentId the container ID + * @param request HttpServletRequest object + * @param userId the User ID + * @param componentInstInputsMapObj the list of properties to be declared and the "list input" to be created. + * the type of the input must be "list". + * schema.type of the input will be the name of new data type. + * @return the created input + */ + @POST + @Path("/{componentType}/{componentId}/create/listInput") + @ApiOperation(value = "Create a list input on service", httpMethod = "POST", notes = "Return input", response = Resource.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) + public Response createListInput(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @ApiParam(value = "ComponentIns Inputs Object to be created", required = true) String componentInstInputsMapObj) { + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("#createListInput: Start handle request of {}", url); + Response response = null; + + try { + InputsBusinessLogic businessLogic = getInputBL(context); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); + + Either componentInstInputsMapRes = + parseToComponentInstListInput(componentInstInputsMapObj, modifier); + if (componentInstInputsMapRes.isRight()) { + log.debug("failed to parse componentInstInputsMap"); + response = buildErrorResponse(componentInstInputsMapRes.right().value()); + return response; + } + + ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + ComponentInstListInput componentInstInputsMap = componentInstInputsMapRes.left().value(); + if (log.isDebugEnabled()) { + // for inspection on debug + log.debug("parsed componentInstInputsMap={}", ReflectionToStringBuilder.toString(componentInstInputsMap)); + } + + Either, ResponseFormat> inputPropertiesRes = businessLogic.createListInput( + userId, componentId, componentTypeEnum, componentInstInputsMap, true, false); + if (inputPropertiesRes.isRight()) { + log.debug("failed to create list input for service: {}", componentId); + return buildErrorResponse(inputPropertiesRes.right().value()); + } + Object properties = RepresentationUtils.toRepresentation(inputPropertiesRes.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), properties); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create list input for service with id: " + componentId); + log.debug("createListInput failed with exception", e); + response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + @DELETE @Path("/{componentType}/{componentId}/delete/{inputId}/input") @@ -304,4 +385,142 @@ public class InputsServlet extends AbstractValidationsServlet { } } + /** + * Gets a specific data type associated with a component. + * @param componentType the container type (service, resource, ...) + * @param componentId the container ID + * @param dataTypeName the data type name + * @param request HttpServletRequest object + * @return the data type info + */ + @GET + @Path("/{componentType}/{componentId}/dataType/{dataTypeName}") + @ApiOperation(value = "Get data type in service", httpMethod = "GET", notes = "Get data type in service", + response = DataTypeDefinition.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Data type found"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Data type not found")}) + public Response getDataType( + @PathParam("componentType") final String componentType, + @PathParam("componentId") final String componentId, + @PathParam("dataTypeName") final String dataTypeName, + @Context final HttpServletRequest request + ) { + ServletContext context = request.getSession().getServletContext(); + ComponentsUtils componentsUtils = getComponentsUtils(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(getDataType) Start handle request of {}", url); + Response response; + + try { + DataTypeBusinessLogic businessLogic = getDataTypeBL(context); + Either getResult = businessLogic.getPrivateDataType(componentId, dataTypeName); + if (getResult.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getResult.right().value()); + return buildErrorResponse(componentsUtils.getResponseFormat(actionStatus)); + } + Object json = RepresentationUtils.toRepresentation(getResult.left().value()); + return buildOkResponse(componentsUtils.getResponseFormat(ActionStatus.OK), json); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get data type from service + " + componentId + " + with name: " + dataTypeName); + log.debug("Get data type failed with exception", e); + response = buildErrorResponse(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + /** + * Gets a list of data types which a component has. + * @param componentType the container type (service, resource, ...) + * @param componentId the container ID + * @param request HttpServletRequest object + * @return the list of data types in the component + */ + @GET + @Path("/{componentType}/{componentId}/dataTypes") + @ApiOperation(value = "Get data types that service has", httpMethod = "GET", notes = "Get data types in service", + response = Resource.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Data type found"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Component not found")}) + public Response getDataTypes( + @PathParam("componentType") final String componentType, + @PathParam("componentId") final String componentId, + @Context final HttpServletRequest request + ) { + ServletContext context = request.getSession().getServletContext(); + ComponentsUtils componentsUtils = getComponentsUtils(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(getDataType) Start handle request of {}", url); + Response response; + + try { + DataTypeBusinessLogic businessLogic = getDataTypeBL(context); + Either, StorageOperationStatus> getResult = businessLogic.getPrivateDataTypes(componentId); + if (getResult.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getResult.right().value()); + return buildErrorResponse(componentsUtils.getResponseFormat(actionStatus)); + } + Object json = RepresentationUtils.toRepresentation(getResult.left().value()); + return buildOkResponse(componentsUtils.getResponseFormat(ActionStatus.OK), json); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get data type from service + " + componentId); + log.debug("Get data type failed with exception", e); + response = buildErrorResponse(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + /** + * Deletes a data type from a component. + * @param componentType the container type (service, resource, ...) + * @param componentId the container ID + * @param dataTypeName the data type name to be deleted + * @param request HttpServletRequest object + * @return operation result + */ + @DELETE + @Path("/{componentType}/{componentId}/dataType/{dataTypeName}") + @ApiOperation(value = "Delete data type from service", httpMethod = "DELETE", notes = "Delete service input", + response = Resource.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Data type deleted"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 404, message = "Data type not found")}) + public Response deleteDataType( + @PathParam("componentType") final String componentType, + @PathParam("componentId") final String componentId, + @PathParam("dataTypeName") final String dataTypeName, + @Context final HttpServletRequest request + ) { + ServletContext context = request.getSession().getServletContext(); + ComponentsUtils componentsUtils = getComponentsUtils(); + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("(get) Start handle request of {}", url); + Response response; + + try { + DataTypeBusinessLogic businessLogic = getDataTypeBL(context); + Either deleteResult = businessLogic.deletePrivateDataType(componentId, dataTypeName); + if (deleteResult.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(deleteResult.right().value()); + return buildErrorResponse(componentsUtils.getResponseFormat(actionStatus)); + } + Object json = RepresentationUtils.toRepresentation(deleteResult.left().value()); + return buildOkResponse(componentsUtils.getResponseFormat(ActionStatus.OK), json); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete data type for service + " + componentId + " + with name: " + dataTypeName); + log.debug("Delete data type failed with exception", e); + response = buildErrorResponse(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return response; + } + } + + private DataTypeBusinessLogic getDataTypeBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + return webApplicationContext.getBean(DataTypeBusinessLogic.class); + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java index 405db5a465..baf5b30267 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java @@ -22,6 +22,7 @@ package org.openecomp.sdc.be.tosca; import com.google.gson.Gson; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.stream.JsonReader; import fj.data.Either; @@ -32,6 +33,7 @@ import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.tosca.ToscaFunctions; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.converters.DataTypePropertyConverter; import org.openecomp.sdc.be.model.tosca.converters.ToscaMapValueConverter; @@ -185,25 +187,31 @@ public class PropertyConvertor { log.trace("It's well defined type. convert it"); ToscaValueConverter converter = type.getValueConverter(); return converter.convertToToscaValue(value, innerType, dataTypes); - } else { - log.trace("It's data type or inputs in primitive type. convert as map"); - Object convertedValue; - if (innerConverter != null && (ToscaPropertyType.MAP.equals(type) || ToscaPropertyType.LIST.equals(type))) { - convertedValue = innerConverter.convertToToscaValue(value, innerType, dataTypes); - } else { - if (isScalar) { - // complex json for scalar type - convertedValue = mapConverterInst.handleComplexJsonValue(jsonElement); - } else { - if (innerConverter != null) { - convertedValue = innerConverter.convertToToscaValue(value, innerType, dataTypes); - } else { - convertedValue = mapConverterInst.convertDataTypeToToscaObject(innerType, dataTypes, innerConverter, isScalar, jsonElement, preserveEmptyValue); - } - } + } + log.trace("It's data type or inputs in primitive type. convert as map"); + if (jsonElement.isJsonObject()) { + JsonObject jsonObj = jsonElement.getAsJsonObject(); + // check if value is a get_input function + if (jsonObj.entrySet().size() == 1 && jsonObj.has(ToscaFunctions.GET_INPUT.getFunctionName())) { + Object obj = mapConverterInst.handleComplexJsonValue(jsonElement); + log.debug("It's get_input function. obj={}", obj); + return obj; } - return convertedValue; } + Object convertedValue; + if (innerConverter != null && (ToscaPropertyType.MAP.equals(type) || ToscaPropertyType.LIST.equals(type))) { + convertedValue = innerConverter.convertToToscaValue(value, innerType, dataTypes); + } else if (isScalar) { + // complex json for scalar type + convertedValue = mapConverterInst.handleComplexJsonValue(jsonElement); + } else if (innerConverter != null) { + convertedValue = innerConverter.convertToToscaValue(value, innerType, dataTypes); + } else { + convertedValue = mapConverterInst.convertDataTypeToToscaObject( + innerType, dataTypes, innerConverter, isScalar, jsonElement, preserveEmptyValue); + } + + return convertedValue; } catch (Exception e) { log.debug("convertToToscaValue failed to parse json value :", e); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index 54cf4cf096..65451e9dc5 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -76,7 +76,6 @@ import java.util.stream.Collectors; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.collections.MapUtils.isNotEmpty; -import static org.apache.commons.lang.StringUtils.isNotEmpty; import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceDefinitionElement; import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceTypeElement; @@ -313,6 +312,7 @@ public class ToscaExportHandler { topologyTemplate.setSubstitution_mappings(substitutionMapping); toscaNode.setTopology_template(topologyTemplate); + return Either.left(toscaNode); } @@ -560,6 +560,30 @@ public class ToscaExportHandler { resolveDefaultPropertyValue(inputDef, mergedProperties, dataTypes); toscaNodeType.setProperties(mergedProperties); } + + /* convert private data_types */ + List privateDataTypes = component.getDataTypes(); + if (CollectionUtils.isNotEmpty(privateDataTypes) ) { + Map toscaDataTypeMap = new HashMap<>(); + for (DataTypeDefinition dataType: privateDataTypes) { + log.debug("Emitting private data type: component.name={} dataType.name={}", + component.getNormalizedName(), dataType.getName()); + ToscaDataType toscaDataType = new ToscaDataType(); + toscaDataType.setDerived_from(dataType.getDerivedFromName()); + toscaDataType.setDescription(dataType.getDescription()); + toscaDataType.setVersion(dataType.getVersion()); + if (CollectionUtils.isNotEmpty(dataType.getProperties())) { + toscaDataType.setProperties(dataType.getProperties().stream() + .collect(Collectors.toMap( + s -> s.getName(), + s -> propertyConvertor.convertProperty(dataTypes, s, PropertyConvertor.PropertyType.PROPERTY) + ))); + } + toscaDataTypeMap.put(dataType.getName(), toscaDataType); + } + toscaNode.setData_types(toscaDataTypeMap); + } + // Extracted to method for code reuse return convertReqCapAndTypeName(componentsCache, component, toscaNode, nodeTypes, toscaNodeType, dataTypes); } @@ -570,17 +594,30 @@ public class ToscaExportHandler { for (Map.Entry mergedPropertyEntry : mergedProperties.entrySet()) { ToscaProperty value = mergedPropertyEntry.getValue(); if (Objects.nonNull(value) && value.getDefaultp() instanceof Map) { - Map valueAsMap = (Map) value.getDefaultp(); - String inputName = valueAsMap.get(ToscaFunctions.GET_INPUT.getFunctionName()); - Optional matchedInputDefinition = inputDef.stream() - .filter(componentInput -> componentInput.getName().equals(inputName)) - .findFirst(); - if (matchedInputDefinition.isPresent()) { - InputDefinition matchedInput = matchedInputDefinition.get(); - Object resolvedDefaultValue = new PropertyConvertor().convertToToscaObject(matchedInput.getType(), - matchedInput.getDefaultValue(), matchedInput.getSchemaType(), dataTypes, false); - value.setDefaultp(resolvedDefaultValue); - mergedProperties.put(mergedPropertyEntry.getKey(), value); + Map valueAsMap = (Map) value.getDefaultp(); + Object getInputValue = valueAsMap.get(ToscaFunctions.GET_INPUT.getFunctionName()); + if (getInputValue instanceof String) { + String inputName = (String)getInputValue; + Optional matchedInputDefinition = inputDef.stream() + .filter(componentInput -> componentInput.getName().equals(inputName)) + .findFirst(); + if (matchedInputDefinition.isPresent()) { + InputDefinition matchedInput = matchedInputDefinition.get(); + Object resolvedDefaultValue = new PropertyConvertor().convertToToscaObject(matchedInput.getType(), + matchedInput.getDefaultValue(), matchedInput.getSchemaType(), dataTypes, false); + value.setDefaultp(resolvedDefaultValue); + mergedProperties.put(mergedPropertyEntry.getKey(), value); + } + } else if (getInputValue instanceof List) { + // new get_input syntax to refer to sub-element (introduced from TOSCA v1.3) + // e.g. get_input: [input_name, INDEX, inner_property] + // currently resolving default value for the syntax is not supported + log.debug("#resolveDefaultPropertyValue: ignore get_input list syntax. propname={}, val={}", + mergedPropertyEntry.getKey(), getInputValue); + } else { + // Ignore unknown get_input syntax + log.debug("#resolveDefaultPropertyValue: ignore unknown get_input syntax. propname={}, val={}", + mergedPropertyEntry.getKey(), getInputValue); } } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaDataType.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaDataType.java new file mode 100644 index 0000000000..8a4ec7c301 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaDataType.java @@ -0,0 +1,126 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 Fujitsu Limited. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import java.util.Map; + +/** + * Represents a data type (in data_types in TOSCA model). + */ +public class ToscaDataType { + + private String derived_from; + private String version; + private Map metadata; + private String description; + //private List constraints; + private Map properties; + + /** + * Gets derived_from. + * + * @return Current derived_from value. + */ + public String getDerived_from() { + return derived_from; + } + + /** + * Sets derived_from. + * + * @param derived_from New derived_from value. + */ + public void setDerived_from(String derived_from) { + this.derived_from = derived_from; + } + + /** + * Gets version. + * + * @return Current version value. + */ + public String getVersion() { + return version; + } + + /** + * Sets version. + * + * @param version New version value. + */ + public void setVersion(String version) { + this.version = version; + } + + /** + * Gets metadata map. + * + * @return Current metadata map. + */ + public Map getMetadata() { + return metadata; + } + + /** + * Sets metadata map. + * + * @param metadata New metadata map. + */ + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + /** + * Gets description. + * + * @return Current description value. + */ + public String getDescription() { + return description; + } + + /** + * Sets description. + * + * @param description New description value. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets properties map. + * + * @return Current properties map. + */ + public Map getProperties() { + return properties; + } + + /** + * Sets properties map. + * + * @param properties New properties map. + */ + public void setProperties(Map properties) { + this.properties = properties; + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java index 65a6dbf282..742e8bb233 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java @@ -32,6 +32,7 @@ public class ToscaTemplate { private ToscaMetadata metadata; private List>> imports; private Map interface_types; + private Map data_types; private Map node_types; private ToscaTopolgyTemplate topology_template; @@ -102,5 +103,21 @@ public class ToscaTemplate { this.interface_types = interface_types; } + + /** + * Gets data_types map. + * @return Current data_types map. + */ + public Map getData_types() { + return data_types; + } + + /** + * Sets data_types map. + * @param data_types New data_types map. + */ + public void setData_types(Map data_types) { + this.data_types = data_types; + } } -- cgit 1.2.3-korg