/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.netconf.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.StringWriter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.junit.Ignore; import org.junit.Test; import org.openexi.proc.common.AlignmentType; import org.openexi.proc.common.GrammarOptions; import org.openexi.proc.grammars.GrammarCache; import org.openexi.sax.EXIReader; import org.openexi.sax.Transmogrifier; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.InputSource; /** * This test case tests nagasena library used for exi encode/decode. * * This library does not work correctly, since it is impossible to encode and then decode DOM xml. * Encoding DOM using sax Transformer produces invalid xml, that cannot be decoded (Problem seems to be the namespace handling). * */ @Ignore public class EXILibTest { public static final AlignmentType ALIGNMENT_TYPE = AlignmentType.preCompress; @Test public void testExiLibWithSaxTransformer() throws Exception { final byte[] encode = encodeEXI(getDom2()); final byte[] encodeWithTransformer = encodeEXITransformer(getDom2()); // System.err.println(Arrays.toString(encode)); // System.err.println(Arrays.toString(encodeWithTransformer)); // This works fine (encoded from string) decodeEXI(encode); // Error, encoded from Dom with Transformer cannot be decoded, Exception is thrown // // either: // 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. // // or: // java.lang.NullPointerException // // depends on GrammarOptions.addNS(go); option set decodeEXI(encodeWithTransformer); } private static final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); public static byte[] encodeEXITransformer(final Element xml) throws Exception { final Transmogrifier transmogrifier = new Transmogrifier(); transmogrifier.setAlignmentType(ALIGNMENT_TYPE); final ByteArrayOutputStream out = new ByteArrayOutputStream(); transmogrifier.setGrammarCache(getGrammarCache()); transmogrifier.setOutputStream(out); final Transformer transformer = saxTransformerFactory.newTransformer(); transformer.transform(new DOMSource(xml), new SAXResult(transmogrifier.getSAXTransmogrifier())); return out.toByteArray(); } public static byte[] encodeEXI(final Element xml) throws Exception { final Transmogrifier transmogrifier = new Transmogrifier(); transmogrifier.setAlignmentType(ALIGNMENT_TYPE); final ByteArrayOutputStream out = new ByteArrayOutputStream(); transmogrifier.setGrammarCache(getGrammarCache()); transmogrifier.setOutputStream(out); transmogrifier.encode(new InputSource(new ByteArrayInputStream(toString(xml, false).getBytes()))); out.flush(); return out.toByteArray(); } private static GrammarCache getGrammarCache() { short go = GrammarOptions.DEFAULT_OPTIONS; // This option on or off, nagasena still fails // go = GrammarOptions.addNS(go); return new GrammarCache(null, go); } public static Document decodeEXI(final byte[] input) throws Exception { final GrammarCache grammarCache; final DOMResult domResult = new DOMResult(); try(ByteArrayInputStream in = new ByteArrayInputStream(input)) { final EXIReader reader = new EXIReader(); reader.setAlignmentType(ALIGNMENT_TYPE); grammarCache = getGrammarCache(); reader.setGrammarCache(grammarCache); final SAXTransformerFactory transformerFactory = (SAXTransformerFactory) TransformerFactory.newInstance(); final TransformerHandler handler = transformerFactory.newTransformerHandler(); handler.setResult(domResult); reader.setContentHandler(handler); reader.parse(new InputSource(in)); } return (Document) domResult.getNode(); } public static Element getDom() { final Element dom; final Document d = newDocument(); dom = d.createElement("rpc"); dom.setAttribute("xmlns", "a.b.c"); dom.setAttribute("message-id", "id"); dom.appendChild(d.createElement("inner")); return dom; } public static Element getDom2() { final Element dom; final Document d = newDocument(); dom = d.createElementNS("a.b.c", "rpc"); dom.setAttribute("message-id", "id"); dom.appendChild(d.createElement("inner")); return dom; } private static final DocumentBuilderFactory BUILDERFACTORY; static { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); factory.setCoalescing(true); factory.setIgnoringElementContentWhitespace(true); factory.setIgnoringComments(true); BUILDERFACTORY = factory; } private static Document newDocument() { try { final DocumentBuilder builder = BUILDERFACTORY.newDocumentBuilder(); return builder.newDocument(); } catch (final ParserConfigurationException e) { throw new RuntimeException("Failed to create document", e); } } private static String toString(final Element xml, final boolean addXmlDeclaration) { try { final Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, addXmlDeclaration ? "no" : "yes"); final StreamResult result = new StreamResult(new StringWriter()); final DOMSource source = new DOMSource(xml); transformer.transform(source, result); return result.getWriter().toString(); } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) { throw new RuntimeException("Unable to serialize xml element " + xml, e); } } }