2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the terms of the Eclipse
5 * Public License v1.0 which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.datastore.util;
10 import java.io.ByteArrayInputStream;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.StringWriter;
15 import java.text.ParseException;
16 import java.text.SimpleDateFormat;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.List;
24 import javax.xml.parsers.DocumentBuilder;
25 import javax.xml.parsers.DocumentBuilderFactory;
26 import javax.xml.parsers.ParserConfigurationException;
27 import javax.xml.transform.OutputKeys;
28 import javax.xml.transform.Transformer;
29 import javax.xml.transform.TransformerException;
30 import javax.xml.transform.TransformerFactory;
31 import javax.xml.transform.TransformerFactoryConfigurationError;
32 import javax.xml.transform.dom.DOMSource;
33 import javax.xml.transform.stream.StreamResult;
35 import org.custommonkey.xmlunit.Diff;
36 import org.custommonkey.xmlunit.XMLUnit;
37 import org.junit.Test;
38 import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage;
39 import org.opendaylight.yangtools.yang.common.QName;
40 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
46 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
47 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
48 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
49 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
50 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
51 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
52 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
53 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
54 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
55 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
56 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
57 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
58 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
59 import org.opendaylight.yangtools.yang.model.api.Module;
60 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
61 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64 import org.w3c.dom.Document;
65 import org.w3c.dom.Element;
66 import org.xml.sax.SAXException;
68 import com.google.common.base.Preconditions;
69 import com.google.common.collect.Lists;
70 import com.google.common.collect.Maps;
71 import com.google.common.collect.Sets;
75 * Two of the testcases in the yangtools/yang-data-impl are leveraged (with modification) to
76 * create the serialization of NormalizedNode using the ProtocolBuffer
83 public class NormalizedNodeXmlConverterTest {
84 private static final Logger logger = LoggerFactory
85 .getLogger(NormalizedNodeXmlConverterTest.class);
86 public static final String NAMESPACE =
87 "urn:opendaylight:params:xml:ns:yang:controller:test";
88 private static Date revision;
89 private ContainerNode expectedNode;
90 private ContainerSchemaNode containerNode;
91 private String xmlPath;
95 revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13");
96 } catch (ParseException e) {
97 throw new RuntimeException(e);
101 public static DataSchemaNode getSchemaNode(final SchemaContext context,
102 final String moduleName, final String childNodeName) {
103 for (Module module : context.getModules()) {
104 if (module.getName().equals(moduleName)) {
105 DataSchemaNode found =
106 findChildNode(module.getChildNodes(), childNodeName);
107 Preconditions.checkState(found != null, "Unable to find %s",
112 throw new IllegalStateException("Unable to find child node "
116 static DataSchemaNode findChildNode(final Set<DataSchemaNode> children, final String name) {
117 List<DataNodeContainer> containers = Lists.newArrayList();
119 for (DataSchemaNode dataSchemaNode : children) {
120 if (dataSchemaNode.getQName().getLocalName().equals(name)) {
121 return dataSchemaNode;
123 if (dataSchemaNode instanceof DataNodeContainer) {
124 containers.add((DataNodeContainer) dataSchemaNode);
125 } else if (dataSchemaNode instanceof ChoiceNode) {
126 containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
130 for (DataNodeContainer container : containers) {
131 DataSchemaNode retVal = findChildNode(container.getChildNodes(), name);
132 if (retVal != null) {
140 private static InstanceIdentifier.NodeIdentifier getNodeIdentifier(
141 final String localName) {
142 return new InstanceIdentifier.NodeIdentifier(QName.create(
143 URI.create(NAMESPACE), revision, localName));
146 public static InstanceIdentifier.AugmentationIdentifier getAugmentIdentifier(
147 final String... childNames) {
148 Set<QName> qn = Sets.newHashSet();
150 for (String childName : childNames) {
151 qn.add(getNodeIdentifier(childName).getNodeType());
154 return new InstanceIdentifier.AugmentationIdentifier(qn);
158 private static ContainerNode augmentChoiceExpectedNode() {
160 DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> b =
161 Builders.containerBuilder();
162 b.withNodeIdentifier(getNodeIdentifier("container"));
166 .withNodeIdentifier(getNodeIdentifier("ch2"))
168 Builders.leafBuilder()
169 .withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2")
174 .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
179 getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
180 .withValue("2").build()).build()).build());
184 .withNodeIdentifier(getNodeIdentifier("ch3"))
186 Builders.leafBuilder()
187 .withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3")
191 .augmentationBuilder()
192 .withNodeIdentifier(getAugmentIdentifier("augLeaf"))
194 Builders.leafBuilder()
195 .withNodeIdentifier(getNodeIdentifier("augLeaf"))
196 .withValue("augment").build()).build());
199 .augmentationBuilder()
200 .withNodeIdentifier(getAugmentIdentifier("ch"))
204 .withNodeIdentifier(getNodeIdentifier("ch"))
206 Builders.leafBuilder()
207 .withNodeIdentifier(getNodeIdentifier("c1Leaf"))
208 .withValue("1").build())
211 .augmentationBuilder()
213 getAugmentIdentifier("c1Leaf_AnotherAugment",
219 getNodeIdentifier("c1Leaf_AnotherAugment"))
220 .withValue("1").build())
225 getNodeIdentifier("deepChoice"))
230 getNodeIdentifier("deepLeafc1"))
231 .withValue("1").build()).build())
232 .build()).build()).build());
239 public void init(final String yangPath, final String xmlPath, final ContainerNode expectedNode)
241 SchemaContext schema = parseTestSchema(yangPath);
242 this.xmlPath = xmlPath;
244 (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
245 this.expectedNode = expectedNode;
248 SchemaContext parseTestSchema(final String yangPath) throws Exception {
250 YangParserImpl yangParserImpl = new YangParserImpl();
252 NormalizedNodeXmlConverterTest.class.getResourceAsStream(yangPath);
253 ArrayList<InputStream> al = new ArrayList<InputStream>();
255 Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(al);
256 return yangParserImpl.resolveSchemaContext(modules);
262 public void testConversionWithAugmentChoice() throws Exception {
263 init("/augment_choice.yang", "/augment_choice.xml",
264 augmentChoiceExpectedNode());
265 Document doc = loadDocument(xmlPath);
267 ContainerNode built =
268 DomToNormalizedNodeParserFactory
269 .getInstance(DomUtils.defaultValueCodecProvider())
270 .getContainerNodeParser()
271 .parse(Collections.singletonList(doc.getDocumentElement()),
274 if (expectedNode != null) {
275 junit.framework.Assert.assertEquals(expectedNode, built);
278 logger.info("{}", built);
280 Iterable<Element> els =
281 DomFromNormalizedNodeSerializerFactory
282 .getInstance(XmlDocumentUtils.getDocument(),
283 DomUtils.defaultValueCodecProvider())
284 .getContainerNodeSerializer().serialize(containerNode, built);
286 Element el = els.iterator().next();
288 XMLUnit.setIgnoreWhitespace(true);
289 XMLUnit.setIgnoreComments(true);
291 System.out.println(toString(doc.getDocumentElement()));
292 System.out.println(toString(el));
295 XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
296 XMLUnit.buildTestDocument(toString(el))).similar();
299 private static ContainerNode listLeafListWithAttributes() {
300 DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> b =
301 Builders.containerBuilder();
302 b.withNodeIdentifier(getNodeIdentifier("container"));
304 CollectionNodeBuilder<MapEntryNode, MapNode> listBuilder =
305 Builders.mapBuilder().withNodeIdentifier(getNodeIdentifier("list"));
307 Map<QName, Object> predicates = Maps.newHashMap();
308 predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L);
310 DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> list1Builder =
311 Builders.mapEntryBuilder().withNodeIdentifier(
312 new InstanceIdentifier.NodeIdentifierWithPredicates(
313 getNodeIdentifier("list").getNodeType(), predicates));
314 NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> uint32InListBuilder =
315 Builders.leafBuilder().withNodeIdentifier(
316 getNodeIdentifier("uint32InList"));
318 list1Builder.withChild(uint32InListBuilder.withValue(3L).build());
320 listBuilder.withChild(list1Builder.build());
321 b.withChild(listBuilder.build());
323 NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> booleanBuilder =
324 Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean"));
325 booleanBuilder.withValue(false);
326 b.withChild(booleanBuilder.build());
328 ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListBuilder =
329 Builders.leafSetBuilder().withNodeIdentifier(
330 getNodeIdentifier("leafList"));
332 NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, Object, LeafSetEntryNode<Object>> leafList1Builder =
333 Builders.leafSetEntryBuilder().withNodeIdentifier(
334 new InstanceIdentifier.NodeWithValue(getNodeIdentifier("leafList")
335 .getNodeType(), "a"));
337 leafList1Builder.withValue("a");
339 leafListBuilder.withChild(leafList1Builder.build());
340 b.withChild(leafListBuilder.build());
347 public void testConversionWithAttributes() throws Exception {
348 init("/test.yang", "/simple_xml_with_attributes.xml",
349 listLeafListWithAttributes());
350 Document doc = loadDocument(xmlPath);
352 ContainerNode built =
353 DomToNormalizedNodeParserFactory
354 .getInstance(DomUtils.defaultValueCodecProvider())
355 .getContainerNodeParser()
356 .parse(Collections.singletonList(doc.getDocumentElement()),
359 if (expectedNode != null) {
360 junit.framework.Assert.assertEquals(expectedNode, built);
363 logger.info("{}", built);
365 Iterable<Element> els =
366 DomFromNormalizedNodeSerializerFactory
367 .getInstance(XmlDocumentUtils.getDocument(),
368 DomUtils.defaultValueCodecProvider())
369 .getContainerNodeSerializer().serialize(containerNode, built);
371 Element el = els.iterator().next();
373 XMLUnit.setIgnoreWhitespace(true);
374 XMLUnit.setIgnoreComments(true);
376 System.out.println(toString(doc.getDocumentElement()));
377 System.out.println(toString(el));
380 XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
381 XMLUnit.buildTestDocument(toString(el))).similar();
385 private Document loadDocument(final String xmlPath) throws Exception {
386 InputStream resourceAsStream =
387 NormalizedNodeXmlConverterTest.class.getResourceAsStream(xmlPath);
389 Document currentConfigElement = readXmlToDocument(resourceAsStream);
390 Preconditions.checkNotNull(currentConfigElement);
391 return currentConfigElement;
394 private static final DocumentBuilderFactory BUILDERFACTORY;
397 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
398 factory.setNamespaceAware(true);
399 factory.setCoalescing(true);
400 factory.setIgnoringElementContentWhitespace(true);
401 factory.setIgnoringComments(true);
402 BUILDERFACTORY = factory;
405 private Document readXmlToDocument(final InputStream xmlContent)
406 throws IOException, SAXException {
407 DocumentBuilder dBuilder;
409 dBuilder = BUILDERFACTORY.newDocumentBuilder();
410 } catch (ParserConfigurationException e) {
411 throw new RuntimeException("Failed to parse XML document", e);
413 Document doc = dBuilder.parse(xmlContent);
415 doc.getDocumentElement().normalize();
419 public static String toString(final Element xml) {
421 Transformer transformer =
422 TransformerFactory.newInstance().newTransformer();
423 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
425 StreamResult result = new StreamResult(new StringWriter());
426 DOMSource source = new DOMSource(xml);
427 transformer.transform(source, result);
429 return result.getWriter().toString();
430 } catch (IllegalArgumentException | TransformerFactoryConfigurationError
431 | TransformerException e) {
432 throw new RuntimeException("Unable to serialize xml element " + xml, e);
437 public void testConversionToNormalizedXml() throws Exception {
438 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
439 EncoderDecoderUtil.encode(parseTestSchema("/augment_choice.yang"),
440 augmentChoiceExpectedNode());
441 Document expectedDoc = loadDocument("/augment_choice.xml");
442 Document convertedDoc =
443 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
444 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
445 System.out.println(toString(convertedDoc.getDocumentElement()));
446 XMLUnit.setIgnoreWhitespace(true);
447 XMLUnit.setIgnoreComments(true);
448 new Diff(XMLUnit.buildControlDocument(toString(expectedDoc
449 .getDocumentElement())),
450 XMLUnit.buildTestDocument(toString(convertedDoc
451 .getDocumentElement()))).similar();
452 System.out.println(toString(expectedDoc.getDocumentElement()));
458 public void testConversionFromXmlToNormalizedNode() throws Exception {
459 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
460 EncoderDecoderUtil.encode(parseTestSchema("/test.yang"),
461 listLeafListWithAttributes());
462 Document expectedDoc = loadDocument("/simple_xml_with_attributes.xml");
463 Document convertedDoc =
464 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
465 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
466 System.out.println(toString(convertedDoc.getDocumentElement()));
467 XMLUnit.setIgnoreWhitespace(true);
468 XMLUnit.setIgnoreComments(true);
469 new Diff(XMLUnit.buildControlDocument(toString(expectedDoc
470 .getDocumentElement())),
471 XMLUnit.buildTestDocument(toString(convertedDoc
472 .getDocumentElement()))).similar();
473 System.out.println(toString(expectedDoc.getDocumentElement()));
475 // now we will try to convert xml back to normalize node.
477 (ContainerNode) EncoderDecoderUtil.decode(
478 parseTestSchema("/test.yang"), nnXml);
479 junit.framework.Assert.assertEquals(listLeafListWithAttributes(), cn);
484 public void testInMemoryTestModelProtoBuffEncoding() throws Exception {
486 SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
487 EncoderDecoderUtil.encode(parseTestSchema("/odl-datastore-test.yang"),
488 TestModel.createFamily());
490 Document convertedDoc =
491 EncoderDecoderUtil.factory.newDocumentBuilder().parse(
492 new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
493 System.out.println(toString(convertedDoc.getDocumentElement()));
495 // now we will try to convert xml back to normalize node.
497 (ContainerNode) EncoderDecoderUtil.decode(
498 parseTestSchema("/odl-datastore-test.yang"), nnXml);
499 junit.framework.Assert.assertEquals(TestModel.createFamily(), cn);