VES Heartbeat and Software Management Feature
[oam/tr069-adapter.git] / config-data / src / main / java / org / commscope / tr069adapter / config / parser / ConfigurationXMLDataParser.java
1 /*\r
2  * ============LICENSE_START========================================================================\r
3  * ONAP : tr-069-adapter\r
4  * =================================================================================================\r
5  * Copyright (C) 2020 CommScope Inc Intellectual Property.\r
6  * =================================================================================================\r
7  * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,\r
8  * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You\r
9  * may obtain a copy of the License at\r
10  *\r
11  * http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
14  * either express or implied. See the License for the specific language governing permissions and\r
15  * limitations under the License.\r
16  * ===============LICENSE_END=======================================================================\r
17  */\r
18 \r
19 package org.commscope.tr069adapter.config.parser;\r
20 \r
21 import java.io.ByteArrayInputStream;\r
22 import java.io.InputStream;\r
23 import java.nio.charset.StandardCharsets;\r
24 import java.util.ArrayList;\r
25 import java.util.HashMap;\r
26 import java.util.List;\r
27 import java.util.Map;\r
28 \r
29 import javax.xml.XMLConstants;\r
30 import javax.xml.parsers.SAXParser;\r
31 import javax.xml.parsers.SAXParserFactory;\r
32 import javax.xml.transform.stream.StreamSource;\r
33 import javax.xml.validation.Schema;\r
34 import javax.xml.validation.SchemaFactory;\r
35 import javax.xml.validation.Validator;\r
36 \r
37 import org.apache.commons.logging.Log;\r
38 import org.apache.commons.logging.LogFactory;\r
39 import org.commscope.tr069adapter.acs.common.dto.ConfigurationData;\r
40 import org.commscope.tr069adapter.config.constants.ConfigurationServiceConstant;\r
41 import org.commscope.tr069adapter.config.exceptions.InvalidConfigurationServiceException;\r
42 import org.commscope.tr069adapter.config.model.ConfigFileContent;\r
43 import org.springframework.stereotype.Component;\r
44 import org.xml.sax.Attributes;\r
45 import org.xml.sax.ErrorHandler;\r
46 import org.xml.sax.SAXException;\r
47 import org.xml.sax.SAXParseException;\r
48 import org.xml.sax.helpers.DefaultHandler;\r
49 \r
50 @Component\r
51 public class ConfigurationXMLDataParser extends DefaultHandler {\r
52 \r
53   private static final Log logger = LogFactory.getLog(ConfigurationXMLDataParser.class);\r
54 \r
55   private List<ConfigurationData> completeConfigurationDataList;\r
56 \r
57   private ConfigurationData configurationData;\r
58   private Map<String, String> parameterMONameValueMap;\r
59 \r
60   private String moAttr;\r
61   private String moValue;\r
62 \r
63   public void validateFile(ConfigFileContent configFileContent)\r
64       throws InvalidConfigurationServiceException {\r
65     SAXParserFactory factory = SAXParserFactory.newInstance();\r
66     factory.setValidating(true);\r
67     factory.setNamespaceAware(true);\r
68 \r
69     String xmlFileContent = configFileContent.getFileContent();\r
70     byte[] byteArray;\r
71 \r
72     try {\r
73       byteArray = xmlFileContent.getBytes(StandardCharsets.UTF_8);\r
74     } catch (Exception e) {\r
75       logger.error("Error while parsing device configuration XML file. {}", e);\r
76       throw new InvalidConfigurationServiceException(\r
77           "UnsupportedEncodingException error. " + e.getMessage());\r
78     }\r
79 \r
80     ByteArrayInputStream xmlFileContentInputStream = new ByteArrayInputStream(byteArray);\r
81 \r
82     logger.debug("Validating XML file");\r
83 \r
84     validateXmlWithSchema(xmlFileContentInputStream);\r
85 \r
86     logger.debug("XML file validation is successful");\r
87 \r
88   }\r
89 \r
90   public ConfigurationData parseFile(ConfigFileContent configFileContent)\r
91       throws InvalidConfigurationServiceException {\r
92     SAXParserFactory factory = SAXParserFactory.newInstance();\r
93     factory.setValidating(true);\r
94     factory.setNamespaceAware(true);\r
95 \r
96     try {\r
97       String xmlFileContent = configFileContent.getFileContent();\r
98       byte[] byteArray = xmlFileContent.getBytes(StandardCharsets.UTF_8);\r
99       ByteArrayInputStream xmlFileContentInputStream = new ByteArrayInputStream(byteArray);\r
100 \r
101       logger.debug("Validating XML file");\r
102 \r
103       validateXmlWithSchema(xmlFileContentInputStream);\r
104 \r
105       logger.debug("XML file validation is successful");\r
106 \r
107       byteArray = xmlFileContent.getBytes(StandardCharsets.UTF_8);\r
108       xmlFileContentInputStream = new ByteArrayInputStream(byteArray);\r
109 \r
110       SAXParser parser = null;\r
111       parser = factory.newSAXParser();\r
112       parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");\r
113       parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");\r
114       setProperty();\r
115 \r
116       parser.parse(xmlFileContentInputStream, this);\r
117 \r
118     } catch (SAXException e) {\r
119       logger.error("Error while parsing device configuration XML file. {}", e);\r
120       throw new InvalidConfigurationServiceException("File parsing error. " + e.getMessage());\r
121     } catch (Exception e) {\r
122       logger.error("Unknown error occurred while parsing device configuration XML file. {}", e);\r
123       throw new InvalidConfigurationServiceException("UNKNOWN ERROR. " + e.getMessage());\r
124     }\r
125 \r
126     if (null == completeConfigurationDataList || completeConfigurationDataList.isEmpty()) {\r
127       return null;\r
128     } else {\r
129       return completeConfigurationDataList.get(0);\r
130     }\r
131   }\r
132 \r
133   @Override\r
134   public void startElement(String uri, String localName, String qName, Attributes attributes)\r
135       throws SAXException {\r
136     qName = qName.trim();\r
137     if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA_FILE)) {\r
138       completeConfigurationDataList = new ArrayList<>();\r
139       return;\r
140     }\r
141 \r
142     if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA)) {\r
143       moAttr = null;\r
144       configurationData = new ConfigurationData();\r
145       parameterMONameValueMap = new HashMap<>();\r
146 \r
147       configurationData.setParameterMONameValueMap(parameterMONameValueMap);\r
148     } else if (qName.equalsIgnoreCase(ConfigurationServiceConstant.FILE_HEADER)) {\r
149       logger.debug("File hearder start element parsing started");\r
150     } else {\r
151       createAttribute(qName, attributes);\r
152     }\r
153   }\r
154 \r
155   @Override\r
156   public void endElement(String uri, String localName, String qName) throws SAXException {\r
157     qName = qName.trim();\r
158 \r
159     if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA_FILE)) {\r
160       logger.debug("ignoreing the datafile end element");\r
161     } else if (qName.equalsIgnoreCase(ConfigurationServiceConstant.CONFIG_DATA)) {\r
162       completeConfigurationDataList.add(configurationData);\r
163     } else if (qName.equalsIgnoreCase(ConfigurationServiceConstant.MANAGED_ELEMENT)\r
164         || qName.equalsIgnoreCase(ConfigurationServiceConstant.FILE_HEADER)) {\r
165       logger.debug("File hearder end element parsing started");\r
166     } else {\r
167       if (moValue != null && !moValue.equals("") && !moValue.trim().isEmpty()) {\r
168         parameterMONameValueMap.put(moAttr, moValue);\r
169         moValue = null;\r
170       }\r
171       try {\r
172         if (moAttr.lastIndexOf(qName) > 0) {\r
173           moAttr = moAttr.substring(0, moAttr.lastIndexOf(qName) - 1);\r
174         }\r
175       } catch (StringIndexOutOfBoundsException e) {\r
176         logger.error("Error occurred while parshing XML file. Cause: {}", e);\r
177       }\r
178     }\r
179   }\r
180 \r
181   private void createAttribute(String attrName, Attributes attributes) {\r
182 \r
183     if (attrName.equalsIgnoreCase(ConfigurationServiceConstant.MANAGED_ELEMENT)) {\r
184       configurationData.setOUI(attributes.getValue("OUI"));\r
185       configurationData.setProductClass(attributes.getValue("ProductClass"));\r
186       configurationData.setHardwareVersion(attributes.getValue("hwVersion"));\r
187       configurationData.setSoftwareVersion(attributes.getValue("swVersion"));\r
188       configurationData.setLocalDn(attributes.getValue("localDn"));\r
189 \r
190       return;\r
191     }\r
192     if (moAttr != null) {\r
193       moAttr = moAttr + "." + attrName;\r
194     } else {\r
195       moAttr = attrName;\r
196     }\r
197 \r
198     if (attributes.getValue(ConfigurationServiceConstant.TABULAR_INDEX_NAME) != null) {\r
199       moAttr = moAttr + "." + attributes.getValue(ConfigurationServiceConstant.TABULAR_INDEX_NAME);\r
200     }\r
201 \r
202   }\r
203 \r
204   @Override\r
205   public void characters(char[] ch, int start, int length) throws SAXException {\r
206     String tmp = new String(ch, start, length);\r
207     if (moValue == null) {\r
208       moValue = tmp.trim();\r
209     } else {\r
210       moValue = moValue + tmp.trim();\r
211     }\r
212   }\r
213 \r
214   public void validateXmlWithSchema(ByteArrayInputStream xmlFileContentInputStream)\r
215       throws InvalidConfigurationServiceException {\r
216     logger.info("Validating the XML file against XSD file: "\r
217         + ConfigurationServiceConstant.CONFIGURATION_DATA_XSD_PATH);\r
218     try {\r
219       SchemaFactory factory = SchemaFactory.newInstance(ConfigurationServiceConstant.XML_SCHEMA_NS);\r
220       factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");\r
221       factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");\r
222 \r
223       InputStream xsdInputStream =\r
224           getClass().getResourceAsStream(ConfigurationServiceConstant.CONFIGURATION_DATA_XSD_PATH);\r
225       if (xsdInputStream == null) {\r
226         throw new InvalidConfigurationServiceException("File parsing error: Unable to find XSD "\r
227             + ConfigurationServiceConstant.CONFIGURATION_DATA_XSD_PATH);\r
228       }\r
229 \r
230       Schema schema = factory.newSchema(new StreamSource(xsdInputStream));\r
231       Validator validator = schema.newValidator();\r
232 \r
233       final StringBuilder exceptions = new StringBuilder();\r
234       validator.setErrorHandler(new ErrorHandler() {\r
235         @Override\r
236         public void warning(SAXParseException exception) {\r
237           handleMessage(exception);\r
238         }\r
239 \r
240         @Override\r
241         public void error(SAXParseException exception) {\r
242           handleMessage(exception);\r
243         }\r
244 \r
245         @Override\r
246         public void fatalError(SAXParseException exception) {\r
247           handleMessage(exception);\r
248         }\r
249 \r
250         private void handleMessage(SAXParseException exception) {\r
251           int lineNumber = exception.getLineNumber();\r
252           int columnNumber = exception.getColumnNumber();\r
253           String message = exception.getMessage();\r
254           exceptions.append("\n" + lineNumber + ":" + columnNumber + ": " + message);\r
255         }\r
256       });\r
257 \r
258       validator.validate(new StreamSource(xmlFileContentInputStream));\r
259       if (exceptions.length() > 0) {\r
260         throw new SAXException(" Line=" + exceptions);\r
261       }\r
262     } catch (Exception e) {\r
263       logger.error("Error while parsing the XML file " + e.toString());\r
264       throw new InvalidConfigurationServiceException("File parsing error. " + e.toString());\r
265     }\r
266 \r
267     logger.debug("File is valid.");\r
268   }\r
269 \r
270   protected void setProperty() {\r
271     logger.debug("property added.");\r
272   }\r
273 \r
274 }\r