BUG-472 Initial EXI encoder/decoder implementation in Netconf
[controller.git] / opendaylight / netconf / netconf-util / src / test / java / org / opendaylight / controller / netconf / util / EXILibTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.netconf.util;
9
10 import java.io.ByteArrayInputStream;
11 import java.io.ByteArrayOutputStream;
12 import java.io.StringWriter;
13
14 import javax.xml.parsers.DocumentBuilder;
15 import javax.xml.parsers.DocumentBuilderFactory;
16 import javax.xml.parsers.ParserConfigurationException;
17 import javax.xml.transform.OutputKeys;
18 import javax.xml.transform.Transformer;
19 import javax.xml.transform.TransformerException;
20 import javax.xml.transform.TransformerFactory;
21 import javax.xml.transform.TransformerFactoryConfigurationError;
22 import javax.xml.transform.dom.DOMResult;
23 import javax.xml.transform.dom.DOMSource;
24 import javax.xml.transform.sax.SAXResult;
25 import javax.xml.transform.sax.SAXTransformerFactory;
26 import javax.xml.transform.sax.TransformerHandler;
27 import javax.xml.transform.stream.StreamResult;
28
29 import org.junit.Ignore;
30 import org.junit.Test;
31 import org.openexi.proc.common.AlignmentType;
32 import org.openexi.proc.common.GrammarOptions;
33 import org.openexi.proc.grammars.GrammarCache;
34 import org.openexi.sax.EXIReader;
35 import org.openexi.sax.Transmogrifier;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.xml.sax.InputSource;
39
40 /**
41  * This test case tests nagasena library used for exi encode/decode.
42  *
43  * This library does not work correctly, since it is impossible to encode and then decode DOM xml.
44  * Encoding DOM using sax Transformer produces invalid xml, that cannot be decoded (Problem seems to be the namespace handling).
45  *
46  */
47 @Ignore
48 public class EXILibTest {
49
50     public static final AlignmentType ALIGNMENT_TYPE = AlignmentType.preCompress;
51
52     @Test
53     public void testExiLibWithSaxTransformer() throws Exception {
54         final byte[] encode = encodeEXI(getDom2());
55         final byte[] encodeWithTransformer = encodeEXITransformer(getDom2());
56
57         // System.err.println(Arrays.toString(encode));
58         // System.err.println(Arrays.toString(encodeWithTransformer));
59
60         // This works fine (encoded from string)
61         decodeEXI(encode);
62         // Error, encoded from Dom with Transformer cannot be decoded, Exception is thrown
63         //
64         // either:
65         // org.w3c.dom.DOMException: NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
66         //
67         // or:
68         // java.lang.NullPointerException
69         //
70         // depends on GrammarOptions.addNS(go); option set
71         decodeEXI(encodeWithTransformer);
72     }
73
74     private static final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
75
76     public static byte[] encodeEXITransformer(final Element xml) throws Exception {
77         final Transmogrifier transmogrifier = new Transmogrifier();
78
79         transmogrifier.setAlignmentType(ALIGNMENT_TYPE);
80
81         final ByteArrayOutputStream out = new ByteArrayOutputStream();
82
83         transmogrifier.setGrammarCache(getGrammarCache());
84
85         transmogrifier.setOutputStream(out);
86
87         final Transformer transformer = saxTransformerFactory.newTransformer();
88         transformer.transform(new DOMSource(xml), new SAXResult(transmogrifier.getSAXTransmogrifier()));
89
90         return out.toByteArray();
91     }
92
93     public static byte[] encodeEXI(final Element xml) throws Exception {
94         final Transmogrifier transmogrifier = new Transmogrifier();
95
96         transmogrifier.setAlignmentType(ALIGNMENT_TYPE);
97
98         final ByteArrayOutputStream out = new ByteArrayOutputStream();
99
100         transmogrifier.setGrammarCache(getGrammarCache());
101
102         transmogrifier.setOutputStream(out);
103
104         transmogrifier.encode(new InputSource(new ByteArrayInputStream(toString(xml, false).getBytes())));
105
106         out.flush();
107
108         return out.toByteArray();
109     }
110
111     private static GrammarCache getGrammarCache() {
112         short go = GrammarOptions.DEFAULT_OPTIONS;
113
114         // This option on or off, nagasena still fails
115 //        go = GrammarOptions.addNS(go);
116
117         return new GrammarCache(null, go);
118     }
119
120     public static Document decodeEXI(final byte[] input) throws Exception {
121
122         final GrammarCache grammarCache;
123         final DOMResult domResult = new DOMResult();
124
125         try(ByteArrayInputStream in = new ByteArrayInputStream(input)) {
126
127             final EXIReader reader = new EXIReader();
128
129             reader.setAlignmentType(ALIGNMENT_TYPE);
130             grammarCache = getGrammarCache();
131
132             reader.setGrammarCache(grammarCache);
133
134             final SAXTransformerFactory transformerFactory
135                     = (SAXTransformerFactory) TransformerFactory.newInstance();
136             final TransformerHandler handler = transformerFactory.newTransformerHandler();
137             handler.setResult(domResult);
138
139             reader.setContentHandler(handler);
140
141             reader.parse(new InputSource(in));
142         }
143
144         return (Document) domResult.getNode();
145     }
146
147     public static Element getDom() {
148         final Element dom;
149
150         final Document d = newDocument();
151
152         dom = d.createElement("rpc");
153         dom.setAttribute("xmlns", "a.b.c");
154         dom.setAttribute("message-id", "id");
155         dom.appendChild(d.createElement("inner"));
156
157         return dom;
158     }
159
160     public static Element getDom2() {
161         final Element dom;
162
163         final Document d = newDocument();
164
165         dom = d.createElementNS("a.b.c", "rpc");
166         dom.setAttribute("message-id", "id");
167         dom.appendChild(d.createElement("inner"));
168
169         return dom;
170     }
171
172     private static final DocumentBuilderFactory BUILDERFACTORY;
173
174     static {
175         final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
176         factory.setNamespaceAware(true);
177         factory.setCoalescing(true);
178         factory.setIgnoringElementContentWhitespace(true);
179         factory.setIgnoringComments(true);
180         BUILDERFACTORY = factory;
181     }
182
183     private static Document newDocument() {
184         try {
185             final DocumentBuilder builder = BUILDERFACTORY.newDocumentBuilder();
186             return builder.newDocument();
187         } catch (final ParserConfigurationException e) {
188             throw new RuntimeException("Failed to create document", e);
189         }
190     }
191
192     private static String toString(final Element xml, final boolean addXmlDeclaration) {
193         try {
194             final Transformer transformer = TransformerFactory.newInstance().newTransformer();
195             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
196             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, addXmlDeclaration ? "no" : "yes");
197
198             final StreamResult result = new StreamResult(new StringWriter());
199             final DOMSource source = new DOMSource(xml);
200             transformer.transform(source, result);
201
202             return result.getWriter().toString();
203         } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
204             throw new RuntimeException("Unable to serialize xml element " + xml, e);
205         }
206     }
207 }