Initial source code
[oam/tr069-adapter.git] / config-data / src / main / java / org / commscope / tr069adapter / config / parser / ConfigurationXMLDataParser.java
diff --git a/config-data/src/main/java/org/commscope/tr069adapter/config/parser/ConfigurationXMLDataParser.java b/config-data/src/main/java/org/commscope/tr069adapter/config/parser/ConfigurationXMLDataParser.java
new file mode 100644 (file)
index 0000000..4be0ccf
--- /dev/null
@@ -0,0 +1,277 @@
+/*\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.config.parser;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.InputStream;\r
+import java.nio.charset.StandardCharsets;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import javax.xml.XMLConstants;\r
+import javax.xml.parsers.SAXParser;\r
+import javax.xml.parsers.SAXParserFactory;\r
+import javax.xml.transform.stream.StreamSource;\r
+import javax.xml.validation.Schema;\r
+import javax.xml.validation.SchemaFactory;\r
+import javax.xml.validation.Validator;\r
+\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+import org.commscope.tr069adapter.config.constants.ConfigurationServiceConstant;\r
+import org.commscope.tr069adapter.config.dto.ConfigurationData;\r
+import org.commscope.tr069adapter.config.exceptions.InvalidConfigurationServiceException;\r
+import org.commscope.tr069adapter.config.model.ConfigFileContent;\r
+import org.springframework.stereotype.Component;\r
+import org.xml.sax.Attributes;\r
+import org.xml.sax.ErrorHandler;\r
+import org.xml.sax.SAXException;\r
+import org.xml.sax.SAXNotRecognizedException;\r
+import org.xml.sax.SAXNotSupportedException;\r
+import org.xml.sax.SAXParseException;\r
+import org.xml.sax.helpers.DefaultHandler;\r
+\r
+@Component\r
+public class ConfigurationXMLDataParser extends DefaultHandler {\r
+\r
+  private static final Log logger = LogFactory.getLog(ConfigurationXMLDataParser.class);\r
+\r
+  private List<ConfigurationData> completeConfigurationDataList;\r
+\r
+  private ConfigurationData configurationData;\r
+  private Map<String, String> parameterMONameValueMap;\r
+\r
+  private String moAttr;\r
+  private String moValue;\r
+\r
+  public void validateFile(ConfigFileContent configFileContent)\r
+      throws InvalidConfigurationServiceException {\r
+    SAXParserFactory factory = SAXParserFactory.newInstance();\r
+    factory.setValidating(true);\r
+    factory.setNamespaceAware(true);\r
+\r
+    String xmlFileContent = configFileContent.getFileContent();\r
+    byte[] byteArray;\r
+\r
+    try {\r
+      byteArray = xmlFileContent.getBytes(StandardCharsets.UTF_8);\r
+    } catch (Exception e) {\r
+      logger.error("Error while parsing device configuration XML file. {}", e);\r
+      throw new InvalidConfigurationServiceException(\r
+          "UnsupportedEncodingException error. " + e.getMessage());\r
+    }\r
+\r
+    ByteArrayInputStream xmlFileContentInputStream = new ByteArrayInputStream(byteArray);\r
+\r
+    logger.debug("Validating XML file");\r
+\r
+    validateXmlWithSchema(xmlFileContentInputStream);\r
+\r
+    logger.debug("XML file validation is successful");\r
+\r
+  }\r
+\r
+  public ConfigurationData parseFile(ConfigFileContent configFileContent)\r
+      throws InvalidConfigurationServiceException {\r
+    SAXParserFactory factory = SAXParserFactory.newInstance();\r
+    factory.setValidating(true);\r
+    factory.setNamespaceAware(true);\r
+\r
+    try {\r
+      String xmlFileContent = configFileContent.getFileContent();\r
+      byte[] byteArray = xmlFileContent.getBytes(StandardCharsets.UTF_8);\r
+      ByteArrayInputStream xmlFileContentInputStream = new ByteArrayInputStream(byteArray);\r
+\r
+      logger.debug("Validating XML file");\r
+\r
+      validateXmlWithSchema(xmlFileContentInputStream);\r
+\r
+      logger.debug("XML file validation is successful");\r
+\r
+      byteArray = xmlFileContent.getBytes(StandardCharsets.UTF_8);\r
+      xmlFileContentInputStream = new ByteArrayInputStream(byteArray);\r
+\r
+      SAXParser parser = null;\r
+      parser = factory.newSAXParser();\r
+      parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");\r
+      parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");\r
+      setProperty(parser);\r
+\r
+      parser.parse(xmlFileContentInputStream, this);\r
+\r
+    } catch (SAXException e) {\r
+      logger.error("Error while parsing device configuration XML file. {}", e);\r
+      throw new InvalidConfigurationServiceException("File parsing error. " + e.getMessage());\r
+    } catch (Exception e) {\r
+      logger.error("Unknown error occurred while parsing device configuration XML file. {}", e);\r
+      throw new InvalidConfigurationServiceException("UNKNOWN ERROR. " + e.getMessage());\r
+    }\r
+\r
+    if (null == completeConfigurationDataList || completeConfigurationDataList.isEmpty()) {\r
+      return null;\r
+    } else {\r
+      return completeConfigurationDataList.get(0);\r
+    }\r
+  }\r
+\r
+  @Override\r
+  public void startElement(String uri, String localName, String qName, Attributes attributes)\r
+      throws SAXException {\r
+    qName = qName.trim();\r
+    if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA_FILE)) {\r
+      completeConfigurationDataList = new ArrayList<>();\r
+      return;\r
+    }\r
+\r
+    if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA)) {\r
+      moAttr = null;\r
+      configurationData = new ConfigurationData();\r
+      parameterMONameValueMap = new HashMap<>();\r
+\r
+      configurationData.setParameterMONameValueMap(parameterMONameValueMap);\r
+    } else if (qName.equalsIgnoreCase(ConfigurationServiceConstant.FILE_HEADER)) {\r
+      logger.debug("File hearder start element parsing started");\r
+    } else {\r
+      createAttribute(qName, attributes);\r
+    }\r
+  }\r
+\r
+  @Override\r
+  public void endElement(String uri, String localName, String qName) throws SAXException {\r
+    qName = qName.trim();\r
+\r
+    if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA_FILE)) {\r
+      logger.debug("ignoreing the datafile end element");\r
+    } else if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA)) {\r
+      completeConfigurationDataList.add(configurationData);\r
+    } else if (qName.equalsIgnoreCase(ConfigurationServiceConstant.MANAGED_ELEMENT)\r
+        || qName.equalsIgnoreCase(ConfigurationServiceConstant.FILE_HEADER)) {\r
+      logger.debug("File hearder end element parsing started");\r
+    } else {\r
+      if (moValue != null && !moValue.equals("") && !moValue.trim().isEmpty()) {\r
+        parameterMONameValueMap.put(moAttr, moValue);\r
+        moValue = null;\r
+      }\r
+      try {\r
+        if (moAttr.lastIndexOf(qName) > 0) {\r
+          moAttr = moAttr.substring(0, moAttr.lastIndexOf(qName) - 1);\r
+        }\r
+      } catch (StringIndexOutOfBoundsException e) {\r
+        logger.error("Error occurred while parshing XML file. Cause: {}", e);\r
+      }\r
+    }\r
+  }\r
+\r
+  private void createAttribute(String attrName, Attributes attributes) {\r
+\r
+    if (attrName.equalsIgnoreCase(ConfigurationServiceConstant.MANAGED_ELEMENT)) {\r
+      configurationData.setOUI(attributes.getValue("OUI"));\r
+      configurationData.setProductClass(attributes.getValue("ProductClass"));\r
+      configurationData.setHardwareVersion(attributes.getValue("hwVersion"));\r
+      configurationData.setSoftwareVersion(attributes.getValue("swVersion"));\r
+      configurationData.setLocalDn(attributes.getValue("localDn"));\r
+\r
+      return;\r
+    }\r
+    if (moAttr != null) {\r
+      moAttr = moAttr + "." + attrName;\r
+    } else {\r
+      moAttr = attrName;\r
+    }\r
+\r
+    if (attributes.getValue(ConfigurationServiceConstant.TABULAR_INDEX_NAME) != null) {\r
+      moAttr = moAttr + "." + attributes.getValue(ConfigurationServiceConstant.TABULAR_INDEX_NAME);\r
+    }\r
+\r
+  }\r
+\r
+  @Override\r
+  public void characters(char[] ch, int start, int length) throws SAXException {\r
+    String tmp = new String(ch, start, length);\r
+    if (moValue == null) {\r
+      moValue = tmp.trim();\r
+    } else {\r
+      moValue = moValue + tmp.trim();\r
+    }\r
+  }\r
+\r
+  public void validateXmlWithSchema(ByteArrayInputStream xmlFileContentInputStream)\r
+      throws InvalidConfigurationServiceException {\r
+    logger.info("Validating the XML file against XSD file: "\r
+        + ConfigurationServiceConstant.CONFIGURATION_DATA_XSD_PATH);\r
+    try {\r
+      SchemaFactory factory = SchemaFactory.newInstance(ConfigurationServiceConstant.XML_SCHEMA_NS);\r
+      factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");\r
+      factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");\r
+\r
+      InputStream xsdInputStream =\r
+          getClass().getResourceAsStream(ConfigurationServiceConstant.CONFIGURATION_DATA_XSD_PATH);\r
+      if (xsdInputStream == null) {\r
+        throw new InvalidConfigurationServiceException("File parsing error: Unable to find XSD "\r
+            + ConfigurationServiceConstant.CONFIGURATION_DATA_XSD_PATH);\r
+      }\r
+\r
+      Schema schema = factory.newSchema(new StreamSource(xsdInputStream));\r
+      Validator validator = schema.newValidator();\r
+\r
+      final StringBuilder exceptions = new StringBuilder();\r
+      validator.setErrorHandler(new ErrorHandler() {\r
+        @Override\r
+        public void warning(SAXParseException exception) {\r
+          handleMessage(exception);\r
+        }\r
+\r
+        @Override\r
+        public void error(SAXParseException exception) {\r
+          handleMessage(exception);\r
+        }\r
+\r
+        @Override\r
+        public void fatalError(SAXParseException exception) {\r
+          handleMessage(exception);\r
+        }\r
+\r
+        private void handleMessage(SAXParseException exception) {\r
+          int lineNumber = exception.getLineNumber();\r
+          int columnNumber = exception.getColumnNumber();\r
+          String message = exception.getMessage();\r
+          exceptions.append("\n" + lineNumber + ":" + columnNumber + ": " + message);\r
+        }\r
+      });\r
+\r
+      validator.validate(new StreamSource(xmlFileContentInputStream));\r
+      if (exceptions.length() > 0) {\r
+        throw new SAXException(" Line=" + exceptions);\r
+      }\r
+    } catch (Exception e) {\r
+      logger.error("Error while parsing the XML file " + e.toString());\r
+      throw new InvalidConfigurationServiceException("File parsing error. " + e.toString());\r
+    }\r
+\r
+    logger.debug("File is valid.");\r
+  }\r
+\r
+  protected void setProperty(SAXParser parser)\r
+      throws SAXNotRecognizedException, SAXNotSupportedException {\r
+      logger.debug("property added.");\r
+  }\r
+\r
+}\r