diff options
author | mark.j.leonard <mark.j.leonard@gmail.com> | 2018-11-27 11:49:58 +0000 |
---|---|---|
committer | mark.j.leonard <mark.j.leonard@gmail.com> | 2018-11-27 11:49:58 +0000 |
commit | 91d6d53930576dba11a92d25e20795c1ba1f8817 (patch) | |
tree | 7b54b14b37c9b3d1320f33046b09b874ec12c75f /src | |
parent | 36606e8fbcae1248aff9740717a666120cf9d8a0 (diff) |
Refactor model generation algorithm
Reorganize the Service and Resource Model generation code for
readability. Resort methods to put public before private.
Rename generateService() to generateAllArtifacts()
Reimplement this method such that the NodeTemplate list is iterated once
only. This is intended to simplify future changes to the code.
Change-Id: Ie0c6003eab99f42945747c6d79827881e05afc87
Issue-ID: AAI-1884
Signed-off-by: mark.j.leonard <mark.j.leonard@gmail.com>
Diffstat (limited to 'src')
4 files changed, 466 insertions, 481 deletions
diff --git a/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java b/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java index ed7fc19..827e552 100644 --- a/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java +++ b/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java @@ -26,14 +26,13 @@ import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.onap.aai.babel.logging.ApplicationMsgs; + import org.onap.aai.babel.logging.LogHelper; import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil; import org.onap.aai.babel.xml.generator.model.AllotedResource; @@ -42,8 +41,6 @@ import org.onap.aai.babel.xml.generator.model.L3NetworkWidget; import org.onap.aai.babel.xml.generator.model.Model; import org.onap.aai.babel.xml.generator.model.ProvidingService; import org.onap.aai.babel.xml.generator.model.Resource; -import org.onap.aai.babel.xml.generator.model.Service; -import org.onap.aai.babel.xml.generator.model.TunnelXconnectWidget; import org.onap.aai.babel.xml.generator.model.VfModule; import org.onap.aai.babel.xml.generator.model.Widget; import org.onap.aai.babel.xml.generator.types.ModelType; @@ -150,101 +147,16 @@ public class ArtifactGeneratorToscaParser { } /** - * Process the service TOSCA. - * - * @param service - * model of the service artifact - * @param idTypeStore - * ID->Type mapping - * @param nodeTemplates - * a list of service nodes - */ - public void processServiceTosca(Service service, Map<String, String> idTypeStore, - List<NodeTemplate> nodeTemplates) { - log.debug("Processing (TOSCA) Service object"); - - for (NodeTemplate nodeTemplate : nodeTemplates) { - if (nodeTemplate.getMetaData() != null) { - addNodeToService(idTypeStore, service, nodeTemplate); - } else { - log.warn(ApplicationMsgs.MISSING_SERVICE_METADATA, nodeTemplate.getName()); - } - } - } - - /** - * Generates a Resource List using input Service Node Templates. - * - * @param serviceNodeTemplates - * input Service Node Templates - * @param idTypeStore - * ID->Type mapping - * - * @return the processed resource models - */ - public List<Resource> processResourceToscas(List<NodeTemplate> serviceNodeTemplates, - Map<String, String> idTypeStore) { - List<Resource> resources = new LinkedList<>(); - for (NodeTemplate serviceNodeTemplate : serviceNodeTemplates) { - if (serviceNodeTemplate.getMetaData() != null) { - resources.addAll(processResourceTosca(idTypeStore, serviceNodeTemplate, - csarHelper.getNodeTemplateChildren(serviceNodeTemplate))); - } else { - log.warn(ApplicationMsgs.MISSING_SERVICE_METADATA, serviceNodeTemplate.getName()); - } - } - return resources; - } - - /** - * @param idTypeStore - * ID->Type mapping - * @param serviceNodeTemplate - * @param resourceNodeTemplates - * the (non-VNF) substituted node templates - * @return the processed resource models - */ - private List<Resource> processResourceTosca(Map<String, String> idTypeStore, NodeTemplate serviceNodeTemplate, - List<NodeTemplate> resourceNodeTemplates) { - List<Resource> resources = new LinkedList<>(); - String resourceUuId = serviceNodeTemplate.getMetaData().getValue("UUID"); - String nodeTypeName = idTypeStore.get(resourceUuId); - if (nodeTypeName != null) { - Model resourceModel = Model.getModelFor(nodeTypeName, serviceNodeTemplate.getMetaData().getValue("type")); - - log.debug("Processing resource " + nodeTypeName + ": " + resourceUuId); - Map<String, String> serviceMetadata = serviceNodeTemplate.getMetaData().getAllProperties(); - resourceModel.populateModelIdentificationInformation(serviceMetadata); - - idTypeStore.remove(resourceModel.getModelNameVersionId()); - processResourceModels(idTypeStore, resourceModel, resourceNodeTemplates); - - if (csarHelper.getServiceVfList() != null) { - processVfModules(resources, resourceModel, serviceNodeTemplate); - } - - if (hasSubCategoryTunnelXConnect(serviceMetadata) && hasAllottedResource(serviceMetadata)) { - resourceModel.addWidget(new TunnelXconnectWidget()); - } - - resources.addAll(processInstanceGroups(resourceModel, serviceNodeTemplate)); - resources.add((Resource) resourceModel); - } - - return resources; - } - - /** * Process groups for this service node, according to the defined filter. * * @param resourceModel - * @param serviceNode + * @param serviceNodeTemplate * @return resources for which XML Models should be generated */ - List<Resource> processInstanceGroups(Model resourceModel, NodeTemplate serviceNode) { + public List<Resource> processInstanceGroups(Model resourceModel, NodeTemplate serviceNodeTemplate) { List<Resource> resources = new ArrayList<>(); - if (serviceNode.getSubMappingToscaTemplate() != null) { - List<Group> serviceGroups = csarHelper.getGroupsOfOriginOfNodeTemplate(serviceNode); + if (serviceNodeTemplate.getSubMappingToscaTemplate() != null) { + List<Group> serviceGroups = csarHelper.getGroupsOfOriginOfNodeTemplate(serviceNodeTemplate); for (Group group : serviceGroups) { if (WidgetConfigurationUtil.isSupportedInstanceGroup(group.getType())) { resources.addAll(processInstanceGroup(resourceModel, group.getMemberNodes(), @@ -265,13 +177,96 @@ public class ArtifactGeneratorToscaParser { * Map of TOSCA Property Type Object values to merge in (or overwrite) * @return a Map of the property values converted to String */ - private Map<String, String> mergeProperties(Map<String, String> stringProps, Map<String, Property> toscaProps) { + public Map<String, String> mergeProperties(Map<String, String> stringProps, Map<String, Property> toscaProps) { Map<String, String> props = new HashMap<>(stringProps); toscaProps.forEach((key, toscaProp) -> props.put(key, toscaProp.getValue() == null ? "" : toscaProp.getValue().toString())); return props; } + public Resource createInstanceGroupModel(Map<String, String> properties) { + Resource groupModel = new InstanceGroup(); + groupModel.populateModelIdentificationInformation(properties); + return groupModel; + } + + /** + * @param model + * @param relation + */ + public void addRelatedModel(final Model model, final Model relation) { + if (relation instanceof Resource) { + model.addResource((Resource) relation); + } else { + model.addWidget((Widget) relation); + } + } + + public String normaliseNodeTypeName(NodeTemplate nodeType) { + String nodeTypeName = nodeType.getType(); + Metadata metadata = nodeType.getMetaData(); + if (metadata != null && hasAllottedResource(metadata.getAllProperties())) { + if (nodeType.getType().contains("org.openecomp.resource.vf.")) { + nodeTypeName = "org.openecomp.resource.vf.allottedResource"; + } + if (nodeType.getType().contains("org.openecomp.resource.vfc.")) { + nodeTypeName = "org.openecomp.resource.vfc.AllottedResource"; + } + } + return nodeTypeName; + } + + public boolean hasAllottedResource(Map<String, String> metadata) { + return ALLOTTED_RESOURCE.equals(metadata.get(CATEGORY)); + } + + public boolean hasSubCategoryTunnelXConnect(Map<String, String> metadata) { + return TUNNEL_XCONNECT.equals(metadata.get(SUBCATEGORY)); + } + + /** + * Process TOSCA Group information for VF Modules. + * + * @param resources + * @param model + * @param serviceNode + */ + public void processVfModules(List<Resource> resources, Model resourceModel, NodeTemplate serviceNode) { + // Get the customisation UUID for each VF node and use it to get its Groups + String uuid = csarHelper.getNodeTemplateCustomizationUuid(serviceNode); + List<Group> serviceGroups = csarHelper.getVfModulesByVf(uuid); + + // Process each VF Group + for (Group serviceGroup : serviceGroups) { + Model groupModel = Model.getModelFor(serviceGroup.getType()); + if (groupModel instanceof VfModule) { + processVfModule(resources, resourceModel, serviceGroup, serviceNode, (VfModule) groupModel); + } + } + } + + /** + * @param resourceModel + * @param resourceNodeTemplates + */ + public void processResourceModels(Model resourceModel, List<NodeTemplate> resourceNodeTemplates) { + boolean foundProvidingService = false; + + for (NodeTemplate resourceNodeTemplate : resourceNodeTemplates) { + String nodeTypeName = normaliseNodeTypeName(resourceNodeTemplate); + Metadata metaData = resourceNodeTemplate.getMetaData(); + String metaDataType = Optional.ofNullable(metaData).map(m -> m.getValue("type")).orElse(nodeTypeName); + Model resourceNode = Model.getModelFor(nodeTypeName, metaDataType); + foundProvidingService |= processModel(resourceModel, resourceNodeTemplate, metaData, resourceNode); + } + + if (resourceModel instanceof AllotedResource && !foundProvidingService) { + final String modelInvariantId = resourceModel.getModelId(); + throw new IllegalArgumentException(String.format(GENERATOR_AAI_PROVIDING_SERVICE_MISSING, + modelInvariantId == null ? "<null ID>" : modelInvariantId)); + } + } + /** * Create an Instance Group Model and populate it with the supplied data. * @@ -298,12 +293,6 @@ public class ArtifactGeneratorToscaParser { return resources; } - private Resource createInstanceGroupModel(Map<String, String> properties) { - Resource groupModel = new InstanceGroup(); - groupModel.populateModelIdentificationInformation(properties); - return groupModel; - } - /** * @param memberNodes * @param groupModel @@ -328,89 +317,29 @@ public class ArtifactGeneratorToscaParser { return resources; } - /** - * Add the supplied Node Template to the Service, provided that it is a valid Resource or Widget. If the Node - * Template is a Resource type, this is also recorded in the supplied nodesById Map. - * - * @param nodesById - * a map of Resource node type names, keyed by UUID - * @param service - * the Service to which the Node Template should be added - * @param nodeTemplate - * the Node Template to add (only if this is a Resource or Widget type) - */ - private void addNodeToService(Map<String, String> nodesById, Service service, NodeTemplate nodeTemplate) { - String nodeTypeName = normaliseNodeTypeName(nodeTemplate); - Model model = Model.getModelFor(nodeTypeName, nodeTemplate.getMetaData().getValue("type")); - if (model != null) { - if (nodeTemplate.getMetaData() != null) { - model.populateModelIdentificationInformation(nodeTemplate.getMetaData().getAllProperties()); - } - - addRelatedModel(service, model); - if (model instanceof Resource) { - nodesById.put(model.getModelNameVersionId(), nodeTypeName); - } - } - } - - /** - * @param model - * @param relation - */ - private void addRelatedModel(final Model model, final Model relation) { - if (relation instanceof Resource) { - model.addResource((Resource) relation); - } else { - model.addWidget((Widget) relation); - } - } + private void processVfModule(List<Resource> resources, Model vfModel, Group groupDefinition, + NodeTemplate serviceNode, VfModule groupModel) { + groupModel.populateModelIdentificationInformation( + mergeProperties(groupDefinition.getMetadata().getAllProperties(), groupDefinition.getProperties())); - /** - * Process TOSCA Group information for VF Modules. - * - * @param resources - * @param model - * @param serviceNode - */ - private void processVfModules(List<Resource> resources, Model resourceModel, NodeTemplate serviceNode) { - // Get the customisation UUID for each VF node and use it to get its Groups - String uuid = csarHelper.getNodeTemplateCustomizationUuid(serviceNode); - List<Group> serviceGroups = csarHelper.getVfModulesByVf(uuid); + processVfModuleGroup(groupModel, csarHelper.getMembersOfVfModule(serviceNode, groupDefinition)); - // Process each VF Group - for (Group serviceGroup : serviceGroups) { - Model groupModel = Model.getModelFor(serviceGroup.getType()); - if (groupModel instanceof VfModule) { - processVfModule(resources, resourceModel, serviceGroup, serviceNode, (VfModule) groupModel); - } + vfModel.addResource(groupModel); // Add group (VfModule) to the (VF) model + // Check if we have already encountered the same VfModule across all the artifacts + if (!resources.contains(groupModel)) { + resources.add(groupModel); } } - private void processVfModule(List<Resource> resources, Model model, Group groupDefinition, NodeTemplate serviceNode, - VfModule groupModel) { - groupModel.populateModelIdentificationInformation( - mergeProperties(groupDefinition.getMetadata().getAllProperties(), groupDefinition.getProperties())); - processVfModuleGroup(resources, model, groupDefinition, serviceNode, groupModel); - } - - private void processVfModuleGroup(List<Resource> resources, Model model, Group groupDefinition, - NodeTemplate serviceNode, VfModule groupModel) { - // Get names of the members of the service group - List<NodeTemplate> members = csarHelper.getMembersOfVfModule(serviceNode, groupDefinition); + private void processVfModuleGroup(VfModule groupModel, List<NodeTemplate> members) { if (members != null && !members.isEmpty()) { + // Get names of the members of the service group List<String> memberNames = members.stream().map(NodeTemplate::getName).collect(Collectors.toList()); groupModel.setMembers(memberNames); for (NodeTemplate member : members) { processGroupMembers(groupModel, member); } } - - model.addResource(groupModel); // Added group (VfModule) to the (VF) model - // Check if we have already encountered the same VfModule across all the artifacts - if (!resources.contains(groupModel)) { - resources.add(groupModel); - } } private void processGroupMembers(Model group, NodeTemplate member) { @@ -429,28 +358,6 @@ public class ArtifactGeneratorToscaParser { } } - private String normaliseNodeTypeName(NodeTemplate nodeType) { - String nodeTypeName = nodeType.getType(); - Metadata metadata = nodeType.getMetaData(); - if (metadata != null && hasAllottedResource(metadata.getAllProperties())) { - if (nodeType.getType().contains("org.openecomp.resource.vf.")) { - nodeTypeName = "org.openecomp.resource.vf.allottedResource"; - } - if (nodeType.getType().contains("org.openecomp.resource.vfc.")) { - nodeTypeName = "org.openecomp.resource.vfc.AllottedResource"; - } - } - return nodeTypeName; - } - - private boolean hasAllottedResource(Map<String, String> metadata) { - return ALLOTTED_RESOURCE.equals(metadata.get(CATEGORY)); - } - - private boolean hasSubCategoryTunnelXConnect(Map<String, String> metadata) { - return TUNNEL_XCONNECT.equals(metadata.get(SUBCATEGORY)); - } - /** * Create a Map of property name against String property value from the input Map * @@ -464,31 +371,14 @@ public class ArtifactGeneratorToscaParser { } /** - * @param idTypeStore * @param resourceModel - * @param resourceNodeTemplates + * @param resourceNodeTemplate + * @param metaData + * @param resourceNode + * @return */ - private void processResourceModels(Map<String, String> idTypeStore, Model resourceModel, - List<NodeTemplate> resourceNodeTemplates) { - boolean foundProvidingService = false; - - for (NodeTemplate resourceNodeTemplate : resourceNodeTemplates) { - String nodeTypeName = normaliseNodeTypeName(resourceNodeTemplate); - Metadata metaData = resourceNodeTemplate.getMetaData(); - String metaDataType = Optional.ofNullable(metaData).map(m -> m.getValue("type")).orElse(nodeTypeName); - Model resourceNode = Model.getModelFor(nodeTypeName, metaDataType); - foundProvidingService |= processModel(idTypeStore, resourceModel, resourceNodeTemplate, nodeTypeName, - metaData, resourceNode); - } - - if (resourceModel instanceof AllotedResource && !foundProvidingService) { - throw new IllegalArgumentException( - String.format(GENERATOR_AAI_PROVIDING_SERVICE_MISSING, resourceModel.getModelId())); - } - } - - private boolean processModel(Map<String, String> idTypeStore, Model resourceModel, - NodeTemplate resourceNodeTemplate, String nodeTypeName, Metadata metaData, Model resourceNode) { + private boolean processModel(Model resourceModel, NodeTemplate resourceNodeTemplate, Metadata metaData, + Model resourceNode) { boolean foundProvidingService = false; if (resourceNode instanceof ProvidingService) { foundProvidingService = true; @@ -497,7 +387,6 @@ public class ArtifactGeneratorToscaParser { if (metaData != null) { resourceNode.populateModelIdentificationInformation(metaData.getAllProperties()); } - idTypeStore.put(resourceNode.getModelNameVersionId(), nodeTypeName); resourceModel.addResource((Resource) resourceNode); } return foundProvidingService; diff --git a/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java b/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java index 67c0b2f..bd7144f 100644 --- a/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java +++ b/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java @@ -23,9 +23,10 @@ package org.onap.aai.babel.xml.generator.api; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; import java.util.Map; + import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.onap.aai.babel.logging.ApplicationMsgs; @@ -41,6 +42,7 @@ import org.onap.aai.babel.xml.generator.model.Model; import org.onap.aai.babel.xml.generator.model.ProvidingService; import org.onap.aai.babel.xml.generator.model.Resource; import org.onap.aai.babel.xml.generator.model.Service; +import org.onap.aai.babel.xml.generator.model.TunnelXconnectWidget; import org.onap.aai.cl.api.Logger; import org.onap.sdc.tosca.parser.api.ISdcCsarHelper; import org.onap.sdc.tosca.parser.impl.SdcToscaParserFactory; @@ -49,230 +51,300 @@ import org.slf4j.MDC; public class AaiArtifactGenerator implements ArtifactGenerator { - private static Logger log = LogHelper.INSTANCE; - - private static final String MDC_PARAM_MODEL_INFO = "ARTIFACT_MODEL_INFO"; - private static final String GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION = "xml"; - private static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA = - "Service tosca missing from list of input artifacts"; - private static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION = - "Cannot generate artifacts. Service version is not specified"; - private static final String GENERATOR_AAI_INVALID_SERVICE_VERSION = - "Cannot generate artifacts. Service version is incorrect"; - - private AaiModelGenerator modelGenerator = new AaiModelGeneratorImpl(); - - @Override - public GenerationData generateArtifact(byte[] csarArchive, List<Artifact> input, - Map<String, String> additionalParams) { - Path csarPath; - - try { - csarPath = createTempFile(csarArchive); - } catch (IOException e) { - log.error(ApplicationMsgs.TEMP_FILE_ERROR, e); - return createErrorData(e); - } - - try { - ArtifactGeneratorToscaParser.initWidgetConfiguration(); - ArtifactGeneratorToscaParser.initGroupFilterConfiguration(); - ISdcCsarHelper csarHelper = - SdcToscaParserFactory.getInstance().getSdcCsarHelper(csarPath.toAbsolutePath().toString()); - return generateService(validateServiceVersion(additionalParams), csarHelper); - } catch (Exception e) { - log.error(ApplicationMsgs.INVALID_CSAR_FILE, e); - return createErrorData(e); - } finally { - FileUtils.deleteQuietly(csarPath.toFile()); - } - } - - private GenerationData createErrorData(Exception e) { - GenerationData generationData = new GenerationData(); - generationData.add(ArtifactType.AAI.name(), e.getMessage()); - return generationData; - } - - /** - * Generate model artifacts for the Service and its associated Resources. - * - * @param serviceVersion - * @param csarHelper TOSCA parser - * @return the generated Artifacts - */ - private GenerationData generateService(final String serviceVersion, ISdcCsarHelper csarHelper) { - List<NodeTemplate> serviceNodeTemplates = csarHelper.getServiceNodeTemplates(); - if (serviceNodeTemplates == null) { - throw new IllegalArgumentException(GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA); - } - - // Populate basic service model metadata - Service serviceModel = new Service(); - serviceModel.setModelVersion(serviceVersion); - serviceModel.populateModelIdentificationInformation(csarHelper.getServiceMetadataAllProperties()); - - Map<String, String> idTypeStore = new HashMap<>(); - - ArtifactGeneratorToscaParser parser = new ArtifactGeneratorToscaParser(csarHelper); - if (!serviceNodeTemplates.isEmpty()) { - parser.processServiceTosca(serviceModel, idTypeStore, serviceNodeTemplates); - } - - // Process the resource TOSCA files - List<Resource> resources = parser.processResourceToscas(serviceNodeTemplates, idTypeStore); - - MDC.put(MDC_PARAM_MODEL_INFO, serviceModel.getModelName() + "," + getArtifactLabel(serviceModel)); - String aaiServiceModel = modelGenerator.generateModelFor(serviceModel); - - GenerationData generationData = new GenerationData(); - generationData.add(getServiceArtifact(serviceModel, aaiServiceModel)); - - // Generate AAI XML resource model - for (Resource resource : resources) { - generateResourceArtifact(generationData, resource); - for (Resource childResource : resource.getResources()) { - if (!(childResource instanceof ProvidingService)) { - generateResourceArtifact(generationData, childResource); - } - } - } - - return generationData; - } - - /** - * @param generationData - * @param resource - */ - private void generateResourceArtifact(GenerationData generationData, Resource resource) { - if (!isContained(generationData, getArtifactName(resource))) { - log.info(ApplicationMsgs.DISTRIBUTION_EVENT, "Generating resource model"); - Artifact resourceArtifact = getResourceArtifact(resource, modelGenerator.generateModelFor(resource)); - generationData.add(resourceArtifact); - } - } - - private Path createTempFile(byte[] bytes) throws IOException { - log.debug("Creating temp file on file system for the csar"); - Path path = Files.createTempFile("temp", ".csar"); - Files.write(path, bytes); - return path; - } - - /** - * Create the artifact label for an AAI model. - * - * @param model - * @return the artifact label as String - */ - private String getArtifactLabel(Model model) { - StringBuilder artifactName = new StringBuilder(ArtifactType.AAI.name()); - artifactName.append("-"); - artifactName.append(model.getModelType().name().toLowerCase()); - artifactName.append("-"); - artifactName.append(hashCodeUuId(model.getModelNameVersionId())); - return (artifactName.toString()).replaceAll("[^a-zA-Z0-9 +]+", "-"); - } - - /** - * Method to generate the artifact name for an AAI model. - * - * @param model AAI artifact model - * @return Model artifact name - */ - private String getArtifactName(Model model) { - StringBuilder artifactName = new StringBuilder(ArtifactType.AAI.name()); - artifactName.append("-"); - - String truncatedArtifactName = truncateName(model.getModelName()); - artifactName.append(truncatedArtifactName); - - artifactName.append("-"); - artifactName.append(model.getModelType().name().toLowerCase()); - artifactName.append("-"); - artifactName.append(model.getModelVersion()); - - artifactName.append("."); - artifactName.append(GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION); - return artifactName.toString(); - } - - /** - * Create Resource artifact model from the AAI xml model string. - * - * @param resourceModel Model of the resource artifact - * @param aaiResourceModel AAI model as string - * @return Generated {@link Artifact} model for the resource - */ - private Artifact getResourceArtifact(Model resourceModel, String aaiResourceModel) { - final String resourceArtifactLabel = getArtifactLabel(resourceModel); - MDC.put(MDC_PARAM_MODEL_INFO, resourceModel.getModelName() + "," + resourceArtifactLabel); - final byte[] bytes = aaiResourceModel.getBytes(); - - Artifact artifact = new Artifact(ArtifactType.MODEL_INVENTORY_PROFILE.name(), GroupType.DEPLOYMENT.name(), - GeneratorUtil.checkSum(bytes), GeneratorUtil.encode(bytes)); - artifact.setName(getArtifactName(resourceModel)); - artifact.setLabel(resourceArtifactLabel); - artifact.setDescription(ArtifactGeneratorToscaParser.getArtifactDescription(resourceModel)); - return artifact; - } - - /** - * @param generationData - * @param artifactName - * @return - */ - private boolean isContained(GenerationData generationData, final String artifactName) { - return generationData.getResultData().stream() - .anyMatch(artifact -> StringUtils.equals(artifact.getName(), artifactName)); - } - - /** - * Create Service artifact model from the AAI xml model string. - * - * @param serviceModel Model of the service artifact - * @param aaiServiceModel AAI model as string - * @return Generated {@link Artifact} model for the service - */ - private Artifact getServiceArtifact(Service serviceModel, String aaiServiceModel) { - Artifact artifact = new Artifact(ArtifactType.MODEL_INVENTORY_PROFILE.name(), GroupType.DEPLOYMENT.name(), - GeneratorUtil.checkSum(aaiServiceModel.getBytes()), GeneratorUtil.encode(aaiServiceModel.getBytes())); - String serviceArtifactName = getArtifactName(serviceModel); - String serviceArtifactLabel = getArtifactLabel(serviceModel); - artifact.setName(serviceArtifactName); - artifact.setLabel(serviceArtifactLabel); - String description = ArtifactGeneratorToscaParser.getArtifactDescription(serviceModel); - artifact.setDescription(description); - return artifact; - } - - private int hashCodeUuId(String uuId) { - int hashcode = 0; - for (int i = 0; i < uuId.length(); i++) { - hashcode = 31 * hashcode + uuId.charAt(i); - } - return hashcode; - } - - private String truncateName(String name) { - String truncatedName = name; - if (name.length() >= 200) { - truncatedName = name.substring(0, 199); - } - return truncatedName; - } - - private String validateServiceVersion(Map<String, String> additionalParams) { - String serviceVersion = additionalParams.get(AdditionalParams.SERVICE_VERSION.getName()); - if (serviceVersion == null) { - throw new IllegalArgumentException(GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION); - } else { - String versionRegex = "^[1-9]\\d*(\\.0)$"; - if (!(serviceVersion.matches(versionRegex))) { - throw new IllegalArgumentException(String.format(GENERATOR_AAI_INVALID_SERVICE_VERSION)); - } - } - return serviceVersion; - } + private static Logger log = LogHelper.INSTANCE; + + private static final String MDC_PARAM_MODEL_INFO = "ARTIFACT_MODEL_INFO"; + private static final String GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION = "xml"; + private static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA = "Service tosca missing from list of input artifacts"; + private static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION = "Cannot generate artifacts. Service version is not specified"; + private static final String GENERATOR_AAI_INVALID_SERVICE_VERSION = "Cannot generate artifacts. Service version is incorrect"; + + private AaiModelGenerator modelGenerator = new AaiModelGeneratorImpl(); + + @Override + public GenerationData generateArtifact(byte[] csarArchive, List<Artifact> input, + Map<String, String> additionalParams) { + Path csarPath; + + try { + csarPath = createTempFile(csarArchive); + } catch (IOException e) { + log.error(ApplicationMsgs.TEMP_FILE_ERROR, e); + return createErrorData(e); + } + + try { + ArtifactGeneratorToscaParser.initWidgetConfiguration(); + ArtifactGeneratorToscaParser.initGroupFilterConfiguration(); + ISdcCsarHelper csarHelper = SdcToscaParserFactory.getInstance() + .getSdcCsarHelper(csarPath.toAbsolutePath().toString()); + return generateAllArtifacts(validateServiceVersion(additionalParams), csarHelper); + } catch (Exception e) { + log.error(ApplicationMsgs.INVALID_CSAR_FILE, e); + return createErrorData(e); + } finally { + FileUtils.deleteQuietly(csarPath.toFile()); + } + } + + private GenerationData createErrorData(Exception e) { + GenerationData generationData = new GenerationData(); + generationData.add(ArtifactType.AAI.name(), e.getMessage()); + return generationData; + } + + /** + * Generate model artifacts for the Service and its associated Resources. + * + * @param serviceVersion + * @param csarHelper + * interface to the TOSCA parser + * @return the generated Artifacts (containing XML models) + */ + private GenerationData generateAllArtifacts(final String serviceVersion, ISdcCsarHelper csarHelper) { + List<NodeTemplate> serviceNodeTemplates = csarHelper.getServiceNodeTemplates(); + if (serviceNodeTemplates == null) { + throw new IllegalArgumentException(GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA); + } + + Service serviceModel = createServiceModel(serviceVersion, csarHelper.getServiceMetadataAllProperties()); + + MDC.put(MDC_PARAM_MODEL_INFO, serviceModel.getModelName() + "," + getArtifactLabel(serviceModel)); + + List<Resource> resources = generateResourceModels(csarHelper, serviceNodeTemplates, serviceModel); + + // Generate the A&AI XML model for the Service. + final String serviceArtifact = modelGenerator.generateModelFor(serviceModel); + + // Build a Babel Artifact to be returned to the caller. + GenerationData generationData = new GenerationData(); + generationData.add(getServiceArtifact(serviceModel, serviceArtifact)); + + // For each Resource, generate the A&AI XML model and then create an additional Artifact for that model. + for (Resource resource : resources) { + generateResourceArtifact(generationData, resource); + for (Resource childResource : resource.getResources()) { + if (!(childResource instanceof ProvidingService)) { + generateResourceArtifact(generationData, childResource); + } + } + } + + return generationData; + } + + /** + * Create a Service from the provided metadata + * + * @param serviceVersion + * @param properties + * @return + */ + private Service createServiceModel(final String serviceVersion, Map<String, String> properties) { + log.debug("Processing (TOSCA) Service object"); + Service serviceModel = new Service(); + serviceModel.setModelVersion(serviceVersion); + serviceModel.populateModelIdentificationInformation(properties); + return serviceModel; + } + + /** + * @param csarHelper + * @param serviceNodeTemplates + * @param serviceModel + * @return the generated Models + */ + private List<Resource> generateResourceModels(ISdcCsarHelper csarHelper, List<NodeTemplate> serviceNodeTemplates, + Service serviceModel) { + final ArtifactGeneratorToscaParser parser = new ArtifactGeneratorToscaParser(csarHelper); + + List<Resource> resources = new ArrayList<>(); + + for (NodeTemplate nodeTemplate : serviceNodeTemplates) { + if (nodeTemplate.getMetaData() != null) { + generateModelFromNodeTemplate(csarHelper, serviceModel, resources, parser, nodeTemplate); + } else { + log.warn(ApplicationMsgs.MISSING_SERVICE_METADATA, nodeTemplate.getName()); + } + } + + return resources; + } + + private void generateModelFromNodeTemplate(ISdcCsarHelper csarHelper, Service serviceModel, + List<Resource> resources, ArtifactGeneratorToscaParser parser, NodeTemplate nodeTemplate) { + String nodeTypeName = parser.normaliseNodeTypeName(nodeTemplate); + Model model = Model.getModelFor(nodeTypeName, nodeTemplate.getMetaData().getValue("type")); + if (model != null) { + if (nodeTemplate.getMetaData() != null) { + model.populateModelIdentificationInformation(nodeTemplate.getMetaData().getAllProperties()); + } + + parser.addRelatedModel(serviceModel, model); + if (model instanceof Resource) { + generateResourceModel(csarHelper, resources, parser, nodeTemplate, nodeTypeName); + } + } + } + + private void generateResourceModel(ISdcCsarHelper csarHelper, List<Resource> resources, + ArtifactGeneratorToscaParser parser, NodeTemplate nodeTemplate, String nodeTypeName) { + log.debug("Processing resource " + nodeTypeName + ": " + nodeTemplate.getMetaData().getValue("UUID")); + Model resourceModel = Model.getModelFor(nodeTypeName, nodeTemplate.getMetaData().getValue("type")); + + Map<String, String> serviceMetadata = nodeTemplate.getMetaData().getAllProperties(); + resourceModel.populateModelIdentificationInformation(serviceMetadata); + + parser.processResourceModels(resourceModel, csarHelper.getNodeTemplateChildren(nodeTemplate)); + + if (csarHelper.getServiceVfList() != null) { + parser.processVfModules(resources, resourceModel, nodeTemplate); + } + + if (parser.hasSubCategoryTunnelXConnect(serviceMetadata) && parser.hasAllottedResource(serviceMetadata)) { + resourceModel.addWidget(new TunnelXconnectWidget()); + } + + resources.addAll(parser.processInstanceGroups(resourceModel, nodeTemplate)); + resources.add((Resource) resourceModel); + } + + /** + * @param generationData + * @param resource + */ + private void generateResourceArtifact(GenerationData generationData, Resource resource) { + if (!isContained(generationData, getArtifactName(resource))) { + log.info(ApplicationMsgs.DISTRIBUTION_EVENT, "Generating resource model"); + generationData.add(getResourceArtifact(resource, modelGenerator.generateModelFor(resource))); + } + } + + private Path createTempFile(byte[] bytes) throws IOException { + log.debug("Creating temp file on file system for the csar"); + Path path = Files.createTempFile("temp", ".csar"); + Files.write(path, bytes); + return path; + } + + /** + * Create the artifact label for an AAI model. + * + * @param model + * @return the artifact label as String + */ + private String getArtifactLabel(Model model) { + StringBuilder artifactName = new StringBuilder(ArtifactType.AAI.name()); + artifactName.append("-"); + artifactName.append(model.getModelType().name().toLowerCase()); + artifactName.append("-"); + artifactName.append(hashCodeUuId(model.getModelNameVersionId())); + return (artifactName.toString()).replaceAll("[^a-zA-Z0-9 +]+", "-"); + } + + /** + * Method to generate the artifact name for an AAI model. + * + * @param model + * AAI artifact model + * @return Model artifact name + */ + private String getArtifactName(Model model) { + StringBuilder artifactName = new StringBuilder(ArtifactType.AAI.name()); + artifactName.append("-"); + + String truncatedArtifactName = truncateName(model.getModelName()); + artifactName.append(truncatedArtifactName); + + artifactName.append("-"); + artifactName.append(model.getModelType().name().toLowerCase()); + artifactName.append("-"); + artifactName.append(model.getModelVersion()); + + artifactName.append("."); + artifactName.append(GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION); + return artifactName.toString(); + } + + /** + * Create Resource artifact model from the AAI xml model string. + * + * @param resourceModel + * Model of the resource artifact + * @param aaiResourceModel + * AAI model as string + * @return Generated {@link Artifact} model for the resource + */ + private Artifact getResourceArtifact(Model resourceModel, String aaiResourceModel) { + final String resourceArtifactLabel = getArtifactLabel(resourceModel); + MDC.put(MDC_PARAM_MODEL_INFO, resourceModel.getModelName() + "," + resourceArtifactLabel); + final byte[] bytes = aaiResourceModel.getBytes(); + + Artifact artifact = new Artifact(ArtifactType.MODEL_INVENTORY_PROFILE.name(), GroupType.DEPLOYMENT.name(), + GeneratorUtil.checkSum(bytes), GeneratorUtil.encode(bytes)); + artifact.setName(getArtifactName(resourceModel)); + artifact.setLabel(resourceArtifactLabel); + artifact.setDescription(ArtifactGeneratorToscaParser.getArtifactDescription(resourceModel)); + return artifact; + } + + /** + * @param generationData + * @param artifactName + * @return + */ + private boolean isContained(GenerationData generationData, final String artifactName) { + return generationData.getResultData().stream() + .anyMatch(artifact -> StringUtils.equals(artifact.getName(), artifactName)); + } + + /** + * Create Service artifact model from the AAI XML model. + * + * @param serviceModel + * Model of the service artifact + * @param aaiServiceModel + * AAI model as string + * @return Generated {@link Artifact} model for the service + */ + private Artifact getServiceArtifact(Service serviceModel, String aaiServiceModel) { + Artifact artifact = new Artifact(ArtifactType.MODEL_INVENTORY_PROFILE.name(), GroupType.DEPLOYMENT.name(), + GeneratorUtil.checkSum(aaiServiceModel.getBytes()), GeneratorUtil.encode(aaiServiceModel.getBytes())); + String serviceArtifactName = getArtifactName(serviceModel); + String serviceArtifactLabel = getArtifactLabel(serviceModel); + artifact.setName(serviceArtifactName); + artifact.setLabel(serviceArtifactLabel); + String description = ArtifactGeneratorToscaParser.getArtifactDescription(serviceModel); + artifact.setDescription(description); + return artifact; + } + + private int hashCodeUuId(String uuId) { + int hashcode = 0; + for (int i = 0; i < uuId.length(); i++) { + hashcode = 31 * hashcode + uuId.charAt(i); + } + return hashcode; + } + + private String truncateName(String name) { + String truncatedName = name; + if (name.length() >= 200) { + truncatedName = name.substring(0, 199); + } + return truncatedName; + } + + private String validateServiceVersion(Map<String, String> additionalParams) { + String serviceVersion = additionalParams.get(AdditionalParams.SERVICE_VERSION.getName()); + if (serviceVersion == null) { + throw new IllegalArgumentException(GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION); + } else { + String versionRegex = "^[1-9]\\d*(\\.0)$"; + if (!(serviceVersion.matches(versionRegex))) { + throw new IllegalArgumentException(String.format(GENERATOR_AAI_INVALID_SERVICE_VERSION)); + } + } + return serviceVersion; + } } diff --git a/src/main/java/org/onap/aai/babel/xml/generator/model/Resource.java b/src/main/java/org/onap/aai/babel/xml/generator/model/Resource.java index 9d4feab..b3d42ec 100644 --- a/src/main/java/org/onap/aai/babel/xml/generator/model/Resource.java +++ b/src/main/java/org/onap/aai/babel/xml/generator/model/Resource.java @@ -22,33 +22,34 @@ package org.onap.aai.babel.xml.generator.model; public class Resource extends Model { - @Override - public int hashCode() { - return getModelNameVersionId().hashCode(); - } + @Override + public int hashCode() { + final String uuid = getModelNameVersionId(); + return uuid == null ? 0 : uuid.hashCode(); + } - @Override - public boolean equals(Object obj) { - if (obj instanceof Resource) { - return getModelNameVersionId().equals(((Resource) obj).getModelNameVersionId()); - } - return false; - } + @Override + public boolean equals(Object obj) { + if (obj instanceof Resource) { + return getModelNameVersionId().equals(((Resource) obj).getModelNameVersionId()); + } + return false; + } - @Override - public boolean addResource(Resource resource) { - return resources.add(resource); - } + @Override + public boolean addResource(Resource resource) { + return resources.add(resource); + } - @Override - public boolean addWidget(Widget widget) { - return widgets.add(widget); - } + @Override + public boolean addWidget(Widget widget) { + return widgets.add(widget); + } - @Override - public Widget.Type getWidgetType() { - org.onap.aai.babel.xml.generator.types.Model model = - this.getClass().getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); - return model.widget(); - } + @Override + public Widget.Type getWidgetType() { + org.onap.aai.babel.xml.generator.types.Model model = this.getClass() + .getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); + return model.widget(); + } } diff --git a/src/test/java/org/onap/aai/babel/parser/TestArtifactGeneratorToscaParser.java b/src/test/java/org/onap/aai/babel/parser/TestArtifactGeneratorToscaParser.java index 6cf6d31..3cbaa13 100644 --- a/src/test/java/org/onap/aai/babel/parser/TestArtifactGeneratorToscaParser.java +++ b/src/test/java/org/onap/aai/babel/parser/TestArtifactGeneratorToscaParser.java @@ -30,9 +30,11 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Properties; + import org.junit.Test; import org.mockito.Mockito; import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil; +import org.onap.aai.babel.xml.generator.model.AllotedResource; import org.onap.aai.babel.xml.generator.model.InstanceGroup; import org.onap.aai.babel.xml.generator.model.Resource; import org.onap.sdc.tosca.parser.api.ISdcCsarHelper; @@ -41,7 +43,8 @@ import org.onap.sdc.toscaparser.api.NodeTemplate; import org.onap.sdc.toscaparser.api.SubstitutionMappings; /** - * Direct tests of the TOSCA parser-based Artifact Generator, to cover exceptional cases. + * Direct tests of the TOSCA parser-based Artifact Generator {@link ArtifactGeneratorToscaParser}., to cover exceptional + * cases. */ public class TestArtifactGeneratorToscaParser { @@ -49,14 +52,23 @@ public class TestArtifactGeneratorToscaParser { private static final String TEST_UUID = "1234"; /** - * Process a dummy Node Template object for a Service. A WARNING should be logged for the missing metadata. + * Process an Allotted Resource that does not have a Providing Service. */ - @Test - public void testMissingServiceData() { + @Test(expected = IllegalArgumentException.class) + public void testMissingProvidingService() { List<NodeTemplate> nodeTemplateList = Collections.singletonList(buildNodeTemplate("name", "BlockStorage")); - ArtifactGeneratorToscaParser parser = new ArtifactGeneratorToscaParser(null); - parser.processServiceTosca(null, Collections.emptyMap(), nodeTemplateList); - parser.processResourceToscas(nodeTemplateList, null); + new ArtifactGeneratorToscaParser(null).processResourceModels(new AllotedResource(), nodeTemplateList); + } + + /** + * + * Add a CR (a type of Resource which is not a Providing Service) to a Resource Model. + */ + @Test(expected = IllegalArgumentException.class) + public void testAddResourceNotProvidingService() { + List<NodeTemplate> nodeTemplateList = Collections.singletonList(buildNodeTemplate("testCR", "CR")); + final Resource dummyResource = new AllotedResource(); // Any Resource to which the CR can be added + new ArtifactGeneratorToscaParser(null).processResourceModels(dummyResource, nodeTemplateList); } /** @@ -72,22 +84,33 @@ public class TestArtifactGeneratorToscaParser { ISdcCsarHelper helper = Mockito.mock(ISdcCsarHelper.class); SubstitutionMappings sm = Mockito.mock(SubstitutionMappings.class); - NodeTemplate serviceNode = buildNodeTemplate("service", "org.openecomp.resource.cr.a-collection-resource"); - serviceNode.setSubMappingToscaTemplate(sm); - Mockito.when(helper.getNodeTemplateByName(serviceNode.getName())).thenReturn(serviceNode); + NodeTemplate serviceNodeTemplate = buildNodeTemplate("service", + "org.openecomp.resource.cr.a-collection-resource"); + serviceNodeTemplate.setSubMappingToscaTemplate(sm); + Mockito.when(helper.getNodeTemplateByName(serviceNodeTemplate.getName())).thenReturn(serviceNodeTemplate); ArrayList<Group> groups = new ArrayList<>(); groups.add(buildGroup("group", instanceGroupType)); - Mockito.when(helper.getGroupsOfOriginOfNodeTemplate(serviceNode)).thenReturn(groups); + Mockito.when(helper.getGroupsOfOriginOfNodeTemplate(serviceNodeTemplate)).thenReturn(groups); ArtifactGeneratorToscaParser parser = new ArtifactGeneratorToscaParser(helper); - List<Resource> resources = parser.processInstanceGroups(new InstanceGroup(), serviceNode); + List<Resource> resources = parser.processInstanceGroups(new InstanceGroup(), serviceNodeTemplate); assertThat(resources.size(), is(1)); Resource resource = resources.get(0); assertThat(resource.getModelNameVersionId(), is(equalTo(TEST_UUID))); } + /** + * Create a NodeTemplate for unit testing purposes. In production code this object would only be created by the + * sdc-tosca parser. + * + * @param name + * name of the NodeTemplate + * @param type + * type of the NodeTemplate + * @return a new NodeTemplate object + */ private NodeTemplate buildNodeTemplate(String name, String type) { LinkedHashMap<String, Object> nodeTemplateMap = new LinkedHashMap<>(); nodeTemplateMap.put(name, buildMap("type", type)); |