Development of NETCONF RPCs for tr-069 adapter to
[oam/tr069-adapter.git] / mapper / src / main / java / org / commscope / tr069adapter / mapper / netconf / NetConfNotificationSender.java
1 /*
2  * ============LICENSE_START========================================================================
3  * ONAP : tr-069-adapter
4  * =================================================================================================
5  * Copyright (C) 2020 CommScope Inc Intellectual Property.
6  * =================================================================================================
7  * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
9  * may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
14  * either express or implied. See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ===============LICENSE_END=======================================================================
17  */
18
19 package org.commscope.tr069adapter.mapper.netconf;
20
21 import java.io.StringWriter;
22 import java.text.SimpleDateFormat;
23 import java.util.ArrayList;
24 import java.util.Date;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.StringTokenizer;
29
30 import javax.xml.XMLConstants;
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34 import javax.xml.transform.Transformer;
35 import javax.xml.transform.TransformerFactory;
36 import javax.xml.transform.dom.DOMSource;
37 import javax.xml.transform.stream.StreamResult;
38
39 import org.commscope.tr069adapter.acs.common.DeviceInform;
40 import org.commscope.tr069adapter.acs.common.ParameterDTO;
41 import org.commscope.tr069adapter.acs.common.inform.TransferCompleteInform;
42 import org.commscope.tr069adapter.mapper.MOMetaData;
43 import org.commscope.tr069adapter.mapper.MapperConfigProperties;
44 import org.commscope.tr069adapter.mapper.model.NetConfNotificationDTO;
45 import org.commscope.tr069adapter.mapper.util.MOMetaDataUtil;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.beans.factory.annotation.Autowired;
49 import org.springframework.http.ResponseEntity;
50 import org.springframework.stereotype.Component;
51 import org.springframework.web.client.RestTemplate;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Element;
54
55 @Component
56 public class NetConfNotificationSender {
57
58   private static final Logger LOG = LoggerFactory.getLogger(NetConfNotificationSender.class);
59   private static final String BOOLEAN_TRUE_VALUE = "1";
60   private static final String BOOLEAN_FALSE_VALUE = "0";
61   private static final String BOOLEAN_DATA_TYPE = "boolean";
62   public static final String NOTIFICATION_ELEMENT_NAME = "notification";
63   public static final String EVENT_TIME = "eventTime";
64   private static final String INDEX_STR = "index";
65   private static final String INDEX_REGEX = "[0-9]{1,}";
66
67
68   @Autowired
69   MapperConfigProperties config;
70
71   @Autowired
72   MOMetaDataUtil metaDataUtil;
73
74   @Autowired
75   RestTemplate restTemplate;
76
77   public ResponseEntity sendNotification(DeviceInform deviceInform) {
78     ResponseEntity response = null;
79     final String uri = getUri();
80     LOG.debug("Posting notification to netconf server {}", uri);
81
82     try {
83       LOG.debug("deviceInform : {} {}", deviceInform.getInformTypeList(),
84           deviceInform.getParameters());
85       List<ParameterDTO> parameters = new ArrayList<>();
86       for (ParameterDTO parameterDTO : deviceInform.getParameters()) {
87         if (!parameterDTO.getParamName().equalsIgnoreCase("Device.DeviceInfo.SerialNumber"))
88           parameters.add(parameterDTO);
89       }
90       parameters.add(new ParameterDTO("Device.DeviceInfo.SerialNumber",
91           deviceInform.getDeviceDetails().getDeviceId()));
92
93       convertTR069ToNetConfParams(parameters, deviceInform.getDeviceDetails().getSoftwareVersion(),
94           deviceInform.getDeviceDetails().getHardwareVersion());
95
96       String nameSpace = metaDataUtil.getMetaDataByTR69Name(deviceInform.getInformType().toString(),
97           deviceInform.getDeviceDetails().getSoftwareVersion(),
98           deviceInform.getDeviceDetails().getHardwareVersion()).getURI();
99
100       String notificationXml =
101           getNetconfResponseXML(parameters, deviceInform.getInformType().toString(), nameSpace);
102       NetConfNotificationDTO netConfDTO = new NetConfNotificationDTO(
103           deviceInform.getDeviceDetails().getDeviceId(), notificationXml);
104
105       LOG.debug("Posting notification to netconf server");
106       response = restTemplate.postForObject(uri, netConfDTO, ResponseEntity.class);
107       LOG.debug("Posting notification to netconf server completed ");
108     } catch (Exception e) {
109       LOG.error("Exception while sending the notification.", e);
110     }
111     return response;
112   }
113
114   public ResponseEntity sendTransferCompleteNotification(TransferCompleteInform tcInform) {
115     ResponseEntity response = null;
116     final String uri = getUri();
117     LOG.debug("Posting notification to netconf server {}", uri);
118
119     try {
120       // LOG.debug("deviceInform : {} {}", tcInform.getInformTypeList(),
121       // tcInform.getParameters());
122       // List<ParameterDTO> parameters = new ArrayList<>();
123       // for (ParameterDTO parameterDTO : tcInform.getParameters()) {
124       // parameters.add(parameterDTO);
125       // }
126
127       List<ParameterDTO> parameters = new ArrayList<>();
128       parameters.add(new ParameterDTO("command-key", tcInform.getCommandKey()));
129       parameters.add(new ParameterDTO("fault-code", String.valueOf(tcInform.getFaultCode())));
130       parameters.add(new ParameterDTO("fault-string", tcInform.getFaultString()));
131       parameters.add(new ParameterDTO("start-time", tcInform.getStartTime()));
132       parameters.add(new ParameterDTO("complete-time", tcInform.getCompleteTime()));
133
134       String nameSpace = metaDataUtil.getMetaDataByTR69Name(tcInform.getInformType().toString(),
135           tcInform.getDeviceDetails().getSoftwareVersion(),
136           tcInform.getDeviceDetails().getHardwareVersion()).getURI();
137
138       String notificationXml =
139           getNetConfReposneXMLForTC(parameters, tcInform.getInformType().toString(), nameSpace);
140       NetConfNotificationDTO netConfDTO =
141           new NetConfNotificationDTO(tcInform.getDeviceDetails().getDeviceId(), notificationXml);
142
143       LOG.debug("Posting notification to netconf server");
144       response = restTemplate.postForObject(uri, netConfDTO, ResponseEntity.class);
145       LOG.debug("Posting notification to netconf server completed ");
146     } catch (Exception e) {
147       LOG.error("Exception while sending the notification.", e);
148     }
149     return response;
150   }
151
152   public ResponseEntity sendCustomNotification(String deviceId, List<ParameterDTO> parameters,
153       String nameSpace) {
154     ResponseEntity response = null;
155     final String uri = getUri();
156     LOG.debug("Posting custom notification to netconf server {}", uri);
157     try {
158       String notificationXml = getNetconfResponseXML(parameters, null, nameSpace);
159       NetConfNotificationDTO netConfDTO = new NetConfNotificationDTO(deviceId, notificationXml);
160
161       response = restTemplate.postForObject(uri, netConfDTO, ResponseEntity.class);
162       LOG.debug("Posting custom notification to netconf server sucessfull");
163     } catch (Exception e) {
164       LOG.error("Exception while sending the custom notification.", e);
165     }
166     return response;
167   }
168
169   private void convertTR069ToNetConfParams(List<ParameterDTO> parameters, String swVersion,
170       String hwVersion) {
171     List<ParameterDTO> removeList = new ArrayList<>();
172     if (null != parameters) {
173       for (ParameterDTO param : parameters) {
174         if (param.getParamValue() == null || param.getParamValue().trim().length() <= 0) {
175           removeList.add(param);
176           continue;
177         }
178         handleBooleanParameters(param, swVersion, hwVersion);
179         if (null != param.getParamName()) {
180           String netConfMOName = metaDataUtil
181               .getNetconfNameByTR69NameWithIndexes(param.getParamName(), swVersion, hwVersion);
182           if (null != netConfMOName)
183             param.setParamName(netConfMOName);
184           else
185             removeList.add(param); // unknown parameter found.
186         }
187       }
188       parameters.removeAll(removeList);
189     }
190   }
191
192   private void handleBooleanParameters(ParameterDTO param, String swVersion, String hwVersion) {
193     MOMetaData metaData =
194         metaDataUtil.getMetaDataByTR69Name(param.getParamName(), swVersion, hwVersion);
195     if (null != metaData && BOOLEAN_DATA_TYPE.equalsIgnoreCase(metaData.getDataType())) {
196       if (BOOLEAN_TRUE_VALUE.equalsIgnoreCase(param.getParamValue().trim())) {
197         param.setParamValue(Boolean.TRUE.toString());
198       } else if (BOOLEAN_FALSE_VALUE.equalsIgnoreCase(param.getParamValue().trim())) {
199         param.setParamValue(Boolean.FALSE.toString());
200       }
201     }
202   }
203
204   private String getUri() {
205     return config.getNbiNotificationUri();
206   }
207
208   private static String getNetconfResponseXML(List<ParameterDTO> parameters,
209       String notificationType, String nameSpace) {
210     if (parameters == null || parameters.isEmpty()) {
211       LOG.debug("There are no parameters found in the response.");
212       return null;
213     }
214
215     String result = null;
216     try {
217       DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
218       docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
219       docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
220       DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
221       Document doc = docBuilder.newDocument();
222
223       Map<String, Element> parentNodeMap = new HashMap<>();
224       Element dataNode = null; // root of all nodes
225
226       for (ParameterDTO paramDto : parameters) {
227         String paramName = paramDto.getParamName();
228         String paramValue = paramDto.getParamValue();
229         StringTokenizer tokenizer = new StringTokenizer(paramName, ".");
230         String parentNodeName = null;
231         String parentNodeKey = null;
232         Element parentNode = null;
233         while (tokenizer.hasMoreElements()) {
234           String nodeName = (String) tokenizer.nextElement();
235           if (null == parentNodeName) { // construct first node or
236                                         // Device node
237             parentNodeName = nodeName;
238             parentNodeKey = nodeName;
239             // check if the node already exists in parentNodeMap
240             parentNode = parentNodeMap.get(parentNodeKey);
241             if (null == dataNode) {
242               dataNode = parentNode;
243             }
244             continue;
245           } else if (nodeName.matches(INDEX_REGEX)) { // construct
246                                                       // tabular and
247                                                       // index nodes
248
249             // get parent tabular node from parent MAP
250             StringBuilder bld = new StringBuilder();
251             bld.append(parentNodeKey);
252             bld.append(".");
253             bld.append(nodeName);
254             parentNodeKey = bld.toString();
255             Element node = parentNodeMap.get(parentNodeKey);
256
257             // create a tabular parent node if doesn't exit in MAP
258             if (null == node) {
259               node = doc.createElement(parentNodeName);
260               parentNodeMap.put(parentNodeKey, node);
261
262               // update current tabular parent node.
263               if (null != parentNode)
264                 parentNode.appendChild(node);
265               else
266                 parentNode = node;
267
268               // prepare and add index node to tabular parent node
269               Element indexNode = doc.createElement(INDEX_STR);
270               indexNode.setTextContent(nodeName);
271               node.appendChild(indexNode);
272             }
273             parentNode = node; // move parent to child
274             parentNodeName = nodeName;
275           } else if (parentNodeName.matches(INDEX_REGEX)) { // move to
276                                                             // next
277                                                             // node
278                                                             // if
279                                                             // tabular
280                                                             // attribute
281                                                             // is
282                                                             // found
283             StringBuilder bld = new StringBuilder();
284             bld.append(parentNodeKey);
285             bld.append(".");
286             bld.append(nodeName);
287             parentNodeKey = bld.toString();
288             parentNodeName = nodeName;
289           } else {
290             // construct intermediate nodes
291             Element node = parentNodeMap.get(parentNodeKey);
292             if (null == node) {
293               if (null == dataNode) {
294                 node = doc.createElementNS(nameSpace, parentNodeName);
295                 dataNode = node;
296               } else {
297                 node = doc.createElement(parentNodeName);
298               }
299               parentNodeMap.put(parentNodeKey, node);
300               if (null != parentNode)
301                 parentNode.appendChild(node);
302             }
303             StringBuilder bld = new StringBuilder();
304             bld.append(parentNodeKey);
305             bld.append(".");
306             bld.append(nodeName);
307             parentNodeKey = bld.toString();
308             parentNodeName = nodeName;
309             parentNode = node;
310           }
311         }
312         // construct leaf node
313         Element leafNode = doc.createElement(parentNodeName);
314         leafNode.setTextContent(paramValue);
315         if (null != parentNode)
316           parentNode.appendChild(leafNode);
317       }
318
319       if (null != dataNode) {
320         final Element element = doc.createElement(NOTIFICATION_ELEMENT_NAME);
321         final Element eventTime = doc.createElement(EVENT_TIME);
322         eventTime
323             .setTextContent(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
324         element.appendChild(element.getOwnerDocument().importNode(eventTime, true));
325
326         if (notificationType != null) {
327           final Element evtTypeElement = doc.createElementNS(nameSpace, notificationType);
328           evtTypeElement.appendChild(dataNode);
329           element.appendChild(element.getOwnerDocument().importNode(evtTypeElement, true));
330         } else {
331           element.appendChild(element.getOwnerDocument().importNode(dataNode, true));
332         }
333
334         result = convertDocumentToString(element);
335       }
336     } catch (ParserConfigurationException pce) {
337       LOG.error("Exception while converting the notification: {}", pce.getMessage());
338     }
339
340     return result;
341   }
342
343   private static String getNetConfReposneXMLForTC(List<ParameterDTO> parameters,
344       String notificationType, String nameSpace) {
345     String result = null;
346     try {
347       DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
348       docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
349       docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
350       DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
351       Document doc = docBuilder.newDocument();
352       final Element element = doc.createElement(NOTIFICATION_ELEMENT_NAME);
353       final Element eventTime = doc.createElement(EVENT_TIME);
354       eventTime.setTextContent(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
355       element.appendChild(element.getOwnerDocument().importNode(eventTime, true));
356
357       final Element evtTypeElement = doc.createElementNS(nameSpace, notificationType);
358
359       for (ParameterDTO paramDto : parameters) {
360         final Element paramNode = doc.createElement(paramDto.getParamName());
361         paramNode.setTextContent(paramDto.getParamValue());
362         evtTypeElement.appendChild(paramNode);
363       }
364       element.appendChild(element.getOwnerDocument().importNode(evtTypeElement, true));
365       result = convertDocumentToString(element);
366     } catch (Exception e) {
367       LOG.error("Exception in getNetConfReposneXMLForTC: {}", e.getMessage());
368     }
369     return result;
370   }
371
372   public static String convertDocumentToString(Element element) {
373     String strxml = null;
374     try {
375       TransformerFactory transformerFactory = TransformerFactory.newInstance();
376       transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
377       transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
378       Transformer transformer = transformerFactory.newTransformer();
379       DOMSource source = new DOMSource(element);
380       StreamResult result = new StreamResult(new StringWriter());
381       transformer.transform(source, result);
382       strxml = result.getWriter().toString();
383     } catch (Exception e) {
384       LOG.error("Error while converting Element to String", e);
385     }
386     LOG.debug("Converted XML is : {}", strxml);
387     return strxml;
388   }
389 }