From 3849231a17930b1bb2ba09af15673bfd07538b9d Mon Sep 17 00:00:00 2001 From: KrupaNagabhushan Date: Thu, 19 Nov 2020 14:28:00 +0000 Subject: Create inputs independent of properties Issue-ID: SDC-3431 Signed-off-by: KrupaNagabhushan Change-Id: I4f29d0e490a14292fd1aa9f96ca6621b37f325d8 --- .../files/default/error-configuration.yaml | 17 +++- .../be/components/impl/InputsBusinessLogic.java | 110 ++++++++++++++++++++- .../sdc/be/servlets/BeGenericServlet.java | 56 ++++++++++- .../openecomp/sdc/be/servlets/InputsServlet.java | 62 ++++++++++++ 4 files changed, 240 insertions(+), 5 deletions(-) (limited to 'catalog-be') diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml index 4aa93cb268..ecaf852a16 100644 --- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml +++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml @@ -2410,10 +2410,23 @@ errors: message: 'Error: Invalid Content. %1 has invalid format.', messageId: "SVC4723" } -#---------SVC4732------------------------------ +#---------SVC4734------------------------------ # %1 - list of validation errors INVALID_PM_DICTIONARY_FILE: { code: 400, message: 'Error: Invalid PM Dictionary File. %1', - messageId: "SVC4732" + messageId: "SVC4734" + } +#-----------SVC4735--------------------------- + #%1 - input name + INPUT_ALREADY_EXIST: { + code: 409, + message: "Error: Input with '%1' name already exists.", + messageId: "SVC4735" + } +#---------SVC4736------------------------------ + INVALID_INPUT_NAME: { + code: 400, + message: "Error: Input name contains invalid characters. It should have only letters, numbers and underscores.", + messageId: "SVC4736" } 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 69adb90493..5b197de183 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 @@ -23,6 +23,7 @@ package org.openecomp.sdc.be.components.impl; import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang.BooleanUtils; @@ -33,6 +34,7 @@ import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponent 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.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; import org.openecomp.sdc.be.dao.utils.MapUtil; @@ -40,7 +42,9 @@ import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUti import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; +import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstInputsMap; import org.openecomp.sdc.be.model.ComponentInstListInput; import org.openecomp.sdc.be.model.ComponentInstance; @@ -61,15 +65,16 @@ 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.InterfaceLifecycleOperation; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; +import org.openecomp.sdc.be.resources.data.EntryData; import org.openecomp.sdc.common.log.elements.LoggerSupportability; import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions; import org.openecomp.sdc.common.log.enums.StatusCode; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Arrays; @@ -81,7 +86,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -@Component("inputsBusinessLogic") +@org.springframework.stereotype.Component("inputsBusinessLogic") public class InputsBusinessLogic extends BaseBusinessLogic { private static final String CREATE_INPUT = "CreateInput"; @@ -874,4 +879,105 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } + public Either, ResponseFormat> addInputToComponent(String componentId, + String inputName, + InputDefinition newInputDefinition, + String userId) { + Either, ResponseFormat> result = null; + + validateUserExists(userId); + + Either serviceElement = + toscaOperationFacade.getToscaElement(componentId); + if (serviceElement.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + return result; + } + + Component component = serviceElement.left().value(); + NodeTypeEnum nodeType = component.getComponentType().getNodeType(); + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance() + .logBeFailedLockObjectError(CREATE_INPUT, nodeType.name().toLowerCase(), componentId); + log.info("Failed to lock component {}. Error - {}", componentId, lockResult); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + + try { + if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + return result; + } + + List inputs = component.getInputs(); + + if (CollectionUtils.isEmpty(inputs)) { + inputs = new ArrayList<>(); + } + + if (isInputExistInComponent(inputs, inputName)) { + + result = Either.right(componentsUtils.getResponseFormat(ActionStatus + .INPUT_ALREADY_EXIST, inputName)); + return result; + } + + Map allDataTypes = getAllDataTypes(applicationDataTypeCache); + + // validate input default values + Either defaultValuesValidation = validatePropertyDefaultValue( + newInputDefinition, allDataTypes); + if (defaultValuesValidation.isRight()) { + result = Either.right(defaultValuesValidation.right().value()); + return result; + } + + // convert Input + ToscaPropertyType type = getType(newInputDefinition.getType()); + if (type != null) { + PropertyValueConverter converter = type.getConverter(); + // get inner type + String innerType = null; + SchemaDefinition schema = newInputDefinition.getSchema(); + if (schema != null) { + PropertyDataDefinition prop = schema.getProperty(); + if (prop != null) { + innerType = prop.getType(); + } + } + if (newInputDefinition.getDefaultValue() != null) { + String convertedValue = converter + .convert(newInputDefinition.getDefaultValue(), innerType, allDataTypes); + newInputDefinition.setDefaultValue(convertedValue); + } + } + + Either addInputEither = + toscaOperationFacade.addInputToComponent(inputName, newInputDefinition, component); + + if (addInputEither.isRight()) { + log.info("Failed to add new input {}. Error - {}", componentId, + addInputEither.right().value()); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus + .GENERAL_ERROR)); + return result; + } + + result = Either.left(new EntryData<>(inputName, newInputDefinition)); + return result; + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(componentId, nodeType); + } + } + + private boolean isInputExistInComponent(List inputs, String inputName) { + return CollectionUtils.isNotEmpty(inputs) && + inputs.stream().anyMatch(input -> input.getName().equals(inputName)); + } + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java index b497b702c3..1a8a305d2a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java @@ -68,6 +68,7 @@ import org.openecomp.sdc.be.impl.WebAppContextWrapper; import org.openecomp.sdc.be.model.ComponentInstInputsMap; import org.openecomp.sdc.be.model.PropertyConstraint; import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintJacksonDeserializer; @@ -393,6 +394,19 @@ public class BeGenericServlet extends BasicServlet { return Either.left(propertyDefinition); } + private Either getInputDefinitionFromJson(String componentId, String inputName, JSONObject value) { + String jsonString = value.toJSONString(); + Either convertJsonToObject = convertJsonToObject(jsonString, InputDefinition.class); + if (convertJsonToObject.isRight()) { + return Either.right(convertJsonToObject.right().value()); + } + InputDefinition inputDefinition = convertJsonToObject.left().value(); + String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(componentId, inputName); + inputDefinition.setUniqueId(uniqueId); + + return Either.left(inputDefinition); + } + protected Either, ActionStatus> getPropertiesListForUpdate(String data) { Map properties = new HashMap<>(); @@ -421,7 +435,6 @@ public class BeGenericServlet extends BasicServlet { } - protected String propertyToJson(Map.Entry property) { JSONObject root = new JSONObject(); String propertyName = property.getKey(); @@ -565,4 +578,45 @@ public class BeGenericServlet extends BasicServlet { return getInputBL(context); } + + protected Either, ActionStatus> getInputModel(String componentId, String data) { + JSONParser parser = new JSONParser(); + JSONObject root; + try { + Map inputs = new HashMap<>(); + root = (JSONObject) parser.parse(data); + + Set entrySet = root.entrySet(); + Iterator iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Entry next = (Entry) iterator.next(); + String inputName = (String) next.getKey(); + + if(!isInputNameValid(inputName)) { + return Either.right(ActionStatus.INVALID_INPUT_NAME); + } + + JSONObject value = (JSONObject) next.getValue(); + Either inputDefinitionEither = + getInputDefinitionFromJson(componentId, inputName, value); + + if(inputDefinitionEither.isRight()) { + return Either.right(inputDefinitionEither.right().value()); + } + + inputs.put(inputName, inputDefinitionEither.left().value()); + } + + return Either.left(inputs); + } catch (ParseException e) { + log.warn("Input content is invalid - {}", data, e); + return Either.right(ActionStatus.INVALID_CONTENT); + } + } + + protected boolean isInputNameValid(String inputName) { + return Objects.nonNull(inputName) + && inputName.matches(PROPERTY_NAME_REGEX); + + } } 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 bff8436fa4..1f80b4be87 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 @@ -57,6 +57,7 @@ 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.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.EntryData; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; import org.openecomp.sdc.be.user.UserBusinessLogic; import org.openecomp.sdc.common.api.Constants; @@ -84,6 +85,7 @@ import javax.ws.rs.core.Response; import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.Map; @Loggable(prepend = true, value = Loggable.DEBUG, trim = false) @Tags({@Tag(name = "SDC Internal APIs")}) @@ -97,6 +99,7 @@ public class InputsServlet extends AbstractValidationsServlet { private static final Logger log = Logger.getLogger(InputsServlet.class); private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(InputsServlet.class.getName()); private static final String START_HANDLE_REQUEST_OF = "(get) Start handle request of {}"; + private static final String CREATE_INPUT = "CreateInput"; private final DataTypeBusinessLogic businessLogic; private final InputsBusinessLogic inputsBusinessLogic; @@ -334,6 +337,21 @@ public class InputsServlet extends AbstractValidationsServlet { DeclarationTypeEnum.INPUT, request); } + @POST + @Path("/{componentType}/{componentId}/create/input") + @Operation(description = "Create inputs on service", method = "POST", summary = "Return inputs list", responses = { + @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))), + @ApiResponse(responseCode = "200", description = "Component found"), + @ApiResponse(responseCode = "403", description = "Restricted operation"), + @ApiResponse(responseCode = "404", description = "Component not found")}) + public Response createInput(@PathParam("componentType") final String componentType, + @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + @Parameter(description = "ComponentIns Inputs Object to be created", + required = true) String componentInstInputsMapObj) { + + return createInput(componentId, componentInstInputsMapObj, request, userId); + } /** * Creates a "list input" and updates given list of properties to get value from the input. @@ -566,4 +584,48 @@ public class InputsServlet extends AbstractValidationsServlet { return response; } } + + private Response createInput(String componentId, String data, HttpServletRequest request,String userId) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data); + loggerSupportability.log(LoggerSupportabilityActions.CREATE_INPUTS, StatusCode.STARTED,"CREATE_INPUTS by user {} ", userId); + + try{ + Either, ActionStatus> inputDefinition = + getInputModel(componentId, data); + if (inputDefinition.isRight()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(inputDefinition.right().value()); + return buildErrorResponse(responseFormat); + } + + Map inputs = inputDefinition.left().value(); + if (inputs == null || inputs.size() != 1) { + log.info("Input content is invalid - {}", data); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + return buildErrorResponse(responseFormat); + } + + Map.Entry entry = inputs.entrySet().iterator().next(); + InputDefinition newInputDefinition = entry.getValue(); + newInputDefinition.setParentUniqueId(componentId); + String inputName = newInputDefinition.getName(); + + Either, ResponseFormat> addInputEither = + inputsBusinessLogic.addInputToComponent(componentId, inputName, newInputDefinition, userId); + + if(addInputEither.isRight()) { + return buildErrorResponse(addInputEither.right().value()); + } + + loggerSupportability.log(LoggerSupportabilityActions.CREATE_INPUTS, StatusCode.COMPLETE,"CREATE_INPUTS by user {} ", userId); + return buildOkResponse(newInputDefinition); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_INPUT); + log.debug("create input failed with exception", e); + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } } -- cgit 1.2.3-korg