diff options
Diffstat (limited to 'openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services')
5 files changed, 2082 insertions, 0 deletions
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/composition/CompositionDataExtractorImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/composition/CompositionDataExtractorImpl.java new file mode 100644 index 0000000000..d72a0dbe23 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/composition/CompositionDataExtractorImpl.java @@ -0,0 +1,470 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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.vendorsoftwareproduct.services.impl.composition; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; +import org.openecomp.sdc.common.errors.CoreException; +import org.openecomp.sdc.datatypes.error.ErrorLevel; +import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage; +import org.openecomp.sdc.logging.context.impl.MdcDataErrorMessage; +import org.openecomp.sdc.logging.types.LoggerConstants; +import org.openecomp.sdc.logging.types.LoggerErrorCode; +import org.openecomp.sdc.logging.types.LoggerErrorDescription; +import org.openecomp.sdc.logging.types.LoggerTragetServiceName; +import org.openecomp.sdc.tosca.datatypes.ToscaCapabilityType; +import org.openecomp.sdc.tosca.datatypes.ToscaFunctions; +import org.openecomp.sdc.tosca.datatypes.ToscaNodeType; +import org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType; +import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel; +import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate; +import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition; +import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment; +import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate; +import org.openecomp.sdc.tosca.errors.ToscaInvalidEntryNotFoundErrorBuilder; +import org.openecomp.sdc.tosca.errors.ToscaInvalidSubstituteNodeTemplateErrorBuilder; +import org.openecomp.sdc.tosca.errors.ToscaMissingSubstitutionMappingForReqCapErrorBuilder; +import org.openecomp.sdc.tosca.services.ToscaAnalyzerService; +import org.openecomp.sdc.tosca.services.ToscaConstants; +import org.openecomp.sdc.tosca.services.impl.ToscaAnalyzerServiceImpl; +import org.openecomp.sdc.tosca.services.yamlutil.ToscaExtensionYamlUtil; +import org.openecomp.sdc.vendorsoftwareproduct.services.composition.CompositionDataExtractor; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Component; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComponentData; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionData; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ExtractCompositionDataContext; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Network; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Nic; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class CompositionDataExtractorImpl implements CompositionDataExtractor { + + protected static Logger logger; + private static ToscaAnalyzerService toscaAnalyzerService; + private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage(); + + static { + logger = LoggerFactory.getLogger(CompositionDataExtractorImpl.class); + toscaAnalyzerService = new ToscaAnalyzerServiceImpl(); + } + + /** + * Extract service composition data composition data. + * + * @param toscaServiceModel the tosca service model + * @return the composition data + */ + public CompositionData extractServiceCompositionData(ToscaServiceModel toscaServiceModel) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + ExtractCompositionDataContext context = new ExtractCompositionDataContext(); + String entryDefinitionServiceTemplateFileName = + toscaServiceModel.getEntryDefinitionServiceTemplate(); + ServiceTemplate entryDefinitionServiceTemplate = + toscaServiceModel.getServiceTemplates().get(entryDefinitionServiceTemplateFileName); + extractServiceCompositionData(entryDefinitionServiceTemplateFileName, + entryDefinitionServiceTemplate, toscaServiceModel, context); + + CompositionData compositionData = new CompositionData(); + compositionData.setNetworks(context.getNetworks()); + compositionData.setComponents(context.getComponents()); + + mdcDataDebugMessage.debugExitMessage(null); + return compositionData; + } + + private void extractServiceCompositionData(String serviceTemplateFileName, + ServiceTemplate serviceTemplate, + ToscaServiceModel toscaServiceModel, + ExtractCompositionDataContext context) { + if (context.getHandledServiceTemplates().contains(serviceTemplateFileName)) { + return; + } + context.addNetworks(extractNetworks(serviceTemplate, toscaServiceModel)); + extractComponents(serviceTemplate, toscaServiceModel, context); + handleSubstitution(serviceTemplate, toscaServiceModel, context); + context.addHandledServiceTemplates(serviceTemplateFileName); + } + + private void handleSubstitution(ServiceTemplate serviceTemplate, + ToscaServiceModel toscaServiceModel, + ExtractCompositionDataContext context) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + Map<String, NodeTemplate> substitutableNodeTemplates = + toscaAnalyzerService.getSubstitutableNodeTemplates(serviceTemplate); + + if (substitutableNodeTemplates != null) { + for (String substitutableNodeTemplateId : substitutableNodeTemplates.keySet()) { + handleSubstitutableNodeTemplate(serviceTemplate, toscaServiceModel, + substitutableNodeTemplateId, + substitutableNodeTemplates.get(substitutableNodeTemplateId), context); + } + } + + mdcDataDebugMessage.debugExitMessage(null); + } + + private void handleSubstitutableNodeTemplate(ServiceTemplate serviceTemplate, + ToscaServiceModel toscaServiceModel, + String substitutableNodeTemplateId, + NodeTemplate substitutableNodeTemplate, + ExtractCompositionDataContext context) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil(); + Optional<String> substituteServiceTemplateFileName = toscaAnalyzerService + .getSubstituteServiceTemplateName(substitutableNodeTemplateId, substitutableNodeTemplate); + if (!substituteServiceTemplateFileName.isPresent()) { + MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API, + LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(), + LoggerErrorCode.DATA_ERROR.getErrorCode(), + LoggerErrorDescription.EXTRACT_COMPOSITION_DATA); + throw new CoreException( + new ToscaInvalidSubstituteNodeTemplateErrorBuilder(substitutableNodeTemplateId).build()); + } + if (context.getHandledServiceTemplates().contains(substituteServiceTemplateFileName.get())) { + //each substitution is should be handled once, and will get the connection to the upper + // service level according to the first one which was processed + mdcDataDebugMessage.debugExitMessage(null); + return; + } + + ServiceTemplate substituteServiceTemplate = + toscaServiceModel.getServiceTemplates().get(substituteServiceTemplateFileName.get()); + extractServiceCompositionData(substituteServiceTemplateFileName.get(), + substituteServiceTemplate, toscaServiceModel, context); + + List<Map<String, RequirementAssignment>> substitutableRequirements = + substitutableNodeTemplate.getRequirements(); + + if (CollectionUtils.isEmpty(substitutableRequirements)) { + mdcDataDebugMessage.debugExitMessage(null); + return; + } + + for (Map<String, RequirementAssignment> substitutableReq : substitutableRequirements) { + substitutableReq.keySet().stream().filter(reqId -> { + RequirementAssignment reqAssignment = toscaExtensionYamlUtil + .yamlToObject(toscaExtensionYamlUtil.objectToYaml(substitutableReq.get(reqId)), + RequirementAssignment.class); + + mdcDataDebugMessage.debugExitMessage(null); + return isLinkToNetworkRequirementAssignment(reqAssignment); + }).forEach(reqId -> { + RequirementAssignment linkToNetworkRequirement = toscaExtensionYamlUtil + .yamlToObject(toscaExtensionYamlUtil.objectToYaml(substitutableReq.get(reqId)), + RequirementAssignment.class); + String connectedNodeId = linkToNetworkRequirement.getNode(); + Optional<NodeTemplate> connectedNodeTemplate = + toscaAnalyzerService.getNodeTemplateById(serviceTemplate, connectedNodeId); + + if (connectedNodeTemplate.isPresent() && toscaAnalyzerService + .isTypeOf(connectedNodeTemplate.get(), ToscaNodeType.NATIVE_NETWORK, + serviceTemplate, toscaServiceModel)) { + Optional<Map.Entry<String, NodeTemplate>> mappedNodeTemplate = toscaAnalyzerService + .getSubstitutionMappedNodeTemplateByExposedReq( + substituteServiceTemplateFileName.get(), substituteServiceTemplate, reqId); + if (!mappedNodeTemplate.isPresent()) { + MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API, + LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(), + LoggerErrorCode.DATA_ERROR.getErrorCode(), + LoggerErrorDescription.EXTRACT_COMPOSITION_DATA); + throw new CoreException(new ToscaMissingSubstitutionMappingForReqCapErrorBuilder( + ToscaMissingSubstitutionMappingForReqCapErrorBuilder.MappingExposedEntry + .REQUIREMENT, connectedNodeId).build()); + } + + if (toscaAnalyzerService.isTypeOf(mappedNodeTemplate.get().getValue(), + ToscaNodeType.NATIVE_NETWORK_PORT, serviceTemplate, + toscaServiceModel)) { + Nic port = context.getNics().get(mappedNodeTemplate.get().getKey()); + if (port != null) { + port.setNetworkName(connectedNodeId); + } else { + logger.warn( + "Different ports define for the same component which is used in different " + + "substitution service templates."); + } + } + } else if (!connectedNodeTemplate.isPresent()) { + MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API, + LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(), + LoggerErrorCode.DATA_ERROR.getErrorCode(), + LoggerErrorDescription.EXTRACT_COMPOSITION_DATA); + throw new CoreException( + new ToscaInvalidEntryNotFoundErrorBuilder("Node Template", connectedNodeId).build()); + } + }); + } + } + + private boolean isLinkToNetworkRequirementAssignment(RequirementAssignment requirement) { + return toscaAnalyzerService.isDesiredRequirementAssignment(requirement, + ToscaCapabilityType.NATIVE_NETWORK_LINKABLE, null, + ToscaRelationshipType.NATIVE_NETWORK_LINK_TO); + } + + + private void connectPortToNetwork(Nic port, NodeTemplate portNodeTemplate) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + List<RequirementAssignment> linkRequirementsToNetwork = + toscaAnalyzerService.getRequirements(portNodeTemplate, ToscaConstants.LINK_REQUIREMENT_ID); + + //port is connected to one network + for (RequirementAssignment linkRequirementToNetwork : linkRequirementsToNetwork) { + port.setNetworkName(linkRequirementToNetwork.getNode()); + } + + mdcDataDebugMessage.debugExitMessage(null); + } + + /* + return Map with key - compute node template id, value - list of connected port node template id + */ + private Map<String, List<String>> getComputeToPortsConnection( + Map<String, NodeTemplate> portNodeTemplates) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + Map<String, List<String>> computeToPortConnection = new HashMap<>(); + if (MapUtils.isEmpty(portNodeTemplates)) { + return computeToPortConnection; + } + for (String portId : portNodeTemplates.keySet()) { + List<RequirementAssignment> bindingRequirementsToCompute = toscaAnalyzerService + .getRequirements(portNodeTemplates.get(portId), ToscaConstants.BINDING_REQUIREMENT_ID); + for (RequirementAssignment bindingRequirementToCompute : bindingRequirementsToCompute) { + computeToPortConnection + .putIfAbsent(bindingRequirementToCompute.getNode(), new ArrayList<>()); + computeToPortConnection.get(bindingRequirementToCompute.getNode()).add(portId); + } + } + + mdcDataDebugMessage.debugExitMessage(null); + return computeToPortConnection; + } + + private void extractComponents(ServiceTemplate serviceTemplate, + ToscaServiceModel toscaServiceModel, + ExtractCompositionDataContext context) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + Map<String, NodeTemplate> computeNodeTemplates = toscaAnalyzerService + .getNodeTemplatesByType(serviceTemplate, ToscaNodeType.NATIVE_COMPUTE, + toscaServiceModel); + if (MapUtils.isEmpty(computeNodeTemplates)) { + return; + } + Map<String, NodeTemplate> portNodeTemplates = toscaAnalyzerService + .getNodeTemplatesByType(serviceTemplate, ToscaNodeType.NATIVE_NETWORK_PORT, + toscaServiceModel); + Map<String, List<String>> computeToPortsConnection = + getComputeToPortsConnection(portNodeTemplates); + Map<String, List<String>> computesGroupedByType = + getNodeTemplatesGroupedByType(computeNodeTemplates); + + computesGroupedByType.keySet() + .stream() + .filter(nodeType -> + !context.getCreatedComponents().contains(nodeType)) + .forEach(nodeType -> extractComponent(serviceTemplate, computeToPortsConnection, + computesGroupedByType, nodeType, context)); + + mdcDataDebugMessage.debugExitMessage(null); + } + + private void extractComponent(ServiceTemplate serviceTemplate, + Map<String, List<String>> computeToPortsConnection, + Map<String, List<String>> computesGroupedByType, + String computeNodeType, + ExtractCompositionDataContext context) { + ComponentData component = new ComponentData(); + component.setName(computeNodeType); + component.setDisplayName(getComponentDisplayName(component.getName())); + component.setVfcCode(component.getDisplayName()); + Component componentModel = new Component(); + componentModel.setData(component); + + String computeId = computesGroupedByType.get(computeNodeType).get(0); + List<String> connectedPortIds = computeToPortsConnection.get(computeId); + + if (connectedPortIds != null) { + componentModel.setNics(new ArrayList<>()); + for (String portId : connectedPortIds) { + Nic port = extractPort(serviceTemplate, portId); + componentModel.getNics().add(port); + context.addNic(portId, port); + } + } + context.addComponent(componentModel); + context.getCreatedComponents().add(computeNodeType); + } + + private Nic extractPort(ServiceTemplate serviceTemplate, String portNodeTemplateId) { + Optional<NodeTemplate> portNodeTemplate = + toscaAnalyzerService.getNodeTemplateById(serviceTemplate, portNodeTemplateId); + if (portNodeTemplate.isPresent()) { + Nic port = new Nic(); + port.setName(portNodeTemplateId); + connectPortToNetwork(port, portNodeTemplate.get()); + return port; + } else { + MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API, + LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(), + LoggerErrorCode.DATA_ERROR.getErrorCode(), + LoggerErrorDescription.EXTRACT_COMPOSITION_DATA); + throw new CoreException( + new ToscaInvalidEntryNotFoundErrorBuilder("Node Template", portNodeTemplateId).build()); + } + } + + + private Map<String, List<String>> getNodeTemplatesGroupedByType( + Map<String, NodeTemplate> nodeTemplates) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + Map<String, List<String>> nodeTemplatesGrouped = + new HashMap<>(); //key - node type, value - list of node ids with this type + for (String nodeId : nodeTemplates.keySet()) { + String nodeType = nodeTemplates.get(nodeId).getType(); + nodeTemplatesGrouped.putIfAbsent(nodeType, new ArrayList<>()); + nodeTemplatesGrouped.get(nodeType).add(nodeId); + } + + mdcDataDebugMessage.debugExitMessage(null); + return nodeTemplatesGrouped; + } + + private List<Network> extractNetworks(ServiceTemplate serviceTemplate, + ToscaServiceModel toscaServiceModel) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + List<Network> networks = new ArrayList<>(); + Map<String, NodeTemplate> networkNodeTemplates = toscaAnalyzerService + .getNodeTemplatesByType(serviceTemplate, ToscaNodeType.NATIVE_NETWORK, + toscaServiceModel); + if (MapUtils.isEmpty(networkNodeTemplates)) { + mdcDataDebugMessage.debugExitMessage(null); + return networks; + } + for (String networkId : networkNodeTemplates.keySet()) { + Network network = new Network(); + network.setName(networkId); + Optional<Boolean> networkDhcpValue = + getNetworkDhcpValue(serviceTemplate, networkNodeTemplates.get(networkId)); + network.setDhcp(networkDhcpValue.isPresent() ? networkDhcpValue.get() : true); + networks.add(network); + } + + mdcDataDebugMessage.debugExitMessage(null); + return networks; + } + + //dhcp default value is true + private Optional<Boolean> getNetworkDhcpValue(ServiceTemplate serviceTemplate, + NodeTemplate networkNodeTemplate) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + if (networkNodeTemplate == null) { + return Optional.empty(); + } + if (networkNodeTemplate.getProperties() == null + || networkNodeTemplate.getProperties().get(ToscaConstants.DHCP_ENABLED_PROPERTY_NAME) + == null) { + mdcDataDebugMessage.debugExitMessage(null); + return Optional.of(true); + } + + Object dhcp = + networkNodeTemplate.getProperties().get(ToscaConstants.DHCP_ENABLED_PROPERTY_NAME); + if (dhcp instanceof String) { + mdcDataDebugMessage.debugExitMessage(null); + return Optional.of(Boolean.valueOf((String) dhcp)); + } else if (dhcp instanceof Boolean) { + mdcDataDebugMessage.debugExitMessage(null); + return Optional.of((Boolean) dhcp); + } else if (dhcp instanceof Map) { + String inputParameterName = + (String) ((Map) dhcp).get(ToscaFunctions.GET_INPUT.getDisplayName()); + if (inputParameterName != null) { + ParameterDefinition inputParameterDefinition = + serviceTemplate.getTopology_template().getInputs().get(inputParameterName); + if (inputParameterDefinition != null) { + if (inputParameterDefinition.get_default() != null) { + mdcDataDebugMessage.debugExitMessage(null); + return Optional.of(Boolean.valueOf(inputParameterDefinition.get_default().toString())); + } + } else { + MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API, + LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(), + LoggerErrorCode.DATA_ERROR.getErrorCode(), + LoggerErrorDescription.EXTRACT_COMPOSITION_DATA); + throw new CoreException( + new ToscaInvalidEntryNotFoundErrorBuilder("Input Parameter", inputParameterName) + .build()); + } + } + } + + mdcDataDebugMessage.debugExitMessage(null); + return Optional.of(true); + } + + @Override + public String getComponentDisplayName(String componentName) { + if (componentName == null) { + return null; + } + String delimiterChar = "."; + if (componentName.contains(delimiterChar)) { + return componentName.substring(componentName.lastIndexOf(delimiterChar) + 1); + } + return componentName; + + } + +} diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/composition/CompositionEntityDataManagerImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/composition/CompositionEntityDataManagerImpl.java new file mode 100644 index 0000000000..81cacf75ac --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/composition/CompositionEntityDataManagerImpl.java @@ -0,0 +1,585 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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.vendorsoftwareproduct.services.impl.composition; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.openecomp.core.utilities.json.JsonSchemaDataGenerator; +import org.openecomp.core.utilities.json.JsonUtil; +import org.openecomp.sdc.common.errors.CoreException; +import org.openecomp.sdc.common.errors.ErrorCategory; +import org.openecomp.sdc.common.errors.ErrorCode; +import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage; +import org.openecomp.sdc.vendorsoftwareproduct.dao.ComponentDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.NetworkDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentEntity; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.CompositionEntity; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NetworkEntity; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NicEntity; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspQuestionnaireEntity; +import org.openecomp.sdc.vendorsoftwareproduct.services.composition.CompositionEntityDataManager; +import org.openecomp.sdc.vendorsoftwareproduct.services.schemagenerator.SchemaGenerator; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Component; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComponentData; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionData; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityId; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityType; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityValidationData; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Network; +import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Nic; +import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateContext; +import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateInput; +import org.openecomp.sdc.versioning.dao.types.Version; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +public class CompositionEntityDataManagerImpl implements CompositionEntityDataManager { + + private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR = + "COMPOSITION_ENTITY_DATA_MANAGER_ERR"; + private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG = + "Invalid input: %s may not be null"; + + private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage(); + + private Map<CompositionEntityId, CompositionEntityData> entities = new HashMap<>(); + private Map<CompositionEntityType, String> nonDynamicSchemas = new HashMap<>(); + private List<CompositionEntityValidationData> roots = new ArrayList<>(); + + private VendorSoftwareProductInfoDao vspInfoDao; + private ComponentDao componentDao; + private NicDao nicDao; + private NetworkDao networkDao; + + public CompositionEntityDataManagerImpl(VendorSoftwareProductInfoDao vspInfoDao, + ComponentDao componentDao, + NicDao nicDao, NetworkDao networkDao) { + this.vspInfoDao = vspInfoDao; + this.componentDao = componentDao; + this.nicDao = nicDao; + this.networkDao = networkDao; + } + + /** + * Validate entity composition entity validation data. + * + * @param entity the entity + * @param schemaTemplateContext the schema template context + * @param schemaTemplateInput the schema template input + * @return the composition entity validation data + */ + @Override + public CompositionEntityValidationData validateEntity(CompositionEntity entity, + SchemaTemplateContext schemaTemplateContext, + SchemaTemplateInput schemaTemplateInput) { + mdcDataDebugMessage.debugEntryMessage(null); + + if (entity == null) { + throw new CoreException( + new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION) + .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage( + String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity")) + .build()); + } + if (schemaTemplateContext == null) { + throw new CoreException( + new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION) + .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage( + String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "schema template context")) + .build()); + } + + CompositionEntityValidationData validationData = + new CompositionEntityValidationData(entity.getType(), entity.getId()); + String json = + schemaTemplateContext == SchemaTemplateContext.composition ? entity.getCompositionData() + : entity.getQuestionnaireData(); + validationData.setErrors(JsonUtil.validate( + json == null ? JsonUtil.object2Json(new Object()) : json, + generateSchema(schemaTemplateContext, entity.getType(), schemaTemplateInput))); + + mdcDataDebugMessage.debugExitMessage(null); + return validationData; + } + + /** + * Add entity. + * + * @param entity the entity + * @param schemaTemplateInput the schema template input + */ + @Override + public void addEntity(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) { + if (entity == null) { + throw new CoreException( + new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION) + .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage( + String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity")) + .build()); + } + entities.put(entity.getCompositionEntityId(), + new CompositionEntityData(entity, schemaTemplateInput)); + } + + /** + * Validate entities questionnaire map. + * + * @return the map + */ + @Override + public Map<CompositionEntityId, Collection<String>> validateEntitiesQuestionnaire() { + mdcDataDebugMessage.debugEntryMessage(null); + + Map<CompositionEntityId, Collection<String>> errorsByEntityId = new HashMap<>(); + entities.entrySet().forEach(entry -> { + Collection<String> errors = validateQuestionnaire(entry.getValue()); + if (errors != null) { + errorsByEntityId.put(entry.getKey(), errors); + } + }); + + mdcDataDebugMessage.debugExitMessage(null); + return errorsByEntityId; + } + + /** + * Build trees. + */ + @Override + public void buildTrees() { + Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData = + new HashMap<>(); + entities.entrySet().forEach( + entry -> addValidationDataEntity(entitiesValidationData, entry.getKey(), + entry.getValue().entity)); + } + + public Collection<CompositionEntityValidationData> getTrees() { + return roots; + } + + @Override + public void saveCompositionData(String vspId, Version version, CompositionData compositionData) { + mdcDataDebugMessage.debugEntryMessage(null); + + if (Objects.isNull(compositionData)) { + return; + } + + Map<String, String> networkIdByName = saveNetworks(vspId, version, compositionData); + saveComponents(vspId, version, compositionData, networkIdByName); + + mdcDataDebugMessage.debugExitMessage(null); + } + + @Override + public Set<CompositionEntityValidationData> getAllErrorsByVsp(String vspId) { + CompositionEntityValidationData matchVsp = null; + Set<CompositionEntityValidationData> entitiesWithErrors = new HashSet<>(); + for (CompositionEntityValidationData root : roots) { + if (root.getEntityId().equals(vspId)) { + matchVsp = root; + break; + } + } + + getEntityListWithErrors(matchVsp, entitiesWithErrors); + if (CollectionUtils.isNotEmpty(entitiesWithErrors)) { + updateValidationCompositionEntityName(entitiesWithErrors); + return entitiesWithErrors; + } + + return null; + } + + private boolean isThereErrorsInSubTree(CompositionEntityValidationData entity) { + if (Objects.isNull(entity)) { + return false; + } + + if (CollectionUtils.isNotEmpty(entity.getErrors())) { + return true; + } + + Collection<CompositionEntityValidationData> subEntitiesValidationData = + entity.getSubEntitiesValidationData(); + return !CollectionUtils.isEmpty(subEntitiesValidationData) && + checkForErrorsInChildren(subEntitiesValidationData); + + } + + private boolean checkForErrorsInChildren( + Collection<CompositionEntityValidationData> subEntitiesValidationData) { + boolean result = false; + for (CompositionEntityValidationData subEntity : subEntitiesValidationData) { + if (CollectionUtils.isNotEmpty(subEntity.getErrors())) { + return true; + } + + result = result || isThereErrorsInSubTree(subEntity); + if (result) { + return true; + } + } + return false; + } + + public void saveComponents(String vspId, Version version, CompositionData compositionData, + Map<String, String> networkIdByName) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + if (CollectionUtils.isNotEmpty(compositionData.getComponents())) { + for (Component component : compositionData.getComponents()) { + ComponentEntity componentEntity = new ComponentEntity(vspId, version, null); + componentEntity.setComponentCompositionData(component.getData()); + + String componentId = createComponent(componentEntity).getId(); + + saveNicsByComponent(vspId, version, networkIdByName, component, componentId); + } + } + + mdcDataDebugMessage.debugExitMessage(null); + } + + public void saveNicsByComponent(String vspId, Version version, + Map<String, String> networkIdByName, Component component, + String componentId) { + if (CollectionUtils.isNotEmpty(component.getNics())) { + for (Nic nic : component.getNics()) { + if (nic.getNetworkName() != null && MapUtils.isNotEmpty(networkIdByName)) { + nic.setNetworkId(networkIdByName.get(nic.getNetworkName())); + } + nic.setNetworkName(null); + + NicEntity nicEntity = new NicEntity(vspId, version, componentId, null); + nicEntity.setNicCompositionData(nic); + createNic(nicEntity); + } + } + } + + public Map<String, String> saveNetworks(String vspId, Version version, + CompositionData compositionData) { + mdcDataDebugMessage.debugEntryMessage(null); + + Map<String, String> networkIdByName = new HashMap<>(); + if (CollectionUtils.isNotEmpty(compositionData.getNetworks())) { + for (Network network : compositionData.getNetworks()) { + + NetworkEntity networkEntity = new NetworkEntity(vspId, version, null); + networkEntity.setNetworkCompositionData(network); + + if (network.getName() != null) { + networkIdByName.put(network.getName(), createNetwork(networkEntity).getId()); + } + } + } + + mdcDataDebugMessage.debugExitMessage(null); + return networkIdByName; + } + + @Override + public NetworkEntity createNetwork(NetworkEntity network) { + mdcDataDebugMessage.debugEntryMessage(null); + + //network.setId(CommonMethods.nextUuId()); will be set by the dao + networkDao.create(network); + mdcDataDebugMessage.debugExitMessage(null); + return network; + } + + @Override + public ComponentEntity createComponent(ComponentEntity component) { + mdcDataDebugMessage.debugEntryMessage(null); + + //component.setId(CommonMethods.nextUuId()); will be set by the dao + component.setQuestionnaireData( + new JsonSchemaDataGenerator( + generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.component, + null)) + .generateData()); + + componentDao.create(component); + + mdcDataDebugMessage.debugExitMessage(null); + return component; + } + + @Override + public NicEntity createNic(NicEntity nic) { + mdcDataDebugMessage.debugEntryMessage(null); + + //nic.setId(CommonMethods.nextUuId()); will be set by the dao + nic.setQuestionnaireData( + new JsonSchemaDataGenerator( + generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.nic, null)) + .generateData()); + + nicDao.create(nic); + + mdcDataDebugMessage.debugExitMessage(null); + return nic; + } + + + public void addErrorsToTrees(Map<CompositionEntityId, Collection<String>> errors) { + roots.forEach(root -> addErrorsToTree(root, null, errors)); + } + + /* * + * get a flat list of all questionnaire entities that have validation errors + * */ + public Set<CompositionEntityValidationData> getEntityListWithErrors() { + mdcDataDebugMessage.debugEntryMessage(null); + Set<CompositionEntityValidationData> treeAsList = new HashSet<>(); + + for (CompositionEntityValidationData entity : roots) { + if (CollectionUtils.isNotEmpty(entity.getErrors())) { + addNodeWithErrors(entity, treeAsList); + } + getEntityListWithErrors(entity, treeAsList); + } + + updateValidationCompositionEntityName(treeAsList); + + mdcDataDebugMessage.debugExitMessage(null); + return treeAsList; + } + + public void getEntityListWithErrors(CompositionEntityValidationData entity, + Set<CompositionEntityValidationData> compositionSet) { + Collection<CompositionEntityValidationData> childNodes = + entity.getSubEntitiesValidationData(); + + if (CollectionUtils.isEmpty(childNodes)) { + return; + } + + for (CompositionEntityValidationData child : childNodes) { + if (CollectionUtils.isNotEmpty(child.getErrors())) { + addNodeWithErrors(child, compositionSet); + } + getEntityListWithErrors(child, compositionSet); + } + } + + + public void addNodeWithErrors(CompositionEntityValidationData node, + Set<CompositionEntityValidationData> entitiesWithErrors) { + CompositionEntityValidationData compositionNodeToAdd = new CompositionEntityValidationData(node + .getEntityType(), node.getEntityId()); + compositionNodeToAdd.setErrors(node.getErrors()); + compositionNodeToAdd.setSubEntitiesValidationData(null); + + entitiesWithErrors.add(compositionNodeToAdd); + } + + public void removeNodesWithoutErrors() { + roots.forEach(root -> removeNodesWithoutErrors(root, null)); + } + + + private CompositionEntityData getCompositionEntityDataById(CompositionEntityValidationData + entity) { + for (Map.Entry<CompositionEntityId, CompositionEntityData> entityEntry : entities + .entrySet()) { + if (entityEntry.getKey().getId().equals(entity.getEntityId())) { + return entityEntry.getValue(); + } + } + return null; + } + + + private void updateValidationCompositionEntityName(Set<CompositionEntityValidationData> + compositionSet) { + for (CompositionEntityValidationData entity : compositionSet) { + String compositionData = getCompositionDataAsString(entity); + if (entity.getEntityType().equals(CompositionEntityType.vsp) || + Objects.nonNull(compositionData)) { + entity.setEntityName(getEntityNameByEntityType(compositionData, entity)); + } + } + } + + private String getCompositionDataAsString(CompositionEntityValidationData entity) { + CompositionEntityData compositionEntityData = getCompositionEntityDataById(entity); + return compositionEntityData == null ? null : compositionEntityData.entity.getCompositionData(); + } + + + private String getEntityNameByEntityType(String compositionData, + CompositionEntityValidationData entity) { + switch (entity.getEntityType()) { + case component: + ComponentData component = JsonUtil.json2Object(compositionData, ComponentData.class); + return component.getDisplayName(); + + case nic: + Nic nic = JsonUtil.json2Object(compositionData, Nic.class); + return nic.getName(); + + case network: + Network network = JsonUtil.json2Object(compositionData, Network.class); + return network.getName(); + + case vsp: + CompositionEntityData vspEntity = getCompositionEntityDataById(entity); + VspQuestionnaireEntity vspQuestionnaireEntity = (VspQuestionnaireEntity) vspEntity.entity; + VspDetails vspDetails = + vspInfoDao.get(new VspDetails(vspQuestionnaireEntity.getId(), + vspQuestionnaireEntity.getVersion())); + return vspDetails.getName(); + } + + return null; + } + + private void removeNodesWithoutErrors(CompositionEntityValidationData node, + CompositionEntityValidationData parent) { + + if (Objects.isNull(node)) { + return; + } + + if (hasChildren(node)) { + Collection<CompositionEntityValidationData> subNodes = + new ArrayList<>(node.getSubEntitiesValidationData()); + subNodes.forEach(subNode -> removeNodesWithoutErrors(subNode, node)); + node.setSubEntitiesValidationData(subNodes); + + if (canNodeGetRemovedFromValidationDataTree(node)) { + removeNodeFromChildren(parent, node); + } + } else if (canNodeGetRemovedFromValidationDataTree(node)) { + removeNodeFromChildren(parent, node); + } + } + + private void removeNodeFromChildren(CompositionEntityValidationData parent, + CompositionEntityValidationData childToRemove) { + if (!Objects.isNull(parent)) { + parent.getSubEntitiesValidationData().remove(childToRemove); + } + } + + private boolean hasChildren(CompositionEntityValidationData node) { + return !CollectionUtils.isEmpty(node.getSubEntitiesValidationData()); + } + + private boolean canNodeGetRemovedFromValidationDataTree(CompositionEntityValidationData node) { + return !hasChildren(node) && CollectionUtils.isEmpty(node.getErrors()); + } + + + private void addValidationDataEntity( + Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData, + CompositionEntityId entityId, CompositionEntity entity) { + if (entitiesValidationData.containsKey(entityId)) { + return; + } + + CompositionEntityValidationData validationData = + new CompositionEntityValidationData(entity.getType(), entity.getId()); + entitiesValidationData.put(entityId, validationData); + + CompositionEntityId parentEntityId = entityId.getParentId(); + if (parentEntityId == null) { + roots.add(validationData); + } else { + CompositionEntityData parentEntity = entities.get(parentEntityId); + if (parentEntity == null) { + roots.add(validationData); + } else { + addValidationDataEntity(entitiesValidationData, parentEntityId, parentEntity.entity); + entitiesValidationData.get(parentEntityId).addSubEntityValidationData(validationData); + } + } + } + + private void addErrorsToTree(CompositionEntityValidationData node, + CompositionEntityId parentNodeId, + Map<CompositionEntityId, Collection<String>> errors) { + if (node == null) { + return; + } + CompositionEntityId nodeId = new CompositionEntityId(node.getEntityId(), parentNodeId); + node.setErrors(errors.get(nodeId)); + + if (node.getSubEntitiesValidationData() != null) { + node.getSubEntitiesValidationData() + .forEach(subNode -> addErrorsToTree(subNode, nodeId, errors)); + } + } + + private Collection<String> validateQuestionnaire(CompositionEntityData compositionEntityData) { + return JsonUtil.validate( + compositionEntityData.entity.getQuestionnaireData() == null + ? JsonUtil.object2Json(new Object()) + : compositionEntityData.entity.getQuestionnaireData(), + getSchema(compositionEntityData.entity.getType(), SchemaTemplateContext.questionnaire, + compositionEntityData.schemaTemplateInput)); + } + + private String getSchema(CompositionEntityType compositionEntityType, + SchemaTemplateContext schemaTemplateContext, + SchemaTemplateInput schemaTemplateInput) { + return schemaTemplateInput == null + ? nonDynamicSchemas.computeIfAbsent(compositionEntityType, + k -> generateSchema(schemaTemplateContext, compositionEntityType, null)) + : generateSchema(schemaTemplateContext, compositionEntityType, schemaTemplateInput); + } + + private static class CompositionEntityData { + private CompositionEntity entity; + private SchemaTemplateInput schemaTemplateInput; + + CompositionEntityData(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) { + this.entity = entity; + this.schemaTemplateInput = schemaTemplateInput; + } + + } + + // todo - make SchemaGenerator non static and mock it in UT instead of mocking this method (and + // make the method private + + protected String generateSchema(SchemaTemplateContext schemaTemplateContext, + CompositionEntityType compositionEntityType, + SchemaTemplateInput schemaTemplateInput) { + return SchemaGenerator + .generate(schemaTemplateContext, compositionEntityType, schemaTemplateInput); + } +} diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/CandidateServiceImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/CandidateServiceImpl.java new file mode 100644 index 0000000000..2822d958d0 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/CandidateServiceImpl.java @@ -0,0 +1,621 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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.vendorsoftwareproduct.services.impl.filedatastructuremodule; + +import org.apache.commons.collections4.CollectionUtils; +import org.openecomp.core.utilities.file.FileContentHandler; +import org.openecomp.core.utilities.json.JsonUtil; +import org.openecomp.sdc.common.errors.CoreException; +import org.openecomp.sdc.common.errors.ErrorCategory; +import org.openecomp.sdc.common.errors.ErrorCode; +import org.openecomp.sdc.common.errors.Messages; +import org.openecomp.sdc.common.utils.SdcCommon; +import org.openecomp.sdc.datatypes.error.ErrorLevel; +import org.openecomp.sdc.datatypes.error.ErrorMessage; +import org.openecomp.sdc.heat.datatypes.manifest.FileData; +import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent; +import org.openecomp.sdc.heat.datatypes.structure.Artifact; +import org.openecomp.sdc.heat.datatypes.structure.HeatStructureTree; +import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage; +import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateCandidateDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateCandidateDaoFactory; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails; +import org.openecomp.sdc.vendorsoftwareproduct.errors.utils.ErrorsUtil; +import org.openecomp.sdc.vendorsoftwareproduct.services.HeatFileAnalyzer; +import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.CandidateService; +import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.ManifestCreator; +import org.openecomp.sdc.vendorsoftwareproduct.services.utils.CandidateServiceValidator; +import org.openecomp.sdc.vendorsoftwareproduct.types.CandidateDataEntityTo; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.AnalyzedZipHeatFiles; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module; +import org.openecomp.sdc.versioning.dao.types.Version; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +public class CandidateServiceImpl implements CandidateService { + protected static final Logger logger = LoggerFactory.getLogger(CandidateServiceImpl.class); + private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage(); + + private CandidateServiceValidator candidateServiceValidator = new CandidateServiceValidator(); + private ManifestCreator manifestCreator; + private OrchestrationTemplateCandidateDao orchestrationTemplateCandidateDataDao; + + public CandidateServiceImpl(ManifestCreator manifestCreator, + OrchestrationTemplateCandidateDao orchestrationTemplateCandidateDataDao) { + this.manifestCreator = manifestCreator; + this.orchestrationTemplateCandidateDataDao = orchestrationTemplateCandidateDataDao; + + } + + public CandidateServiceImpl() { + } + + @Override + public Optional<ErrorMessage> validateNonEmptyFileToUpload(InputStream heatFileToUpload) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + if (Objects.isNull(heatFileToUpload)) { + return Optional.of(new ErrorMessage(ErrorLevel.ERROR, + Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage())); + } else { + try { + int available = heatFileToUpload.available(); + if (available == 0) { + mdcDataDebugMessage.debugExitMessage(null); + return Optional.of(new ErrorMessage(ErrorLevel.ERROR, + Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage())); + } + } catch (IOException e) { + mdcDataDebugMessage.debugExitMessage(null); + return Optional.of(new ErrorMessage(ErrorLevel.ERROR, + Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage())); + } + } + + mdcDataDebugMessage.debugExitMessage(null); + return Optional.empty(); + } + + @Override + public Optional<ErrorMessage> validateRawZipData(byte[] uploadedFileData) { + if (Objects.isNull(uploadedFileData)) { + return Optional.of(new ErrorMessage(ErrorLevel.ERROR, + Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage())); + } + return Optional.empty(); + } + + private String heatStructureTreeToFileDataStructure(HeatStructureTree tree, + FileContentHandler zipContentMap, + Map<String, List<ErrorMessage>> uploadErrors, + AnalyzedZipHeatFiles analyzedZipHeatFiles) + throws Exception { + FilesDataStructure structure = new FilesDataStructure(); + Set<String> usedEnvFiles = new HashSet<>(); + addHeatsToFileDataStructure(tree, usedEnvFiles, structure, uploadErrors, + analyzedZipHeatFiles); + handleOtherResources(tree, usedEnvFiles, structure); + FilesDataStructure fileDataStructureFromManifest = + createFileDataStructureFromManifest(zipContentMap.getFileContent + (SdcCommon.MANIFEST_NAME)); + structure.getArtifacts().addAll(fileDataStructureFromManifest.getArtifacts()); + handleArtifactsFromTree(tree, structure); + + return JsonUtil.object2Json(structure); + } + + @Override + public OrchestrationTemplateCandidateData createCandidateDataEntity( + CandidateDataEntityTo candidateDataEntityTo, InputStream zipFileManifest, + AnalyzedZipHeatFiles analyzedZipHeatFiles) throws Exception { + + + mdcDataDebugMessage.debugEntryMessage(null); + + FileContentHandler zipContentMap = candidateDataEntityTo.getContentMap(); + FilesDataStructure filesDataStructure; + String dataStructureJson; + + if (zipFileManifest != null) { + // create data structure from manifest + filesDataStructure = createFileDataStructureFromManifest(zipFileManifest); + Set<String> zipFileList = zipContentMap.getFileList(); + balanceManifestFilesWithZipFiles(filesDataStructure, + zipContentMap, analyzedZipHeatFiles); + Set<String> filesDataStructureFiles = getFlatFileNames(filesDataStructure); + filesDataStructure.getUnassigned().addAll(zipFileList.stream() + .filter(fileName -> (!filesDataStructureFiles.contains(fileName) && + !filesDataStructure.getNested().contains(fileName) && + !fileName.equals(SdcCommon.MANIFEST_NAME))) + .collect(Collectors.toList())); + dataStructureJson = JsonUtil.object2Json(filesDataStructure); + } else { + // create data structure from based on naming convention + dataStructureJson = + heatStructureTreeToFileDataStructure(candidateDataEntityTo.getTree(), zipContentMap, + candidateDataEntityTo.getErrors(), analyzedZipHeatFiles); + } + + mdcDataDebugMessage.debugExitMessage(null); + return new OrchestrationTemplateCandidateData( + ByteBuffer.wrap(candidateDataEntityTo.getUploadedFileData()), dataStructureJson); + } + + private void balanceManifestFilesWithZipFiles( + FilesDataStructure filesDataStructure, + FileContentHandler fileContentHandler, AnalyzedZipHeatFiles analyzedZipHeatFiles) + throws Exception { + Set<String> zipFileList = fileContentHandler.getFileList(); + filesDataStructure.getNested().addAll(analyzedZipHeatFiles.getNestedFiles()); + List<Module> modules = filesDataStructure.getModules(); + if (CollectionUtils.isEmpty(modules)) { + return; + } + + for (int i = 0; i < modules.size(); i++) { + Module module = modules.get(i); + if (!isFileExistInZipContains(zipFileList, module.getYaml())) { + addFileToUnassigned(filesDataStructure, zipFileList, module.getEnv()); + addFileToUnassigned(filesDataStructure, zipFileList, module.getVol()); + addFileToUnassigned(filesDataStructure, zipFileList, module.getVolEnv()); + modules.remove(i--); + } else if (Objects.nonNull(module.getVol()) && !zipFileList.contains(module.getVol())) { + module.setVol(null); + CollectionUtils.addIgnoreNull(filesDataStructure.getUnassigned(), module.getVolEnv()); + } else { + if (filesDataStructure.getNested().contains(module.getYaml())) { + moveModuleFileToNested(filesDataStructure, i--, module); + } + } + } + } + + private void addFileToUnassigned(FilesDataStructure filesDataStructure, Set<String> zipFileList, + String fileName) { + if (isFileExistInZipContains(zipFileList, fileName)) { + filesDataStructure.getUnassigned().add(fileName); + } + } + + private boolean isFileExistInZipContains(Set<String> zipFileList, String fileName) { + return Objects.nonNull(fileName) && zipFileList.contains(fileName); + } + + private void moveModuleFileToNested(FilesDataStructure filesDataStructure, int i, Module module) { + if (!filesDataStructure.getNested().contains(module.getYaml())) { + filesDataStructure.getNested().add(module.getYaml()); + } + if (Objects.nonNull(module.getEnv())) { + filesDataStructure.getNested().add(module.getEnv()); + } + if (Objects.nonNull(module.getVol())) { + filesDataStructure.getNested().add(module.getVol()); + } + if (Objects.nonNull(module.getVolEnv())) { + filesDataStructure.getNested().add(module.getVolEnv()); + } + filesDataStructure.getModules().remove(i); + } + + private Set<String> getFlatFileNames(FilesDataStructure filesDataStructure) { + Set<String> fileNames = new HashSet<>(); + if (!CollectionUtils.isEmpty(filesDataStructure.getModules())) { + for (Module module : filesDataStructure.getModules()) { + CollectionUtils.addIgnoreNull(fileNames, module.getEnv()); + CollectionUtils.addIgnoreNull(fileNames, module.getVol()); + CollectionUtils.addIgnoreNull(fileNames, module.getVolEnv()); + CollectionUtils.addIgnoreNull(fileNames, module.getYaml()); + } + } + fileNames.addAll(filesDataStructure.getArtifacts().stream().collect(Collectors.toSet())); + fileNames.addAll(filesDataStructure.getNested().stream().collect(Collectors.toSet())); + fileNames.addAll(filesDataStructure.getUnassigned().stream().collect(Collectors.toSet())); + + return fileNames; + } + + private FilesDataStructure createFileDataStructureFromManifest(InputStream isManifestContent) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + ManifestContent manifestContent = + JsonUtil.json2Object(isManifestContent, ManifestContent.class); + FilesDataStructure structure = new FilesDataStructure(); + for (FileData fileData : manifestContent.getData()) { + if (Objects.nonNull(fileData.getType()) && fileData.getType().equals(FileData.Type.HEAT)) { + Module module = new Module(); + module.setYaml(fileData.getFile()); + module.setIsBase(fileData.getBase()); + addHeatDependenciesToModule(module, fileData.getData()); + structure.getModules().add(module); + } else if (HeatFileAnalyzer.isYamlOrEnvFile(fileData.getFile()) && + !FileData.Type.isArtifact(fileData.getType())) { + structure.getUnassigned().add(fileData.getFile()); + } else { + structure.getArtifacts().add(fileData.getFile()); + } + } + + mdcDataDebugMessage.debugExitMessage(null); + return structure; + } + + private void addHeatDependenciesToModule(Module module, List<FileData> data) { + if (CollectionUtils.isEmpty(data)) { + return; + } + + for (FileData fileData : data) { + if (fileData.getType().equals(FileData.Type.HEAT_ENV)) { + module.setEnv(fileData.getFile()); + } else if (fileData.getType().equals(FileData.Type.HEAT_VOL))// must be volume + { + module.setVol(fileData.getFile()); + if (!CollectionUtils.isEmpty(fileData.getData())) { + FileData volEnv = fileData.getData().get(0); + if (volEnv.getType().equals(FileData.Type.HEAT_ENV)) { + module.setVolEnv(volEnv.getFile()); + } else { + throw new CoreException((new ErrorCode.ErrorCodeBuilder()) + .withMessage(Messages.ILLEGAL_MANIFEST.getErrorMessage()) + .withId(Messages.ILLEGAL_MANIFEST.getErrorMessage()) + .withCategory(ErrorCategory.APPLICATION).build()); + } + } + } else { + throw new CoreException((new ErrorCode.ErrorCodeBuilder()) + .withMessage(Messages.FILE_TYPE_NOT_LEGAL.getErrorMessage()) + .withId(Messages.FILE_TYPE_NOT_LEGAL.getErrorMessage()) + .withCategory(ErrorCategory.APPLICATION).build()); + } + } + } + + @Override + public void updateCandidateUploadData(OrchestrationTemplateCandidateData uploadData, + String itemId) { + mdcDataDebugMessage.debugEntryMessage(null); + + //vendorSoftwareProductDao.updateCandidateUploadData(uploadData); + orchestrationTemplateCandidateDataDao.update(itemId, uploadData); + + mdcDataDebugMessage.debugExitMessage(null); + } + + @Override + public Optional<FilesDataStructure> getOrchestrationTemplateCandidateFileDataStructure( + String vspId, Version version) { + + mdcDataDebugMessage.debugEntryMessage("VSP Id", vspId); + + Optional<String> jsonFileDataStructure = + orchestrationTemplateCandidateDataDao.getStructure(vspId, version); + + if (jsonFileDataStructure.isPresent()) { + mdcDataDebugMessage.debugExitMessage("VSP Id", vspId); + return Optional + .of(JsonUtil.json2Object(jsonFileDataStructure.get(), FilesDataStructure.class)); + } else { + mdcDataDebugMessage.debugExitMessage("VSP Id", vspId); + return Optional.empty(); + } + } + + @Override + public void updateOrchestrationTemplateCandidateFileDataStructure(String vspId, Version version, + FilesDataStructure fileDataStructure) { + OrchestrationTemplateCandidateDaoFactory.getInstance().createInterface() + .updateStructure(vspId, version, fileDataStructure); + } + + @Override + public OrchestrationTemplateCandidateData getOrchestrationTemplateCandidate(String vspId, + Version version) { + mdcDataDebugMessage.debugEntryMessage("VSP Id", vspId); + mdcDataDebugMessage.debugExitMessage("VSP Id", vspId); + + return orchestrationTemplateCandidateDataDao.get(vspId, version); + } + + @Override + public String createManifest(VspDetails vspDetails, FilesDataStructure structure) { + + mdcDataDebugMessage.debugEntryMessage("VSP Id", vspDetails.getId()); + + Optional<ManifestContent> manifest = manifestCreator.createManifest(vspDetails, structure); + if (!manifest.isPresent()) { + throw new RuntimeException(Messages.CREATE_MANIFEST_FROM_ZIP.getErrorMessage()); + } + + mdcDataDebugMessage.debugExitMessage("VSP Id", vspDetails.getId()); + return JsonUtil.object2Json(manifest.get()); + } + + @Override + public Optional<ManifestContent> createManifest(VspDetails vspDetails, + FileContentHandler fileContentHandler, + AnalyzedZipHeatFiles analyzedZipHeatFiles) { + + + mdcDataDebugMessage.debugEntryMessage("VSP Id", vspDetails.getId()); + + mdcDataDebugMessage.debugExitMessage("VSP Id", vspDetails.getId()); + return manifestCreator.createManifest(vspDetails, fileContentHandler, analyzedZipHeatFiles); + } + + @Override + public Optional<ByteArrayInputStream> fetchZipFileByteArrayInputStream(String vspId, + OrchestrationTemplateCandidateData candidateDataEntity, + String manifest, + Map<String, List<ErrorMessage>> uploadErrors) { + byte[] file; + ByteArrayInputStream byteArrayInputStream = null; + try { + file = replaceManifestInZip(candidateDataEntity.getContentData(), manifest, vspId); + byteArrayInputStream = new ByteArrayInputStream( + Objects.isNull(file) ? candidateDataEntity.getContentData().array() + : file); + } catch (IOException e) { + ErrorMessage errorMessage = + new ErrorMessage(ErrorLevel.ERROR, Messages.CANDIDATE_PROCESS_FAILED.getErrorMessage()); + logger.error(errorMessage.getMessage(), e); + ErrorsUtil.addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE, errorMessage, uploadErrors); + } + return Optional.ofNullable(byteArrayInputStream); + } + + @Override + public byte[] replaceManifestInZip(ByteBuffer contentData, String manifest, String vspId) + throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + try (final ZipOutputStream zos = new ZipOutputStream(baos); + ZipInputStream zipStream = new ZipInputStream( + new ByteArrayInputStream(contentData.array()))) { + ZipEntry zipEntry; + boolean manifestWritten = false; + while ((zipEntry = zipStream.getNextEntry()) != null) { + if (!zipEntry.getName().equalsIgnoreCase(SdcCommon.MANIFEST_NAME)) { + ZipEntry loc_ze = new ZipEntry(zipEntry.getName()); + zos.putNextEntry(loc_ze); + byte[] buf = new byte[1024]; + int len; + while ((len = zipStream.read(buf)) > 0) { + zos.write(buf, 0, (len < buf.length) ? len : buf.length); + } + } else { + manifestWritten = true; + writeManifest(manifest, zos); + } + zos.closeEntry(); + } + if (!manifestWritten) { + writeManifest(manifest, zos); + zos.closeEntry(); + } + } + return baos.toByteArray(); + } + + @Override + public Optional<List<ErrorMessage>> validateFileDataStructure( + FilesDataStructure filesDataStructure) { + return candidateServiceValidator.validateFileDataStructure(filesDataStructure); + } + + private void writeManifest(String manifest, ZipOutputStream zos) throws IOException { + zos.putNextEntry(new ZipEntry(SdcCommon.MANIFEST_NAME)); + try (InputStream manifestStream = new ByteArrayInputStream( + manifest.getBytes(StandardCharsets.UTF_8))) { + byte[] buf = new byte[1024]; + int len; + while ((len = (manifestStream.read(buf))) > 0) { + zos.write(buf, 0, (len < buf.length) ? len : buf.length); + } + } + } + + private void handleArtifactsFromTree(HeatStructureTree tree, FilesDataStructure structure) { + + if (Objects.isNull(tree) || Objects.isNull(tree.getArtifacts())) { + return; + } + + if (CollectionUtils.isNotEmpty(tree.getArtifacts())) { + structure.getArtifacts().addAll( + tree.getArtifacts() + .stream() + .map(Artifact::getFileName) + .filter(fileName -> !structure.getArtifacts().contains(fileName)) + .collect(Collectors.toList())); + } + } + + private void handleOtherResources(HeatStructureTree tree, Set<String> usedEnvFiles, + FilesDataStructure structure) { + Set<HeatStructureTree> others = tree.getOther(); + if (Objects.isNull(others)) { + return; + } + + List<String> artifacts = new ArrayList<>(); + List<String> unassigned = new ArrayList<>(); + for (HeatStructureTree other : others) { + if (HeatFileAnalyzer.isYamlOrEnvFile(other.getFileName())) { + if (isEnvFileUsedByHeatFile(usedEnvFiles, other)) { + continue; + } + unassigned.add(other.getFileName()); + } else { + artifacts.add(other.getFileName()); + } + handleArtifactsFromTree(other, structure); + } + structure.getArtifacts().addAll(artifacts); + structure.getUnassigned().addAll(unassigned); + } + + private boolean isEnvFileUsedByHeatFile(Set<String> usedEnvFiles, HeatStructureTree other) { + if (HeatFileAnalyzer.isEnvFile(other.getFileName())) { + if (usedEnvFiles.contains(other.getFileName())) { + return true; + } + } + return false; + } + + private void addHeatsToFileDataStructure(HeatStructureTree tree, Set<String> usedEnvFiles, + FilesDataStructure structure, + Map<String, List<ErrorMessage>> uploadErrors, + AnalyzedZipHeatFiles analyzedZipHeatFiles) + throws Exception { + List<Module> modules = new ArrayList<>(); + Set<HeatStructureTree> heatsSet = tree.getHeat(); + if (Objects.isNull(heatsSet)) { + return; + } + for (HeatStructureTree heat : heatsSet) { + if (isFileBaseFile(heat.getFileName())) { + handleSingleHeat(structure, modules, heat, uploadErrors); + } else if (isFileModuleFile(heat.getFileName(), analyzedZipHeatFiles.getModuleFiles())) { + handleSingleHeat(structure, modules, heat, uploadErrors); + } else { + structure.getUnassigned().add(heat.getFileName()); + addNestedToFileDataStructure(heat, structure); + } + if (!Objects.isNull(heat.getEnv())) { + usedEnvFiles.add(heat.getEnv() == null ? null : heat.getEnv().getFileName()); + } + } + structure.setModules(modules); + + } + + private boolean isFileModuleFile(String fileName, Set<String> modulesFileNames) { + return modulesFileNames.contains(fileName); + } + + private boolean isFileBaseFile(String fileName) { + return manifestCreator.isFileBaseFile(fileName); + } + + private void handleSingleHeat(FilesDataStructure structure, List<Module> modules, + HeatStructureTree heat, + Map<String, List<ErrorMessage>> uploadErrors) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + Module module = new Module(); + module.setYaml(heat.getFileName()); + module.setIsBase(heat.getBase()); + addNestedToFileDataStructure(heat, structure); + Set<HeatStructureTree> volumeSet = heat.getVolume(); + int inx = 0; + if (Objects.nonNull(volumeSet)) { + handleVolumes(module, volumeSet, structure, inx, uploadErrors); + } + handleEnv(module, heat, false, structure); + modules.add(module); + + mdcDataDebugMessage.debugExitMessage(null); + } + + private void handleVolumes(Module module, Set<HeatStructureTree> volumeSet, + FilesDataStructure structure, int inx, + Map<String, List<ErrorMessage>> uploadErrors) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + for (HeatStructureTree volume : volumeSet) { + if (inx++ > 0) { + ErrorsUtil.addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE, + new ErrorMessage(ErrorLevel.WARNING, + Messages.MORE_THEN_ONE_VOL_FOR_HEAT.getErrorMessage()), uploadErrors); + break; + } + handleArtifactsFromTree(volume, structure); + module.setVol(volume.getFileName()); + handleEnv(module, volume, true, structure); + } + + mdcDataDebugMessage.debugExitMessage(null); + } + + private void handleEnv(Module module, HeatStructureTree tree, boolean isVolEnv, + FilesDataStructure structure) { + + + mdcDataDebugMessage.debugEntryMessage(null); + + if (Objects.nonNull(tree.getEnv())) { + if (isVolEnv) { + module.setVolEnv(tree.getEnv().getFileName()); + } else { + module.setEnv(tree.getEnv().getFileName()); + } + handleArtifactsFromTree(tree.getEnv(), structure); + } + + mdcDataDebugMessage.debugExitMessage(null); + } + + private void addNestedToFileDataStructure(HeatStructureTree heat, FilesDataStructure structure) { + Set<HeatStructureTree> nestedSet = heat.getNested(); + if (Objects.isNull(nestedSet)) { + return; + } + for (HeatStructureTree nested : nestedSet) { + if (structure.getNested().contains(nested.getFileName())) { + continue; + } + structure.getNested().add(nested.getFileName()); + if (CollectionUtils.isNotEmpty(nested.getArtifacts())) { + handleArtifactsFromTree(nested, structure); + } + addNestedToFileDataStructure(nested, structure); + } + } +} diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/ManifestCreatorNamingConventionImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/ManifestCreatorNamingConventionImpl.java new file mode 100644 index 0000000000..eed575ff02 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/ManifestCreatorNamingConventionImpl.java @@ -0,0 +1,309 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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.vendorsoftwareproduct.services.impl.filedatastructuremodule; + +import org.apache.commons.collections4.CollectionUtils; +import org.openecomp.core.utilities.file.FileContentHandler; +import org.openecomp.sdc.heat.datatypes.manifest.FileData; +import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent; +import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails; +import org.openecomp.sdc.vendorsoftwareproduct.services.HeatFileAnalyzer; +import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.ManifestCreator; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.AnalyzedZipHeatFiles; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Constants; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Pattern; + +public class ManifestCreatorNamingConventionImpl implements ManifestCreator { + protected static final Logger logger = + LoggerFactory.getLogger(ManifestCreatorNamingConventionImpl.class); + private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage(); + + + @Override + public Optional<ManifestContent> createManifest( + VspDetails vspDetails, FilesDataStructure filesDataStructure) { + + + mdcDataDebugMessage.debugEntryMessage(null, null); + + if (Objects.isNull(filesDataStructure)) { + return Optional.empty(); + } + + List<FileData> fileDataList = new ArrayList<>(); + addModulesToManifestFileDataList(filesDataStructure, fileDataList); + addNestedToManifest(filesDataStructure, fileDataList); + addArtifactsToManifestFileDataList(filesDataStructure, fileDataList); + ManifestContent manifestContent = createManifest(vspDetails, fileDataList); + + mdcDataDebugMessage.debugExitMessage(null, null); + return Optional.of(manifestContent); + } + + private void addNestedToManifest( + FilesDataStructure filesDataStructure, List<FileData> fileDataList) { + + + mdcDataDebugMessage.debugEntryMessage(null, null); + + if (CollectionUtils.isNotEmpty(filesDataStructure.getNested())) { + for (String nested : filesDataStructure.getNested()) { + fileDataList.add(createBaseFileData(FileData.Type.HEAT, nested)); + } + } + + mdcDataDebugMessage.debugExitMessage(null, null); + } + + @Override + public Optional<ManifestContent> createManifest(VspDetails vspDetails, + FileContentHandler fileContentHandler, + AnalyzedZipHeatFiles analyzedZipHeatFiles) { + logger.info("Trying to generate manifest"); + if (Objects.isNull(fileContentHandler) + || CollectionUtils.isEmpty(fileContentHandler.getFileList())) { + logger.info("fileContentHandler or filesList is empty. ManifestContent will not be created"); + return Optional.empty(); + } + + Map<String, byte[]> files = fileContentHandler.getFiles(); + + List<FileData> fileDataList = + createFileDataListFromZipFiles(fileContentHandler, files, + analyzedZipHeatFiles.getFilesNotEligbleForModules()); + ManifestContent manifestContent = createManifest(vspDetails, fileDataList); + + return Optional.of(manifestContent); + } + + private ManifestContent createManifest(VspDetails vspDetails, List<FileData> fileDataList) { + ManifestContent manifestContent = new ManifestContent(); + manifestContent.setName(vspDetails.getName()); + manifestContent.setDescription(vspDetails.getDescription()); + manifestContent + .setVersion(vspDetails.getVersion() == null ? null : vspDetails.getVersion().toString()); + // vsp version, need to check in confluence + manifestContent.setData(fileDataList); + return manifestContent; + } + + private List<FileData> createFileDataListFromZipFiles(FileContentHandler fileContentHandler, + Map<String, byte[]> files, + Collection<String> filesNotEligibleForModules) { + + Set<String> processedFiles = new HashSet<>(); + List<FileData> fileDataList = new ArrayList<>(); + for (String fileName : files.keySet()) { + if (processedFiles.contains(fileName)) { + continue; + } + if (isFileBaseFile(fileName)) { + fileDataList + .add(createModuleFileData( + fileName, true, processedFiles, fileContentHandler.getFileList(), fileDataList)); + } else if (isFileModuleFile(fileName, filesNotEligibleForModules)) { + fileDataList + .add(createModuleFileData( + fileName, false, processedFiles, fileContentHandler.getFileList(), fileDataList)); + } else { + if (HeatFileAnalyzer.isYamlFile(fileName)) { + fileDataList.add(createBasicFileData(fileName, FileData.Type.HEAT, null)); + } else if (HeatFileAnalyzer.isEnvFile(fileName)) { + fileDataList.add(createBasicFileData(fileName, FileData.Type.HEAT_ENV, null)); + } else { + fileDataList.add(createBasicFileData(fileName, FileData.Type.OTHER, null)); + } + } + } + return fileDataList; + } + + private boolean doesHeatTemplateVersionExist(byte[] value) { + return false; + } + + private boolean isFileModuleFile(String fileName, Collection<String> filesCannotBeModule) { + return !filesCannotBeModule.contains(fileName); + } + + @Override + public boolean isFileBaseFile(String fileName) { + return Pattern.matches(Constants.BASE_HEAT_REGEX, fileName) && !isVolFile(fileName); + } + + + private void addArtifactsToManifestFileDataList( + FilesDataStructure filesDataStructure, List<FileData> fileDataList) { + + + mdcDataDebugMessage.debugEntryMessage(null, null); + + Collection<String> forArtifacts = CollectionUtils + .union(filesDataStructure.getArtifacts(), filesDataStructure.getUnassigned()); + if (CollectionUtils.isNotEmpty(forArtifacts)) { + for (String artifact : forArtifacts) { + fileDataList.add(createBaseFileData(FileData.Type.OTHER, artifact)); + } + } + + mdcDataDebugMessage.debugExitMessage(null, null); + } + + private void addModulesToManifestFileDataList( + FilesDataStructure filesDataStructure, List<FileData> fileDataList) { + + + mdcDataDebugMessage.debugEntryMessage(null, null); + + if (CollectionUtils.isNotEmpty(filesDataStructure.getModules())) { + for (Module module : filesDataStructure.getModules()) { + FileData fileData = createBaseFileData(FileData.Type.HEAT, module.getYaml()); + fileData.setBase(module.getIsBase()); + addEnv(module, fileData); + addVolume(module, fileData); + fileDataList.add(fileData); + } + } + + mdcDataDebugMessage.debugExitMessage(null, null); + } + + private void addEnv(Module module, FileData fileData) { + if (Objects.nonNull(module.getEnv())) { + FileData env = createBaseFileData(FileData.Type.HEAT_ENV, module.getEnv()); + fileData.addFileData(env); + } + } + + private void addVolume(Module module, FileData fileData) { + String volModule = module.getVol(); + if (Objects.nonNull(volModule)) { + FileData vol = createBaseFileData(FileData.Type.HEAT_VOL, volModule); + if (Objects.nonNull(module.getVolEnv())) { + vol.addFileData(createBaseFileData(FileData.Type.HEAT_ENV, module.getVolEnv())); + } + fileData.addFileData(vol); + } + } + + private FileData createBaseFileData(FileData.Type heat, String yaml) { + FileData fileData = new FileData(); + fileData.setType(heat); + fileData.setFile(yaml); + return fileData; + } + + private FileData createModuleFileData( + String moduleFileName, boolean isBase, Set<String> processedFiles, + Set<String> fileNames, List<FileData> fileDataList) { + FileData moduleFileData = createBasicFileData(moduleFileName, FileData.Type.HEAT, isBase); + Optional<String> volFile = fetchRelatedVolume(moduleFileName, fileNames); + volFile.ifPresent(vol -> { + markFileAsProcessed(vol, processedFiles); + removeFromFileDataListIfAlreadyProcessed(fileDataList, vol); + FileData volFileData = createBasicFileData(vol, FileData.Type.HEAT_VOL, null); + Optional<String> envFile = fetchRelatedEnv(vol, fileNames); + envFile.ifPresent(env -> { + markFileAsProcessed(env, processedFiles); + removeFromFileDataListIfAlreadyProcessed(fileDataList, env); + FileData envFileData = createBasicFileData(env, FileData.Type.HEAT_ENV, null); + volFileData.addFileData(envFileData); + }); + moduleFileData.addFileData(volFileData); + }); + Optional<String> envFile = fetchRelatedEnv(moduleFileName, fileNames); + envFile.ifPresent(env -> { + markFileAsProcessed(env, processedFiles); + FileData envFileData = createBasicFileData(env, FileData.Type.HEAT_ENV, null); + moduleFileData.addFileData(envFileData); + }); + return moduleFileData; + } + + private void removeFromFileDataListIfAlreadyProcessed(List<FileData> fileDataList, String vol) { + fileDataList.removeIf(fileData -> fileData.getFile().equals(vol)); + } + + private FileData createBasicFileData(String fileName, FileData.Type type, Boolean isBase) { + FileData fileData = new FileData(); + if (isBase != null) { + fileData.setBase(isBase); + } + fileData.setType(type); + fileData.setFile(fileName); + return fileData; + } + + private Optional<String> fetchRelatedEnv(String fileName, Set<String> fileNames) { + String envFileName + = fileName.substring(0, fileName.lastIndexOf(".")) + Constants.ENV_FILE_EXTENSION; + return fileNames.contains(envFileName) ? Optional.of(envFileName) : Optional.empty(); + } + + private Optional<String> fetchRelatedVolume(String fileName, Set<String> fileNames) { + + String volFile1stExt = + extractVolFileName(fileName, ".yaml"); + String volFile2ndExt = + extractVolFileName(fileName, ".yml"); + + if (fileNames.contains(volFile1stExt)) { + return Optional.of(volFile1stExt); + } + if (fileNames.contains(volFile2ndExt)) { + return Optional.of(volFile2ndExt); + } + return Optional.empty(); + } + + private String extractVolFileName(String fileName, String fileExt) { + return fileName.substring( + 0, fileName.lastIndexOf(".")) + + Constants.VOL_FILE_NAME_SUFFIX + fileExt; + } + + + private boolean isVolFile(String fileName) { + return fileName + .endsWith( + Constants.VOL_FILE_NAME_SUFFIX + ".yaml") + || fileName.endsWith(Constants.VOL_FILE_NAME_SUFFIX + ".yml"); + } + + + private void markFileAsProcessed(String fileName, Set<String> processedFiles) { + processedFiles.add(fileName); + } +} diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/utils/CandidateServiceValidator.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/utils/CandidateServiceValidator.java new file mode 100644 index 0000000000..05c95a7596 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/utils/CandidateServiceValidator.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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.vendorsoftwareproduct.services.utils; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder; +import org.openecomp.sdc.common.errors.Messages; +import org.openecomp.sdc.datatypes.error.ErrorLevel; +import org.openecomp.sdc.datatypes.error.ErrorMessage; +import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure; +import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * Created by Talio on 12/6/2016. + */ +public class CandidateServiceValidator { + private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage(); + + public Optional<List<ErrorMessage>> validateFileDataStructure( + FilesDataStructure filesDataStructure) { + if (Objects.isNull(filesDataStructure)) { + return Optional.empty(); + } + if (validateAtLeaseOneModuleExist(filesDataStructure)) { + return Optional.of(Arrays.asList(new ErrorMessage(ErrorLevel.ERROR, Messages + .NO_MODULES_IN_MANIFEST.getErrorMessage()))); + } + + List<ErrorMessage> errors = new ArrayList<>(); + for (Module module : filesDataStructure.getModules()) { + validateModuleHaveYaml(errors, module); + validateNoVolEnvWithoutVol(errors, module); + } + return Optional.of(errors); + } + + + private boolean validateAtLeaseOneModuleExist(FilesDataStructure filesDataStructure) { + + mdcDataDebugMessage.debugEntryMessage(null, null); + + mdcDataDebugMessage.debugExitMessage(null, null); + return CollectionUtils.isEmpty(filesDataStructure.getModules()); + } + + private void validateNoVolEnvWithoutVol(List<ErrorMessage> errors, Module module) { + + mdcDataDebugMessage.debugEntryMessage(null, null); + + if (StringUtils.isEmpty(module.getVol()) && StringUtils.isNotEmpty(module.getVolEnv())) { + errors.add(new ErrorMessage(ErrorLevel.ERROR, ErrorMessagesFormatBuilder + .getErrorWithParameters(Messages.MODULE_IN_MANIFEST_VOL_ENV_NO_VOL.getErrorMessage(), + module.getName()))); + } + + mdcDataDebugMessage.debugExitMessage(null, null); + } + + private void validateModuleHaveYaml(List<ErrorMessage> errors, Module module) { + + mdcDataDebugMessage.debugEntryMessage(null, null); + + if (StringUtils.isEmpty(module.getYaml())) { + errors.add(new ErrorMessage(ErrorLevel.ERROR, ErrorMessagesFormatBuilder + .getErrorWithParameters(Messages.MODULE_IN_MANIFEST_NO_YAML.getErrorMessage(), + module.getName()))); + } + + mdcDataDebugMessage.debugExitMessage(null, null); + } +} |