0134a5a47892181765dcfb5aae4397514556b707
[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.model.api.Module;
49 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
50 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
51 import org.w3c.dom.Document;
52 import org.xml.sax.InputSource;
53 import org.xml.sax.SAXException;
54
55 /**
56  * Utilities for data format serializer.
57  */
58 public final class DfSerializerUtil {
59
60     static final String JSON_WRITE_ERR = "Unable to write to JSON from " +
61             "properties.";
62
63     static final String NODE_TYPE_ERR = "The node type %s is not supported.";
64
65     static final String JSON_LIS_ERR = "The JSON serializer doesn't have " +
66             "JSON listener";
67
68     static final String XML_LIS_ERR = "The XML serializer doesn't have XML " +
69             "listener";
70
71     static final String PROP_NODE_ERR = "The property node doesn't have " +
72             "schema node bound to it.";
73
74     static final String DF_ERR = "Type mismatch for the node %s. The schema " +
75             "node does not match with the data format node type %s.";
76
77     static final String XML_PREFIX = "yangid";
78
79     private static final String YES = "yes";
80
81     private static final String INDENT_XMLNS = "{http://xml.apache" +
82             ".org/xslt}indent-amount";
83
84     private static final String XML_PARSE_ERR = "Unable to parse the xml to " +
85             "document : \n";
86
87     private static final String URI_ERR = "Unable to parse the URI";
88
89     /**
90      * Data format error message for unsupported types.
91      */
92     public static final String FORMAT_ERR = "Only JSON and XML formats are " +
93             "supported. %s is not supported";
94
95     /**
96      * UTF header message for XML data format message.
97      */
98     public static final String UTF_HEADER = "<?xml version=\"1.0\" " +
99             "encoding=\"UTF-8\"?>";
100
101     /**
102      * Error message when a JSON tree creation fails.
103      */
104     public static final String JSON_TREE_ERR = "Unable to form JSON tree " +
105             "object from the JSON body provided.";
106
107     /**
108      * Error message when a XML tree creation fails.
109      */
110     public static final String XML_TREE_ERR = "Unable to form XML tree object" +
111             " from the XML body provided.";
112
113     //No instantiation.
114     private DfSerializerUtil() {
115     }
116
117     /**
118      * Returns the writer which contains the pretty formatted XML string.
119      *
120      * @param input  input XML
121      * @param indent indentation level
122      * @return writer with XML
123      * @throws SvcLogicException when transformation of source fails
124      */
125     public static Writer getXmlWriter(String input, String indent)
126             throws SvcLogicException {
127         try {
128             TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
129             // Remediate XML external entity vulnerabilty - prohibit the use of all protocols by external entities:
130             factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
131             factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
132             Transformer transformer = factory.newTransformer();
133             transformer.setOutputProperty(INDENT, YES);
134             transformer.setOutputProperty(INDENT_XMLNS, indent);
135             StreamResult result = new StreamResult(new StringWriter());
136             DOMSource source = new DOMSource(parseXml(input));
137             transformer.transform(source, result);
138             return result.getWriter();
139         } catch (TransformerException e) {
140             throw new SvcLogicException(XML_PARSE_ERR + input, e);
141         }
142     }
143
144     /**
145      * Parses the XML and converts it into dom document which can be used for
146      * formatting the XML.
147      *
148      * @param in input XML
149      * @return dom document of XML
150      * @throws SvcLogicException when document building fails
151      */
152     private static Document parseXml(String in) throws SvcLogicException {
153         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
154
155         try {
156             // To remediate XML external entity vulnerability, completely disable external entities declarations:
157             dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
158              dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
159             DocumentBuilder db = dbf.newDocumentBuilder();
160             InputSource is = new InputSource(new StringReader(in));
161             return db.parse(is);
162         } catch (SAXException | IOException | ParserConfigurationException e) {
163             throw new SvcLogicException(XML_PARSE_ERR + in, e);
164         }
165     }
166
167     /**
168      * Returns the resolved namespace object from the input received from the
169      * abstract data format.
170      *
171      * @param mName  module name
172      * @param mUri   module URI
173      * @param ctx    schema context
174      * @param parent parent properties node
175      * @return namespace
176      * @throws SvcLogicException when resolving namespace fails
177      */
178     static Namespace getResolvedNamespace(String mName, String mUri,
179                                           SchemaContext ctx,
180                                           PropertiesNode parent)
181             throws SvcLogicException {
182         if (mName == null && mUri == null) {
183             Namespace parentNs = parent.namespace();
184             return new Namespace(parentNs.moduleName(), parentNs.moduleNs(),
185                                  parentNs.revision());
186         }
187
188         Iterator<? extends Module> it;
189         Module mod;
190         if (mName != null) {
191             it = ctx.findModules(mName).iterator();
192         } else {
193             URI modUri = null;
194             try {
195                modUri = new URI(mUri);
196             } catch (URISyntaxException e) {
197                 throw new SvcLogicException(URI_ERR, e);
198             }
199             it = ctx.findModules(modUri).iterator();
200         }
201
202         if (!it.hasNext()) {
203             return null;
204         }
205         mod = it.next();
206
207         return new Namespace(mod.getName(), mod.getQNameModule().getNamespace(),
208                              getRevision(mod.getRevision()));
209     }
210
211     /**
212      * Returns the node type of a XML element.
213      *
214      * @param element XML element
215      * @return node type of the XML element
216      */
217     static XmlNodeType getXmlNodeType(Element element) {
218         Element newElement = element.createCopy();
219         newElement.remove(element.getNamespace());
220         return newElement.hasContent() && newElement.isTextOnly() ?
221                 TEXT_NODE : OBJECT_NODE;
222     }
223
224     /**
225      * Resolves the super type to the base type from type definition.
226      *
227      * @param type super type
228      * @return base type definition
229      */
230     static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
231         TypeDefinition superType = type;
232         while (superType.getBaseType() != null) {
233             superType = superType.getBaseType();
234         }
235         return superType;
236     }
237 }