/**\r
- * ============LICENSE_START==========================================\r
+ * ============LICENSE_START=======================================================\r
* org.onap.aai\r
- * ===================================================================\r
+ * ================================================================================\r
* Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.\r
- * Copyright © 2017-2018 Amdocs\r
- * ===================================================================\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
+ * 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
+ * ============LICENSE_END=========================================================\r
*/\r
package org.onap.aai.modelloader.entity.catalog;\r
\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
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
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
logger.warn(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Empty image data supplied, skipping ingestion.");\r
- return;\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
+ continue;\r
}\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
+ 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
- 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
String uuid = UUID.randomUUID().toString();\r
dataItem.put(ATTR_UUID, uuid);\r
\r
- String payload = createVnfImagePayload(dataItem);\r
+ String payload = new Gson().toJson(dataItem);\r
String putUrl = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "/vnf-image/" + uuid;\r
OperationResult putResp =\r
restClient.putResource(putUrl, payload, distributionId, MediaType.APPLICATION_JSON_TYPE);\r
return putResp != null && putResp.getResultCode() == Response.Status.CREATED.getStatusCode();\r
}\r
\r
- private String createVnfImagePayload(Map<String, String> dataItem) {\r
- dataItem.put(ATTR_UUID, UUID.randomUUID().toString());\r
- return new Gson().toJson(dataItem);\r
- }\r
-\r
private List<Map<String, String>> unmarshallVnfcData(Artifact vnfcArtifact) {\r
// Unmarshall Babel JSON payload into a List of Maps of JSON attribute name/values.\r
return new Gson().fromJson(StringEscapeUtils.unescapeJson(vnfcArtifact.getPayload()),\r
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