Development of NETCONF RPCs for tr-069 adapter to
[oam/tr069-adapter.git] / acs / cpe / src / main / java / org / commscope / tr069adapter / acs / cpe / TR069RPC.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
20 package org.commscope.tr069adapter.acs.cpe;
21
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.Serializable;
25 import java.security.SecureRandom;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.Random;
29
30 import javax.xml.soap.MessageFactory;
31 import javax.xml.soap.Name;
32 import javax.xml.soap.Node;
33 import javax.xml.soap.SOAPBody;
34 import javax.xml.soap.SOAPBodyElement;
35 import javax.xml.soap.SOAPElement;
36 import javax.xml.soap.SOAPEnvelope;
37 import javax.xml.soap.SOAPException;
38 import javax.xml.soap.SOAPFactory;
39 import javax.xml.soap.SOAPHeader;
40 import javax.xml.soap.SOAPHeaderElement;
41 import javax.xml.soap.SOAPMessage;
42 import javax.xml.soap.SOAPPart;
43
44 import org.commscope.tr069adapter.acs.cpe.rpc.Fault;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 public abstract class TR069RPC implements Serializable {
49
50   private static final String HTTP_SCHEMA_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";
51
52   private static final long serialVersionUID = 7270475819053880884L;
53
54   protected static final Logger logger = LoggerFactory.getLogger(TR069RPC.class);
55
56   private Random mrandom = new SecureRandom();
57
58   /** Creates a new instance of Message */
59   public TR069RPC() {}
60
61   public static final String ENVELOPE_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/";
62
63   protected abstract void createBody(SOAPBodyElement body, SOAPFactory spf) throws SOAPException;
64
65   protected abstract void parseBody(SOAPBodyElement body, SOAPFactory f) throws SOAPException;
66
67   protected class ArrayType {
68
69     public ArrayType() {
70       super();
71     }
72
73     private String type;
74
75     public String getType() {
76       return type;
77     }
78
79     public Name getType(SOAPBodyElement body, SOAPFactory spf) throws SOAPException {
80       int i = type.indexOf(':');
81       if (i == -1) {
82         return spf.createName(type);
83       } else {
84         String prefix = type.substring(0, i);
85         SOAPBody b = (SOAPBody) body.getParentElement();
86         SOAPEnvelope e = (SOAPEnvelope) b.getParentElement();
87         SOAPHeader h = e.getHeader();
88         String uri = null;
89         try {
90           uri = h.lookupNamespaceURI(prefix);
91         } catch (Exception ee) {
92           logger.error("While geting namespace URI 1 {}", ee.toString());
93         }
94         if (uri == null) {
95           try {
96             uri = e.lookupNamespaceURI(prefix);
97           } catch (Exception ee) {
98             logger.error("While geting namespace URI 2 {}", ee.toString());
99           }
100         }
101         if (uri == null) {
102           try {
103             uri = b.lookupNamespaceURI(prefix);
104           } catch (Exception ee) {
105             logger.error("While geting namespace URI {} ", ee.toString());
106           }
107         }
108         return spf.createName(type.substring(i + 1), prefix, uri);
109       }
110     }
111
112     public void setType(String type) {
113       this.type = type;
114     }
115   }
116
117   public static SOAPBodyElement getRequest(SOAPMessage msg) throws SOAPException {
118     SOAPBodyElement request = null;
119     Iterator<Node> i1 = msg.getSOAPBody().getChildElements();
120     while (i1.hasNext()) {
121       Node n = i1.next();
122       if (n.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
123         request = (SOAPBodyElement) n;
124       }
125     }
126     return request;
127   }
128
129   private static String getRequestName(SOAPMessage msg) throws SOAPException {
130     if (msg.getSOAPBody().hasFault()) {
131       return "Fault";
132     }
133     String name = "";
134     SOAPBodyElement element = getRequest(msg);
135     if (element != null) {
136       name = element.getNodeName();
137     }
138     if (name.startsWith("cwmp:")) {
139       name = name.substring(5);
140     } else if (name.startsWith("cwmp_x:")) {
141       name = name.substring(7);
142     } else if (name.indexOf(':') != -1) {
143       name = name.substring(name.indexOf(':') + 1, name.length());
144     }
145     return name;
146   }
147
148   public static TR069RPC parse(SOAPMessage soapMsg)
149       throws SOAPException, InstantiationException, IllegalAccessException, ClassNotFoundException {
150     String reqname = TR069RPC.getRequestName(soapMsg);
151
152     TR069RPC msg = null;
153     try {
154       msg = (TR069RPC) Class.forName("org.commscope.tr069adapter.acs.cpe.rpc." + reqname)
155           .newInstance();
156     } catch (Exception e) {
157       msg = (TR069RPC) Class.forName("org.commscope.tr069adapter.acs.cpe.rpc." + reqname)
158           .newInstance();
159     }
160     msg = msg.parseSoapMessage(soapMsg);
161     return msg;
162   }
163
164   @SuppressWarnings("unchecked")
165   private TR069RPC parseSoapMessage(SOAPMessage soapMsg) throws SOAPException {
166     SOAPEnvelope env = soapMsg.getSOAPPart().getEnvelope();
167
168     Iterator<String> pfxs = env.getNamespacePrefixes();
169     while (pfxs.hasNext()) {
170       String pfx = pfxs.next();
171       String uri = env.getNamespaceURI(pfx);
172       if (uri.startsWith("urn:dslforum-org:cwmp-")) {
173         urnCWMP = uri;
174       }
175     }
176     SOAPFactory spf = SOAPFactory.newInstance();
177     SOAPBodyElement soaprequest = getRequest(soapMsg);
178     SOAPHeader hdr = soapMsg.getSOAPHeader();
179     id = "device_did_not_send_id"; // or make it null?...
180     if (hdr != null) {
181       try {
182         id = getHeaderElement(spf, hdr, "ID");
183       } catch (Exception e) {
184         logger.error("While parsing the soap message {}", e.toString());
185       }
186     }
187     name = getRequestName(soapMsg);
188     if (soaprequest != null) {
189       Fault fault = parseSOAPRequest(soaprequest, spf);
190       if (fault != null)
191         return fault;
192     }
193     return this;
194   }
195
196   private Fault parseSOAPRequest(SOAPBodyElement soaprequest, SOAPFactory spf)
197       throws SOAPException {
198     if (soaprequest != null) {
199       try {
200         parseBody(soaprequest, spf);
201       } catch (Exception e) {
202         SOAPElement se = getRequestChildElement(spf, soaprequest, FAULT_CODE);
203         String fc = (se != null) ? se.getValue() : "0";
204         SOAPElement se2 = getRequestChildElement(spf, soaprequest, FAULT_STRING);
205         String fs = (se2 != null) ? se2.getValue() : "0";
206
207         if (se != null || se2 != null) {
208           return new Fault(fc, fs, id);
209         }
210         throw e;
211       }
212     }
213     return null;
214   }
215
216   public void writeTo(OutputStream out) {
217     try {
218       SOAPFactory spf = SOAPFactory.newInstance();
219       MessageFactory factory = MessageFactory.newInstance();
220       SOAPMessage soapMsg = factory.createMessage();
221       SOAPPart part = soapMsg.getSOAPPart();
222
223       SOAPEnvelope envelope = part.getEnvelope();
224       SOAPHeader header = envelope.getHeader();
225       SOAPBody body = envelope.getBody();
226
227       String responseId = getId();
228
229       envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
230       envelope.addNamespaceDeclaration("cwmp", urnCWMP);
231       envelope.addNamespaceDeclaration("SOAP-ENC", HTTP_SCHEMA_ENCODING);
232       envelope.addNamespaceDeclaration("SOAP-ENV", ENVELOPE_NAMESPACE);
233       envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
234
235       SOAPElement element = header.addChildElement(spf.createName("ID", "cwmp", urnCWMP));
236       element.addAttribute(spf.createName("mustUnderstand", "SOAP-ENV", ENVELOPE_NAMESPACE),
237           responseId);
238       element.addTextNode("1");
239
240       body.setEncodingStyle(HTTP_SCHEMA_ENCODING);
241       SOAPBodyElement bd = body.addBodyElement(spf.createName(name, CWMP, urnCWMP));
242
243       if (name == null || name.equals("")) {
244         name = this.getClass().getSimpleName();
245       }
246       createBody(bd, spf, id);
247
248       soapMsg.writeTo(out);
249     } catch (SOAPException ex) {
250       logger.error("Exception occurred while constructing SOAP message: {}", ex.getMessage());
251     } catch (IOException e) {
252       logger.error("Exception occurred while constructing SOAP message: {}", e.getMessage());
253     }
254   }
255
256   protected void createBody(SOAPBodyElement body, SOAPFactory spf, String key)
257       throws SOAPException {
258     logger.debug("Key element is: {}", key);
259     createBody(body, spf);
260   }
261
262   protected SOAPElement getRequestChildElement(SOAPFactory f, SOAPElement req, String name) {
263     @SuppressWarnings("unchecked")
264     Iterator<Object> i = req.getChildElements();
265     f.getClass();
266     while (i.hasNext()) {
267       Object o = i.next();
268       try {
269         Node nn = (Node) o;
270         String n = nn.getLocalName();
271         if (n != null && n.equals(name)) {
272           return (SOAPElement) o;
273         }
274       } catch (Exception e) {
275         logger.debug("Exception: {}, {}", e.getMessage(), e.getClass().getName());
276       }
277     }
278     return null;
279   }
280
281   protected SOAPElement getRequestChildElement2(SOAPFactory f, SOAPElement req, String name)
282       throws SOAPException {
283     return (SOAPElement) req.getChildElements(f.createName(name, CWMP, urnCWMP)).next();
284   }
285
286   protected String getRequestElement(SOAPFactory f, SOAPElement req, String name) {
287     return getRequestChildElement(f, req, name).getValue();
288   }
289
290   protected String getRequestElement(SOAPFactory f, SOAPElement req, String name, String def) {
291     String v = getRequestChildElement(f, req, name).getValue();
292     return (v != null) ? v : def;
293   }
294
295   protected SOAPElement getRequestChildElement(SOAPElement req, Name name) {
296     return (SOAPElement) req.getChildElements(name).next();
297   }
298
299   protected String getRequestElement(SOAPElement req, Name name) {
300     return getRequestChildElement(req, name).getValue();
301   }
302
303   protected String getHeaderElement(SOAPFactory f, SOAPHeader hdr, String name)
304       throws SOAPException {
305     return ((SOAPHeaderElement) hdr.getChildElements(f.createName(name, CWMP, urnCWMP)).next())
306         .getValue();
307   }
308
309   protected HashMap<String, String> parseParamList(SOAPElement body, SOAPFactory spf)
310       throws SOAPException {
311     return parseParamList(body, spf, "ParameterValueStruct", "Value");
312   }
313
314   protected HashMap<String, String> parseParamList(SOAPElement body, SOAPFactory spf, String sn,
315       String vn) throws SOAPException {
316     Iterator<SOAPElement> pi =
317         getRequestChildElement(spf, body, "ParameterList").getChildElements(spf.createName(sn));
318     Name nameKey = spf.createName("Name");
319     Name nameValue = spf.createName(vn);
320     HashMap<String, String> pl = new HashMap<>();
321     while (pi.hasNext()) {
322       SOAPElement param = pi.next();
323       String key = getRequestElement(param, nameKey);
324       String value = getRequestElement(param, nameValue);
325       if (value == null) {
326         value = "";
327       }
328       pl.put(key, value);
329     }
330     return pl;
331   }
332
333   protected int getArrayCount(SOAPFactory spf, SOAPElement e) throws SOAPException {
334     return getArrayCount(spf, e, null);
335   }
336
337   protected int getArrayCount(SOAPFactory spf, SOAPElement e, ArrayType type) throws SOAPException {
338     Name nameArray = spf.createName("arrayType", "soap-enc", HTTP_SCHEMA_ENCODING);
339     String attr = e.getAttributeValue(nameArray);
340     if (attr == null) {
341       return 0;
342     }
343     attr = attr.replace(" ", "");
344     int i = attr.indexOf('[');
345     String c = attr.substring(i + 1, attr.length() - 1);
346     if (type != null) {
347       type.setType(attr.substring(0, i));
348     }
349     return Integer.parseInt(c);
350   }
351
352   public boolean isFault() {
353     return name.equals("Fault");
354   }
355
356   protected String b2s(boolean b) {
357     return (b) ? "1" : "0";
358   }
359
360   protected String name;
361
362   public String getName() {
363     return name;
364   }
365
366   protected String id;
367
368   public String getId() {
369     if (id == null) {
370       id = "" + mrandom.nextInt(99999);
371     }
372     return id;
373   }
374
375   protected void println(StringBuilder b, String n, String v) {
376     b.append(n);
377     b.append(": ");
378     b.append(v);
379     b.append("\n");
380   }
381
382   protected void println(StringBuilder b, String n, String n2, String v) {
383     b.append(n);
384     println(b, n2, v);
385   }
386
387   public String getCWMPVersion() {
388     return urnCWMP;
389   }
390
391   public void setCWMPVersion(String cwmpVersion) {
392     urnCWMP = cwmpVersion;
393   }
394
395   protected String urnCWMP = "urn:dslforum-org:cwmp-1-0";
396   protected static final String CWMP = "cwmp";
397   protected static final String PARAMETER_KEY = "ParameterKey";
398   protected static final String COMMAND_KEY = "CommandKey";
399   protected static final String XSI_TYPE = "xsi:type";
400   protected static final String XSD_STRING = "xsd:string";
401   protected static final String XSD_UNSIGNEDINT = "xsd:unsignedInt";
402   protected static final String XSD_INT = "xsd:int";
403   protected static final String XSD_BOOLEAN = "xsd:boolean";
404   protected static final String XSD_DATETIME = "xsd:dateTime";
405   protected static final String XSD_BASE64 = "xsd:base64";
406   protected static final String SOAP_ARRAY_TYPE = "SOAP-ENC:arrayType";
407   public static final String FAULT_CODE = "FaultCode";
408   public static final String FAULT_STRING = "FaultString";
409   public static final String TYPE_OBJECT = "object";
410   public static final String TYPE_STRING = "string";
411   public static final String TYPE_BOOLEAN = "boolean";
412   public static final String TYPE_DATETIME = "dateTime";
413   public static final String TYPE_UNSIGNEDINT = "unsignedInt";
414   public static final String TYPE_INT = "int";
415   public static final String TYPE_BASE64 = "base64";
416
417   public String getXmlType(String type) {
418     if (type.equals(TYPE_BASE64)) {
419       return TR069RPC.XSD_BASE64;
420     } else if (type.equals(TYPE_BOOLEAN)) {
421       return TR069RPC.XSD_BOOLEAN;
422     } else if (type.equals(TYPE_DATETIME)) {
423       return TR069RPC.XSD_DATETIME;
424     } else if (type.equals(TYPE_INT)) {
425       return TR069RPC.XSD_INT;
426     } else if (type.equals(TYPE_OBJECT)) {
427       return "";
428     } else if (type.equals(TYPE_STRING)) {
429       return TR069RPC.XSD_STRING;
430     } else if (type.equals(TYPE_UNSIGNEDINT)) {
431       return TR069RPC.XSD_UNSIGNEDINT;
432     }
433     return type;
434   }
435 }