Add support for loading VNF Catalog XML files 55/50955/1
authormark.j.leonard <mark.j.leonard@gmail.com>
Thu, 7 Jun 2018 15:45:38 +0000 (16:45 +0100)
committermark.j.leonard <mark.j.leonard@gmail.com>
Thu, 7 Jun 2018 16:17:30 +0000 (17:17 +0100)
Issue-ID: AAI-1214
Change-Id: I5d0eb3456916e6f3e5ba3a9b4e828feaff0cde4e
Signed-off-by: mark.j.leonard <mark.j.leonard@gmail.com>
23 files changed:
Readme.md
pom.xml
src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java
src/main/java/org/onap/aai/modelloader/entity/ArtifactType.java
src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifact.java
src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler.java
src/main/java/org/onap/aai/modelloader/extraction/VnfCatalogExtractor.java [new file with mode: 0644]
src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java
src/main/java/org/onap/aai/modelloader/notification/NotificationPublisher.java
src/main/java/org/onap/aai/modelloader/service/ModelLoaderMsgs.java
src/main/java/org/onap/aai/modelloader/util/JsonXmlConverter.java
src/main/resources/org/onap/aai/modelloader/service/ModelLoaderMsgs.properties
src/test/java/org/onap/aai/modelloader/csar/extractor/VnfCatalogExtractorTest.java [new file with mode: 0644]
src/test/java/org/onap/aai/modelloader/entity/catalog/TestVnfCatalogArtifactHandler.java
src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerVnfcTest.java [new file with mode: 0644]
src/test/java/org/onap/aai/modelloader/service/TestModelLoaderService.java
src/test/java/org/onap/aai/modelloader/util/TestJsonXmlConverter.java
src/test/resources/compressedArtifacts/noVnfcFilesArchive.csar [new file with mode: 0644]
src/test/resources/compressedArtifacts/threeVnfcFilesArchive.csar [new file with mode: 0644]
src/test/resources/xmlFiles/fortigate.xml [new file with mode: 0644]
src/test/resources/xmlFiles/vnfcatalog-1.xml [new file with mode: 0644]
src/test/resources/xmlFiles/vnfcatalog-2.xml [new file with mode: 0644]
src/test/resources/xmlFiles/vnfcatalog-3.xml [new file with mode: 0644]

index d8f1f02..3d7aaae 100644 (file)
--- a/Readme.md
+++ b/Readme.md
@@ -1,7 +1,7 @@
 # Introduction
 
 The A&AI Model Loader Service is an application that facilitates the distribution and ingestion of 
-new service and resource models from the SDC to the A&AI.
+new service and resource models and VNF catalogs from the SDC to the A&AI.
 
 ## Features
 
@@ -11,7 +11,18 @@ The Model Loader:
 * polls the UEB/DMaap cluster for notification events
 * downloads artifacts from SDC upon receipt of a distribution event
 * pushes distribution components to A&AI
+                   
+### VNF Catalog loading
 
+The Model Loader supports two methods for supplying VNF Catalog data for loading into A&AI:
+
+* Embedded TOSCA image and vendor data<br/>VNF Catalog data can be embedded within the TOSCA yaml files contained in the CSAR.
+
+
+* VNF Catalog XML files<br/>VNF Catalog data in the form of XML files can be supplied in the CSAR under the path `Artifacts/Deployment/VNF_CATALOG`
+
+**Note: Each CSAR should provide VNF Catalog information using only one of the above methods. If a CSAR contains both TOSCA and XML VNF Catalog information, a deploy failure will be logged and published to SDC, and no VNF Catalog data will be loaded into A&AI** 
+                   
 ## Compiling Model Loader
 
 Model Loader can be compiled by running `mvn clean install`
@@ -35,7 +46,7 @@ You will be mounting these as data volumes when you start the Docker container.
 
 The following file must be present in this directory on the host machine:
     
-_model-loader.properties_
+_model-loader.properties_  
 
     # Always false.  TLS Auth currently not supported 
     ml.distribution.ACTIVE_SERVER_TLS_AUTH=false
@@ -127,6 +138,6 @@ You can now start the Docker container for the _Model Loader Service_, e.g:
            {{your docker repo}}/model-loader
     
 where
+
     {{your docker repo}}
 is the Docker repository you have published your image to.
diff --git a/pom.xml b/pom.xml
index ae5e7cd..16c478c 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
        <parent>
                <groupId>org.onap.oparent</groupId>
                <artifactId>oparent</artifactId>
-               <version>1.1.0</version>
+               <version>1.1.1</version>
                <relativePath />
        </parent>
 
@@ -52,6 +52,7 @@
                <docker.location>${basedir}/target</docker.location>
                <spring-boot.version>1.5.12.RELEASE</spring-boot.version>
                <apache.commons-text.version>1.1</apache.commons-text.version>
+               <commons-compress.version>1.14</commons-compress.version>
                <hamcrest-all.version>1.3</hamcrest-all.version>
                <babel.version>1.2.0</babel.version>
                <aai.rest.client.version>1.2.1</aai.rest.client.version>
                        <artifactId>jline</artifactId>
                        <version>2.12.1</version>
                </dependency>
+               <dependency>
+                       <groupId>org.apache.commons</groupId>
+                       <artifactId>commons-compress</artifactId>
+                       <version>${commons-compress.version}</version>
+               </dependency>
                <dependency>
                        <groupId>commons-io</groupId>
                        <artifactId>commons-io</artifactId>
index 0a2bc85..01505ba 100644 (file)
@@ -21,6 +21,8 @@
 package org.onap.aai.modelloader.config;
 
 import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
