Initial source code
[oam/tr069-adapter.git] / mapper / src / main / java / org / commscope / tr069adapter / mapper / util / NetconfToTr069MapperUtil.java
diff --git a/mapper/src/main/java/org/commscope/tr069adapter/mapper/util/NetconfToTr069MapperUtil.java b/mapper/src/main/java/org/commscope/tr069adapter/mapper/util/NetconfToTr069MapperUtil.java
new file mode 100644 (file)
index 0000000..680495e
--- /dev/null
@@ -0,0 +1,430 @@
+/*\r
+ * ============LICENSE_START========================================================================\r
+ * ONAP : tr-069-adapter\r
+ * =================================================================================================\r
+ * Copyright (C) 2020 CommScope Inc Intellectual Property.\r
+ * =================================================================================================\r
+ * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,\r
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You\r
+ * may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
+ * either express or implied. See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ===============LICENSE_END=======================================================================\r
+ */\r
+\r
+package org.commscope.tr069adapter.mapper.util;\r
+\r
+import java.io.Serializable;\r
+import java.io.StringReader;\r
+import java.io.StringWriter;\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.StringTokenizer;\r
+\r
+import javax.xml.XMLConstants;\r
+import javax.xml.parsers.DocumentBuilder;\r
+import javax.xml.parsers.DocumentBuilderFactory;\r
+import javax.xml.parsers.ParserConfigurationException;\r
+import javax.xml.transform.Transformer;\r
+import javax.xml.transform.TransformerFactory;\r
+import javax.xml.transform.dom.DOMSource;\r
+import javax.xml.transform.stream.StreamResult;\r
+\r
+import org.commscope.tr069adapter.acs.common.DeviceRPCRequest;\r
+import org.commscope.tr069adapter.acs.common.DeviceRPCResponse;\r
+import org.commscope.tr069adapter.acs.common.OperationOptions;\r
+import org.commscope.tr069adapter.acs.common.ParameterDTO;\r
+import org.commscope.tr069adapter.acs.common.dto.TR069DeviceDetails;\r
+import org.commscope.tr069adapter.acs.common.dto.TR069OperationCode;\r
+import org.commscope.tr069adapter.acs.common.dto.TR069OperationDetails;\r
+import org.commscope.tr069adapter.mapper.ErrorCodeMetaData;\r
+import org.commscope.tr069adapter.mapper.model.ErrorCodeDetails;\r
+import org.commscope.tr069adapter.mapper.model.NetConfResponse;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
+import org.springframework.stereotype.Component;\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
+@Component\r
+public class NetconfToTr069MapperUtil {\r
+\r
+  @Autowired\r
+  MOMetaDataUtil metaDataUtil;\r
+\r
+  private static final Logger logger = LoggerFactory.getLogger(NetconfToTr069MapperUtil.class);\r
+  private static final String INDEX_STR = "index";\r
+  private static final String INDEX_REGEX = "[0-9]{1,}";\r
+\r
+  @Autowired\r
+  private ErrorCodeUtil errorCodeUtil;\r
+\r
+  public static Element convertStringToDocument(String xmlStr) {\r
+    try {\r
+      Document doc = convertStringToDocumentXml(xmlStr);\r
+      if (null != doc)\r
+        return doc.getDocumentElement();\r
+    } catch (Exception e) {\r
+      logger.error("Error while converting String to element {}", e.getMessage());\r
+    }\r
+    return null;\r
+  }\r
+\r
+  public static Document convertStringToDocumentXml(String xmlStr) {\r
+    try {\r
+      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\r
+      factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");\r
+      factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");\r
+      DocumentBuilder builder;\r
+      builder = factory.newDocumentBuilder();\r
+      return builder.parse(new InputSource(new StringReader(xmlStr)));\r
+    } catch (Exception e) {\r
+      logger.error("Error while converting String to element {}", e.getMessage());\r
+    }\r
+    return null;\r
+  }\r
+\r
+  public static DeviceRPCRequest prepareTR069Request(String deviceId, Element operationElement,\r
+      String netconfTag, TR069OperationCode opCode) {\r
+    Node requestDataNode = getDeviceDataNode(operationElement, netconfTag);\r
+    if (requestDataNode == null) {\r
+      logger.debug("No matching device parameters found in the netconf request XML.");\r
+      return null;\r
+    }\r
+    Map<String, String> map = getParameterMapForNode(requestDataNode, -1);\r
+    List<ParameterDTO> params = new ArrayList<>();\r
+\r
+    for (java.util.Map.Entry<String, String> entry : map.entrySet()) {\r
+      if (!entry.getKey().equalsIgnoreCase("filter")) {\r
+        String moName = entry.getKey();\r
+        String value = entry.getValue();\r
+        if (moName.endsWith("." + INDEX_STR)\r
+            && (TR069OperationCode.GET_PARAMETER_VALUES.equals(opCode)\r
+                || TR069OperationCode.DELETE_OBJECT.equals(opCode))) {\r
+          logger.debug("Index node found : {}", moName);\r
+          moName = moName.replaceFirst("." + INDEX_STR, ".");\r
+          value = null;\r
+\r
+        }\r
+\r
+        ParameterDTO param = new ParameterDTO(moName, value);\r
+        params.add(param);\r
+      }\r
+    }\r
+\r
+    TR069OperationDetails opDetails = new TR069OperationDetails();\r
+    opDetails.setOpCode(opCode);\r
+    opDetails.setParmeters(params);\r
+\r
+    DeviceRPCRequest deviceRPCRequest = new DeviceRPCRequest();\r
+    TR069DeviceDetails tr069DeviceDetails = new TR069DeviceDetails();\r
+    tr069DeviceDetails.setDeviceId(deviceId);\r
+    deviceRPCRequest.setOpDetails(opDetails);\r
+    deviceRPCRequest.setDeviceDetails(tr069DeviceDetails);\r
+    OperationOptions options = new OperationOptions();\r
+    options.setExecutionTimeout(60l);\r
+    deviceRPCRequest.setOptions(options);\r
+    return deviceRPCRequest;\r
+  }\r
+\r
+  public NetConfResponse getNetconfResponse(DeviceRPCResponse opResult) {\r
+    NetConfResponse netConfResponse = new NetConfResponse();\r
+    ErrorCodeMetaData errorCodeMetaData =\r
+        errorCodeUtil.getErrorCodeMetaData(opResult.getFaultKey());\r
+    ErrorCodeDetails errorCode = new ErrorCodeDetails();\r
+    if (errorCodeMetaData != null) {\r
+      errorCode.setFaultCode(opResult.getFaultKey());\r
+      errorCode.setErrorMessage(errorCodeMetaData.getErrorMessage());\r
+      errorCode.setErrorType(errorCodeMetaData.getErrorType());\r
+      errorCode.setErrorTag(errorCodeMetaData.getErrorTag());\r
+      errorCode.setErrorSeverity(errorCodeMetaData.getErrorSeverity());\r
+      netConfResponse.setErrorCode(errorCode);\r
+      netConfResponse.setErrorMessage(opResult.getFaultString());\r
+    } else if (opResult.getFaultKey() != null && opResult.getFaultString() != null) {\r
+      errorCode.setFaultCode(opResult.getFaultKey());\r
+      errorCode.setErrorMessage(opResult.getFaultString());\r
+      errorCode.setErrorType("application");\r
+      errorCode.setErrorTag("operation-failed");\r
+      errorCode.setErrorSeverity("ERROR");\r
+      netConfResponse.setErrorCode(errorCode);\r
+      netConfResponse.setErrorMessage(opResult.getFaultString());\r
+    }\r
+    netConfResponse.setNetconfResponseXml(\r
+        getNetconfResponseXML(opResult.getOperationResponse().getParameterDTOs()));\r
+    return netConfResponse;\r
+  }\r
+\r
+  private String getNetconfResponseXML(List<ParameterDTO> parameters) {\r
+    if (null == parameters || parameters.isEmpty()) {\r
+\r
+      return null;\r
+    }\r
+    Collections.sort(parameters, new SortByParamterName());\r
+\r
+    String result = null;\r
+    try {\r
+      DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();\r
+      docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");\r
+      docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");\r
+      DocumentBuilder docBuilder = docFactory.newDocumentBuilder();\r
+      Document doc = docBuilder.newDocument();\r
+\r
+      Map<String, Element> parentNodeMap = new HashMap<>();\r
+      Element dataNode = null; // root of all nodes\r
+\r
+      for (ParameterDTO paramDto : parameters) {\r
+        String paramName =\r
+            metaDataUtil.getNetconfNameByTR69NameWithIndexes(paramDto.getParamName());\r
+        String paramValue = paramDto.getParamValue();\r
+        if (paramValue == null || paramValue.trim().isEmpty()) {\r
+          logger.debug("Values is empty so skipping this parameter.");\r
+          continue;\r
+        }\r
+        StringTokenizer tokenizer = new StringTokenizer(paramName, ".");\r
+        String parentNodeName = null;\r
+        String parentNodeKey = null;\r
+        Element parentNode = null;\r
+        while (tokenizer.hasMoreElements()) {\r
+          String nodeName = (String) tokenizer.nextElement();\r
+          if (null == parentNodeName) { // construct first node or\r
+                                        // Device node\r
+            parentNodeName = nodeName;\r
+            parentNodeKey = nodeName;\r
+            // check if the node already exists in parentNodeMap\r
+            parentNode = parentNodeMap.get(parentNodeKey);\r
+            if (null == dataNode) {\r
+              dataNode = parentNode;\r
+            }\r
+\r
+          } else if (nodeName.matches(INDEX_REGEX)) { // construct\r
+                                                      // tabular and\r
+                                                      // index nodes\r
+\r
+            // get parent tabular node from parent MAP\r
+            StringBuilder bld = new StringBuilder(parentNodeKey);\r
+            bld.append(".");\r
+            bld.append(nodeName);\r
+            parentNodeKey = bld.toString();\r
+            Element node = parentNodeMap.get(parentNodeKey);\r
+\r
+            // create a tabular parent node if doesn't exit in MAP\r
+            if (null == node) {\r
+              if (metaDataUtil.getMetaDataByNetConfName(parentNodeKey + ".") != null\r
+                  && metaDataUtil.getMetaDataByNetConfName(parentNodeKey + ".").getURI() != null) {\r
+                node = doc.createElementNS(\r
+                    metaDataUtil.getMetaDataByNetConfName(parentNodeKey + ".").getURI(),\r
+                    parentNodeName);\r
+              } else {\r
+                node = doc.createElement(parentNodeName);\r
+              }\r
+              parentNodeMap.put(parentNodeKey, node);\r
+\r
+              // update current tabular parent node.\r
+              if (null != parentNode)\r
+                parentNode.appendChild(node);\r
+\r
+              // prepare and add index node to tabular parent node\r
+              Element indexNode = doc.createElement(INDEX_STR);\r
+              indexNode.setTextContent(nodeName);\r
+              node.appendChild(indexNode);\r
+            }\r
+            parentNode = node; // move parent to child\r
+            parentNodeName = nodeName;\r
+          } else if (parentNodeName.matches(INDEX_REGEX)) { // move to\r
+                                                            // next\r
+                                                            // node\r
+                                                            // if\r
+                                                            // tabular\r
+                                                            // attribute\r
+                                                            // is\r
+                                                            // found\r
+            StringBuilder bld = new StringBuilder(parentNodeName);\r
+            bld.append(".");\r
+            bld.append(nodeName);\r
+            parentNodeKey = bld.toString();\r
+            parentNodeName = nodeName;\r
+          } else {\r
+            // construct intermediate nodes\r
+            Element node = parentNodeMap.get(parentNodeKey);\r
+            if (null == node) {\r
+              if (metaDataUtil.getMetaDataByNetConfName(parentNodeKey) != null\r
+                  && metaDataUtil.getMetaDataByNetConfName(parentNodeKey).getURI() != null) {\r
+                node = doc.createElementNS(\r
+                    metaDataUtil.getMetaDataByNetConfName(parentNodeKey).getURI(), parentNodeName);\r
+                if (dataNode == null)\r
+                  dataNode = node;\r
+              } else {\r
+                node = doc.createElement(parentNodeName);\r
+              }\r
+              parentNodeMap.put(parentNodeKey, node);\r
+              if (null != parentNode)\r
+                parentNode.appendChild(node);\r
+\r
+            }\r
+            StringBuilder bld = new StringBuilder(parentNodeKey);\r
+            bld.append(".");\r
+            bld.append(nodeName);\r
+            parentNodeKey = bld.toString();\r
+            parentNodeName = nodeName;\r
+            parentNode = node;\r
+          }\r
+        }\r
+        // construct leaf node\r
+        Element leafNode = doc.createElement(parentNodeName);\r
+        leafNode.setTextContent(paramValue);\r
+        if (null != parentNode)\r
+          parentNode.appendChild(leafNode);\r
+      }\r
+\r
+      if (null != dataNode) {\r
+        result = NetconfToTr069MapperUtil.convertDocumentToString(dataNode);\r
+      }\r
+    } catch (ParserConfigurationException pce) {\r
+      logger.error("Exception : {}", pce.getMessage());\r
+    }\r
+\r
+    return result;\r
+  }\r
+\r
+  public static String convertDocumentToString(Element element) {\r
+    String strxml = null;\r
+    try {\r
+      TransformerFactory transformerFactory = TransformerFactory.newInstance();\r
+      transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");\r
+      transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");\r
+      Transformer transformer = transformerFactory.newTransformer();\r
+      DOMSource source = new DOMSource(element);\r
+      StreamResult result = new StreamResult(new StringWriter());\r
+      transformer.transform(source, result);\r
+      strxml = result.getWriter().toString();\r
+    } catch (Exception e) {\r
+      logger.error("Error while converting Element to String {}", e.toString());\r
+    }\r
+    logger.debug("Converted XML is : {} ", strxml);\r
+    return strxml;\r
+  }\r
+\r
+  // TODO: Need to optimize the Node element logic for better performance\r
+  private static Map<String, String> getParameterMapForNode(Node moRNode, int numberOfChilds) {\r
+    Map<String, String> result = new HashMap<>();\r
+    if (moRNode.getNodeType() == Node.ELEMENT_NODE) {\r
+      NodeList childs = moRNode.getChildNodes();\r
+      boolean hasChildElements = false;\r
+      if (childs.getLength() > 0) {\r
+        int counter = 0;\r
+        for (int i = 0; i < childs.getLength(); i++) {\r
+          Node cNode = childs.item(i);\r
+          if (cNode != null && cNode.getNodeType() == Node.ELEMENT_NODE) {\r
+            counter++;\r
+          }\r
+        }\r
+\r
+        for (int i = 0; i < childs.getLength(); i++) {\r
+          Node cNode = childs.item(i);\r
+          if (cNode != null && cNode.getNodeType() == Node.ELEMENT_NODE) {\r
+            hasChildElements = true;\r
+            Map<String, String> subResult = getParameterMapForNode(cNode, counter);\r
+            result.putAll(subResult);\r
+          }\r
+        }\r
+      }\r
+      if (!hasChildElements) {\r
+        String moName = getMOName(moRNode);\r
+        if ((null != moName && !moName.endsWith("." + INDEX_STR))\r
+            || (null != moName && numberOfChilds == 1)) {\r
+          result.put(moName, moRNode.getTextContent());\r
+        }\r
+      }\r
+    }\r
+\r
+    return result;\r
+  }\r
+\r
+  private static String getMOName(Node moRNode) {\r
+    String result = removeNS(moRNode.getNodeName());\r
+    Node pNode = moRNode;\r
+    while (true) {\r
+      pNode = pNode.getParentNode();\r
+      if (pNode == null || pNode.getNodeType() != Node.ELEMENT_NODE\r
+          || pNode.getNodeName().equals("edit-config") || pNode.getNodeName().equals("config")\r
+          || pNode.getNodeName().equals("get-config") || pNode.getNodeName().equals("filter")\r
+          || pNode.getNodeName().equals("get")) {\r
+        return result;\r
+      } else {\r
+        String indexStr = getMOIndex(pNode);\r
+        StringBuilder bld = new StringBuilder(removeNS(pNode.getNodeName()));\r
+        bld.append(".");\r
+        if (indexStr == null) {\r
+          bld.append(result);\r
+          result = bld.toString();\r
+        } else {\r
+          bld.append(indexStr);\r
+          bld.append(".");\r
+          bld.append(result);\r
+          result = bld.toString();\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  private static Node getDeviceDataNode(Element el, String filter) {\r
+    try {\r
+      NodeList nodeList = el.getElementsByTagName(filter);\r
+      if (nodeList.getLength() > 0) {\r
+        nodeList = nodeList.item(0).getChildNodes();\r
+        for (int i = 0; i < nodeList.getLength(); i++) {\r
+          Node node = nodeList.item(i);\r
+          if (node.getNodeType() == Node.ELEMENT_NODE) {\r
+            return node;\r
+          }\r
+        }\r
+      }\r
+    } catch (Exception e) {\r
+      logger.error("exception occured while parsing the request xml {}", e.getMessage());\r
+    }\r
+    return null;\r
+  }\r
+\r
+  private static String removeNS(String nodeName) {\r
+    // remove name space\r
+    int li = nodeName.lastIndexOf(':');\r
+    nodeName = nodeName.substring(li + 1);\r
+    return nodeName;\r
+  }\r
+\r
+  private static String getMOIndex(Node pNode) {\r
+    if (null != pNode) {\r
+      NodeList nodeList = pNode.getChildNodes();\r
+      for (int i = 0; i < nodeList.getLength(); i++) {\r
+        Node childNode = nodeList.item(i);\r
+        String nodeName = removeNS(childNode.getNodeName());\r
+        if (nodeName.equalsIgnoreCase(INDEX_STR)) {\r
+          return childNode.getTextContent();\r
+        }\r
+      }\r
+    }\r
+    return null;\r
+  }\r
+\r
+}\r
+\r
+\r
+class SortByParamterName implements Comparator<ParameterDTO>, Serializable {\r
+  private static final long serialVersionUID = 3010693349267067945L;\r
+\r
+  public int compare(ParameterDTO a, ParameterDTO b) {\r
+    return a.getParamName().compareTo(b.getParamName());\r
+  }\r
+}\r