ab554dd45db6b6ed7f54cf22b8d18a4ffc7822ed
[ccsdk/sli.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - CCSDK
4  * ================================================================================
5  * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer;
22
23 import static javax.xml.transform.OutputKeys.INDENT;
24 import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.OBJECT_NODE;
25 import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.TEXT_NODE;
26 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision;
27 import java.io.IOException;
28 import java.io.StringReader;
29 import java.io.StringWriter;
30 import java.io.Writer;
31 import java.net.URI;
32 import java.net.URISyntaxException;
33 import java.util.Iterator;
34
35 import javax.xml.XMLConstants;
36 import javax.xml.parsers.DocumentBuilder;
37 import javax.xml.parsers.DocumentBuilderFactory;
38 import javax.xml.parsers.ParserConfigurationException;
39 import javax.xml.transform.Transformer;
40 import javax.xml.transform.TransformerException;
41 import javax.xml.transform.TransformerFactory;
42 import javax.xml.transform.dom.DOMSource;
43 import javax.xml.transform.stream.StreamResult;
44 import org.dom4j.Element;
45 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
46 import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace;
47 import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode;
48 import org.opendaylight.yangtools.yang.common.XMLNamespace;
49 import org.opendaylight.yangtools.yang.model.api.Module;
50 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
51 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
52 import org.w3c.dom.Document;
53 import org.xml.sax.InputSource;
54 import org.xml.sax.SAXException;
55
56 /**
57  * Utilities for data format serializer.
58  */
59 public final class DfSerializerUtil {
60
61     static final String JSON_WRITE_ERR = "Unable to write to JSON from " +
62             "properties.";
63
64     static final String NODE_TYPE_ERR = "The node type %s is not supported.";
65
66     static final String JSON_LIS_ERR = "The JSON serializer doesn't have " +
67             "JSON listener";
68
69     static final String XML_LIS_ERR = "The XML serializer doesn't have XML " +
70             "listener";
71
72     static final String PROP_NODE_ERR = "The property node doesn't have " +
73             "schema node bound to it.";
74
75     static final String DF_ERR = "Type mismatch for the node %s. The schema " +
76             "node does not match with the data format node type %s.";
77
78     static final String XML_PREFIX = "yangid";
79
80     private static final String YES = "yes";
81
82     private static final String INDENT_XMLNS = "{http://xml.apache" +
83             ".org/xslt}indent-amount";
84
85     private static final String XML_PARSE_ERR = "Unable to parse the xml to " +
86             "document : \n";
87
88     private static final String URI_ERR = "Unable to parse the URI";
89
90     /**
91      * Data format error message for unsupported types.
92      */
93     public static final String FORMAT_ERR = "Only JSON and XML formats are " +
94             "supported. %s is not supported";
95
96     /**
97      * UTF header message for XML data format message.
98      */
99     public static final String UTF_HEADER = "<?xml version=\"1.0\" " +
100             "encoding=\"UTF-8\"?>";
101
102     /**
103      * Error message when a JSON tree creation fails.
104      */
105     public static final String JSON_TREE_ERR = "Unable to form JSON tree " +
106             "object from the JSON body provided.";
107
108     /**
109      * Error message when a XML tree creation fails.
110      */
111     public static final String XML_TREE_ERR = "Unable to form XML tree object" +
112             " from the XML body provided.";
113
114     //No instantiation.
115     private DfSerializerUtil() {
116     }
117
118     /**
119      * Returns the writer which contains the pretty formatted XML string.
120      *
121      * @param input  input XML
122      * @param indent indentation level
123      * @return writer with XML
124      * @throws SvcLogicException when transformation of source fails
125      */
126     public static Writer getXmlWriter(String input, String indent)
127             throws SvcLogicException {
128         try {
129             TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
130             // Remediate XML external entity vulnerabilty - prohibit the use of all protocols by external entities:
131             factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
132             factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
133             Transformer transformer = factory.newTransformer();
134             transformer.setOutputProperty(INDENT, YES);
135             transformer.setOutputProperty(INDENT_XMLNS, indent);
136             StreamResult result = new StreamResult(new StringWriter());
137             DOMSource source = new DOMSource(parseXml(input));
138             transformer.transform(source, result);
139             return result.getWriter();
140         } catch (TransformerException e) {
141             throw new SvcLogicException(XML_PARSE_ERR + input, e);
142         }
143     }
144
145     /**
146      * Parses the XML and converts it into dom document which can be used for
147      * formatting the XML.
148      *
149      * @param in input XML
150      * @return dom document of XML
151      * @throws SvcLogicException when document building fails
152      */
153     private static Document parseXml(String in) throws SvcLogicException {
154         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
155
156         try {
157             // To remediate XML external entity vulnerability, completely disable external entities declarations:
158             dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
159              dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
160             DocumentBuilder db = dbf.newDocumentBuilder();
161             InputSource is = new InputSource(new StringReader(in));
162             return db.parse(is);
163         } catch (SAXException | IOException | ParserConfigurationException e) {
164             throw new SvcLogicException(XML_PARSE_ERR + in, e);
165         }
166     }
167
168     /**
169      * Returns the resolved namespace object from the input received from the
170      * abstract data format.
171      *
172      * @param mName  module name
173      * @param mUri   module URI
174      * @param ctx    schema context
175      * @param parent parent properties node
176      * @return namespace
177      * @throws SvcLogicException when resolving namespace fails
178      */
179     static Namespace getResolvedNamespace(String mName, String mUri,
180                                           SchemaContext ctx,
181                                           PropertiesNode parent)
182             throws SvcLogicException {
183         if (mName == null && mUri == null) {
184             Namespace parentNs = parent.namespace();
185             return new Namespace(parentNs.moduleName(), parentNs.moduleNs(),
186                                  parentNs.revision());
187         }
188
189         Iterator<? extends Module> it;
190         Module mod;
191         if (mName != null) {
192             it = ctx.findModules(mName).iterator();
193         } else {
194
195             it = ctx.findModules(XMLNamespace.of(mUri)).iterator();
196         }
197
198         if (!it.hasNext()) {
199             return null;
200         }
201         mod = it.next();
202
203         return new Namespace(mod.getName(), mod.getQNameModule().getNamespace(),
204                              getRevision(mod.getRevision()));
205     }
206
207     /**
208      * Returns the node type of a XML element.
209      *
210      * @param element XML element
211      * @return node type of the XML element
212      */
213     static XmlNodeType getXmlNodeType(Element element) {
214         Element newElement = element.createCopy();
215         newElement.remove(element.getNamespace());
216         return newElement.hasContent() && newElement.isTextOnly() ?
217                 TEXT_NODE : OBJECT_NODE;
218     }
219
220     /**
221      * Resolves the super type to the base type from type definition.
222      *
223      * @param type super type
224      * @return base type definition
225      */
226     static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
227         TypeDefinition superType = type;
228         while (superType.getBaseType() != null) {
229             superType = superType.getBaseType();
230         }
231         return superType;
232     }
233 }