@@ -47,29 +49,29 @@ public class ModelLoaderConfig implements IConfiguration {
     private static final String SUFFIX_TRUSTSTORE_PASS = "TRUSTSTORE_PASSWORD";
 
     // Configuration file properties
-       protected static final String PROP_ML_DISTRIBUTION_ACTIVE_SERVER_TLS_AUTH = PREFIX_DISTRIBUTION_CLIENT
-                       + "ACTIVE_SERVER_TLS_AUTH";
-       protected static final String PROP_ML_DISTRIBUTION_ASDC_CONNECTION_DISABLED = PREFIX_DISTRIBUTION_CLIENT
-                       + "ASDC_CONNECTION_DISABLE";
+    protected static final String PROP_ML_DISTRIBUTION_ACTIVE_SERVER_TLS_AUTH =
+            PREFIX_DISTRIBUTION_CLIENT + "ACTIVE_SERVER_TLS_AUTH";
+    protected static final String PROP_ML_DISTRIBUTION_ASDC_CONNECTION_DISABLED =
+            PREFIX_DISTRIBUTION_CLIENT + "ASDC_CONNECTION_DISABLE";
     protected static final String PROP_ML_DISTRIBUTION_ASDC_ADDRESS = PREFIX_DISTRIBUTION_CLIENT + "ASDC_ADDRESS";
     protected static final String PROP_ML_DISTRIBUTION_CONSUMER_GROUP = PREFIX_DISTRIBUTION_CLIENT + "CONSUMER_GROUP";
     protected static final String PROP_ML_DISTRIBUTION_CONSUMER_ID = PREFIX_DISTRIBUTION_CLIENT + "CONSUMER_ID";
-       protected static final String PROP_ML_DISTRIBUTION_ENVIRONMENT_NAME = PREFIX_DISTRIBUTION_CLIENT
-                       + "ENVIRONMENT_NAME";
-       protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_PASSWORD = PREFIX_DISTRIBUTION_CLIENT
-                       + SUFFIX_KEYSTORE_PASS;
-       protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_FILE = PREFIX_DISTRIBUTION_CLIENT
-                       + SUFFIX_KEYSTORE_FILE;
+    protected static final String PROP_ML_DISTRIBUTION_ENVIRONMENT_NAME =
+            PREFIX_DISTRIBUTION_CLIENT + "ENVIRONMENT_NAME";
+    protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_PASSWORD =
+            PREFIX_DISTRIBUTION_CLIENT + SUFFIX_KEYSTORE_PASS;
+    protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_FILE =
+            PREFIX_DISTRIBUTION_CLIENT + SUFFIX_KEYSTORE_FILE;
     protected static final String PROP_ML_DISTRIBUTION_PASSWORD = PREFIX_DISTRIBUTION_CLIENT + "PASSWORD";
-       protected static final String PROP_ML_DISTRIBUTION_POLLING_INTERVAL = PREFIX_DISTRIBUTION_CLIENT
-                       + "POLLING_INTERVAL";
+    protected static final String PROP_ML_DISTRIBUTION_POLLING_INTERVAL =
+            PREFIX_DISTRIBUTION_CLIENT + "POLLING_INTERVAL";
     protected static final String PROP_ML_DISTRIBUTION_POLLING_TIMEOUT = PREFIX_DISTRIBUTION_CLIENT + "POLLING_TIMEOUT";
     protected static final String PROP_ML_DISTRIBUTION_USER = PREFIX_DISTRIBUTION_CLIENT + "USER";
     protected static final String PROP_ML_DISTRIBUTION_ARTIFACT_TYPES = PREFIX_DISTRIBUTION_CLIENT + "ARTIFACT_TYPES";
-       protected static final String PROP_ML_DISTRIBUTION_MSG_BUS_ADDRESSES = PREFIX_DISTRIBUTION_CLIENT
-                       + "MSG_BUS_ADDRESSES";
-       protected static final String PROP_ML_DISTRIBUTION_HTTPS_WITH_DMAAP = PREFIX_DISTRIBUTION_CLIENT
-                       + "USE_HTTPS_WITH_DMAAP";
+    protected static final String PROP_ML_DISTRIBUTION_MSG_BUS_ADDRESSES =
+            PREFIX_DISTRIBUTION_CLIENT + "MSG_BUS_ADDRESSES";
+    protected static final String PROP_ML_DISTRIBUTION_HTTPS_WITH_DMAAP =
+            PREFIX_DISTRIBUTION_CLIENT + "USE_HTTPS_WITH_DMAAP";
 
     protected static final String PROP_AAI_BASE_URL = PREFIX_AAI + "BASE_URL";
     protected static final String PROP_AAI_KEYSTORE_FILE = PREFIX_AAI + SUFFIX_KEYSTORE_FILE;
@@ -88,29 +90,16 @@ public class ModelLoaderConfig implements IConfiguration {
     protected static final String PROP_BABEL_GENERATE_RESOURCE_URL = PREFIX_BABEL + "GENERATE_ARTIFACTS_URL";
 
     protected static final String PROP_DEBUG_INGEST_SIMULATOR = PREFIX_DEBUG + "INGEST_SIMULATOR";
-    private static String configHome;
+    protected static final String FILESEP =
+            (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator");
 
+    private static String configHome;
     private Properties modelLoaderProperties = null;
-
     private String certLocation = ".";
-
     private List<String> artifactTypes = null;
-
     private List<String> msgBusAddrs = null;
-
     private String modelVersion = null;
 
-       protected static final String FILESEP = (System.getProperty("file.separator") == null) ? "/"
-                       : System.getProperty("file.separator");
-
-    public static void setConfigHome(String configHome) {
-        ModelLoaderConfig.configHome = configHome;
-    }
-
-    public static String propertiesFile() {
-        return configHome + FILESEP + "model-loader.properties";
-    }
-
     public ModelLoaderConfig(Properties configProperties) {
         this(configProperties, ModelLoaderConfig.configHome + FILESEP + "auth" + FILESEP);
     }
@@ -118,10 +107,8 @@ public class ModelLoaderConfig implements IConfiguration {
     /**
      * Original constructor
      *
-        * @param modelLoaderProperties
-        *            properties needed to be configured for the model loader
-        * @param certLocation
-        *            location of the certificate
+     * @param modelLoaderProperties properties needed to be configured for the model loader
+     * @param certLocation location of the certificate
      */
     public ModelLoaderConfig(Properties modelLoaderProperties, String certLocation) {
         this.modelLoaderProperties = modelLoaderProperties;
@@ -146,6 +133,14 @@ public class ModelLoaderConfig implements IConfiguration {
         }
     }
 
+    public static void setConfigHome(String configHome) {
+        ModelLoaderConfig.configHome = configHome;
+    }
+
+    public static Path propertiesFile() {
+        return Paths.get(configHome, "model-loader.properties");
+    }
+
     @Override
     public boolean activateServerTLSAuth() {
         String value = modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_ACTIVE_SERVER_TLS_AUTH);
index a58c874..587b474 100644 (file)
@@ -24,5 +24,6 @@ public enum ArtifactType {
     MODEL,
     MODEL_V8,
     NAMED_QUERY,
-    VNF_CATALOG;
+    VNF_CATALOG,
+    VNF_CATALOG_XML;
 }
index 9a84cf2..7447726 100644 (file)
@@ -28,6 +28,7 @@ public class VnfCatalogArtifact extends Artifact {
     public VnfCatalogArtifact(String payload) {
         this(ArtifactType.VNF_CATALOG, payload);
     }
+
     public VnfCatalogArtifact(ArtifactType artifactType, String payload) {
         super(artifactType);
         setPayload(payload);
index 3480c68..c54d7b2 100644 (file)
@@ -1,5 +1,5 @@
 /**\r
- * ï»¿============LICENSE_START=======================================================\r
+ * ============LICENSE_START=======================================================\r
  * org.onap.aai\r
  * ================================================================================\r
  * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.\r
@@ -22,14 +22,20 @@ package org.onap.aai.modelloader.entity.catalog;
 \r
 import com.google.gson.Gson;\r
 import com.google.gson.reflect.TypeToken;\r
-import java.io.UnsupportedEncodingException;\r
+import java.io.StringReader;\r
+import java.net.URISyntaxException;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Map.Entry;\r
 import java.util.UUID;\r
 import javax.ws.rs.core.MediaType;\r
 import javax.ws.rs.core.Response;\r
+import javax.xml.parsers.DocumentBuilder;\r
+import javax.xml.parsers.DocumentBuilderFactory;\r
 import org.apache.commons.text.StringEscapeUtils;\r
+import org.apache.http.client.utils.URIBuilder;\r
 import org.onap.aai.cl.api.Logger;\r
 import org.onap.aai.cl.eelf.LoggerFactory;\r
 import org.onap.aai.modelloader.config.ModelLoaderConfig;\r
@@ -38,7 +44,11 @@ import org.onap.aai.modelloader.entity.ArtifactHandler;
 import org.onap.aai.modelloader.restclient.AaiRestClient;\r
 import org.onap.aai.modelloader.service.ModelLoaderMsgs;\r
 import org.onap.aai.restclient.client.OperationResult;\r
-import org.springframework.web.util.UriUtils;\r
+import org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+import org.w3c.dom.Node;\r
+import org.w3c.dom.NodeList;\r
+import org.xml.sax.InputSource;\r
 \r
 /**\r
  * VNF Catalog specific handling\r
@@ -80,11 +90,47 @@ public class VnfCatalogArtifactHandler extends ArtifactHandler {
         return true;\r
     }\r
 \r
+    /*\r
+     * If something fails in the middle of ingesting the catalog we want to roll back any changes to the DB\r
+     */\r
+    @Override\r
+    public void rollback(List<Artifact> completedArtifacts, String distributionId, AaiRestClient aaiClient) {\r
+        for (Artifact completedArtifact : completedArtifacts) {\r
+            Map<String, String> data = new Gson().fromJson(completedArtifact.getPayload(),\r
+                    new TypeToken<Map<String, String>>() {}.getType());\r
+            String url = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "/vnf-image/" + data.get(ATTR_UUID);\r
+            // Try to delete the image. If something goes wrong we can't really do anything here\r
+            aaiClient.getAndDeleteResource(url, distributionId);\r
+        }\r
+    }\r
+\r
     private void distributeVnfcData(AaiRestClient restClient, String distributionId, Artifact vnfcArtifact,\r
             List<Artifact> completedArtifacts) throws VnfImageException {\r
+        List<Map<String, String>> vnfcData;\r
+        switch (vnfcArtifact.getType()) {\r
+            case VNF_CATALOG:\r
+                vnfcData = unmarshallVnfcData(vnfcArtifact);\r
+                break;\r
+            case VNF_CATALOG_XML:\r
+                vnfcData = parseXmlVnfcData(vnfcArtifact);\r
+                break;\r
+            default:\r
+                throw new VnfImageException("Unsupported type " + vnfcArtifact.getType());\r
+        }\r
+        distributeVnfcData(restClient, distributionId, completedArtifacts, vnfcData);\r
+    }\r
 \r
-        List<Map<String, String>> vnfcData = unmarshallVnfcData(vnfcArtifact);\r
-\r
+    /**\r
+     * Build a VNF image from each of the supplied data items, and distribute to AAI\r
+     * \r
+     * @param restClient\r
+     * @param distributionId\r
+     * @param completedArtifacts\r
+     * @param vnfcData\r
+     * @throws VnfImageException\r
+     */\r
+    private void distributeVnfcData(AaiRestClient restClient, String distributionId, List<Artifact> completedArtifacts,\r
+            List<Map<String, String>> vnfcData) throws VnfImageException {\r
         for (Map<String, String> dataItem : vnfcData) {\r
             // If an empty dataItem is supplied, do nothing.\r
             if (dataItem.isEmpty()) {\r
@@ -92,49 +138,47 @@ public class VnfCatalogArtifactHandler extends ArtifactHandler {
                 continue;\r
             }\r
 \r
-            String urlParams;\r
-            StringBuilder imageId = new StringBuilder("vnf image");\r
-\r
-            try {\r
-                urlParams = buildUrlImgIdStrings(imageId, dataItem);\r
-            } catch (UnsupportedEncodingException e) {\r
-                throw new VnfImageException(e);\r
+            StringBuilder imageIdBuilder = new StringBuilder("vnf image");\r
+            for (Entry<String, String> entry : dataItem.entrySet()) {\r
+                imageIdBuilder.append(" ").append(entry.getValue());\r
             }\r
+            String imageId = imageIdBuilder.toString();\r
+            int resultCode = getVnfImage(restClient, distributionId, imageId, dataItem);\r
 \r
-            OperationResult tryGet =\r
-                    restClient.getResource(config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "?" + urlParams,\r
-                            distributionId, MediaType.APPLICATION_JSON_TYPE);\r
-\r
-            if (tryGet == null) {\r
-                throw new VnfImageException(imageId.toString());\r
-            }\r
-\r
-            int resultCode = tryGet.getResultCode();\r
             if (resultCode == Response.Status.NOT_FOUND.getStatusCode()) {\r
                 // This vnf-image is missing, so add it\r
                 boolean success = putVnfImage(restClient, dataItem, distributionId);\r
-                if (!success) {\r
-                    throw new VnfImageException(imageId.toString());\r
+                if (success) {\r
+                    completedArtifacts.add(new VnfCatalogArtifact(new Gson().toJson(dataItem)));\r
+                    logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, imageId + " successfully ingested.");\r
+                } else {\r
+                    throw new VnfImageException(imageId);\r
                 }\r
-                completedArtifacts.add(vnfcArtifact);\r
-                logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, imageId + " successfully ingested.");\r
             } else if (resultCode == Response.Status.OK.getStatusCode()) {\r
                 logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, imageId + " already exists. Skipping ingestion.");\r
             } else {\r
                 // if other than 404 or 200, something went wrong\r
-                throw new VnfImageException(imageId.toString(), resultCode);\r
+                throw new VnfImageException(imageId, resultCode);\r
             }\r
         }\r
     }\r
 \r
-    private String buildUrlImgIdStrings(StringBuilder imageId, Map<String, String> dataItem)\r
-            throws UnsupportedEncodingException {\r
-        StringBuilder urlParams = new StringBuilder();\r
-        for (Entry<String, String> entry : dataItem.entrySet()) {\r
-            urlParams.append(entry.getKey()).append("=").append(UriUtils.encode(entry.getValue(), "UTF-8")).append("&");\r
-            imageId.append(" ").append(entry.getValue());\r
+    private int getVnfImage(AaiRestClient restClient, String distributionId, String imageId,\r
+            Map<String, String> dataItem) throws VnfImageException {\r
+        try {\r
+            URIBuilder b = new URIBuilder(config.getAaiBaseUrl() + config.getAaiVnfImageUrl());\r
+            for (Entry<String, String> entry : dataItem.entrySet()) {\r
+                b.addParameter(entry.getKey(), entry.getValue());\r
+            }\r
+            OperationResult tryGet =\r
+                    restClient.getResource(b.build().toString(), distributionId, MediaType.APPLICATION_JSON_TYPE);\r
+            if (tryGet == null) {\r
+                throw new VnfImageException(imageId);\r
+            }\r
+            return tryGet.getResultCode();\r
+        } catch (URISyntaxException ex) {\r
+            throw new VnfImageException(ex);\r
         }\r
-        return urlParams.deleteCharAt(urlParams.length() - 1).toString();\r
     }\r
 \r
     private boolean putVnfImage(AaiRestClient restClient, Map<String, String> dataItem, String distributionId) {\r
@@ -155,19 +199,79 @@ public class VnfCatalogArtifactHandler extends ArtifactHandler {
                 new TypeToken<List<Map<String, String>>>() {}.getType());\r
     }\r
 \r
-    /*\r
-     * If something fails in the middle of ingesting the catalog we want to roll back any changes to the DB\r
+    /**\r
+     * Parse the VNF Catalog XML and transform into Key/Value pairs.\r
+     * \r
+     * @param vnfcArtifact\r
+     * @return VNF Image data in Map form\r
+     * @throws VnfImageException\r
      */\r
-    @Override\r
-    public void rollback(List<Artifact> completedArtifacts, String distributionId, AaiRestClient aaiClient) {\r
-        for (Artifact completedArtifact : completedArtifacts) {\r
-            List<Map<String, String>> completedImageData = unmarshallVnfcData(completedArtifact);\r
-            for (Map<String, String> data : completedImageData) {\r
-                String url = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "/vnf-image/" + data.get(ATTR_UUID);\r
-                // Try to delete the image. If something goes wrong we can't really do anything here\r
-                aaiClient.getAndDeleteResource(url, distributionId);\r
+    private List<Map<String, String>> parseXmlVnfcData(Artifact vnfcArtifact) throws VnfImageException {\r
+        List<Map<String, String>> vnfcData = new ArrayList<>();\r
+        try {\r
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\r
+            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);\r
+            DocumentBuilder builder = factory.newDocumentBuilder();\r
+            InputSource is = new InputSource(new StringReader(vnfcArtifact.getPayload()));\r
+            Document doc = builder.parse(is);\r
+            doc.getDocumentElement().normalize();\r
+\r
+            NodeList pnl = doc.getElementsByTagName("part-number-list");\r
+            for (int i = 0; i < pnl.getLength(); i++) {\r
+                Node partNumber = pnl.item(i);\r
+                if (partNumber.getNodeType() == Node.ELEMENT_NODE) {\r
+                    Element vendorInfo = getFirstChildNodeByName(partNumber, "vendor-info");\r
+                    if (vendorInfo != null) {\r
+                        Map<String, String> application = new HashMap<>();\r
+                        application.put("application",\r
+                                vendorInfo.getElementsByTagName("vendor-model").item(0).getTextContent());\r
+                        application.put("application-vendor",\r
+                                vendorInfo.getElementsByTagName("vendor-name").item(0).getTextContent());\r
+                        populateSoftwareVersions(vnfcData, application, partNumber);\r
+                    }\r
+                }\r
+            }\r
+        } catch (Exception ex) {\r
+            throw new VnfImageException(ex);\r
+        }\r
+        return vnfcData;\r
+    }\r
+\r
+    /**\r
+     * @param vnfcData to populate\r
+     * @param applicationData\r
+     * @param partNumber\r
+     */\r
+    private void populateSoftwareVersions(List<Map<String, String>> vnfcData, Map<String, String> applicationData,\r
+            Node partNumber) {\r
+        NodeList nodes = partNumber.getChildNodes();\r
+        for (int i = 0; i < nodes.getLength(); i++) {\r
+            Node childNode = nodes.item(i);\r
+            if (childNode.getNodeName().equalsIgnoreCase("software-version-list")) {\r
+                Element softwareVersion = getFirstChildNodeByName(childNode, "software-version");\r
+                if (softwareVersion != null) {\r
+                    HashMap<String, String> vnfImageData = new HashMap<>(applicationData);\r
+                    vnfImageData.put("application-version", softwareVersion.getTextContent());\r
+                    vnfcData.add(vnfImageData);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @param node\r
+     * @param childNodeName\r
+     * @return the first child node matching the given name\r
+     */\r
+    private Element getFirstChildNodeByName(Node node, String childNodeName) {\r
+        NodeList nodes = node.getChildNodes();\r
+        for (int i = 0; i < nodes.getLength(); i++) {\r
+            Node childNode = nodes.item(i);\r
+            if (childNode.getNodeName().equalsIgnoreCase(childNodeName)) {\r
+                return (Element) childNode;\r
             }\r
         }\r
+        return null;\r
     }\r
 \r
 }\r
diff --git a/src/main/java/org/onap/aai/modelloader/extraction/VnfCatalogExtractor.java b/src/main/java/org/onap/aai/modelloader/extraction/VnfCatalogExtractor.java
new file mode 100644 (file)
index 0000000..5682774
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.onap.aai.modelloader.extraction;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.regex.Pattern;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.modelloader.entity.Artifact;
+import org.onap.aai.modelloader.entity.ArtifactType;
+import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifact;
+import org.onap.aai.modelloader.service.ModelLoaderMsgs;
+
+
+/**
+ * The purpose of this class is to process a .csar file in the form of a byte array and extract VNF Catalog XML files
+ * from it.
+ *
+ * A .csar file is a compressed archive like a zip file and this class will treat the byte array as it if were a zip
+ * file.
+ */
+public class VnfCatalogExtractor {
+    private static final Logger logger = LoggerFactory.getInstance().getLogger(VnfCatalogExtractor.class.getName());
+
+    private static final Pattern VNFCFILE_EXTENSION_REGEX =
+            Pattern.compile("(?i)artifacts(\\\\|\\/)deployment(\\\\|\\/)vnf_catalog(\\\\|\\/).*\\.xml$");
+
+    /**
+     * This method is responsible for filtering the contents of the supplied archive and returning a collection of
+     * {@link Artifact}s that represent the VNF Catalog files that have been found in the archive.<br>
+     * <br>
+     * If the archive contains no VNF Catalog files it will return an empty list.<br>
+     *
+     * @param archive the zip file in the form of a byte array containing zero or more VNF Catalog files
+     * @param name the name of the archive file
+     * @return List<Artifact> collection of VNF Catalog XML files found in the archive
+     * @throws InvalidArchiveException if an error occurs trying to extract the VNFC files from the archive or if the
+     *         archive is not a zip file
+     */
+    public List<Artifact> extract(byte[] archive, String name) throws InvalidArchiveException {
+        validateRequest(archive, name);
+
+        logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Extracting CSAR archive: " + name);
+
+        List<Artifact> vnfcFiles = new ArrayList<>();
+        try (SeekableInMemoryByteChannel inMemoryByteChannel = new SeekableInMemoryByteChannel(archive);
+                ZipFile zipFile = new ZipFile(inMemoryByteChannel)) {
+            for (Enumeration<ZipArchiveEntry> enumeration = zipFile.getEntries(); enumeration.hasMoreElements();) {
+                ZipArchiveEntry entry = enumeration.nextElement();
+                if (fileShouldBeExtracted(entry)) {
+                    vnfcFiles.add(new VnfCatalogArtifact(ArtifactType.VNF_CATALOG_XML,
+                            IOUtils.toString(zipFile.getInputStream(entry))));
+                }
+            }
+        } catch (IOException e) {
+            throw new InvalidArchiveException(
+                    "An error occurred trying to create a ZipFile. Is the content being converted really a csar file?",
+                    e);
+        }
+
+        logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, vnfcFiles.size() + " VNF Catalog files extracted.");
+
+        return vnfcFiles;
+    }
+
+    private static void validateRequest(byte[] archive, String name) throws InvalidArchiveException {
+        if (archive == null || archive.length == 0) {
+            throw new InvalidArchiveException("An archive must be supplied for processing.");
+        } else if (StringUtils.isBlank(name)) {
+            throw new InvalidArchiveException("The name of the archive must be supplied for processing.");
+        }
+    }
+
+    private static boolean fileShouldBeExtracted(ZipArchiveEntry entry) {
+        logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Checking if " + entry.getName() + " should be extracted...");
+        boolean extractFile = VNFCFILE_EXTENSION_REGEX.matcher(entry.getName()).matches();
+        logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Keeping file: " + entry.getName() + "? : " + extractFile);
+        return extractFile;
+    }
+}
+
index febc99a..58bb074 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * ï»¿============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
  * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
@@ -38,6 +38,7 @@ import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException;
 import org.onap.aai.modelloader.entity.model.IModelParser;
 import org.onap.aai.modelloader.entity.model.NamedQueryArtifactParser;
 import org.onap.aai.modelloader.extraction.InvalidArchiveException;
+import org.onap.aai.modelloader.extraction.VnfCatalogExtractor;
 import org.onap.aai.modelloader.restclient.BabelServiceClient;
 import org.onap.aai.modelloader.restclient.BabelServiceClientException;
 import org.onap.aai.modelloader.service.BabelServiceClientFactory;
@@ -68,6 +69,7 @@ public class ArtifactDownloadManager {
     private BabelArtifactConverter babelArtifactConverter;
     private ModelLoaderConfig config;
     private BabelServiceClientFactory clientFactory;
+    private VnfCatalogExtractor vnfCatalogExtractor;
 
     public ArtifactDownloadManager(IDistributionClient client, ModelLoaderConfig config,
             BabelServiceClientFactory clientFactory) {
@@ -148,13 +150,33 @@ public class ArtifactDownloadManager {
     }
 
     public void processToscaArtifacts(List<Artifact> modelArtifacts, List<Artifact> catalogArtifacts, byte[] payload,
+            IArtifactInfo artifactInfo, String distributionId, String serviceVersion)
+            throws ProcessToscaArtifactsException, InvalidArchiveException {
+        // Get translated artifacts from Babel Service
+        invokeBabelService(modelArtifacts, catalogArtifacts, payload, artifactInfo, distributionId, serviceVersion);
+
+        // Get VNF Catalog artifacts directly from CSAR
+        List<Artifact> csarCatalogArtifacts = getVnfCatalogExtractor().extract(payload, artifactInfo.getArtifactName());
+
+        // Throw an error if VNF Catalog data is present in the Babel payload and directly in the CSAR
+        if (!catalogArtifacts.isEmpty() && !csarCatalogArtifacts.isEmpty()) {
+            logger.error(ModelLoaderMsgs.DUPLICATE_VNFC_DATA_ERROR, artifactInfo.getArtifactName());
+            throw new InvalidArchiveException("CSAR: " + artifactInfo.getArtifactName()
+                    + " contains VNF Catalog data in the format of both TOSCA and XML files. Only one format can be used for each CSAR file.");
+        } else if (!csarCatalogArtifacts.isEmpty()) {
+            catalogArtifacts.addAll(csarCatalogArtifacts);
+        }
+    }
+
+    public void invokeBabelService(List<Artifact> modelArtifacts, List<Artifact> catalogArtifacts, byte[] payload,
             IArtifactInfo artifactInfo, String distributionId, String serviceVersion)
             throws ProcessToscaArtifactsException {
         try {
             BabelServiceClient babelClient = createBabelServiceClient(artifactInfo, serviceVersion);
 
-            logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT,
-                    "Posting artifact: " + artifactInfo.getArtifactName() + ", version: " + serviceVersion);
+            logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT,
+                    "Posting artifact: " + artifactInfo.getArtifactName() + ", service version: " + serviceVersion
+                            + ", artifact version: " + artifactInfo.getArtifactVersion());
 
             List<BabelArtifact> babelArtifacts =
                     babelClient.postArtifact(payload, artifactInfo.getArtifactName(), serviceVersion, distributionId);
@@ -251,4 +273,12 @@ public class ArtifactDownloadManager {
 
         return babelArtifactConverter;
     }
+
+    private VnfCatalogExtractor getVnfCatalogExtractor() {
+        if (vnfCatalogExtractor == null) {
+            vnfCatalogExtractor = new VnfCatalogExtractor();
+        }
+
+        return vnfCatalogExtractor;
+    }
 }
index 626399e..4f552f7 100644 (file)
@@ -52,7 +52,7 @@ public class NotificationPublisher {
     public NotificationPublisher() {
         Properties configProperties = new Properties();
         try {
-            configProperties.load(Files.newInputStream(Paths.get(ModelLoaderConfig.propertiesFile())));
+            configProperties.load(Files.newInputStream(ModelLoaderConfig.propertiesFile()));
         } catch (IOException e) {
             String errorMsg = "Failed to load configuration: " + e.getMessage();
             logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, e, errorMsg);
index fd39a9a..26a9efa 100644 (file)
-/**\r
- * ï»¿============LICENSE_START=======================================================\r
- * org.onap.aai\r
- * ================================================================================\r
- * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.\r
- * Copyright Â© 2017-2018 European Software Marketing Ltd.\r
- * ================================================================================\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *       http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- * ============LICENSE_END=========================================================\r
- */\r
-package org.onap.aai.modelloader.service;\r
-\r
-import com.att.eelf.i18n.EELFResourceManager;\r
-import org.onap.aai.cl.eelf.LogMessageEnum;\r
-\r
-public enum ModelLoaderMsgs implements LogMessageEnum {\r
-\r
-    /**\r
-     * Arguments: None.\r
-     */\r
-    LOADING_CONFIGURATION,\r
-\r
-    /**\r
-     * Arguments: None.\r
-     */\r
-    STOPPING_CLIENT,\r
-\r
-    /**\r
-     * Arguments: {0} = message.\r
-     */\r
-    INITIALIZING,\r
-\r
-    /**\r
-     * Arguments: {0} = reason.\r
-     */\r
-    ASDC_CONNECTION_ERROR,\r
-\r
-    /**\r
-     * Arguments: {0} = message.\r
-     */\r
-    DISTRIBUTION_EVENT,\r
-\r
-    /**\r
-     * Arguments: {0} = error message.\r
-     */\r
-    DISTRIBUTION_EVENT_ERROR,\r
-\r
-    /**\r
-     * Arguments: {0} = request type. {1} = endpoint. {2} = result code.\r
-     */\r
-    AAI_REST_REQUEST_SUCCESS,\r
-\r
-    /**\r
-     * Arguments: {0} = request type. {1} = endpoint. {2} = result code. {3} = result. message\r
-     */\r
-    AAI_REST_REQUEST_UNSUCCESSFUL,\r
-\r
-    /**\r
-     * Arguments: {0} = request type. {1} = endpoint. {2} = error message.\r
-     */\r
-    AAI_REST_REQUEST_ERROR,\r
-\r
-    /**\r
-     * Arguments: {0} = request type. {1} = endpoint. {2} = error message.\r
-     */\r
-    BABEL_REST_REQUEST_ERROR,\r
-\r
-    /**\r
-     * Arguments: {0} = info request payload.\r
-     **/\r
-    AAI_REST_REQUEST_PAYLOAD,\r
-\r
-    /**\r
-     * Arguments: {0} = artifact name\r
-     */\r
-    ARTIFACT_PARSE_ERROR,\r
-\r
-    /**\r
-     * Arguments: {0} = info request payload.\r
-     **/\r
-    BABEL_REST_REQUEST_PAYLOAD,\r
-\r
-    /**\r
-     * Arguments: {0} = info Babel response payload.\r
-     **/\r
-    BABEL_RESPONSE_PAYLOAD,\r
-\r
-    /**\r
-     * Arguments: {0} = artifact name. {1} = payload.\r
-     */\r
-    DOWNLOAD_COMPLETE,\r
-\r
-    /**\r
-     * Arguments: {0} = event. {1} = artifact name. {2} = result.\r
-     */\r
-    EVENT_PUBLISHED,\r
-\r
-    /**\r
-     * Arguments: {0} = artifact name. {1} = artifact type.\r
-     */\r
-    UNSUPPORTED_ARTIFACT_TYPE;\r
-\r
-    /**\r
-     * Load message bundle (ModelLoaderMsgs.properties file)\r
-     */\r
-    static {\r
-        EELFResourceManager.loadMessageBundle("org/onap/aai/modelloader/service/ModelLoaderMsgs");\r
-    }\r
-\r
-}\r
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.onap.aai.modelloader.service;
+
+import com.att.eelf.i18n.EELFResourceManager;
+import org.onap.aai.cl.eelf.LogMessageEnum;
+
+public enum ModelLoaderMsgs implements LogMessageEnum {
+
+    /**
+     * Arguments: None.
+     */
+    LOADING_CONFIGURATION,
+
+    /**
+     * Arguments: None.
+     */
+    STOPPING_CLIENT,
+
+    /**
+     * Arguments: {0} = message.
+     */
+    INITIALIZING,
+
+    /**
+     * Arguments: {0} = reason.
+     */
+    ASDC_CONNECTION_ERROR,
+
+    /**
+     * Arguments: {0} = message.
+     */
+    DISTRIBUTION_EVENT,
+
+    /**
+     * Arguments: {0} = error message.
+     */
+    DISTRIBUTION_EVENT_ERROR,
+
+    /**
+     * Arguments: {0} = request type. {1} = endpoint. {2} = result code.
+     */
+    AAI_REST_REQUEST_SUCCESS,
+
+    /**
+     * Arguments: {0} = request type. {1} = endpoint. {2} = result code. {3} = result. message
+     */
+    AAI_REST_REQUEST_UNSUCCESSFUL,
+
+    /**
+     * Arguments: {0} = request type. {1} = endpoint. {2} = error message.
+     */
+    AAI_REST_REQUEST_ERROR,
+
+    /**
+     * Arguments: {0} = request type. {1} = endpoint. {2} = error message.
+     */
+    BABEL_REST_REQUEST_ERROR,
+
+    /**
+     * Arguments: {0} = info request payload.
+     **/
+    AAI_REST_REQUEST_PAYLOAD,
+
+    /**
+     * Arguments: {0} = artifact name
+     */
+    ARTIFACT_PARSE_ERROR,
+
+    /**
+     * Arguments: {0} = info request payload.
+     **/
+    BABEL_REST_REQUEST_PAYLOAD,
+
+    /**
+     * Arguments: {0} = info Babel response payload.
+     **/
+    BABEL_RESPONSE_PAYLOAD,
+
+    /**
+     * Arguments: {0} = artifact name. {1} = payload.
+     */
+    DOWNLOAD_COMPLETE,
+
+    /**
+     * Arguments: {0} = event. {1} = artifact name. {2} = result.
+     */
+    EVENT_PUBLISHED,
+
+    /**
+     * Arguments: {0} = artifact name. {1} = artifact type.
+     */
+    UNSUPPORTED_ARTIFACT_TYPE,
+
+    /**
+     * Arguments: {0} = artifact name.
+     */
+    DUPLICATE_VNFC_DATA_ERROR;
+
+    /**
+     * Load message bundle (ModelLoaderMsgs.properties file)
+     */
+    static {
+        EELFResourceManager.loadMessageBundle("org/onap/aai/modelloader/service/ModelLoaderMsgs");
+    }
+
+}
index 87cfdcc..84218e5 100644 (file)
@@ -42,11 +42,11 @@ public final class JsonXmlConverter {
         try {
             new JSONObject(text);
             isValid = true;
-        } catch (JSONException ex) {
+        } catch (JSONException ex) { // NOSONAR
             try {
                 new JSONArray(text);
                 isValid = true;
-            } catch (JSONException ex1) {
+            } catch (JSONException ex1) { // NOSONAR
                 isValid = false;
             }
         }
index 1e5658c..d337915 100644 (file)
@@ -129,6 +129,12 @@ BABEL_REST_REQUEST_ERROR=\
                   Failed to send {0} request to {1}: {2}|\\r
                   Check configuration.  Check network connection to Babel.|\\r
                   A failure occurred attempting to send a request to the Babel|\\r
+\r
+DUPLICATE_VNFC_DATA_ERROR=\\r
+                  MDLSVC2006E|\\r
+                  Artifact: {0} contains both TOSCA and XML VNF Catalog data.|\\r
+                  Check artifact. |\\r
+                  A failure occurred attempting to process VNF Catalog data in artifact from SDC|\\r
                                                     \r
 # DEBUG Level Logs                  \r
 INITIALIZING=\\r
diff --git a/src/test/java/org/onap/aai/modelloader/csar/extractor/VnfCatalogExtractorTest.java b/src/test/java/org/onap/aai/modelloader/csar/extractor/VnfCatalogExtractorTest.java
new file mode 100644 (file)
index 0000000..bd8c33f
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.onap.aai.modelloader.csar.extractor;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.onap.aai.modelloader.entity.Artifact;
+import org.onap.aai.modelloader.entity.ArtifactType;
+import org.onap.aai.modelloader.extraction.InvalidArchiveException;
+import org.onap.aai.modelloader.extraction.VnfCatalogExtractor;
+import org.onap.aai.modelloader.util.ArtifactTestUtils;
+
+
+/**
+ * Tests {@link VnfCatalogExtractor}.
+ */
+public class VnfCatalogExtractorTest {
+
+    private static final String FOO = "foo";
+    private static final String SOME_BYTES = "just some bytes that will pass the firsts validation";
+    private static final String SUPPLY_AN_ARCHIVE = "An archive must be supplied for processing.";
+    private static final String SUPPLY_NAME = "The name of the archive must be supplied for processing.";
+
+    @Test
+    public void nullContentSupplied() {
+        invalidArgumentsTest(null, FOO, SUPPLY_AN_ARCHIVE);
+    }
+
+    @Test
+    public void emptyContentSupplied() {
+        invalidArgumentsTest(new byte[0], FOO, SUPPLY_AN_ARCHIVE);
+    }
+
+    @Test
+    public void nullNameSupplied() {
+        invalidArgumentsTest(SOME_BYTES.getBytes(), null, SUPPLY_NAME);
+    }
+
+    @Test
+    public void blankNameSupplied() {
+        invalidArgumentsTest("just some bytes that will pass the firsts validation".getBytes(), "  \t  ", SUPPLY_NAME);
+    }
+
+    @Test
+    public void emptyNameSupplied() {
+        invalidArgumentsTest("just some bytes that will pass the firsts validation".getBytes(), "", SUPPLY_NAME);
+    }
+
+    @Test
+    public void invalidContentSupplied() {
+        invalidArgumentsTest("This is a piece of nonsense and not a zip file".getBytes(), FOO,
+                "An error occurred trying to create a ZipFile. Is the content being converted really a csar file?");
+    }
+
+    @Test
+    public void archiveContainsNoVnfcFiles() throws InvalidArchiveException, IOException {
+        List<Artifact> vnfcArtifacts = new VnfCatalogExtractor().extract(
+                new ArtifactTestUtils().loadResource("compressedArtifacts/noVnfcFilesArchive.csar"),
+                "noVnfcFilesArchive.csar");
+        assertTrue("No VNFC files should have been extracted, but " + vnfcArtifacts.size() + " were found.",
+                vnfcArtifacts.isEmpty());
+    }
+
+    @Test
+    public void archiveContainsThreeRelevantVnfcFiles() throws IOException, InvalidArchiveException {
+        List<String> payloads = new ArrayList<>();
+        payloads.add("xmlFiles/vnfcatalog-1.xml");
+        payloads.add("xmlFiles/vnfcatalog-2.xml");
+        payloads.add("xmlFiles/vnfcatalog-3.xml");
+        String csarArchiveFile = "threeVnfcFilesArchive.csar";
+        performVnfcAsserts(new VnfCatalogExtractor().extract(
+                new ArtifactTestUtils().loadResource("compressedArtifacts/" + csarArchiveFile), csarArchiveFile),
+                payloads);
+    }
+
+    public void performVnfcAsserts(List<Artifact> actualVnfcArtifacts, List<String> expectedVnfcPayloadsToLoad) {
+        assertThat("An unexpected number of VNFC files have been extracted", actualVnfcArtifacts.size(),
+                is(expectedVnfcPayloadsToLoad.size()));
+
+        for (Artifact artifact : actualVnfcArtifacts) {
+            assertThat("Unexpected artifact type found.", artifact.getType(), is(ArtifactType.VNF_CATALOG_XML));
+        }
+
+        Set<String> expectedVnfcPayloads = expectedVnfcPayloadsToLoad.stream().map(s -> {
+            try {
+                return ArtifactTestUtils.loadResourceAsString(s);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }).collect(Collectors.toSet());
+
+        Set<String> actualVnfcPayloads =
+                actualVnfcArtifacts.stream().map(s -> s.getPayload()).collect(Collectors.toSet());
+
+        assertThat("Unexpected VNF Catalog file(s) found.", expectedVnfcPayloads.containsAll(actualVnfcPayloads),
+                is(true));
+    }
+
+    private void invalidArgumentsTest(byte[] archive, String name, String expectedErrorMessage) {
+        try {
+            new VnfCatalogExtractor().extract(archive, name);
+            fail("An instance of InvalidArchiveException should have been thrown");
+        } catch (Exception ex) {
+            assertTrue(ex instanceof InvalidArchiveException);
+            assertEquals(expectedErrorMessage, ex.getLocalizedMessage());
+        }
+    }
+
+}
+
index b54bb20..cead699 100644 (file)
@@ -41,6 +41,7 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 import org.onap.aai.modelloader.config.ModelLoaderConfig;
 import org.onap.aai.modelloader.entity.Artifact;
+import org.onap.aai.modelloader.entity.ArtifactType;
 import org.onap.aai.modelloader.restclient.AaiRestClient;
 import org.onap.aai.restclient.client.OperationResult;
 
@@ -80,6 +81,40 @@ public class TestVnfCatalogArtifactHandler {
         assertPutOperationsSucceeded();
     }
 
+    @Test
+    public void testUpdateVnfImagesFromXml() throws Exception {
+        // GET operation
+        OperationResult mockGetResp = mock(OperationResult.class);
+
+        // @formatter:off
+        when(mockGetResp.getResultCode())
+                .thenReturn(Response.Status.OK.getStatusCode())
+                .thenReturn(Response.Status.NOT_FOUND.getStatusCode())
+                .thenReturn(Response.Status.NOT_FOUND.getStatusCode())
+                .thenReturn(Response.Status.OK.getStatusCode());
+        // @formatter:on
+
+        when(mockRestClient.getResource(Mockito.anyString(), Mockito.anyString(), Mockito.any(MediaType.class)))
+                .thenReturn(mockGetResp);
+        mockPutOperations();
+
+        // Example VNF Catalog XML
+        VnfCatalogArtifactHandler handler = new VnfCatalogArtifactHandler(createConfig());
+        assertThat(
+                handler.pushArtifacts(createVnfCatalogXmlArtifact(), "test", new ArrayList<Artifact>(), mockRestClient),
+                is(true));
+
+        // Only two of the VNF images should be pushed
+        ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
+        AaiRestClient client = Mockito.verify(mockRestClient, Mockito.times(2));
+        client.putResource(Mockito.anyString(), argument.capture(), Mockito.anyString(), Mockito.any(MediaType.class));
+        assertThat(argument.getAllValues().size(), is(2));
+        assertThat(argument.getAllValues().get(0), containsString("5.2.5"));
+        assertThat(argument.getAllValues().get(0), containsString("VM00"));
+        assertThat(argument.getAllValues().get(1), containsString("5.2.4"));
+        assertThat(argument.getAllValues().get(1), containsString("VM00"));
+    }
+
     private ModelLoaderConfig createConfig() {
         Properties configProperties = new Properties();
         try {
@@ -106,6 +141,20 @@ public class TestVnfCatalogArtifactHandler {
         return artifacts;
     }
 
+    /**
+     * Example VNF Catalog based on VNF_CATALOG XML
+     * 
+     * @return test Artifacts
+     * @throws IOException
+     * @throws UnsupportedEncodingException
+     */
+    private List<Artifact> createVnfCatalogXmlArtifact() throws IOException, UnsupportedEncodingException {
+        byte[] encoded = Files.readAllBytes(Paths.get("src/test/resources/xmlFiles/fortigate.xml"));
+        List<Artifact> artifacts = new ArrayList<Artifact>();
+        artifacts.add(new VnfCatalogArtifact(ArtifactType.VNF_CATALOG_XML, new String(encoded, "utf-8")));
+        return artifacts;
+    }
+
     /**
      * Always return CREATED (success) for a PUT operation.
      */
diff --git a/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerVnfcTest.java b/src/test/java/org/onap/aai/modelloader/notification/ArtifactDownloadManagerVnfcTest.java
new file mode 100644 (file)
index 0000000..6c7a77f
--- /dev/null
@@ -0,0 +1,227 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.onap.aai.modelloader.notification;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.onap.aai.modelloader.fixture.NotificationDataFixtureBuilder.getNotificationDataWithToscaCsarFile;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.internal.util.reflection.Whitebox;
+import org.onap.aai.babel.service.data.BabelArtifact;
+import org.onap.aai.modelloader.config.ModelLoaderConfig;
+import org.onap.aai.modelloader.entity.Artifact;
+import org.onap.aai.modelloader.entity.ArtifactType;
+import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifact;
+import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException;
+import org.onap.aai.modelloader.entity.model.ModelArtifact;
+import org.onap.aai.modelloader.extraction.InvalidArchiveException;
+import org.onap.aai.modelloader.extraction.VnfCatalogExtractor;
+import org.onap.aai.modelloader.restclient.BabelServiceClient;
+import org.onap.aai.modelloader.restclient.BabelServiceClientException;
+import org.onap.aai.modelloader.service.BabelServiceClientFactory;
+import org.onap.aai.modelloader.util.ArtifactTestUtils;
+import org.onap.sdc.api.IDistributionClient;
+import org.onap.sdc.api.notification.IArtifactInfo;
+import org.onap.sdc.api.notification.INotificationData;
+import org.onap.sdc.api.results.IDistributionClientDownloadResult;
+import org.onap.sdc.impl.DistributionClientDownloadResultImpl;
+import org.onap.sdc.utils.DistributionActionResultEnum;
+
+/**
+ * Tests {@link ArtifactDownloadManager} with VNF Catalog Artifacts.
+ */
+public class ArtifactDownloadManagerVnfcTest {
+
+    private ArtifactDownloadManager downloadManager;
+    private BabelServiceClient mockBabelClient;
+    private IDistributionClient mockDistributionClient;
+    private NotificationPublisher mockNotificationPublisher;
+    private BabelArtifactConverter mockBabelArtifactConverter;
+    private BabelServiceClientFactory mockClientFactory;
+    private VnfCatalogExtractor mockVnfCatalogExtractor;
+
+    @Before
+    public void setup() throws Exception {
+        mockBabelClient = mock(BabelServiceClient.class);
+        mockDistributionClient = mock(IDistributionClient.class);
+        mockNotificationPublisher = mock(NotificationPublisher.class);
+        mockBabelArtifactConverter = mock(BabelArtifactConverter.class);
+        mockClientFactory = mock(BabelServiceClientFactory.class);
+        when(mockClientFactory.create(Mockito.any())).thenReturn(mockBabelClient);
+        mockVnfCatalogExtractor = mock(VnfCatalogExtractor.class);
+
+        Properties configProperties = new Properties();
+        configProperties.load(this.getClass().getClassLoader().getResourceAsStream("model-loader.properties"));
+        downloadManager = new ArtifactDownloadManager(mockDistributionClient,
+                new ModelLoaderConfig(configProperties, "."), mockClientFactory);
+
+
+        Whitebox.setInternalState(downloadManager, "notificationPublisher", mockNotificationPublisher);
+        Whitebox.setInternalState(downloadManager, "babelArtifactConverter", mockBabelArtifactConverter);
+        Whitebox.setInternalState(downloadManager, "vnfCatalogExtractor", mockVnfCatalogExtractor);
+    }
+
+    @Test
+    public void downloadArtifacts_validToscaVnfcCsarFile()
+            throws IOException, BabelServiceClientException, BabelArtifactParsingException, InvalidArchiveException {
+        INotificationData data = getNotificationDataWithToscaCsarFile();
+        IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0);
+
+        setupValidDownloadCsarMocks(data, artifactInfo);
+        when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(),
+                Matchers.anyString())).thenReturn(createBabelArtifacts());
+        when(mockVnfCatalogExtractor.extract(Matchers.any(), Matchers.anyString())).thenReturn(new ArrayList<>());
+
+        List<Artifact> modelArtifacts = new ArrayList<>();
+        List<Artifact> catalogFiles = new ArrayList<>();
+        assertThat(downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles),
+                is(true));
+
+        assertEquals("There should have been some catalog files", 2, catalogFiles.size());
+    }
+
+    @Test
+    public void downloadArtifacts_validXmlVnfcCsarFile()
+            throws IOException, BabelServiceClientException, BabelArtifactParsingException, InvalidArchiveException {
+        INotificationData data = getNotificationDataWithToscaCsarFile();
+        IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0);
+
+        setupValidDownloadCsarMocks(data, artifactInfo);
+        when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(),
+                Matchers.anyString())).thenReturn(createBabelArtifactsNoVnfc());
+        when(mockVnfCatalogExtractor.extract(Matchers.any(), Matchers.anyString()))
+                .thenReturn(createXmlVnfcArtifacts());
+
+        List<Artifact> modelArtifacts = new ArrayList<>();
+        List<Artifact> catalogFiles = new ArrayList<>();
+        assertThat(downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles),
+                is(true));
+
+        assertEquals("There should have been some catalog files", 3, catalogFiles.size());
+    }
+
+    @Test
+    public void downloadArtifacts_validNoVnfcCsarFile()
+            throws IOException, BabelServiceClientException, BabelArtifactParsingException, InvalidArchiveException {
+        INotificationData data = getNotificationDataWithToscaCsarFile();
+        IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0);
+
+        setupValidDownloadCsarMocks(data, artifactInfo);
+        when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(),
+                Matchers.anyString())).thenReturn(createBabelArtifactsNoVnfc());
+        when(mockVnfCatalogExtractor.extract(Matchers.any(), Matchers.anyString())).thenReturn(new ArrayList<>());
+
+        List<Artifact> modelArtifacts = new ArrayList<>();
+        List<Artifact> catalogFiles = new ArrayList<>();
+        assertThat(downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles),
+                is(true));
+
+        assertEquals("There should not have been any catalog files", 0, catalogFiles.size());
+    }
+
+    @Test
+    public void downloadArtifacts_invalidXmlAndToscaVnfcCsarFile()
+            throws IOException, BabelServiceClientException, BabelArtifactParsingException, InvalidArchiveException {
+        INotificationData data = getNotificationDataWithToscaCsarFile();
+        IArtifactInfo artifactInfo = data.getServiceArtifacts().get(0);
+
+        setupValidDownloadCsarMocks(data, artifactInfo);
+        when(mockBabelClient.postArtifact(Matchers.any(), Matchers.anyString(), Matchers.anyString(),
+                Matchers.anyString())).thenReturn(createBabelArtifacts());
+        when(mockVnfCatalogExtractor.extract(Matchers.any(), Matchers.anyString()))
+                .thenReturn(createXmlVnfcArtifacts());
+        doNothing().when(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifactInfo);
+
+        List<Artifact> modelArtifacts = new ArrayList<>();
+        List<Artifact> catalogFiles = new ArrayList<>();
+        assertThat(downloadManager.downloadArtifacts(data, data.getServiceArtifacts(), modelArtifacts, catalogFiles),
+                is(false));
+
+        Mockito.verify(mockNotificationPublisher).publishDeployFailure(mockDistributionClient, data, artifactInfo);
+    }
+
+    private IDistributionClientDownloadResult createDistributionClientDownloadResult(
+            DistributionActionResultEnum status, String message, byte[] payload) {
+        IDistributionClientDownloadResult downloadResult = new DistributionClientDownloadResultImpl(status, message);
+
+        ((DistributionClientDownloadResultImpl) downloadResult).setArtifactPayload(payload);
+
+        return downloadResult;
+    }
+
+    private void setupValidDownloadCsarMocks(INotificationData data, IArtifactInfo artifactInfo)
+            throws IOException, BabelServiceClientException, BabelArtifactParsingException {
+        when(mockDistributionClient.download(artifactInfo))
+                .thenReturn(createDistributionClientDownloadResult(DistributionActionResultEnum.SUCCESS, null,
+                        new ArtifactTestUtils().loadResource("compressedArtifacts/service-VscpaasTest-csar.csar")));
+        when(mockBabelArtifactConverter.convertToModel(Mockito.anyListOf(BabelArtifact.class)))
+                .thenReturn(createModelArtifacts());
+        when(mockBabelArtifactConverter.convertToCatalog(Mockito.anyListOf(BabelArtifact.class)))
+                .thenReturn(createToscaVnfcArtifacts());
+    }
+
+    private List<BabelArtifact> createBabelArtifacts() {
+        List<BabelArtifact> artifactList = new ArrayList<>();
+        artifactList.add(new BabelArtifact("ModelArtifact", BabelArtifact.ArtifactType.MODEL, "Some model payload"));
+        artifactList.add(new BabelArtifact("VNFCArtifact", BabelArtifact.ArtifactType.VNFCATALOG, "Some VNFC payload"));
+        return artifactList;
+    }
+
+    private List<BabelArtifact> createBabelArtifactsNoVnfc() {
+        List<BabelArtifact> artifactList = new ArrayList<>();
+        artifactList.add(new BabelArtifact("ModelArtifact", BabelArtifact.ArtifactType.MODEL, "Some model payload"));
+        return artifactList;
+    }
+
+    private List<Artifact> createModelArtifacts() {
+        List<Artifact> modelArtifacts = new ArrayList<>();
+        modelArtifacts.add(new ModelArtifact());
+        modelArtifacts.add(new ModelArtifact());
+        return modelArtifacts;
+    }
+
+    private List<Artifact> createToscaVnfcArtifacts() {
+        List<Artifact> vnfcArtifacts = new ArrayList<>();
+        vnfcArtifacts.add(new VnfCatalogArtifact("Some VNFC payload"));
+        vnfcArtifacts.add(new VnfCatalogArtifact("Some VNFC payload"));
+        return vnfcArtifacts;
+    }
+
+    private List<Artifact> createXmlVnfcArtifacts() {
+        List<Artifact> vnfcArtifacts = new ArrayList<>();
+        vnfcArtifacts.add(new VnfCatalogArtifact(ArtifactType.VNF_CATALOG_XML, "Some VNFC payload"));
+        vnfcArtifacts.add(new VnfCatalogArtifact(ArtifactType.VNF_CATALOG_XML, "Some VNFC payload"));
+        vnfcArtifacts.add(new VnfCatalogArtifact(ArtifactType.VNF_CATALOG_XML, "Some VNFC payload"));
+        return vnfcArtifacts;
+    }
+}
index 8e07650..e40ca3c 100644 (file)
@@ -56,7 +56,7 @@ public class TestModelLoaderService {
     public void testMissingConfig() {
         new ModelLoaderService().start();
     }
-    
+
     @Test
     public void testLoadModel() {
         Response response = service.loadModel("");
@@ -80,7 +80,7 @@ public class TestModelLoaderService {
     public void testIngestModelMissingName() throws IOException {
         byte[] csarPayload = new ArtifactTestUtils().loadResource("compressedArtifacts/service-VscpaasTest-csar.csar");
         Response response = service.ingestModel("", "", Base64.getEncoder().encodeToString(csarPayload));
-        assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode()));
+        assertThat(response.getStatus(), is(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()));
     }
 
 }
index 4b7db56..81a4833 100644 (file)
@@ -49,34 +49,34 @@ public class TestJsonXmlConverter {
 
     @Test
     public void testConversion() throws Exception {
-            byte[] encoded = Files.readAllBytes(Paths.get(XML_MODEL_FILE));
-            assertThat(JsonXmlConverter.isValidJson(new String(encoded)), is(false));
-            encoded = Files.readAllBytes(Paths.get(JSON_MODEL_FILE));
+        byte[] encoded = Files.readAllBytes(Paths.get(XML_MODEL_FILE));
+        assertThat(JsonXmlConverter.isValidJson(new String(encoded)), is(false));
+        encoded = Files.readAllBytes(Paths.get(JSON_MODEL_FILE));
         String originalJson = new String(encoded);
 
         assertThat(JsonXmlConverter.isValidJson(originalJson), is(true));
 
         String xmlFromJson = JsonXmlConverter.convertJsonToXml(originalJson);
 
-            // Spot check one of the attributes
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
-            DocumentBuilder builder = factory.newDocumentBuilder();
-            Document doc = builder.parse(new ByteArrayInputStream(xmlFromJson.getBytes()));
-            NodeList nodeList = doc.getDocumentElement().getChildNodes();
+        // Spot check one of the attributes
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document doc = builder.parse(new ByteArrayInputStream(xmlFromJson.getBytes()));
+        NodeList nodeList = doc.getDocumentElement().getChildNodes();
 
-            String modelVid = "notFound";
-            for (int i = 0; i < nodeList.getLength(); i++) {
-                Node currentNode = nodeList.item(i);
-                if (currentNode.getNodeName().equals("model-invariant-id")) {
-                    modelVid = currentNode.getTextContent();
-                    break;
-                }
+        String modelVid = "notFound";
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            Node currentNode = nodeList.item(i);
+            if (currentNode.getNodeName().equals("model-invariant-id")) {
+                modelVid = currentNode.getTextContent();
+                break;
             }
+        }
 
         assertThat(modelVid.equals("3d560d81-57d0-438b-a2a1-5334dba0651a"), is(true));
 
-            // Convert the XML form back into JSON
-            JsonXmlConverter.convertXmlToJson(xmlFromJson);
+        // Convert the XML form back into JSON
+        JsonXmlConverter.convertXmlToJson(xmlFromJson);
     }
 }
diff --git a/src/test/resources/compressedArtifacts/noVnfcFilesArchive.csar b/src/test/resources/compressedArtifacts/noVnfcFilesArchive.csar
new file mode 100644 (file)
index 0000000..fa2a327
Binary files /dev/null and b/src/test/resources/compressedArtifacts/noVnfcFilesArchive.csar differ
diff --git a/src/test/resources/compressedArtifacts/threeVnfcFilesArchive.csar b/src/test/resources/compressedArtifacts/threeVnfcFilesArchive.csar
new file mode 100644 (file)
index 0000000..fc5080b
Binary files /dev/null and b/src/test/resources/compressedArtifacts/threeVnfcFilesArchive.csar differ
diff --git a/src/test/resources/xmlFiles/fortigate.xml b/src/test/resources/xmlFiles/fortigate.xml
new file mode 100644 (file)
index 0000000..16fce07
--- /dev/null
@@ -0,0 +1,129 @@
+<vnf-catalog>
+    <part-number-list>
+        <part-number>FortiGate-VM00</part-number>
+        <vnf-type>FW</vnf-type>
+        <vendor-info>
+            <vendor-name>FORTINET</vendor-name>
+            <vendor-part-number>FortiGate-VM00</vendor-part-number>
+            <vendor-model>VM00</vendor-model>
+        </vendor-info>
+        <vcpu>
+            <vcpu-default>1</vcpu-default>
+            <vcpu-min>1</vcpu-min>
+            <vcpu-max>1</vcpu-max>
+        </vcpu>
+        <vmemory>
+            <vmemory-default>1</vmemory-default>
+            <vmemory-units>GB</vmemory-units>
+            <vmemory-min>1</vmemory-min>
+            <vmemory-max>1</vmemory-max>
+        </vmemory>
+        <vdisk>
+            <vdisk-default>2</vdisk-default>
+            <vdisk-units>GB</vdisk-units>
+            <vdisk-min>2</vdisk-min>
+            <vdisk-max>32</vdisk-max>
+        </vdisk>
+        <software-version-list>
+            <software-version>5.2.7</software-version>
+            <software-version-state>0</software-version-state>
+            <software-filetype>IMAGE</software-filetype>
+            <file-md5-value>1c59a521885c465004456f74d003726c</file-md5-value>
+            <software-filename>test3</software-filename>
+        </software-version-list>
+        <software-version-list>
+            <software-version>5.2.5</software-version>
+            <software-version-state>1</software-version-state>
+            <software-filetype>IMAGE</software-filetype>
+            <file-md5-value>C4D2CBE51669796E48623E006782F7DC</file-md5-value>
+            <software-filename>test2</software-filename>
+        </software-version-list>
+        <software-version-list>
+            <software-version>5.2.4</software-version>
+            <software-version-state>2</software-version-state>
+            <software-filetype>IMAGE</software-filetype>
+            <file-md5-value>4987E1E743FD641C879E1D3C5D50BCE0</file-md5-value>
+            <software-filename>test1</software-filename>
+        </software-version-list>
+        <vnf-features-list>
+            <vnf-feature>APPID</vnf-feature>
+        </vnf-features-list>
+        <vnf-features-list>
+            <vnf-feature>IPS-IDS</vnf-feature>
+        </vnf-features-list>
+        <vnf-features-list>
+            <vnf-feature>URLF</vnf-feature>
+        </vnf-features-list>
+        <vnf-features-list>
+            <vnf-feature>Anti-Virus</vnf-feature>
+        </vnf-features-list>
+        <license-list>
+            <license-assignment-group>FortiGate-VM00</license-assignment-group>
+            <license-required>FALSE</license-required>
+        </license-list>
+    </part-number-list>
+    <part-number-list>
+        <part-number>FortiGate-VM01</part-number>
+        <vnf-type>FW</vnf-type>
+        <vendor-info>
+            <vendor-name>FORTINET</vendor-name>
+            <vendor-part-number>FortiGate-VM01</vendor-part-number>
+            <vendor-model>VM01</vendor-model>
+        </vendor-info>
+        <vcpu>
+            <vcpu-default>1</vcpu-default>
+            <vcpu-min>1</vcpu-min>
+            <vcpu-max>1</vcpu-max>
+        </vcpu>
+        <vmemory>
+            <vmemory-default>2</vmemory-default>
+            <vmemory-units>GB</vmemory-units>
+            <vmemory-min>1</vmemory-min>
+            <vmemory-max>2</vmemory-max>
+        </vmemory>
+        <vdisk>
+            <vdisk-default>2</vdisk-default>
+            <vdisk-units>GB</vdisk-units>
+            <vdisk-min>2</vdisk-min>
+            <vdisk-max>32</vdisk-max>
+        </vdisk>
+        <software-version-list>
+            <software-version>5.2.7</software-version>
+            <software-version-state>0</software-version-state>
+            <software-filetype>IMAGE</software-filetype>
+            <file-md5-value>1c59a521885c465004456f74d003726c</file-md5-value>
+            <software-filename>software file name 3</software-filename>
+        </software-version-list>
+        <software-version-list>
+            <software-version>5.2.5</software-version>
+            <software-version-state>1</software-version-state>
+            <software-filetype>IMAGE</software-filetype>
+            <file-md5-value>C4D2CBE51669796E48623E006782F7DC</file-md5-value>
+            <software-filename>software file name 2</software-filename>
+        </software-version-list>
+        <software-version-list>
+            <software-version>5.2.4</software-version>
+            <software-version-state>2</software-version-state>
+            <software-filetype>IMAGE</software-filetype>
+            <file-md5-value>4987E1E743FD641C879E1D3C5D50BCE0</file-md5-value>
+            <software-filename>software file name</software-filename>
+        </software-version-list>
+        <vnf-features-list>
+            <vnf-feature>APPID</vnf-feature>
+        </vnf-features-list>
+        <vnf-features-list>
+            <vnf-feature>IPS-IDS</vnf-feature>
+        </vnf-features-list>
+        <vnf-features-list>
+            <vnf-feature>URLF</vnf-feature>
+        </vnf-features-list>
+        <vnf-features-list>
+            <vnf-feature>Anti-Virus</vnf-feature>
+        </vnf-features-list>
+        <license-list>
+            <license-assignment-group>license group</license-assignment-group>
+            <license-required>FALSE</license-required>
+        </license-list>
+    </part-number-list>
+
+</vnf-catalog>
\ No newline at end of file
diff --git a/src/test/resources/xmlFiles/vnfcatalog-1.xml b/src/test/resources/xmlFiles/vnfcatalog-1.xml
new file mode 100644 (file)
index 0000000..979589c
--- /dev/null
@@ -0,0 +1,100 @@
+<vnf-catalog>
+       <part-number-list>
+               <att-part-number>att-part-number1</att-part-number>
+               <vnf-type>vnf-type1</vnf-type>
+               <vendor-info>
+                       <vendor-name>vendor-name1</vendor-name>
+                       <vendor-part-number>vendor-part-number1</vendor-part-number>
+                       <vendor-model>vendor-model1</vendor-model>
+               </vendor-info>
+               <vcpu>
+                       <vcpu-default>2</vcpu-default>
+                       <vcpu-min>2</vcpu-min>
+                       <vcpu-max>2</vcpu-max>
+                </vcpu>
+               <vmemory>
+                       <vmemory-default>2</vmemory-default>
+                       <vmemory-units>GB</vmemory-units>
+                       <vmemory-min>2</vmemory-min>
+                       <vmemory-max>2</vmemory-max>
+               </vmemory>
+               <vdisk>
+                       <vdisk-default>50</vdisk-default>
+                       <vdisk-units>GB</vdisk-units>
+                       <vdisk-min>50</vdisk-min>
+                       <vdisk-max>50</vdisk-max>
+               </vdisk>
+               <software-version-list>
+                       <software-version>software-version1</software-version>
+                       <software-version-state>0</software-version-state>
+                       <software-filetype>IMAGE</software-filetype>
+                       <file-md5-value>BE2B249315B4410896099CFD1AE1948C</file-md5-value>
+                       <software-filename>software-filename1</software-filename>
+               </software-version-list>
+               <vnf-features-list>
+                       <vnf-feature>APPID</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>IPS-IDS</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>URLF</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>Anti-Virus</vnf-feature>
+               </vnf-features-list>
+               <license-list>
+                       <license-assignment-group>license-assignment-group1</license-assignment-group>
+                       <license-required>TRUE</license-required>
+               </license-list>
+       </part-number-list>
+       <part-number-list>
+               <att-part-number>att-part-number2</att-part-number>
+               <vnf-type>vnf-type2</vnf-type>
+               <vendor-info>
+                       <vendor-name>vendor-name2</vendor-name>
+                       <vendor-part-number>vendor-part-number2</vendor-part-number>
+                       <vendor-model>vendor-model2</vendor-model>
+               </vendor-info>
+               <vcpu>
+                       <vcpu-default>2</vcpu-default>
+                       <vcpu-min>2</vcpu-min>
+                       <vcpu-max>2</vcpu-max>
+                </vcpu>
+               <vmemory>
+                       <vmemory-default>2</vmemory-default>
+                       <vmemory-units>GB</vmemory-units>
+                       <vmemory-min>2</vmemory-min>
+                       <vmemory-max>2</vmemory-max>
+               </vmemory>
+               <vdisk>
+                       <vdisk-default>50</vdisk-default>
+                       <vdisk-units>GB</vdisk-units>
+                       <vdisk-min>50</vdisk-min>
+                       <vdisk-max>50</vdisk-max>
+               </vdisk>
+               <software-version-list>
+                       <software-version>software-version2</software-version>
+                       <software-version-state>0</software-version-state>
+                       <software-filetype>IMAGE</software-filetype>
+                       <file-md5-value>BE2B249315B4410896099CFD1AE1948C</file-md5-value>
+                       <software-filename>software-filename2</software-filename>
+               </software-version-list>
+               <vnf-features-list>
+                       <vnf-feature>APPID</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>IPS-IDS</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>URLF</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>Anti-Virus</vnf-feature>
+               </vnf-features-list>
+               <license-list>
+                       <license-assignment-group>license-assignment-group2</license-assignment-group>
+                       <license-required>TRUE</license-required>
+               </license-list>
+       </part-number-list>
+</vnf-catalog>
\ No newline at end of file
diff --git a/src/test/resources/xmlFiles/vnfcatalog-2.xml b/src/test/resources/xmlFiles/vnfcatalog-2.xml
new file mode 100644 (file)
index 0000000..9bcdac3
--- /dev/null
@@ -0,0 +1,100 @@
+<vnf-catalog>
+       <part-number-list>
+               <att-part-number>att-part-number3</att-part-number>
+               <vnf-type>vnf-type3</vnf-type>
+               <vendor-info>
+                       <vendor-name>vendor-name3</vendor-name>
+                       <vendor-part-number>vendor-part-number3</vendor-part-number>
+                       <vendor-model>vendor-model3</vendor-model>
+               </vendor-info>
+               <vcpu>
+                       <vcpu-default>2</vcpu-default>
+                       <vcpu-min>2</vcpu-min>
+                       <vcpu-max>2</vcpu-max>
+                </vcpu>
+               <vmemory>
+                       <vmemory-default>2</vmemory-default>
+                       <vmemory-units>GB</vmemory-units>
+                       <vmemory-min>2</vmemory-min>
+                       <vmemory-max>2</vmemory-max>
+               </vmemory>
+               <vdisk>
+                       <vdisk-default>50</vdisk-default>
+                       <vdisk-units>GB</vdisk-units>
+                       <vdisk-min>50</vdisk-min>
+                       <vdisk-max>50</vdisk-max>
+               </vdisk>
+               <software-version-list>
+                       <software-version>software-version3</software-version>
+                       <software-version-state>0</software-version-state>
+                       <software-filetype>IMAGE</software-filetype>
+                       <file-md5-value>BE2B249315B4410896099CFD1AE1948C</file-md5-value>
+                       <software-filename>software-filename3</software-filename>
+               </software-version-list>
+               <vnf-features-list>
+                       <vnf-feature>APPID</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>IPS-IDS</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>URLF</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>Anti-Virus</vnf-feature>
+               </vnf-features-list>
+               <license-list>
+                       <license-assignment-group>license-assignment-group3</license-assignment-group>
+                       <license-required>TRUE</license-required>
+               </license-list>
+       </part-number-list>
+       <part-number-list>
+               <att-part-number>att-part-number4</att-part-number>
+               <vnf-type>vnf-type4</vnf-type>
+               <vendor-info>
+                       <vendor-name>vendor-name4</vendor-name>
+                       <vendor-part-number>vendor-part-number4</vendor-part-number>
+                       <vendor-model>vendor-model4</vendor-model>
+               </vendor-info>
+               <vcpu>
+                       <vcpu-default>4</vcpu-default>
+                       <vcpu-min>4</vcpu-min>
+                       <vcpu-max>4</vcpu-max>
+                </vcpu>
+               <vmemory>
+                       <vmemory-default>4</vmemory-default>
+                       <vmemory-units>GB</vmemory-units>
+                       <vmemory-min>4</vmemory-min>
+                       <vmemory-max>4</vmemory-max>
+               </vmemory>
+               <vdisk>
+                       <vdisk-default>50</vdisk-default>
+                       <vdisk-units>GB</vdisk-units>
+                       <vdisk-min>50</vdisk-min>
+                       <vdisk-max>50</vdisk-max>
+               </vdisk>
+               <software-version-list>
+                       <software-version>software-version4</software-version>
+                       <software-version-state>0</software-version-state>
+                       <software-filetype>IMAGE</software-filetype>
+                       <file-md5-value>BE2B249315B4410896099CFD1AE1948C</file-md5-value>
+                       <software-filename>software-filename4</software-filename>
+               </software-version-list>
+               <vnf-features-list>
+                       <vnf-feature>APPID</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>IPS-IDS</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>URLF</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>Anti-Virus</vnf-feature>
+               </vnf-features-list>
+               <license-list>
+                       <license-assignment-group>license-assignment-group4</license-assignment-group>
+                       <license-required>TRUE</license-required>
+               </license-list>
+       </part-number-list>
+</vnf-catalog>
\ No newline at end of file
diff --git a/src/test/resources/xmlFiles/vnfcatalog-3.xml b/src/test/resources/xmlFiles/vnfcatalog-3.xml
new file mode 100644 (file)
index 0000000..d420398
--- /dev/null
@@ -0,0 +1,100 @@
+<vnf-catalog>
+       <part-number-list>
+               <att-part-number>att-part-number5</att-part-number>
+               <vnf-type>vnf-type5</vnf-type>
+               <vendor-info>
+                       <vendor-name>vendor-name5</vendor-name>
+                       <vendor-part-number>vendor-part-number5</vendor-part-number>
+                       <vendor-model>vendor-model5</vendor-model>
+               </vendor-info>
+               <vcpu>
+                       <vcpu-default>2</vcpu-default>
+                       <vcpu-min>2</vcpu-min>
+                       <vcpu-max>2</vcpu-max>
+                </vcpu>
+               <vmemory>
+                       <vmemory-default>2</vmemory-default>
+                       <vmemory-units>GB</vmemory-units>
+                       <vmemory-min>2</vmemory-min>
+                       <vmemory-max>2</vmemory-max>
+               </vmemory>
+               <vdisk>
+                       <vdisk-default>50</vdisk-default>
+                       <vdisk-units>GB</vdisk-units>
+                       <vdisk-min>50</vdisk-min>
+                       <vdisk-max>50</vdisk-max>
+               </vdisk>
+               <software-version-list>
+                       <software-version>software-version5</software-version>
+                       <software-version-state>0</software-version-state>
+                       <software-filetype>IMAGE</software-filetype>
+                       <file-md5-value>BE2B249315B4410896099CFD1AE1948C</file-md5-value>
+                       <software-filename>software-filename5</software-filename>
+               </software-version-list>
+               <vnf-features-list>
+                       <vnf-feature>APPID</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>IPS-IDS</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>URLF</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>Anti-Virus</vnf-feature>
+               </vnf-features-list>
+               <license-list>
+                       <license-assignment-group>license-assignment-group5</license-assignment-group>
+                       <license-required>TRUE</license-required>
+               </license-list>
+       </part-number-list>
+       <part-number-list>
+               <att-part-number>att-part-number6</att-part-number>
+               <vnf-type>vnf-type6</vnf-type>
+               <vendor-info>
+                       <vendor-name>vendor-name6</vendor-name>
+                       <vendor-part-number>vendor-part-number6</vendor-part-number>
+                       <vendor-model>vendor-model6</vendor-model>
+               </vendor-info>
+               <vcpu>
+                       <vcpu-default>6</vcpu-default>
+                       <vcpu-min>6</vcpu-min>
+                       <vcpu-max>6</vcpu-max>
+                </vcpu>
+               <vmemory>
+                       <vmemory-default>6</vmemory-default>
+                       <vmemory-units>GB</vmemory-units>
+                       <vmemory-min>6</vmemory-min>
+                       <vmemory-max>6</vmemory-max>
+               </vmemory>
+               <vdisk>
+                       <vdisk-default>50</vdisk-default>
+                       <vdisk-units>GB</vdisk-units>
+                       <vdisk-min>50</vdisk-min>
+                       <vdisk-max>50</vdisk-max>
+               </vdisk>
+               <software-version-list>
+                       <software-version>software-version6</software-version>
+                       <software-version-state>0</software-version-state>
+                       <software-filetype>IMAGE</software-filetype>
+                       <file-md5-value>BE2B249315B4410896099CFD1AE1948C</file-md5-value>
+                       <software-filename>software-filename6</software-filename>
+               </software-version-list>
+               <vnf-features-list>
+                       <vnf-feature>APPID</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>IPS-IDS</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>URLF</vnf-feature>
+               </vnf-features-list>
+               <vnf-features-list>
+                       <vnf-feature>Anti-Virus</vnf-feature>
+               </vnf-features-list>
+               <license-list>
+                       <license-assignment-group>license-assignment-group6</license-assignment-group>
+                       <license-required>TRUE</license-required>
+               </license-list>
+       </part-number-list>
+</vnf-catalog>
\ No newline at end of file