From: Peter Kajsa Date: Mon, 16 Nov 2015 09:31:59 +0000 (+0100) Subject: Bug 3874: Support of yang modeled AnyXML - XML deserialization X-Git-Tag: release/beryllium~33 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=yangtools.git;a=commitdiff_plain;h=ea32c2c6fac2ebe9d0e30c9c4e5279c5ef0d2314 Bug 3874: Support of yang modeled AnyXML - XML deserialization - added support of yang modeled anyXml deserialization from XML - basic unit tests - added anyxml-schema-location extension support and removed hardcoded extension name from AnyxmlStatementImpl Change-Id: I2add4bd5613417514d84b52be786074e2cc75f4f Signed-off-by: Peter Kajsa Signed-off-by: Robert Varga --- diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/ToNormalizedNodeParserFactory.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/ToNormalizedNodeParserFactory.java index f34ca9bc13..966a79f2eb 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/ToNormalizedNodeParserFactory.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/ToNormalizedNodeParserFactory.java @@ -19,6 +19,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; +import org.opendaylight.yangtools.yang.data.api.schema.YangModeledAnyXmlNode; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; @@ -26,6 +27,7 @@ import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; /** * Factory for different normalized node parsers. @@ -44,6 +46,7 @@ public interface ToNormalizedNodeParserFactory { ToNormalizedNodeParser getMapNodeParser(); ToNormalizedNodeParser getUnkeyedListNodeParser(); ToNormalizedNodeParser getUnkeyedListEntryNodeParser(); + ToNormalizedNodeParser getYangModeledAnyXmlNodeParser(); ToNormalizedNodeParser getAnyXmlNodeParser(); ToNormalizedNodeParser getOrderedListNodeParser(); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/NodeParserDispatcher.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/NodeParserDispatcher.java index 1b250a9256..d38b39868a 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/NodeParserDispatcher.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/NodeParserDispatcher.java @@ -18,6 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; /** * @@ -63,6 +64,8 @@ public interface NodeParserDispatcher { return factory.getChoiceNodeParser().parse(childNodes, (ChoiceSchemaNode) schema); } else if (schema instanceof AugmentationSchema) { return factory.getAugmentationNodeParser().parse(childNodes, (AugmentationSchema) schema); + } else if (schema instanceof YangModeledAnyXmlSchemaNode) { + return factory.getYangModeledAnyXmlNodeParser().parse(childNodes,(YangModeledAnyXmlSchemaNode)schema); } else if (schema instanceof AnyXmlSchemaNode) { return factory.getAnyXmlNodeParser().parse(childNodes,(AnyXmlSchemaNode)schema); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/YangModeledAnyXmlNodeBaseParser.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/YangModeledAnyXmlNodeBaseParser.java new file mode 100644 index 0000000000..fe268544df --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/YangModeledAnyXmlNodeBaseParser.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.data.impl.schema.transform.base.parser; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import java.util.Collection; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.YangModeledAnyXmlNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser; +import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; + +/** + * Abstract(base) parser for yang modeled anyXml nodes, parses elements of type E. + * + * @param + * type of elements to be parsed + */ +public abstract class YangModeledAnyXmlNodeBaseParser implements + ToNormalizedNodeParser { + + @Override + public final YangModeledAnyXmlNode parse(Iterable elements, YangModeledAnyXmlSchemaNode schema) { + final int size = Iterables.size(elements); + Preconditions.checkArgument(size == 1, "Elements mapped to yang modeled any-xml node illegal count: %s", size); + + final E e = elements.iterator().next(); + final Collection> value = parseAnyXml(e, schema); + + final DataContainerNodeAttrBuilder yangModeledAnyXmlBuilder = Builders + .yangModeledAnyXmlBuilder(schema); + + return yangModeledAnyXmlBuilder.withValue(value).build(); + } + + /** + * + * Parse the inner value of an YangModeledAnyXmlNode from element of type E. + * + * @param element + * to be parsed + * @param yangModeledAnyXmlSchemaNode + * schema for leaf + * @return parsed element as an Object + */ + protected abstract Collection> parseAnyXml(E element, YangModeledAnyXmlSchemaNode yangModeledAnyXmlSchemaNode); + +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/parser/DomToNormalizedNodeParserFactory.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/parser/DomToNormalizedNodeParserFactory.java index f26434ee5b..fc4cae62e2 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/parser/DomToNormalizedNodeParserFactory.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/parser/DomToNormalizedNodeParserFactory.java @@ -20,6 +20,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; +import org.opendaylight.yangtools.yang.data.api.schema.YangModeledAnyXmlNode; import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider; import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser; import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParserFactory; @@ -37,6 +38,7 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; import org.w3c.dom.Element; public final class DomToNormalizedNodeParserFactory implements ToNormalizedNodeParserFactory { @@ -52,6 +54,7 @@ public final class DomToNormalizedNodeParserFactory implements ToNormalizedNodeP private final UnkeyedListEntryNodeDomParser unkeyedListEntryNodeParser; private final UnkeyedListNodeDomParser unkeyedListNodeParser; private final OrderedListNodeDomParser orderedListNodeParser; + private final YangModeledAnyXmlDomParser yangModeledAnyXmlNodeParser; private final AnyXmlDomParser anyXmlNodeParser; private DomToNormalizedNodeParserFactory(final XmlCodecProvider codecProvider, final SchemaContext schema, final boolean strictParsing) { @@ -64,6 +67,7 @@ public final class DomToNormalizedNodeParserFactory implements ToNormalizedNodeP }; + yangModeledAnyXmlNodeParser = new YangModeledAnyXmlDomParser(dispatcher); containerNodeParser = new ContainerNodeDomParser(dispatcher, strictParsing); mapEntryNodeParser = new MapEntryNodeDomParser(dispatcher, strictParsing); mapNodeParser = new MapNodeDomParser(mapEntryNodeParser); @@ -88,6 +92,7 @@ public final class DomToNormalizedNodeParserFactory implements ToNormalizedNodeP }; + yangModeledAnyXmlNodeParser = new YangModeledAnyXmlDomParser(dispatcher); containerNodeParser = new ContainerNodeDomParser(dispatcher, buildingStratProvider.forContainer(), strictParsing); mapEntryNodeParser = new MapEntryNodeDomParser(dispatcher, buildingStratProvider.forMapEntry(), strictParsing); mapNodeParser = new MapNodeDomParser(mapEntryNodeParser, buildingStratProvider.forMap()); @@ -173,6 +178,11 @@ public final class DomToNormalizedNodeParserFactory implements ToNormalizedNodeP return orderedListNodeParser; } + @Override + public ToNormalizedNodeParser getYangModeledAnyXmlNodeParser() { + return yangModeledAnyXmlNodeParser; + } + @Override public ToNormalizedNodeParser getAnyXmlNodeParser() { return anyXmlNodeParser; @@ -223,4 +233,5 @@ public final class DomToNormalizedNodeParserFactory implements ToNormalizedNodeP return new BaseDispatcherParser.SimpleBuildingStrategy<>(); } } + } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/parser/YangModeledAnyXmlDomParser.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/parser/YangModeledAnyXmlDomParser.java new file mode 100644 index 0000000000..0920aea997 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/parser/YangModeledAnyXmlDomParser.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.data.impl.schema.transform.dom.parser; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import java.util.Collection; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.YangModeledAnyXmlNodeBaseParser; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class YangModeledAnyXmlDomParser extends YangModeledAnyXmlNodeBaseParser { + + private final NodeParserDispatcher dispatcher; + + public YangModeledAnyXmlDomParser(final NodeParserDispatcher dispatcher) { + this.dispatcher = Preconditions.checkNotNull(dispatcher); + } + + @Override + protected Collection> parseAnyXml(final Element element, + final YangModeledAnyXmlSchemaNode yangModeledAnyXmlSchemaNode) { + final QName qName = yangModeledAnyXmlSchemaNode.getQName(); + Preconditions.checkArgument(element.getNodeName().equals(qName.getLocalName())); + Preconditions.checkArgument(element.getNamespaceURI().equals(qName.getNamespace().toString())); + + final ContainerSchemaNode schema = yangModeledAnyXmlSchemaNode.getSchemaOfAnyXmlData(); + + Builder> value = ImmutableList.builder(); + NodeList childNodes = element.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node instanceof Element) { + Element elementChild = (Element) node; + // :FIXME get child by local name and namespace, not only by localName ? + DataSchemaNode schemaChild = schema.getDataChildByName(elementChild.getLocalName()); + + Preconditions.checkNotNull(schemaChild, + "Unable to find schema for child element %s of yang modeled anyXml data %s.", + elementChild.getLocalName(), yangModeledAnyXmlSchemaNode.getQName()); + value.add(dispatcher.dispatchChildElement(schemaChild, ImmutableList.of(elementChild))); + } + } + + return value.build(); + } +} diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/serializer/retest/YangModeledAnyXMLDeserializationTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/serializer/retest/YangModeledAnyXMLDeserializationTest.java new file mode 100644 index 0000000000..c41e74fe12 --- /dev/null +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/serializer/retest/YangModeledAnyXMLDeserializationTest.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.data.impl.schema.transform.dom.serializer.retest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLOutputFactory; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.YangModeledAnyXmlNode; +import org.opendaylight.yangtools.yang.data.impl.RetestUtils; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.Status; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public class YangModeledAnyXMLDeserializationTest { + private static final XMLOutputFactory XML_FACTORY; + private static final DocumentBuilderFactory BUILDERFACTORY; + + static { + XML_FACTORY = XMLOutputFactory.newFactory(); + XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false); + + BUILDERFACTORY = DocumentBuilderFactory.newInstance(); + BUILDERFACTORY.setNamespaceAware(true); + BUILDERFACTORY.setCoalescing(true); + BUILDERFACTORY.setIgnoringElementContentWhitespace(true); + BUILDERFACTORY.setIgnoringComments(true); + } + + private QNameModule fooModuleQName; + private QNameModule barModuleQName; + private QName myContainer1; + private QName myContainer2; + private QName innerContainer; + private QName myLeaf3; + private QName myLeaf2; + private QName myLeaf1; + private QName myAnyXMLDataBar; + private QName myAnyXMLDataFoo; + private SchemaContext schemaContext; + + @Before + public void Init() throws Exception { + barModuleQName = QNameModule.create(new URI("bar"), SimpleDateFormatUtil.getRevisionFormat() + .parse("1970-01-01")); + myContainer1 = QName.create(barModuleQName, "my-container-1"); + myLeaf1 = QName.create(barModuleQName, "my-leaf-1"); + myAnyXMLDataBar = QName.create(barModuleQName, "my-anyxml-data"); + + fooModuleQName = QNameModule.create(new URI("foo"), SimpleDateFormatUtil.getRevisionFormat() + .parse("1970-01-01")); + myContainer2 = QName.create(fooModuleQName, "my-container-2"); + innerContainer = QName.create(fooModuleQName, "inner-container"); + myLeaf3 = QName.create(fooModuleQName, "my-leaf-3"); + myLeaf2 = QName.create(fooModuleQName, "my-leaf-2"); + myAnyXMLDataFoo = QName.create(fooModuleQName, "my-anyxml-data"); + schemaContext = RetestUtils.parseYangSources(new File(getClass().getResource("/anyxml-support/yang/foo.yang") + .toURI()), new File(getClass().getResource("/anyxml-support/yang/bar.yang").toURI()), new File(getClass().getResource("/anyxml-support/yang/yang-ext.yang").toURI())); + } + + @Test + public void testRawAnyXMLFromBar() throws Exception { + final Document doc = loadDocument("/anyxml-support/xml/bar.xml"); + + DataSchemaNode barContainer = schemaContext.getDataChildByName("bar"); + assertTrue(barContainer instanceof ContainerSchemaNode); + final YangModeledAnyXmlSchemaNode yangModeledAnyXML = new YangModeledAnyXMLSchemaNodeImplTest(myAnyXMLDataBar, + (ContainerSchemaNode) barContainer); + + final YangModeledAnyXmlNode output = DomToNormalizedNodeParserFactory + .getInstance(DomUtils.defaultValueCodecProvider(), schemaContext).getYangModeledAnyXmlNodeParser() + .parse(Collections.singletonList(doc.getDocumentElement()), yangModeledAnyXML); + + assertNotNull(output); + + DataSchemaNode schemaOfAnyXmlData = output.getSchemaOfAnyXmlData(); + assertEquals(barContainer, schemaOfAnyXmlData); + + Collection> value = output.getValue(); + assertEquals(2, value.size()); + + Optional> child = output + .getChild(new NodeIdentifier(myContainer1)); + assertTrue(child.orNull() instanceof ContainerNode); + ContainerNode myContainerNode1 = (ContainerNode) child.get(); + + Optional> child2 = myContainerNode1.getChild(new NodeIdentifier( + myLeaf1)); + assertTrue(child2.orNull() instanceof LeafNode); + LeafNode LeafNode1 = (LeafNode) child2.get(); + + Object leafNode1Value = LeafNode1.getValue(); + assertEquals("value1", leafNode1Value); + } + + @Test + public void testRealSchemaContextFromFoo() throws Exception { + final Document doc = loadDocument("/anyxml-support/xml/foo.xml"); + + final ContainerNode output = DomToNormalizedNodeParserFactory + .getInstance(DomUtils.defaultValueCodecProvider(), schemaContext).getContainerNodeParser() + .parse(Collections.singletonList(doc.getDocumentElement()), schemaContext); + + assertNotNull(output); + + Optional> child = output.getChild(new NodeIdentifier( + myAnyXMLDataFoo)); + assertTrue(child.orNull() instanceof YangModeledAnyXmlNode); + YangModeledAnyXmlNode yangModeledAnyXmlNode = (YangModeledAnyXmlNode) child.get(); + + DataSchemaNode schemaOfAnyXmlData = yangModeledAnyXmlNode.getSchemaOfAnyXmlData(); + DataSchemaNode expectedSchemaOfAnyXmlData = schemaContext.getDataChildByName(myContainer2); + assertEquals(expectedSchemaOfAnyXmlData, schemaOfAnyXmlData); + + Collection> value = yangModeledAnyXmlNode.getValue(); + assertEquals(2, value.size()); + + Optional> child2 = yangModeledAnyXmlNode + .getChild(new NodeIdentifier(innerContainer)); + assertTrue(child2.orNull() instanceof ContainerNode); + ContainerNode innerContainerNode = (ContainerNode) child2.get(); + + Optional> child3 = innerContainerNode + .getChild(new NodeIdentifier(myLeaf2)); + assertTrue(child3.orNull() instanceof LeafNode); + LeafNode LeafNode2 = (LeafNode) child3.get(); + + Object leafNode2Value = LeafNode2.getValue(); + assertEquals("any-xml-leaf-2-value", leafNode2Value); + + Optional> child4 = yangModeledAnyXmlNode + .getChild(new NodeIdentifier(myLeaf3)); + assertTrue(child4.orNull() instanceof LeafNode); + LeafNode LeafNode3 = (LeafNode) child4.get(); + + Object leafNode3Value = LeafNode3.getValue(); + assertEquals("any-xml-leaf-3-value", leafNode3Value); + } + + private static Document loadDocument(final String xmlPath) throws IOException, SAXException { + final InputStream resourceAsStream = YangModeledAnyXMLDeserializationTest.class.getResourceAsStream(xmlPath); + + final Document currentConfigElement = readXmlToDocument(resourceAsStream); + Preconditions.checkNotNull(currentConfigElement); + return currentConfigElement; + } + + private static Document readXmlToDocument(final InputStream xmlContent) throws IOException, SAXException { + final DocumentBuilder dBuilder; + try { + dBuilder = BUILDERFACTORY.newDocumentBuilder(); + } catch (final ParserConfigurationException e) { + throw new RuntimeException("Failed to parse XML document", e); + } + final Document doc = dBuilder.parse(xmlContent); + + doc.getDocumentElement().normalize(); + return doc; + } + + static class YangModeledAnyXMLSchemaNodeImplTest implements YangModeledAnyXmlSchemaNode { + private final QName qName; + private final ContainerSchemaNode contentSchema; + + public YangModeledAnyXMLSchemaNodeImplTest(QName qName, ContainerSchemaNode contentSchema) { + this.qName = qName; + this.contentSchema = contentSchema; + } + + @Override + public boolean isAugmenting() { + return false; + } + + @Override + public boolean isAddedByUses() { + return false; + } + + @Override + public boolean isConfiguration() { + return false; + } + + @Override + public ConstraintDefinition getConstraints() { + return null; + } + + @Override + public QName getQName() { + return qName; + } + + @Override + public SchemaPath getPath() { + return null; + } + + @Override + public List getUnknownSchemaNodes() { + return null; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String getReference() { + return null; + } + + @Override + public Status getStatus() { + return null; + } + + @Override + public ContainerSchemaNode getSchemaOfAnyXmlData() { + return contentSchema; + } + } +} diff --git a/yang/yang-data-impl/src/test/resources/anyxml-support/xml/bar.xml b/yang/yang-data-impl/src/test/resources/anyxml-support/xml/bar.xml new file mode 100644 index 0000000000..2bf7dbed3b --- /dev/null +++ b/yang/yang-data-impl/src/test/resources/anyxml-support/xml/bar.xml @@ -0,0 +1,9 @@ + + + + value1 + + + value2 + + \ No newline at end of file diff --git a/yang/yang-data-impl/src/test/resources/anyxml-support/xml/foo.xml b/yang/yang-data-impl/src/test/resources/anyxml-support/xml/foo.xml new file mode 100644 index 0000000000..2492e954c7 --- /dev/null +++ b/yang/yang-data-impl/src/test/resources/anyxml-support/xml/foo.xml @@ -0,0 +1,19 @@ + + + + value1 + + + + value2 + + value3 + + + + + any-xml-leaf-2-value + + any-xml-leaf-3-value + + \ No newline at end of file diff --git a/yang/yang-data-impl/src/test/resources/anyxml-support/yang/bar.yang b/yang/yang-data-impl/src/test/resources/anyxml-support/yang/bar.yang new file mode 100644 index 0000000000..b8c57a8296 --- /dev/null +++ b/yang/yang-data-impl/src/test/resources/anyxml-support/yang/bar.yang @@ -0,0 +1,18 @@ +module bar { + namespace "bar"; + prefix bar; + + container bar { + container my-container-1 { + leaf my-leaf-1 { + type string; + } + } + + container my-container-2 { + leaf my-leaf-2 { + type string; + } + } + } +} diff --git a/yang/yang-data-impl/src/test/resources/anyxml-support/yang/foo.yang b/yang/yang-data-impl/src/test/resources/anyxml-support/yang/foo.yang new file mode 100644 index 0000000000..8d9920ad79 --- /dev/null +++ b/yang/yang-data-impl/src/test/resources/anyxml-support/yang/foo.yang @@ -0,0 +1,27 @@ +module foo { + namespace "foo"; + prefix foo; + + import yang-ext { prefix ext; revision-date 2013-07-09; } + + container my-container-1 { + leaf my-leaf-1 { + type string; + } + } + + container my-container-2 { + container inner-container { + leaf my-leaf-2 { + type string; + } + } + leaf my-leaf-3 { + type string; + } + } + + anyxml my-anyxml-data { + ext:anyxml-schema-location "/my-container-2"; + } +} diff --git a/yang/yang-data-impl/src/test/resources/anyxml-support/yang/yang-ext.yang b/yang/yang-data-impl/src/test/resources/anyxml-support/yang/yang-ext.yang new file mode 100644 index 0000000000..2cdc211c90 --- /dev/null +++ b/yang/yang-data-impl/src/test/resources/anyxml-support/yang/yang-ext.yang @@ -0,0 +1,75 @@ +module yang-ext { + yang-version 1; + namespace "urn:opendaylight:yang:extension:yang-ext"; + prefix "ext"; + + contact "Anton Tkacik "; + + description + "Copyright (c) 2013 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"; + + revision "2013-07-09" { + description ""; + } + + // Augmentation name + + extension "augment-identifier" { + description + "YANG language extension which assigns an identifier to augmentation. + Augment identifier is used to identify specific augment statement + by name. The identifier syntax is defined formally defined by + the rule 'identifier' in Section 12 of RFC 6020. All augment identifiers + defined in a namespace MUST be unique. The namespace of augment + identifiers is shared by module and its submodules."; + + /* + Discussion: + This extension allows for ease of development / debug + of YANG modules and it is suitable for code generation, + where each augment statement is nicely identified by + unique name instead of combination of augment target + and when condition. + */ + argument "identifier"; + } + + // Context-aware RPCs + + grouping rpc-context-ref { + description + "A reference to RPC context."; + leaf context-instance { + type instance-identifier; + description "Pointer to the context. "; + } + } + + extension "rpc-context-instance" { + description + "YANG language extension which defines enclosing (parent) schema + node as referencable context for RPCs. The argument is identity + which is used to identify RPC context type."; + + argument "context-type"; + } + + extension "context-reference" { + argument "context-type"; + } + + extension "context-instance" { + argument "context-type"; + } + + extension "instance-target" { + argument "path"; + } + + extension "anyxml-schema-location" { + argument "target-node"; + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java index 24daa344e2..5da991b527 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java @@ -79,7 +79,7 @@ public class YangStatementParserListenerImpl extends YangStatementParserBaseList } writer.argumentValue(argument, ref); } else { - writer.startStatement(QName.create(validStatementDefinition.getModule(), keywordTxt), ref); + writer.startStatement(validStatementDefinition, ref); if (argument != null) { writer.argumentValue(argument, ref); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YinStatementParserImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YinStatementParserImpl.java index d72c644415..5113e68dfd 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YinStatementParserImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YinStatementParserImpl.java @@ -147,8 +147,7 @@ public class YinStatementParserImpl { if (identifier.equals(Rfc6020Mapping.TYPE.getStatementName())) { isType = true; } else { - startStatement(QName.create(validStatementDefinition.getModule(), getElementFullName - (inputReader)), ref); + startStatement(validStatementDefinition, ref); if (isStatementWithYinElement(identifier, stmtDef)) { action = false; } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SubstatementValidator.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SubstatementValidator.java index 5f0b63f451..362fd04547 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SubstatementValidator.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SubstatementValidator.java @@ -61,7 +61,8 @@ public final class SubstatementValidator { } } - public void validate(StmtContext ctx) throws InvalidSubstatementException, MissingSubstatementException{ + public void validate(final StmtContext ctx) throws InvalidSubstatementException, + MissingSubstatementException { final Map stmtDefMap = new HashMap<>(); final Map validatedMap = new HashMap<>(); final Collection> substatementsInit = new ArrayList<>(); @@ -78,15 +79,16 @@ public final class SubstatementValidator { } if (stmtDefMap.isEmpty() && specialCase == SpecialCase.NOTNULL) { - throw new InvalidSubstatementException(String.format("%s must contain atleast 1 element. Error in module " + - "%s (%s)", currentStatement, ctx.getRoot().getStatementArgument(), ctx.getFromNamespace - (ModuleCtxToModuleQName.class, ctx.getRoot())), ctx.getStatementSourceReference()); + throw new InvalidSubstatementException(String.format("%s must contain atleast 1 element. Error in module " + + "%s (%s)", currentStatement, ctx.getRoot().getStatementArgument(), + ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx.getRoot())), + ctx.getStatementSourceReference()); } for (Map.Entry entry : stmtDefMap.entrySet()) { final StatementDefinition key = (StatementDefinition) entry.getKey(); if (!cardinalityMap.containsKey(key)) { - if (ctx.getFromNamespace(ExtensionNamespace.class, key.getArgumentName()) != null) { + if (ctx.getFromNamespace(ExtensionNamespace.class, key.getStatementName()) != null) { continue; } throw new InvalidSubstatementException(String.format("%s is not valid for %s. Error in module %s (%s)", @@ -94,16 +96,16 @@ public final class SubstatementValidator { ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx.getRoot())), ctx.getStatementSourceReference()); } - if (cardinalityMap.get(key).getMin() > (Integer)entry.getValue()) { - throw new InvalidSubstatementException(String.format("Minimal count of %s for %s is %s, detected %s. " + - "Error in module %s (%s)", key, currentStatement, cardinalityMap.get(key).getMin(), + if (cardinalityMap.get(key).getMin() > (Integer) entry.getValue()) { + throw new InvalidSubstatementException(String.format("Minimal count of %s for %s is %s, detected %s. " + + "Error in module %s (%s)", key, currentStatement, cardinalityMap.get(key).getMin(), entry.getValue(), ctx.getRoot().getStatementArgument(), ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx.getRoot())), ctx.getStatementSourceReference()); } - if (cardinalityMap.get(key).getMax() < (Integer)entry.getValue()) { - throw new InvalidSubstatementException(String.format("Maximal count of %s for %s is %s, detected %s. " + - "Error in module %s (%s)", key, currentStatement, cardinalityMap.get(key).getMax(), + if (cardinalityMap.get(key).getMax() < (Integer) entry.getValue()) { + throw new InvalidSubstatementException(String.format("Maximal count of %s for %s is %s, detected %s. " + + "Error in module %s (%s)", key, currentStatement, cardinalityMap.get(key).getMax(), entry.getValue(), ctx.getRoot().getStatementArgument(), ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx.getRoot())), ctx.getStatementSourceReference()); @@ -114,11 +116,11 @@ public final class SubstatementValidator { final MapDifference diff = Maps.difference(validatedMap, cardinalityMap); for (Map.Entry entry : diff.entriesOnlyOnRight().entrySet()) { - final int min = ((Cardinality)entry.getValue()).getMin(); + final int min = ((Cardinality) entry.getValue()).getMin(); if (min > 0) { - throw new MissingSubstatementException(String.format("%s is missing %s. Minimal count is %s. Error in" + - " module %s (%s)", currentStatement, entry.getKey(), min, ctx.getRoot().getStatementArgument(), - ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx.getRoot())), + throw new MissingSubstatementException(String.format("%s is missing %s. Minimal count is %s. Error in" + + " module %s (%s)", currentStatement, entry.getKey(), min, ctx.getRoot() + .getStatementArgument(), ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx.getRoot())), ctx.getStatementSourceReference()); } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java index 3e830d80c7..77b285f16a 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java @@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.parser.spi.meta; import com.google.common.base.Function; import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import java.util.Collection; @@ -81,6 +82,18 @@ public final class StmtContextUtils { return null; } + @SuppressWarnings("unchecked") + public static > Collection> findAllDeclaredSubstatement( + final StmtContext stmtContext, final Class
declaredType) { + ImmutableList.Builder> listBuilder = ImmutableList.builder(); + for (StmtContext subStmtContext : stmtContext.declaredSubstatements()) { + if (producesDeclared(subStmtContext,declaredType)) { + listBuilder.add((StmtContext) subStmtContext); + } + } + return listBuilder.build(); + } + @SuppressWarnings("unchecked") public static > StmtContext findFirstEffectiveSubstatement( final StmtContext stmtContext, final Class
declaredType) { diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/AnyxmlSchemaLocationNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/AnyxmlSchemaLocationNamespace.java new file mode 100644 index 0000000000..e14c7790d2 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/AnyxmlSchemaLocationNamespace.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.parser.spi.source; + +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; + +/** + * + * Source-specific mapping of prefixes to namespaces + * + */ +public interface AnyxmlSchemaLocationNamespace + extends + IdentifierNamespace, EffectiveStatement>>> { + +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java index 3f34be5ffb..64351b8818 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java @@ -99,24 +99,21 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh if (def == null) { //unknown-stmts (from import, include or local-scope) - if (qNameToStmtDefMap.get(Utils.trimPrefix(name)) != null) { - QName key = Utils.qNameFromArgument(current, name.getLocalName()); - if (key != null) { - final StatementContextBase extension = (StatementContextBase) currentContext - .getAllFromNamespace(ExtensionNamespace.class).get(key); - if (extension != null) { - final QName arg = (QName) extension.getStatementArgument(); - final QName qName = current.getFromNamespace(QNameCacheNamespace.class, + if (qNameToStmtDefMap.get(name) != null) { + final StatementContextBase extension = (StatementContextBase) currentContext + .getAllFromNamespace(ExtensionNamespace.class).get(name); + if (extension != null) { + final QName arg = (QName) extension.getStatementArgument(); + final QName qName = current.getFromNamespace(QNameCacheNamespace.class, QName.create(arg, extension.getIdentifier().getArgument())); - def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition - (getNewStatementDefinition(qName))); - } else { - throw new IllegalArgumentException("Not found unknown statement: " + name); - } + def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition( + getNewStatementDefinition(qName))); + } else { + throw new IllegalArgumentException("Not found unknown statement: " + name); } } else { - //type-body-stmts + // type-body-stmts def = resolveTypeBodyStmts(name.getLocalName()); } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AnyxmlSchemaLocationStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AnyxmlSchemaLocationStatementImpl.java new file mode 100644 index 0000000000..315b2f6b85 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AnyxmlSchemaLocationStatementImpl.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2015 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.yangtools.yang.parser.stmt.rfc6020; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; +import org.opendaylight.yangtools.yang.parser.spi.source.AnyxmlSchemaLocationNamespace; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.AnyxmlSchemaLocationEffectiveStatementImpl; + +@Beta +public final class AnyxmlSchemaLocationStatementImpl extends AbstractDeclaredStatement implements + UnknownStatement { + + AnyxmlSchemaLocationStatementImpl( + StmtContext, ?> context) { + super(context); + } + + public static class AnyxmlSchemaLocationSupport + extends + AbstractStatementSupport, EffectiveStatement>> { + + public AnyxmlSchemaLocationSupport() { + super(SupportedExtensionsMapping.ANYXML_SCHEMA_LOCATION); + } + + @Override + public SchemaNodeIdentifier parseArgumentValue(StmtContext ctx, String value) { + return Utils.nodeIdentifierFromPath(ctx, value); + } + + @Override + public void onFullDefinitionDeclared( + Mutable, EffectiveStatement>> stmt) { + stmt.getParentContext().addToNs(AnyxmlSchemaLocationNamespace.class, + SupportedExtensionsMapping.ANYXML_SCHEMA_LOCATION, stmt); + } + + @Override + public UnknownStatement createDeclared( + StmtContext, ?> ctx) { + return new AnyxmlSchemaLocationStatementImpl(ctx); + } + + @Override + public EffectiveStatement> createEffective( + final StmtContext, EffectiveStatement>> ctx) { + return new AnyxmlSchemaLocationEffectiveStatementImpl(ctx); + } + } + + @Override + public SchemaNodeIdentifier getArgument() { + return argument(); + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AnyxmlStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AnyxmlStatementImpl.java index 135b20988b..8cc179e0ae 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AnyxmlStatementImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AnyxmlStatementImpl.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the @@ -9,10 +9,14 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; import static org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator.MAX; +import com.google.common.base.Optional; import java.util.Collection; +import java.util.Map; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ConfigStatement; import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement; @@ -20,15 +24,20 @@ import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement; import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryStatement; import org.opendaylight.yangtools.yang.model.api.stmt.MustStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement; import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement; import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator; import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement; import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; +import org.opendaylight.yangtools.yang.parser.spi.source.AnyxmlSchemaLocationNamespace; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.AnyXmlEffectiveStatementImpl; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.YangModeledAnyXmlEffectiveStatementImpl; public class AnyxmlStatementImpl extends AbstractDeclaredStatement implements AnyxmlStatement { private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(Rfc6020Mapping @@ -41,21 +50,23 @@ public class AnyxmlStatementImpl extends AbstractDeclaredStatement implem .add(Rfc6020Mapping.REFERENCE, 0, 1) .add(Rfc6020Mapping.STATUS, 0, 1) .add(Rfc6020Mapping.WHEN, 0, 1) + .add(SupportedExtensionsMapping.ANYXML_SCHEMA_LOCATION, 0, 1) .build(); - protected AnyxmlStatementImpl(StmtContext context) { + protected AnyxmlStatementImpl(StmtContext context) { super(context); } - public static class Definition extends AbstractStatementSupport> { + public static class Definition extends + AbstractStatementSupport> { public Definition() { super(Rfc6020Mapping.ANYXML); } @Override - public QName parseArgumentValue(StmtContext ctx, String value) { - return Utils.qNameFromArgument(ctx,value); + public QName parseArgumentValue(StmtContext ctx, String value) { + return Utils.qNameFromArgument(ctx, value); } @Override @@ -64,13 +75,24 @@ public class AnyxmlStatementImpl extends AbstractDeclaredStatement implem } @Override - public AnyxmlStatement createDeclared(StmtContext ctx) { + public AnyxmlStatement createDeclared(StmtContext ctx) { return new AnyxmlStatementImpl(ctx); } @Override - public EffectiveStatement createEffective(StmtContext> ctx) { - return new AnyXmlEffectiveStatementImpl(ctx); + public EffectiveStatement createEffective( + final StmtContext> ctx) { + Map, EffectiveStatement>>> schemaLocations = ctx + .getAllFromCurrentStmtCtxNamespace(AnyxmlSchemaLocationNamespace.class); + if (schemaLocations != null && !schemaLocations.isEmpty()) { + SchemaNodeIdentifier anyXmlSchemaNodeIdentifier = schemaLocations.values().iterator().next() + .getStatementArgument(); + Optional anyXmlSchema = getAnyXmlSchema(ctx, anyXmlSchemaNodeIdentifier); + if (anyXmlSchema.isPresent()) { + return new YangModeledAnyXmlEffectiveStatementImpl(ctx, anyXmlSchema.get()); + } + } + return new AnyXmlEffectiveStatementImpl(ctx); } @Override @@ -79,6 +101,19 @@ public class AnyxmlStatementImpl extends AbstractDeclaredStatement implem super.onFullDefinitionDeclared(stmt); SUBSTATEMENT_VALIDATOR.validate(stmt); } + + private Optional getAnyXmlSchema( + StmtContext> ctx, + SchemaNodeIdentifier contentSchemaPath) { + final StatementContextBase findNode = Utils.findNode(ctx.getRoot(), contentSchemaPath); + if (findNode != null) { + final EffectiveStatement anyXmlSchemaNode = findNode.buildEffective(); + if (anyXmlSchemaNode instanceof ContainerSchemaNode) { + return Optional.of((ContainerSchemaNode) anyXmlSchemaNode); + } + } + return Optional.absent(); + } } @Override diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/SupportedExtensionsMapping.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/SupportedExtensionsMapping.java new file mode 100644 index 0000000000..d68382d852 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/SupportedExtensionsMapping.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.parser.stmt.rfc6020; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.AnyxmlSchemaLocationEffectiveStatementImpl; + +@Beta +public enum SupportedExtensionsMapping implements StatementDefinition { + ANYXML_SCHEMA_LOCATION("urn:opendaylight:yang:extension:yang-ext", "2013-07-09", + AnyxmlSchemaLocationStatementImpl.class, AnyxmlSchemaLocationEffectiveStatementImpl.class, + "anyxml-schema-location", "target-node"); + + private final Class> type; + private final Class> effectiveType; + private final QName name; + private final QName argument; + + private SupportedExtensionsMapping(final String namespace, final String revision, + final Class> declared, + final Class> effective, final String nameStr, + final String argumentStr) { + type = Preconditions.checkNotNull(declared); + effectiveType = Preconditions.checkNotNull(effective); + name = createQName(namespace, revision, nameStr); + argument = createQName(namespace, revision, argumentStr); + } + + @Nonnull + private static QName createQName(final String namespace, final String revision, final String localName) { + return QName.create(namespace, revision, localName).intern(); + } + + @Override + public QName getStatementName() { + return name; + } + + @Override + @Nullable + public QName getArgumentName() { + return argument; + } + + @Override + @Nonnull + public Class> getDeclaredRepresentationClass() { + return type; + } + + @Override + public Class> getEffectiveRepresentationClass() { + return effectiveType; + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java index 85124a198f..4d38896803 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java @@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.global; import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.sourceLocal; import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.treeScoped; + import com.google.common.collect.ImmutableMap; import java.util.Map; import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace; @@ -23,6 +24,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.DerivedIdentitiesNamespac import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; import org.opendaylight.yangtools.yang.parser.spi.meta.QNameCacheNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle; +import org.opendaylight.yangtools.yang.parser.spi.source.AnyxmlSchemaLocationNamespace; import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToModuleContext; import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleIdentifier; import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleName; @@ -147,6 +149,8 @@ public final class YangInferencePipeline { .addSupport(new FeatureStatementImpl.Definition()) .addSupport(new PositionStatementImpl.Definition()) .addSupport(new ValueStatementImpl.Definition()) + .addSupport(new AnyxmlSchemaLocationStatementImpl.AnyxmlSchemaLocationSupport()) + .addSupport(treeScoped(AnyxmlSchemaLocationNamespace.class)) .addSupport(global(StmtOrderingNamespace.class)) .build(); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/AnyXmlEffectiveStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/AnyXmlEffectiveStatementImpl.java index ec16435706..b0b21af625 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/AnyXmlEffectiveStatementImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/AnyXmlEffectiveStatementImpl.java @@ -16,7 +16,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlStatement; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -public final class AnyXmlEffectiveStatementImpl extends AbstractEffectiveDataSchemaNode implements +public class AnyXmlEffectiveStatementImpl extends AbstractEffectiveDataSchemaNode implements AnyXmlSchemaNode, DerivableSchemaNode { private final AnyXmlSchemaNode original; diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/AnyxmlSchemaLocationEffectiveStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/AnyxmlSchemaLocationEffectiveStatementImpl.java new file mode 100644 index 0000000000..27e4cb0de9 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/AnyxmlSchemaLocationEffectiveStatementImpl.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.parser.stmt.rfc6020.effective; + +import com.google.common.annotations.Beta; +import java.util.Objects; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; + +@Beta +public final class AnyxmlSchemaLocationEffectiveStatementImpl extends + UnknownEffectiveStatementBase { + + private final SchemaPath path; + + public AnyxmlSchemaLocationEffectiveStatementImpl( + final StmtContext, ?> ctx) { + super(ctx); + + path = ctx.getParentContext().getSchemaPath().get().createChild(getNodeType()); + } + + @Override + public QName getQName() { + return getNodeType(); + } + + @Override + public SchemaPath getPath() { + return path; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Objects.hashCode(path); + result = prime * result + Objects.hashCode(getNodeType()); + result = prime * result + Objects.hashCode(getNodeParameter()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AnyxmlSchemaLocationEffectiveStatementImpl other = (AnyxmlSchemaLocationEffectiveStatementImpl) obj; + if (!Objects.equals(path, other.path)) { + return false; + } + if (!Objects.equals(getNodeType(), other.getNodeType())) { + return false; + } + if (!Objects.equals(getNodeParameter(), other.getNodeParameter())) { + return false; + } + return true; + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/UnknownEffectiveStatementBase.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/UnknownEffectiveStatementBase.java new file mode 100644 index 0000000000..738f70d555 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/UnknownEffectiveStatementBase.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.parser.stmt.rfc6020.effective; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import java.util.List; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement; +import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.TypeOfCopy; + +public abstract class UnknownEffectiveStatementBase extends AbstractEffectiveDocumentedNode> + implements UnknownSchemaNode { + + private final boolean addedByUses; + private final boolean addedByAugmentation; + + private final ExtensionDefinition extension; + private final List unknownNodes; + private final QName nodeType; + private final String nodeParameter; + + public UnknownEffectiveStatementBase(final StmtContext, ?> ctx) { + super(ctx); + + final StmtContext> extensionInit = ctx + .getFromNamespace(ExtensionNamespace.class, ctx.getPublicDefinition().getStatementName()); + + if (extensionInit == null) { + extension = null; + nodeType = ctx.getPublicDefinition().getArgumentName(); + } else { + extension = (ExtensionEffectiveStatementImpl) extensionInit.buildEffective(); + nodeType = extension.getQName(); + } + + // initCopyType + List copyTypesFromOriginal = ctx.getCopyHistory(); + if (copyTypesFromOriginal.contains(TypeOfCopy.ADDED_BY_USES_AUGMENTATION)) { + this.addedByUses = this.addedByAugmentation = true; + } else { + this.addedByAugmentation = copyTypesFromOriginal.contains(TypeOfCopy.ADDED_BY_AUGMENTATION); + this.addedByUses = copyTypesFromOriginal.contains(TypeOfCopy.ADDED_BY_USES); + } + + nodeParameter = (ctx.rawStatementArgument() == null) ? "" : ctx.rawStatementArgument(); + + // TODO init other fields (see Bug1412Test) + final Builder builder = ImmutableList.builder(); + for (final EffectiveStatement effectiveStatement : effectiveSubstatements()) { + if (effectiveStatement instanceof UnknownSchemaNode) { + builder.add((UnknownSchemaNode) effectiveStatement); + } + } + unknownNodes = builder.build(); + } + + @Override + public boolean isAddedByAugmentation() { + return addedByAugmentation; + } + + @Override + public QName getNodeType() { + return nodeType; + } + + @Override + public String getNodeParameter() { + return nodeParameter; + } + + @Override + public boolean isAddedByUses() { + return addedByUses; + } + + @Override + public ExtensionDefinition getExtensionDefinition() { + return extension; + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(nodeType.getNamespace()); + sb.append(":"); + sb.append(nodeType.getLocalName()); + sb.append(" "); + sb.append(nodeParameter); + return sb.toString(); + } + +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/UnknownEffectiveStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/UnknownEffectiveStatementImpl.java index 0f14b729cc..2ee3f8283d 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/UnknownEffectiveStatementImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/UnknownEffectiveStatementImpl.java @@ -8,57 +8,22 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import java.util.List; import java.util.Objects; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; -import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement; import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement; -import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.TypeOfCopy; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils; -public final class UnknownEffectiveStatementImpl extends AbstractEffectiveDocumentedNode> - implements UnknownSchemaNode { +public final class UnknownEffectiveStatementImpl extends UnknownEffectiveStatementBase { - private final boolean addedByUses; - private final boolean addedByAugmentation; private final QName maybeQNameArgument; private final SchemaPath path; - private final ExtensionDefinition extension; - private final List unknownNodes; - private final QName nodeType; - private final String nodeParameter; public UnknownEffectiveStatementImpl(final StmtContext, ?> ctx) { super(ctx); - final StmtContext> extensionInit = ctx - .getFromNamespace(ExtensionNamespace.class, ctx.getPublicDefinition().getStatementName()); - - if (extensionInit == null) { - extension = null; - nodeType = ctx.getPublicDefinition().getArgumentName(); - } else { - extension = (ExtensionEffectiveStatementImpl) extensionInit.buildEffective(); - nodeType = extension.getQName(); - } - - // initCopyType - List copyTypesFromOriginal = ctx.getCopyHistory(); - if (copyTypesFromOriginal.contains(TypeOfCopy.ADDED_BY_USES_AUGMENTATION)) { - this.addedByUses = this.addedByAugmentation = true; - } else { - this.addedByAugmentation = copyTypesFromOriginal.contains(TypeOfCopy.ADDED_BY_AUGMENTATION); - this.addedByUses = copyTypesFromOriginal.contains(TypeOfCopy.ADDED_BY_USES); - } - // FIXME: Remove following section after fixing 4380 final UnknownSchemaNode original = ctx.getOriginalCtx() == null ? null : (UnknownSchemaNode) ctx .getOriginalCtx().buildEffective(); @@ -69,46 +34,11 @@ public final class UnknownEffectiveStatementImpl extends AbstractEffectiveDocume try { maybeQNameArgumentInit = Utils.qNameFromArgument(ctx, argument()); } catch (IllegalArgumentException e) { - maybeQNameArgumentInit = nodeType; + maybeQNameArgumentInit = getNodeType(); } this.maybeQNameArgument = maybeQNameArgumentInit; } path = ctx.getParentContext().getSchemaPath().get().createChild(maybeQNameArgument); - nodeParameter = (ctx.rawStatementArgument() == null) ? "" : ctx.rawStatementArgument(); - - // TODO init other fields (see Bug1412Test) - final Builder builder = ImmutableList.builder(); - for (final EffectiveStatement effectiveStatement : effectiveSubstatements()) { - if (effectiveStatement instanceof UnknownEffectiveStatementImpl) { - builder.add((UnknownEffectiveStatementImpl) effectiveStatement); - } - } - unknownNodes = builder.build(); - } - - @Override - public boolean isAddedByAugmentation() { - return addedByAugmentation; - } - - @Override - public QName getNodeType() { - return nodeType; - } - - @Override - public String getNodeParameter() { - return nodeParameter; - } - - @Override - public boolean isAddedByUses() { - return addedByUses; - } - - @Override - public ExtensionDefinition getExtensionDefinition() { - return extension; } @Override @@ -121,19 +51,14 @@ public final class UnknownEffectiveStatementImpl extends AbstractEffectiveDocume return path; } - @Override - public List getUnknownSchemaNodes() { - return unknownNodes; - } - @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Objects.hashCode(maybeQNameArgument); result = prime * result + Objects.hashCode(path); - result = prime * result + Objects.hashCode(nodeType); - result = prime * result + Objects.hashCode(nodeParameter); + result = prime * result + Objects.hashCode(getNodeType()); + result = prime * result + Objects.hashCode(getNodeParameter()); return result; } @@ -155,24 +80,12 @@ public final class UnknownEffectiveStatementImpl extends AbstractEffectiveDocume if (!Objects.equals(path, other.path)) { return false; } - if (!Objects.equals(nodeType, other.nodeType)) { + if (!Objects.equals(getNodeType(), other.getNodeType())) { return false; } - if (!Objects.equals(nodeParameter, other.nodeParameter)) { + if (!Objects.equals(getNodeParameter(), other.getNodeParameter())) { return false; } return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(nodeType.getNamespace()); - sb.append(":"); - sb.append(nodeType.getLocalName()); - sb.append(" "); - sb.append(nodeParameter); - return sb.toString(); - } - } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/YangModeledAnyXmlEffectiveStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/YangModeledAnyXmlEffectiveStatementImpl.java new file mode 100644 index 0000000000..d0b7f00dea --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/YangModeledAnyXmlEffectiveStatementImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.parser.stmt.rfc6020.effective; + +import com.google.common.base.Preconditions; +import java.util.Objects; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; + +public final class YangModeledAnyXmlEffectiveStatementImpl extends AnyXmlEffectiveStatementImpl implements + YangModeledAnyXmlSchemaNode { + + private final ContainerSchemaNode schemaOfAnyXmlData; + + public YangModeledAnyXmlEffectiveStatementImpl( + final StmtContext> ctx, final ContainerSchemaNode contentSchema) { + super(ctx); + schemaOfAnyXmlData = Preconditions.checkNotNull(contentSchema); + } + + @Override + public ContainerSchemaNode getSchemaOfAnyXmlData() { + return schemaOfAnyXmlData; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Objects.hashCode(getQName()); + result = prime * result + Objects.hashCode(getPath()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + + YangModeledAnyXmlEffectiveStatementImpl other = (YangModeledAnyXmlEffectiveStatementImpl) obj; + return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(YangModeledAnyXmlEffectiveStatementImpl.class.getSimpleName()); + sb.append("["); + sb.append("qname=").append(getQName()); + sb.append(", path=").append(getPath()); + sb.append("]"); + return sb.toString(); + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug3874ExtensionTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug3874ExtensionTest.java new file mode 100644 index 0000000000..e27d6e0db1 --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug3874ExtensionTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 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.yangtools.yang.stmt.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.FileNotFoundException; +import java.net.URI; +import java.net.URISyntaxException; +import java.text.ParseException; +import java.util.Date; +import java.util.List; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.SupportedExtensionsMapping; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.AnyxmlSchemaLocationEffectiveStatementImpl; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.YangModeledAnyXmlEffectiveStatementImpl; + +public class Bug3874ExtensionTest { + + @Test + public void test() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException, ParseException { + SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug3874"); + + Date revision = SimpleDateFormatUtil.getRevisionFormat().parse("1970-01-01"); + QNameModule foo = QNameModule.create(new URI("foo"), revision); + QName myContainer2QName = QName.create(foo, "my-container-2"); + QName myAnyXmlDataQName = QName.create(foo, "my-anyxml-data"); + + DataSchemaNode dataChildByName = context.getDataChildByName(myAnyXmlDataQName); + assertTrue(dataChildByName instanceof YangModeledAnyXmlEffectiveStatementImpl); + YangModeledAnyXmlEffectiveStatementImpl yangModeledAnyXml = (YangModeledAnyXmlEffectiveStatementImpl) dataChildByName; + + SchemaNode myContainer2 = SchemaContextUtil.findDataSchemaNode(context, SchemaPath.create(true, myContainer2QName)); + assertTrue(myContainer2 instanceof ContainerSchemaNode); + assertEquals(myContainer2, yangModeledAnyXml.getSchemaOfAnyXmlData()); + + List unknownSchemaNodes = yangModeledAnyXml.getUnknownSchemaNodes(); + assertEquals(1, unknownSchemaNodes.size()); + + UnknownSchemaNode next = unknownSchemaNodes.iterator().next(); + assertTrue(next instanceof UnknownSchemaNode); + assertTrue(next instanceof AnyxmlSchemaLocationEffectiveStatementImpl); + AnyxmlSchemaLocationEffectiveStatementImpl anyxmlSchemaLocationUnknownNode= (AnyxmlSchemaLocationEffectiveStatementImpl) next; + assertEquals(SupportedExtensionsMapping.ANYXML_SCHEMA_LOCATION.getStatementName(), anyxmlSchemaLocationUnknownNode.getNodeType()); + assertEquals(SupportedExtensionsMapping.ANYXML_SCHEMA_LOCATION.getStatementName(), anyxmlSchemaLocationUnknownNode.getQName()); + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug3874/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug3874/foo.yang new file mode 100644 index 0000000000..a36ba24ba6 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug3874/foo.yang @@ -0,0 +1,35 @@ +module foo { + namespace "foo"; + prefix foo; + + import yang-ext { prefix ext; revision-date 2013-07-09; } + + container my-container-1 { + leaf my-leaf-1 { + type string; + } + } + + container my-container-2 { + container inner-container { + leaf my-leaf-2 { + type string; + } + } + leaf my-leaf-3 { + type string; + } + } + + anyxml my-anyxml-data { + ext:anyxml-schema-location "/my-container-2"; + } + + foo:my-extension "arg-value" { + foo:my-extension "arg-value-2"; + } + + extension my-extension { + argument arg-name; + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug3874/yang-ext.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug3874/yang-ext.yang new file mode 100644 index 0000000000..2cdc211c90 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug3874/yang-ext.yang @@ -0,0 +1,75 @@ +module yang-ext { + yang-version 1; + namespace "urn:opendaylight:yang:extension:yang-ext"; + prefix "ext"; + + contact "Anton Tkacik "; + + description + "Copyright (c) 2013 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"; + + revision "2013-07-09" { + description ""; + } + + // Augmentation name + + extension "augment-identifier" { + description + "YANG language extension which assigns an identifier to augmentation. + Augment identifier is used to identify specific augment statement + by name. The identifier syntax is defined formally defined by + the rule 'identifier' in Section 12 of RFC 6020. All augment identifiers + defined in a namespace MUST be unique. The namespace of augment + identifiers is shared by module and its submodules."; + + /* + Discussion: + This extension allows for ease of development / debug + of YANG modules and it is suitable for code generation, + where each augment statement is nicely identified by + unique name instead of combination of augment target + and when condition. + */ + argument "identifier"; + } + + // Context-aware RPCs + + grouping rpc-context-ref { + description + "A reference to RPC context."; + leaf context-instance { + type instance-identifier; + description "Pointer to the context. "; + } + } + + extension "rpc-context-instance" { + description + "YANG language extension which defines enclosing (parent) schema + node as referencable context for RPCs. The argument is identity + which is used to identify RPC context type."; + + argument "context-type"; + } + + extension "context-reference" { + argument "context-type"; + } + + extension "context-instance" { + argument "context-type"; + } + + extension "instance-target" { + argument "path"; + } + + extension "anyxml-schema-location" { + argument "target-node"; + } +}