From: Robert Varga Date: Fri, 29 Aug 2014 20:23:26 +0000 (+0000) Subject: Merge "BUG-869: added proper handling of nullable parameter" X-Git-Tag: release/helium~126 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=4302f95307c27902956e838f52d06bf97e879639;hp=ce883060855fa0600e7f7b33bc7893552200f900;p=yangtools.git Merge "BUG-869: added proper handling of nullable parameter" --- diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml new file mode 100644 index 0000000000..e80bfee9f9 --- /dev/null +++ b/benchmarks/pom.xml @@ -0,0 +1,59 @@ + + + + org.opendaylight.yangtools + yangtools-parent + 0.6.2-SNAPSHOT + ../common/parent + + 4.0.0 + + org.opendaylight.yangtools + benchmarks + + + 0.6.2-SNAPSHOT + 0.6.2-SNAPSHOT + 1.7 + 1.7 + 0.9.7 + + + + + ${project.groupId} + yang-data-impl + ${yangtools.version} + + + ${project.groupId} + yang-parser-impl + ${yangtools.version} + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.source.version} + ${java.source.version} + + + + + diff --git a/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/BenchmarkModel.java b/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/BenchmarkModel.java new file mode 100644 index 0000000000..e8cf728b45 --- /dev/null +++ b/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/BenchmarkModel.java @@ -0,0 +1,44 @@ +package org.opendaylight.yangtools.yang.data.impl.tree; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Set; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; + +/** + * @author Lukas Sedlak + */ +public class BenchmarkModel { + + public static final QName TEST_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", "2014-03-13", + "test"); + public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list"); + public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list"); + public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice"); + public static final QName ID_QNAME = QName.create(TEST_QNAME, "id"); + public static final QName NAME_QNAME = QName.create(TEST_QNAME, "name"); + public static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value"); + private static final String DATASTORE_TEST_YANG = "/odl-datastore-test.yang"; + + public static final YangInstanceIdentifier TEST_PATH = YangInstanceIdentifier.of(TEST_QNAME); + public static final YangInstanceIdentifier OUTER_LIST_PATH = YangInstanceIdentifier.builder(TEST_PATH).node(OUTER_LIST_QNAME).build(); + + public static final InputStream getDatastoreBenchmarkInputStream() { + return getInputStream(DATASTORE_TEST_YANG); + } + + private static InputStream getInputStream(final String resourceName) { + return BenchmarkModel.class.getResourceAsStream(resourceName); + } + + public static SchemaContext createTestContext() { + YangParserImpl parser = new YangParserImpl(); + Set modules = parser.parseYangModelsFromStreams(Collections.singletonList( + getDatastoreBenchmarkInputStream())); + return parser.resolveSchemaContext(modules); + } +} diff --git a/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/InMemoryDataTreeBenchmark.java b/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/InMemoryDataTreeBenchmark.java new file mode 100644 index 0000000000..306c14dc07 --- /dev/null +++ b/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/InMemoryDataTreeBenchmark.java @@ -0,0 +1,194 @@ +/** + * 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 + */ +package org.opendaylight.yangtools.yang.data.impl.tree; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.*; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +/** + * Benchmarking of InMemoryDataTree performance. + * + * JMH is used for microbenchmarking. + * + * @author Lukas Sedlak + * + * @see JMH + */ +@State(Scope.Thread) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +public class InMemoryDataTreeBenchmark { + + private static final int OUTER_LIST_100K = 100000; + private static final int OUTER_LIST_50K = 50000; + private static final int OUTER_LIST_10K = 10000; + + private static final YangInstanceIdentifier[] OUTER_LIST_100K_PATHS = initOuterListPaths(OUTER_LIST_100K); + private static final YangInstanceIdentifier[] OUTER_LIST_50K_PATHS = initOuterListPaths(OUTER_LIST_50K); + private static final YangInstanceIdentifier[] OUTER_LIST_10K_PATHS = initOuterListPaths(OUTER_LIST_10K); + + private static YangInstanceIdentifier[] initOuterListPaths(final int outerListPathsCount) { + final YangInstanceIdentifier[] paths = new YangInstanceIdentifier[outerListPathsCount]; + + for (int outerListKey = 0; outerListKey < outerListPathsCount; ++outerListKey) { + paths[outerListKey] = YangInstanceIdentifier.builder(BenchmarkModel.OUTER_LIST_PATH) + .nodeWithKey(BenchmarkModel.OUTER_LIST_QNAME, BenchmarkModel.ID_QNAME, outerListKey) + .build(); + } + return paths; + } + + private static final MapNode ONE_ITEM_INNER_LIST = initInnerListItems(1); + private static final MapNode TWO_ITEM_INNER_LIST = initInnerListItems(2); + private static final MapNode TEN_ITEM_INNER_LIST = initInnerListItems(10); + + private static MapNode initInnerListItems(final int count) { + final CollectionNodeBuilder mapEntryBuilder = ImmutableNodes + .mapNodeBuilder(BenchmarkModel.INNER_LIST_QNAME); + + for (int i = 1; i <= count; ++i) { + mapEntryBuilder + .withChild(ImmutableNodes.mapEntry(BenchmarkModel.INNER_LIST_QNAME, BenchmarkModel.NAME_QNAME, i)); + } + + return mapEntryBuilder.build(); + } + + private static final NormalizedNode[] OUTER_LIST_ONE_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_100K, ONE_ITEM_INNER_LIST); + private static final NormalizedNode[] OUTER_LIST_TWO_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_50K, TWO_ITEM_INNER_LIST); + private static final NormalizedNode[] OUTER_LIST_TEN_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_10K, TEN_ITEM_INNER_LIST); + + private static NormalizedNode[] initOuterListItems(int outerListItemsCount, MapNode innerList) { + final NormalizedNode[] outerListItems = new NormalizedNode[outerListItemsCount]; + + for (int i = 0; i < outerListItemsCount; ++i) { + int outerListKey = i; + outerListItems[i] = ImmutableNodes.mapEntryBuilder(BenchmarkModel.OUTER_LIST_QNAME, BenchmarkModel.ID_QNAME, outerListKey) + .withChild(innerList).build(); + } + return outerListItems; + } + + private SchemaContext schemaContext; + private DataTree datastore; + + public static void main(String... args) throws IOException, RunnerException { + Options opt = new OptionsBuilder() + .include(".*" + InMemoryDataTreeBenchmark.class.getSimpleName() + ".*") + .forks(1) + .build(); + + new Runner(opt).run(); + } + + @Setup(Level.Trial) + public void setup() throws DataValidationFailedException { + schemaContext = BenchmarkModel.createTestContext(); + final InMemoryDataTreeFactory factory = InMemoryDataTreeFactory.getInstance(); + datastore = factory.create(); + datastore.setSchemaContext(schemaContext); + final DataTreeSnapshot snapshot = datastore.takeSnapshot(); + initTestNode(snapshot); + } + + @TearDown + public void tearDown() { + schemaContext = null; + datastore = null; + } + + private void initTestNode(final DataTreeSnapshot snapshot) throws DataValidationFailedException { + final DataTreeModification modification = snapshot.newModification(); + final YangInstanceIdentifier testPath = YangInstanceIdentifier.builder(BenchmarkModel.TEST_PATH) + .build(); + + modification.write(testPath, provideOuterListNode()); + datastore.validate(modification); + final DataTreeCandidate candidate = datastore.prepare(modification); + datastore.commit(candidate); + } + + private DataContainerChild provideOuterListNode() { + return ImmutableContainerNodeBuilder + .create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(BenchmarkModel.TEST_QNAME)) + .withChild( + ImmutableNodes.mapNodeBuilder(BenchmarkModel.OUTER_LIST_QNAME) + .build()).build(); + } + + @Benchmark + @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS) + @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS) + public void singleNodes100KWriteBenchmark() throws Exception { + applyWriteSingleNode(OUTER_LIST_100K); + } + + private void applyWriteSingleNode(final int reps) throws DataValidationFailedException { + final DataTreeSnapshot snapshot = datastore.takeSnapshot(); + final DataTreeModification modification = snapshot.newModification(); + for (int outerListKey = 0; outerListKey < reps; ++outerListKey) { + modification.write(OUTER_LIST_100K_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]); + } + datastore.validate(modification); + final DataTreeCandidate candidate = datastore.prepare(modification); + datastore.commit(candidate); + } + + @Benchmark + @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS) + @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS) + public void twoNodes50KWriteBenchmark() throws Exception { + applyWriteTwoNodes(OUTER_LIST_50K); + } + + private void applyWriteTwoNodes(final int reps) throws DataValidationFailedException { + final DataTreeSnapshot snapshot = datastore.takeSnapshot(); + final DataTreeModification modification = snapshot.newModification(); + for (int outerListKey = 0; outerListKey < reps; ++outerListKey) { + modification.write(OUTER_LIST_50K_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]); + } + datastore.validate(modification); + final DataTreeCandidate candidate = datastore.prepare(modification); + datastore.commit(candidate); + } + + @Benchmark + @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS) + @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS) + public void tenNodes10KWriteBenchmark() throws Exception { + applyWriteTenNodes(OUTER_LIST_10K); + } + + private void applyWriteTenNodes(final int reps) throws DataValidationFailedException { + final DataTreeSnapshot snapshot = datastore.takeSnapshot(); + final DataTreeModification modification = snapshot.newModification(); + for (int outerListKey = 0; outerListKey < reps; ++outerListKey) { + modification.write(OUTER_LIST_10K_PATHS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]); + } + datastore.validate(modification); + final DataTreeCandidate candidate = datastore.prepare(modification); + datastore.commit(candidate); + } +} diff --git a/benchmarks/src/main/resources/odl-datastore-test.yang b/benchmarks/src/main/resources/odl-datastore-test.yang new file mode 100644 index 0000000000..730ca17173 --- /dev/null +++ b/benchmarks/src/main/resources/odl-datastore-test.yang @@ -0,0 +1,42 @@ +module odl-datastore-test { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test"; + prefix "store-test"; + + revision "2014-03-13" { + description "Initial revision."; + } + + container test { + list outer-list { + key id; + leaf id { + type int32; + } + choice outer-choice { + case one { + leaf one { + type string; + } + } + case two-three { + leaf two { + type string; + } + leaf three { + type string; + } + } + } + list inner-list { + key name; + leaf name { + type int32; + } + leaf value { + type string; + } + } + } + } +} \ No newline at end of file diff --git a/code-generator/binding-data-codec/pom.xml b/code-generator/binding-data-codec/pom.xml index 80cfe17b79..b8bf7e11ef 100644 --- a/code-generator/binding-data-codec/pom.xml +++ b/code-generator/binding-data-codec/pom.xml @@ -52,11 +52,12 @@ jsr305 provided - - junit - junit + org.opendaylight.yangtools + binding-test-model + test + org.apache.commons commons-lang3 @@ -65,9 +66,9 @@ com.google.guava guava - - org.eclipse.xtend - org.eclipse.xtend.lib + junit + junit + test diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java index b75afa8b5d..3e10492e10 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java @@ -10,6 +10,9 @@ package org.opendaylight.yangtools.binding.data.codec.api; import java.util.Map; import java.util.Map.Entry; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -18,7 +21,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; /** * Serialization service, which provides two-way serialization between * Java Binding Data representation and NormalizedNode representation. - * */ public interface BindingNormalizedNodeSerializer { @@ -28,15 +30,16 @@ public interface BindingNormalizedNodeSerializer { * @param binding Binding Instance Identifier * @return DOM Instance Identifier */ - YangInstanceIdentifier toYangInstanceIdentifier(InstanceIdentifier binding); + YangInstanceIdentifier toYangInstanceIdentifier(@Nonnull InstanceIdentifier binding); /** * Translates supplied YANG Instance Identifier into Binding instance identifier. * * @param dom YANG Instance Identifier - * @return Binding Instance Identifier + * @return Binding Instance Identifier, or null if the instance identifier is not + * representable. */ - InstanceIdentifier fromYangInstanceIdentifier(YangInstanceIdentifier dom); + @Nullable InstanceIdentifier fromYangInstanceIdentifier(@Nonnull YangInstanceIdentifier dom); /** * Translates supplied Binding Instance Identifier and data into NormalizedNode representation. @@ -45,7 +48,7 @@ public interface BindingNormalizedNodeSerializer { * @param data Data object representing data * @return NormalizedNode representation */ - Entry> toNormalizedNode(InstanceIdentifier path, T data); + Entry> toNormalizedNode(InstanceIdentifier path, T data); /** * Translates supplied YANG Instance Identifier and NormalizedNode into Binding data. @@ -54,7 +57,7 @@ public interface BindingNormalizedNodeSerializer { * @param data NormalizedNode representing data * @return DOM Instance Identifier */ - Entry,DataObject> fromNormalizedNode(YangInstanceIdentifier path, NormalizedNode data); + @Nullable Entry,DataObject> fromNormalizedNode(@Nonnull YangInstanceIdentifier path, NormalizedNode data); /** * Returns map view which contains translated set of entries to normalized nodes. diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java index 46fd45960f..6d1e31c2b4 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java @@ -18,6 +18,7 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -25,6 +26,9 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import org.opendaylight.yangtools.binding.data.codec.impl.NodeCodecContext.CodecContextFactory; import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.concepts.Immutable; @@ -52,10 +56,13 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class BindingCodecContext implements CodecContextFactory, Immutable { - + private static final Logger LOG = LoggerFactory.getLogger(BindingCodecContext.class); private static final String GETTER_PREFIX = "get"; + private final SchemaRootCodecContext root; private final BindingRuntimeContext context; private final Codec> instanceIdentifierCodec = @@ -72,7 +79,7 @@ class BindingCodecContext implements CodecContextFactory, Immutable { return context; } - public Codec> getInstanceIdentifierCodec() { + Codec> getInstanceIdentifierCodec() { return instanceIdentifierCodec; } @@ -102,14 +109,27 @@ class BindingCodecContext implements CodecContextFactory, Immutable { return currentNode; } - public NodeCodecContext getCodecContextNode(final YangInstanceIdentifier dom, - final List builder) { + /** + * Multi-purpose utility function. Traverse the codec tree, looking for + * the appropriate codec for the specified {@link YangInstanceIdentifier}. + * As a side-effect, gather all traversed binding {@link InstanceIdentifier.PathArgument}s + * into the supplied collection. + * + * @param dom {@link YangInstanceIdentifier} which is to be translated + * @param bindingArguments Collection for traversed path arguments + * @return Codec for target node, or @null if the node does not have a + * binding representation (choice, case, leaf). + */ + @Nullable NodeCodecContext getCodecContextNode(final @Nonnull YangInstanceIdentifier dom, + final @Nonnull Collection bindingArguments) { NodeCodecContext currentNode = root; ListNodeCodecContext currentList = null; + for (YangInstanceIdentifier.PathArgument domArg : dom.getPathArguments()) { - Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext); - DataContainerCodecContext previous = (DataContainerCodecContext) currentNode; - NodeCodecContext nextNode = previous.getYangIdentifierChild(domArg); + Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext, "Unexpected child of non-container node %s", currentNode); + final DataContainerCodecContext previous = (DataContainerCodecContext) currentNode; + final NodeCodecContext nextNode = previous.getYangIdentifierChild(domArg); + /* * List representation in YANG Instance Identifier consists of two * arguments: first is list as a whole, second is list as an item so @@ -119,19 +139,13 @@ class BindingCodecContext implements CodecContextFactory, Immutable { * Identifier as Item or IdentifiableItem */ if (currentList != null) { + Preconditions.checkArgument(currentList == nextNode, "List should be referenced two times in YANG Instance Identifier %s", dom); - if (currentList == nextNode) { - - // We entered list, so now we have all information to emit - // list - // path using second list argument. - builder.add(currentList.getBindingPathArgument(domArg)); - currentList = null; - currentNode = nextNode; - } else { - throw new IllegalArgumentException( - "List should be referenced two times in YANG Instance Identifier"); - } + // We entered list, so now we have all information to emit + // list path using second list argument. + bindingArguments.add(currentList.getBindingPathArgument(domArg)); + currentList = null; + currentNode = nextNode; } else if (nextNode instanceof ListNodeCodecContext) { // We enter list, we do not update current Node yet, // since we need to verify @@ -141,24 +155,27 @@ class BindingCodecContext implements CodecContextFactory, Immutable { // it is not supported by binding instance identifier. currentNode = nextNode; } else if (nextNode instanceof DataContainerCodecContext) { - builder.add(((DataContainerCodecContext) nextNode).getBindingPathArgument(domArg)); + bindingArguments.add(((DataContainerCodecContext) nextNode).getBindingPathArgument(domArg)); currentNode = nextNode; } else if (nextNode instanceof LeafNodeCodecContext) { - Preconditions.checkArgument(builder == null, "Instance Identifier for leaf is not representable."); - + LOG.debug("Instance identifier referencing a leaf is not representable (%s)", dom); + return null; } } + // Algorithm ended in list as whole representation // we sill need to emit identifier for list - - if (builder != null) { - Preconditions.checkArgument(!(currentNode instanceof ChoiceNodeCodecContext), - "Instance Identifier for choice is not representable."); - Preconditions.checkArgument(!(currentNode instanceof CaseNodeCodecContext), - "Instance Identifier for case is not representable."); + if (currentNode instanceof ChoiceNodeCodecContext) { + LOG.debug("Instance identifier targeting a choice is not representable (%s)", dom); + return null; + } + if (currentNode instanceof CaseNodeCodecContext) { + LOG.debug("Instance identifier targeting a case is not representable (%s)", dom); + return null; } + if (currentList != null) { - builder.add(currentList.getBindingPathArgument(null)); + bindingArguments.add(currentList.getBindingPathArgument(null)); return currentList; } return currentNode; @@ -264,12 +281,11 @@ class BindingCodecContext implements CodecContextFactory, Immutable { } else if (rootType instanceof InstanceIdentifierTypeDefinition) { return ValueTypeCodec.encapsulatedValueCodecFor(valueType, instanceIdentifierCodec); } else if (rootType instanceof UnionTypeDefinition) { - Callable loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType, - getInstanceIdentifierCodec(), getIdentityCodec()); + Callable loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType); try { return loader.call(); } catch (Exception e) { - throw new IllegalStateException("Unable to load codec for "+valueType,e); + throw new IllegalStateException("Unable to load codec for " + valueType, e); } } return ValueTypeCodec.getCodecFor(valueType, instantiatedType); @@ -279,16 +295,16 @@ class BindingCodecContext implements CodecContextFactory, Immutable { @Override public YangInstanceIdentifier serialize(final InstanceIdentifier input) { - List domArgs = new LinkedList<>(); + List domArgs = new ArrayList<>(); getCodecContextNode(input, domArgs); return YangInstanceIdentifier.create(domArgs); } @Override public InstanceIdentifier deserialize(final YangInstanceIdentifier input) { - List builder = new LinkedList<>(); - getCodecContextNode(input, builder); - return InstanceIdentifier.create(builder); + final List builder = new ArrayList<>(); + final NodeCodecContext codec = getCodecContextNode(input, builder); + return codec == null ? null : InstanceIdentifier.create(builder); } } diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java index 9b772bd9dc..bfdad3efeb 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java @@ -16,7 +16,7 @@ import com.google.common.cache.LoadingCache; import java.io.IOException; import java.util.AbstractMap.SimpleEntry; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -34,7 +34,9 @@ import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -74,23 +76,21 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR @Override public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier binding) { - List builder = new LinkedList<>(); - codecContext.getCodecContextNode(binding, builder); return codecContext.getInstanceIdentifierCodec().serialize(binding); } @Override public InstanceIdentifier fromYangInstanceIdentifier(final YangInstanceIdentifier dom) { return codecContext.getInstanceIdentifierCodec().deserialize(dom); - } + } @Override public Entry> toNormalizedNode(final InstanceIdentifier path, final T data) { NormalizedNodeResult result = new NormalizedNodeResult(); - // We create dom stream writer which produces normalized nodes + // We create DOM stream writer which produces normalized nodes NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result); - // We create Binding Stream Writer wchich translates from Binding to Normalized Nodes + // We create Binding Stream Writer which translates from Binding to Normalized Nodes Entry writeCtx = codecContext.newWriter(path, domWriter); // We get serializer which reads binding data and uses Binding To Normalized Node writer to write result @@ -103,26 +103,51 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR return new SimpleEntry>(writeCtx.getKey(),result.getResult()); } - private boolean isBindingRepresentable(final NormalizedNode data) { - return !(data instanceof MapNode) && !(data instanceof UnkeyedListNode) && !(data instanceof LeafSetNode) && !(data instanceof LeafNode); - } + private static boolean isBindingRepresentable(final NormalizedNode data) { + if (data instanceof ChoiceNode) { + return false; + } + if (data instanceof LeafNode) { + return false; + } + if (data instanceof LeafSetNode) { + return false; + } + if( data instanceof LeafSetEntryNode) { + return false; + } + if (data instanceof MapNode) { + return false; + } + if (data instanceof UnkeyedListNode) { + return false; + } + return true; + } @Override - public Entry, DataObject> fromNormalizedNode(final YangInstanceIdentifier path, - final NormalizedNode data) { - List builder = new LinkedList<>(); - if(isBindingRepresentable(data)) { - DataObject lazyObj = (DataObject) codecContext.getCodecContextNode(path, builder).dataFromNormalizedNode(data); - InstanceIdentifier bindingPath = InstanceIdentifier.create(builder); - return new SimpleEntry, DataObject>(bindingPath,lazyObj); + public Entry, DataObject> fromNormalizedNode(final YangInstanceIdentifier path, final NormalizedNode data) { + if (!isBindingRepresentable(data)) { + return null; } - return null; + + final List builder = new ArrayList<>(); + final NodeCodecContext codec = codecContext.getCodecContextNode(path, builder); + if (codec == null) { + if (data != null) { + LOG.warn("Path {} does not have a binding equivalent, should have been caught earlier ({})", path, data.getClass()); + } + return null; + } + + final DataObject lazyObj = (DataObject) codec.dataFromNormalizedNode(data); + final InstanceIdentifier bindingPath = InstanceIdentifier.create(builder); + return new SimpleEntry, DataObject>(bindingPath, lazyObj); } @Override - public Map, DataObject> fromNormalizedNodes( - final Map> dom) { + public Map, DataObject> fromNormalizedNodes(final Map> dom) { throw new UnsupportedOperationException("Not implemented yet"); } @@ -144,8 +169,8 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR private static class DeserializeFunction implements Function>, Optional> { - private final DataObjectCodecContext ctx; + public DeserializeFunction(final DataObjectCodecContext ctx) { super(); this.ctx = ctx; @@ -159,8 +184,6 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR } return Optional.absent(); } - - } private class GeneratorLoader extends CacheLoader, DataObjectSerializer> { diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java index 700476f86b..bac768703c 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java @@ -11,8 +11,13 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; + import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -36,20 +41,50 @@ final class ChoiceNodeCodecContext extends DataContainerCodecContext Map> byYangCaseChildBuilder = new HashMap<>(); Map, DataContainerCodecPrototype> byClassBuilder = new HashMap<>(); Map, DataContainerCodecPrototype> byCaseChildClassBuilder = new HashMap<>(); - + Set> potentialSubstitutions = new HashSet<>(); + // Walks all cases for supplied choice in current runtime context for (Class caze : factory().getRuntimeContext().getCases(bindingClass())) { + // We try to load case using exact match thus name + // and original schema must equals DataContainerCodecPrototype cazeDef = loadCase(caze); + // If we have case definition, this case is instantiated + // at current location and thus is valid in context of parent choice if (cazeDef != null) { byClassBuilder.put(cazeDef.getBindingClass(), cazeDef); + // Updates collection of case children for (Class cazeChild : BindingReflections.getChildrenClasses((Class) caze)) { byCaseChildClassBuilder.put(cazeChild, cazeDef); } + // Updates collection of YANG instance identifier to case for (DataSchemaNode cazeChild : cazeDef.getSchema().getChildNodes()) { byYangCaseChildBuilder.put(new NodeIdentifier(cazeChild.getQName()), cazeDef); } + } else { + /* + * If case definition is not available, we store it for + * later check if it could be used as substitution of existing one. + */ + potentialSubstitutions.add(caze); } } + Map, DataContainerCodecPrototype> bySubstitutionBuilder = new HashMap<>(); + /* + * Walks all cases which are not directly instantiated and + * tries to match them to instantiated cases - represent same data as instantiated case, + * only case name or schema path is different. This is required due property of + * binding specification, that if choice is in grouping schema path location is lost, + * and users may use incorrect case class using copy builders. + */ + for(Class substitution : potentialSubstitutions) { + search: for(Entry, DataContainerCodecPrototype> real : byClassBuilder.entrySet()) { + if(BindingReflections.isSubstitutionFor(substitution, real.getKey())) { + bySubstitutionBuilder.put(substitution, real.getValue()); + break search; + } + } + } + byClassBuilder.putAll(bySubstitutionBuilder); byYangCaseChild = ImmutableMap.copyOf(byYangCaseChildBuilder); byClass = ImmutableMap.copyOf(byClassBuilder); byCaseChildClass = ImmutableMap.copyOf(byCaseChildClassBuilder); diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java index 32fdf6d80e..19a9600f62 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java @@ -107,6 +107,29 @@ abstract class DataObjectCodecContext extends DataC @Override protected DataContainerCodecContext getStreamChild(final Class childClass) { DataContainerCodecPrototype childProto = byStreamClass.get(childClass); + if (childProto != null) { + return childProto.get(); + } + + if (Augmentation.class.isAssignableFrom(childClass)) { + /* + * It is potentially mismatched valid augmentation - we look up equivalent augmentation + * using reflection and walk all stream child and compare augmenations classes + * if they are equivalent. + * + * FIXME: Cache mapping of mismatched augmentation to real one, to speed up lookup. + */ + Class augTarget = BindingReflections.findAugmentationTarget((Class) childClass); + if ((bindingClass().equals(augTarget))) { + for (DataContainerCodecPrototype realChild : byStreamClass.values()) { + if (Augmentation.class.isAssignableFrom(realChild.getBindingClass()) + && BindingReflections.isSubstitutionFor(childClass,realChild.getBindingClass())) { + childProto = realChild; + break; + } + } + } + } Preconditions.checkArgument(childProto != null, " Child %s is not valid child.",childClass); return childProto.get(); } diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnionTypeCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnionTypeCodec.java index 6cbcc5c156..f94673c288 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnionTypeCodec.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnionTypeCodec.java @@ -8,13 +8,14 @@ package org.opendaylight.yangtools.binding.data.codec.impl; import com.google.common.collect.ImmutableSet; + import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Callable; -import org.opendaylight.yangtools.concepts.Codec; + import org.opendaylight.yangtools.yang.binding.BindingMapping; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; @@ -34,12 +35,10 @@ final class UnionTypeCodec extends ReflectionBasedCodec { } } - @SuppressWarnings("rawtypes") - static final Callable loader(final Class unionCls,final UnionTypeDefinition unionType, final Codec instanceIdentifier, final Codec identity) { + static final Callable loader(final Class unionCls, final UnionTypeDefinition unionType) { return new Callable() { - @Override - public UnionTypeCodec call() throws Exception { + public UnionTypeCodec call() throws NoSuchMethodException, SecurityException { Set values = new HashSet<>(); for(TypeDefinition subtype : unionType.getTypes()) { String methodName = "get" + BindingMapping.getClassName(subtype.getQName()); diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AbstractBindingRuntimeTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AbstractBindingRuntimeTest.java new file mode 100644 index 0000000000..a56364cad1 --- /dev/null +++ b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AbstractBindingRuntimeTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.binding.data.codec.test; + +import org.junit.Before; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public abstract class AbstractBindingRuntimeTest { + + private SchemaContext schemaContext; + private BindingRuntimeContext runtimeContext; + + @Before + public void setup() { + ModuleInfoBackedContext ctx = ModuleInfoBackedContext.create(); + ctx.addModuleInfos(BindingReflections.loadModuleInfos()); + schemaContext = ctx.tryToCreateSchemaContext().get(); + runtimeContext = BindingRuntimeContext.create(ctx, schemaContext); + + } + + public SchemaContext getSchemaContext() { + return schemaContext; + } + + public BindingRuntimeContext getRuntimeContext() { + return runtimeContext; + } +} diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java new file mode 100644 index 0000000000..62d913f8b6 --- /dev/null +++ b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.binding.data.codec.test; + +import javassist.ClassPool; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUses; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; + + +public class AugmentationSubstitutionTest extends AbstractBindingRuntimeTest { + + private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); + private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier.builder(Top.class) + .child(TopLevelList.class, TOP_FOO_KEY).toInstance(); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST + .augmentation(TreeLeafOnlyAugment.class); + private static final InstanceIdentifier BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST + .augmentation(TreeComplexUsesAugment.class); + private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); + + private BindingNormalizedNodeCodecRegistry registry; + + @Override + public void setup() { + super.setup(); + JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); + registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils)); + registry.onBindingRuntimeContextUpdated(getRuntimeContext()); + } + + @Test + public void augmentationInGroupingSubstituted() { + TopLevelList baRpc = new TopLevelListBuilder() + .setKey(TOP_FOO_KEY) + .addAugmentation(RpcComplexUsesAugment.class, new RpcComplexUsesAugmentBuilder(createComplexData()).build()) + .build(); + TopLevelList baTree = new TopLevelListBuilder() + .setKey(TOP_FOO_KEY) + .addAugmentation(TreeComplexUsesAugment.class, new TreeComplexUsesAugmentBuilder(createComplexData()).build()) + .build(); + NormalizedNode domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue(); + NormalizedNode domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue(); + assertEquals(domTreeEntry, domRpcEntry); + } + + private RpcComplexUsesAugment createComplexData() { + return new RpcComplexUsesAugmentBuilder() + .setContainerWithUses(new ContainerWithUsesBuilder() + .setLeafFromGrouping("foo") + .build()) + .setListViaUses(Collections.emptyList()) + .build(); + } + +} diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CaseSubstitutionTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CaseSubstitutionTest.java new file mode 100644 index 0000000000..a01e12d172 --- /dev/null +++ b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CaseSubstitutionTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.binding.data.codec.test; + +import javassist.ClassPool; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUses; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.put.top.input.top.level.list.choice.in.list.ComplexViaUsesWithDifferentNameBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.top.top.level.list.choice.in.list.ComplexViaUsesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; + + +public class CaseSubstitutionTest extends AbstractBindingRuntimeTest { + + private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); + private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier.builder(Top.class) + .child(TopLevelList.class, TOP_FOO_KEY).toInstance(); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST + .augmentation(TreeLeafOnlyAugment.class); + private static final InstanceIdentifier BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST + .augmentation(TreeComplexUsesAugment.class); + private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); + + private BindingNormalizedNodeCodecRegistry registry; + + @Override + public void setup() { + super.setup(); + JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); + registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils)); + registry.onBindingRuntimeContextUpdated(getRuntimeContext()); + } + + @Test + public void choiceInGroupingSubstituted() { + TopLevelList baRpc = new TopLevelListBuilder() + .setKey(TOP_FOO_KEY) + .setChoiceInList(new ComplexViaUsesWithDifferentNameBuilder(createComplexData()).build()) + .build(); + TopLevelList baTree = new TopLevelListBuilder() + .setKey(TOP_FOO_KEY) + .setChoiceInList(new ComplexViaUsesBuilder(createComplexData()).build()) + .build(); + NormalizedNode domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue(); + NormalizedNode domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue(); + assertEquals(domTreeEntry, domRpcEntry); + } + + private RpcComplexUsesAugment createComplexData() { + return new RpcComplexUsesAugmentBuilder() + .setContainerWithUses(new ContainerWithUsesBuilder() + .setLeafFromGrouping("foo") + .build()) + .setListViaUses(Collections.emptyList()) + .build(); + } + +} diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierSerializeDeserializeTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierSerializeDeserializeTest.java new file mode 100644 index 0000000000..67b7d1f903 --- /dev/null +++ b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierSerializeDeserializeTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.binding.data.codec.test; + +import com.google.common.collect.Iterables; +import javassist.ClassPool; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class InstanceIdentifierSerializeDeserializeTest extends AbstractBindingRuntimeTest{ + public static final String TOP_LEVEL_LIST_KEY_VALUE = "foo"; + + private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); + private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier + .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).toInstance(); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY = + BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class); + private static final InstanceIdentifier BA_TREE_COMPLEX_USES = + BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class); + + public static final QName TOP_QNAME = + QName.create("urn:opendaylight:params:xml:ns:yang:yangtools:test:binding", "2014-07-01", "top"); + public static final QName TOP_LEVEL_LIST_QNAME = QName.create(TOP_QNAME, "top-level-list"); + public static final QName TOP_LEVEL_LIST_KEY = QName.create(TOP_QNAME, "name"); + private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); + + public static final YangInstanceIdentifier BI_TOP_PATH = YangInstanceIdentifier.builder().node(TOP_QNAME).build(); + public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_PATH = BI_TOP_PATH.node(TOP_LEVEL_LIST_QNAME); + public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_1_PATH = BI_TOP_LEVEL_LIST_PATH + .node(new YangInstanceIdentifier.NodeIdentifierWithPredicates(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY, TOP_LEVEL_LIST_KEY_VALUE)); + + private BindingNormalizedNodeCodecRegistry registry; + + @Before + public void setup() { + super.setup(); + JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); + registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils)); + registry.onBindingRuntimeContextUpdated(getRuntimeContext()); + } + + @Test + public void testYangIIToBindingAwareII() { + InstanceIdentifier instanceIdentifier = registry.fromYangInstanceIdentifier(BI_TOP_PATH); + assertEquals(Top.class, instanceIdentifier.getTargetType()); + } + + @Test + public void testYangIIToBindingAwareIIListWildcarded() { + InstanceIdentifier instanceIdentifier = registry.fromYangInstanceIdentifier(BI_TOP_LEVEL_LIST_PATH); + assertEquals(TopLevelList.class, instanceIdentifier.getTargetType()); + assertTrue(instanceIdentifier.isWildcarded()); + } + + @Test + public void testYangIIToBindingAwareIIListWithKey() { + InstanceIdentifier instanceIdentifier = registry.fromYangInstanceIdentifier(BI_TOP_LEVEL_LIST_1_PATH); + InstanceIdentifier.PathArgument last = Iterables.getLast(instanceIdentifier.getPathArguments()); + assertEquals(TopLevelList.class, instanceIdentifier.getTargetType()); + assertFalse(instanceIdentifier.isWildcarded()); + assertTrue(last instanceof InstanceIdentifier.IdentifiableItem); + Identifier key = ((InstanceIdentifier.IdentifiableItem) last).getKey(); + assertEquals(TopLevelListKey.class, key.getClass()); + assertEquals(TOP_LEVEL_LIST_KEY_VALUE, ((TopLevelListKey)key).getName()); + } + + @Test + public void testBindingAwareIIToYangIContainer() { + YangInstanceIdentifier yangInstanceIdentifier = registry.toYangInstanceIdentifier( + InstanceIdentifier.create(Top.class).child(TopLevelList.class)); + YangInstanceIdentifier.PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument(); + assertTrue(lastPathArgument instanceof YangInstanceIdentifier.NodeIdentifier); + assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType()); + } + + @Test + public void testBindingAwareIIToYangIIWildcard() { + YangInstanceIdentifier yangInstanceIdentifier = registry.toYangInstanceIdentifier( + InstanceIdentifier.create(Top.class).child(TopLevelList.class)); + YangInstanceIdentifier.PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument(); + assertTrue(lastPathArgument instanceof YangInstanceIdentifier.NodeIdentifier); + assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType()); + } + + @Test + public void testBindingAwareIIToYangIIListWithKey() { + YangInstanceIdentifier yangInstanceIdentifier = registry.toYangInstanceIdentifier( + InstanceIdentifier.create(Top.class).child(TopLevelList.class, TOP_FOO_KEY)); + YangInstanceIdentifier.PathArgument lastPathArgument = yangInstanceIdentifier.getLastPathArgument(); + assertTrue(lastPathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates); + assertTrue(((YangInstanceIdentifier.NodeIdentifierWithPredicates) lastPathArgument).getKeyValues().containsValue(TOP_LEVEL_LIST_KEY_VALUE)); + assertEquals(TopLevelList.QNAME, lastPathArgument.getNodeType()); + } + + @Test + public void testBindingAwareIIToYangIIAugmentation() { + YangInstanceIdentifier.PathArgument lastArg = registry.toYangInstanceIdentifier(BA_TREE_COMPLEX_USES).getLastPathArgument(); + assertTrue(lastArg instanceof YangInstanceIdentifier.AugmentationIdentifier); + } + + @Test + public void testBindingAwareIIToYangIILeafOnlyAugmentation() { + YangInstanceIdentifier.PathArgument leafOnlyLastArg = registry.toYangInstanceIdentifier(BA_TREE_LEAF_ONLY).getLastPathArgument(); + assertTrue(leafOnlyLastArg instanceof YangInstanceIdentifier.AugmentationIdentifier); + assertTrue(((YangInstanceIdentifier.AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME)); + } +} diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierTest.java new file mode 100644 index 0000000000..e011017894 --- /dev/null +++ b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.binding.data.codec.test; + +import javassist.ClassPool; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +public class InstanceIdentifierTest extends AbstractBindingRuntimeTest { + + private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); + private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier.builder(Top.class) + .child(TopLevelList.class, TOP_FOO_KEY).toInstance(); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST + .augmentation(TreeLeafOnlyAugment.class); + private static final InstanceIdentifier BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST + .augmentation(TreeComplexUsesAugment.class); + private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); + + private BindingNormalizedNodeCodecRegistry registry; + + @Override + public void setup() { + super.setup(); + JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); + registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils)); + registry.onBindingRuntimeContextUpdated(getRuntimeContext()); + } + + @Test + public void testComplexAugmentationSerialization() { + YangInstanceIdentifier yangII = registry.toYangInstanceIdentifier(BA_TREE_COMPLEX_USES); + PathArgument lastArg = yangII.getLastPathArgument(); + assertTrue("Last argument should be AugmentationIdentifier", lastArg instanceof AugmentationIdentifier); + InstanceIdentifier bindingII = registry.fromYangInstanceIdentifier(yangII); + assertEquals(BA_TREE_COMPLEX_USES, bindingII); + } + + @Test + public void testLeafOnlyAugmentationSerialization() { + PathArgument leafOnlyLastArg = registry.toYangInstanceIdentifier(BA_TREE_LEAF_ONLY).getLastPathArgument(); + assertTrue("Last argument should be AugmentationIdentifier", leafOnlyLastArg instanceof AugmentationIdentifier); + assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME)); + } + +} diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NormalizedNodeSerializeDeserializeTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NormalizedNodeSerializeDeserializeTest.java new file mode 100644 index 0000000000..4b08fbe17f --- /dev/null +++ b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NormalizedNodeSerializeDeserializeTest.java @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.binding.data.codec.test; + +import javassist.ClassPool; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.ChoiceContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.ChoiceContainerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.TopBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.choice.identifier.ExtendedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.choice.identifier.extended.ExtendedIdBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedListKey; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.top; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.topLevelList; +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode; +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry; +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder; +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder; + +public class NormalizedNodeSerializeDeserializeTest extends AbstractBindingRuntimeTest{ + + public static final String TOP_LEVEL_LIST_FOO_KEY_VALUE = "foo"; + public static final TopLevelListKey TOP_LEVEL_LIST_FOO_KEY = new TopLevelListKey(TOP_LEVEL_LIST_FOO_KEY_VALUE); + + public static final QName TOP_QNAME = + QName.create("urn:opendaylight:params:xml:ns:yang:yangtools:test:binding", "2014-07-01", "top"); + public static final QName TOP_LEVEL_LIST_QNAME = QName.create(TOP_QNAME, "top-level-list"); + public static final QName TOP_LEVEL_LIST_KEY_QNAME = QName.create(TOP_QNAME, "name"); + public static final QName TOP_LEVEL_LEAF_LIST_QNAME = QName.create(TOP_QNAME, "top-level-leaf-list"); + public static final QName NESTED_LIST_QNAME = QName.create(TOP_QNAME, "nested-list"); + public static final QName NESTED_LIST_KEY_QNAME = QName.create(TOP_QNAME, "name"); + public static final QName CHOICE_CONTAINER_QNAME = + QName.create("urn:opendaylight:params:xml:ns:yang:yangtools:test:binding", "2014-07-01", "choice-container"); + public static final QName CHOICE_IDENTIFIER_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "identifier"); + public static final QName CHOICE_IDENTIFIER_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "id"); + public static final QName SIMPLE_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "simple-id"); + public static final QName EXTENDED_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "extended-id"); + private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); + + private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier + .builder(Top.class).child(TopLevelList.class, TOP_LEVEL_LIST_FOO_KEY).toInstance(); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY = + BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class); + private static final InstanceIdentifier BA_TREE_COMPLEX_USES = + BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class); + + public static final YangInstanceIdentifier BI_TOP_PATH = YangInstanceIdentifier.of(TOP_QNAME); + public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_PATH = BI_TOP_PATH.node(TOP_LEVEL_LIST_QNAME); + public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_FOO_PATH = BI_TOP_LEVEL_LIST_PATH + .node(new YangInstanceIdentifier.NodeIdentifierWithPredicates(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)); + public static final YangInstanceIdentifier BI_CHOICE_CONTAINER_PATH = YangInstanceIdentifier.of(CHOICE_CONTAINER_QNAME); + + private BindingNormalizedNodeCodecRegistry registry; + + @Before + public void setup() { + super.setup(); + JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); + registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils)); + registry.onBindingRuntimeContextUpdated(getRuntimeContext()); + } + + @Test + public void containerToNormalized() { + Map.Entry> entry = + registry.toNormalizedNode(InstanceIdentifier.create(Top.class), top()); + ContainerNode topNormalized = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_QNAME)) + .withChild(mapNodeBuilder(TOP_LEVEL_LIST_QNAME).build()).build(); + assertEquals(topNormalized, entry.getValue()); + } + + @Test + public void containerFromNormalized() { + ContainerNode topNormalized = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_QNAME)) + .withChild(mapNodeBuilder(TOP_LEVEL_LIST_QNAME).build()).build(); + Map.Entry, DataObject> entry = registry.fromNormalizedNode(BI_TOP_PATH, topNormalized); + assertEquals(top(), entry.getValue()); + } + + @Test + public void listWithKeysToNormalized() { + Map.Entry> entry = + registry.toNormalizedNode(BA_TOP_LEVEL_LIST, topLevelList(TOP_LEVEL_LIST_FOO_KEY)); + MapEntryNode topLevelListNormalized = ImmutableMapEntryNodeBuilder.create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifierWithPredicates( + TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .build(); + assertEquals(topLevelListNormalized, entry.getValue()); + } + + @Test + public void listWithKeysFromNormalized() { + MapEntryNode topLevelListNormalized = ImmutableMapEntryNodeBuilder.create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifierWithPredicates( + TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .build(); + Map.Entry, DataObject> entry = + registry.fromNormalizedNode(BI_TOP_LEVEL_LIST_FOO_PATH, topLevelListNormalized); + assertEquals(topLevelList(TOP_LEVEL_LIST_FOO_KEY), entry.getValue()); + } + + @Test + public void leafOnlyAugmentationToNormalized() { + Map.Entry> entry = + registry.toNormalizedNode(BA_TREE_LEAF_ONLY, new TreeLeafOnlyAugmentBuilder().setSimpleValue("simpleValue").build()); + Set augmentationChildren = new HashSet<>(); + augmentationChildren.add(SIMPLE_VALUE_QNAME); + AugmentationNode augmentationNode = ImmutableAugmentationNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.AugmentationIdentifier(augmentationChildren)) + .withChild(leafNode(SIMPLE_VALUE_QNAME, "simpleValue")) + .build(); + assertEquals(augmentationNode, entry.getValue()); + } + + @Test + public void leafOnlyAugmentationFromNormalized() { + Set augmentationChildren = new HashSet<>(); + augmentationChildren.add(SIMPLE_VALUE_QNAME); + AugmentationNode augmentationNode = ImmutableAugmentationNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.AugmentationIdentifier(augmentationChildren)) + .withChild(leafNode(SIMPLE_VALUE_QNAME, "simpleValue")) + .build(); + Map.Entry, DataObject> entry = registry.fromNormalizedNode(BI_TOP_LEVEL_LIST_FOO_PATH.node( + new YangInstanceIdentifier.AugmentationIdentifier(augmentationChildren)), augmentationNode); + assertEquals(new TreeLeafOnlyAugmentBuilder().setSimpleValue("simpleValue").build(), entry.getValue()); + } + + @Test + public void leafListToNormalized() { + List topLevelLeafList = new ArrayList<>(); + topLevelLeafList.add("foo"); + Top top = new TopBuilder().setTopLevelLeafList(topLevelLeafList).build(); + + Map.Entry> entry = + registry.toNormalizedNode(InstanceIdentifier.create(Top.class), top); + ContainerNode containerNode = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_QNAME)) + .withChild(ImmutableLeafSetNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_LEVEL_LEAF_LIST_QNAME)) + .withChild( + ImmutableLeafSetEntryNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeWithValue(TOP_LEVEL_LEAF_LIST_QNAME, "foo")) + .withValue("foo") + .build()) + .build()) + .build(); + assertEquals(containerNode, entry.getValue()); + } + + @Test + public void leafListFromNormalized() { + ContainerNode topWithLeafList = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_QNAME)) + .withChild(ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_LEVEL_LEAF_LIST_QNAME)) + .withChild(ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier( + new YangInstanceIdentifier.NodeWithValue(TOP_LEVEL_LEAF_LIST_QNAME, "foo")).withValue("foo").build()).build()) + .build(); + Map.Entry, DataObject> entry = registry.fromNormalizedNode(BI_TOP_PATH, topWithLeafList); + List topLevelLeafList = new ArrayList<>(); + topLevelLeafList.add("foo"); + Top top = new TopBuilder().setTopLevelLeafList(topLevelLeafList).build(); + assertEquals(top, entry.getValue()); + } + + @Test + public void choiceToNormalized() { + ChoiceContainer choiceContainerBA = new ChoiceContainerBuilder().setIdentifier(new ExtendedBuilder().setExtendedId( + new ExtendedIdBuilder().setId("identifier_value").build()).build()).build(); + Map.Entry> entry = + registry.toNormalizedNode(InstanceIdentifier.create(ChoiceContainer.class), choiceContainerBA); + ContainerNode choiceContainer = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_CONTAINER_QNAME)) + .withChild(ImmutableChoiceNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_IDENTIFIER_QNAME)) + .withChild(ImmutableContainerNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(EXTENDED_ID_QNAME)) + .withChild(leafNode(CHOICE_IDENTIFIER_ID_QNAME, "identifier_value")).build()).build()) + .build(); + assertEquals(choiceContainer, entry.getValue()); + } + + @Test + public void choiceFromNormalized() { + ContainerNode choiceContainerBI = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_CONTAINER_QNAME)) + .withChild(ImmutableChoiceNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_IDENTIFIER_QNAME)) + .withChild(ImmutableContainerNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(EXTENDED_ID_QNAME)) + .withChild(leafNode(CHOICE_IDENTIFIER_ID_QNAME, "identifier_value")).build()).build()) + .build(); + Map.Entry, DataObject> entry = registry.fromNormalizedNode(BI_CHOICE_CONTAINER_PATH, choiceContainerBI); + ChoiceContainer choiceContainerBA = new ChoiceContainerBuilder().setIdentifier(new ExtendedBuilder().setExtendedId( + new ExtendedIdBuilder().setId("identifier_value").build()).build()).build(); + assertEquals(choiceContainerBA, entry.getValue()); + } + + @Test + public void orderedLisToNormalized() { + InstanceIdentifier ii = BA_TOP_LEVEL_LIST; + List nestedLists = new ArrayList<>(); + nestedLists.add(new NestedListBuilder().setKey(new NestedListKey("foo")).build()); + nestedLists.add(new NestedListBuilder().setKey(new NestedListKey("bar")).build()); + TopLevelList topLevelList = new TopLevelListBuilder().setKey(TOP_LEVEL_LIST_FOO_KEY).setNestedList(nestedLists).build(); + Map.Entry> entry = registry.toNormalizedNode(ii, topLevelList); + MapEntryNode foo = mapEntryBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifierWithPredicates( + TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .withChild( + ImmutableOrderedMapNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)) + .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "foo")) + .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "bar")).build()).build(); + assertEquals(foo, entry.getValue()); + } + + @Test + public void orderedLisFromNormalized() { + MapEntryNode foo = mapEntryBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifierWithPredicates( + TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE)) + .withChild( + ImmutableOrderedMapNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)) + .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "foo")) + .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "bar")).build()).build(); + InstanceIdentifier ii = BA_TOP_LEVEL_LIST; + + Map.Entry, DataObject> entry = registry.fromNormalizedNode(BI_TOP_LEVEL_LIST_FOO_PATH, foo); + List nestedLists = new ArrayList<>(); + nestedLists.add(new NestedListBuilder().setKey(new NestedListKey("foo")).build()); + nestedLists.add(new NestedListBuilder().setKey(new NestedListKey("bar")).build()); + TopLevelList topLevelList = new TopLevelListBuilder().setKey(TOP_LEVEL_LIST_FOO_KEY).setNestedList(nestedLists).build(); + assertEquals(topLevelList, entry.getValue()); + } +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java index befe3e88e0..af67e659b3 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java @@ -30,7 +30,6 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findP import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -39,7 +38,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; - import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil; import org.opendaylight.yangtools.binding.generator.util.BindingTypes; import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl; @@ -310,7 +308,7 @@ public class BindingGeneratorImpl implements BindingGenerator { return null; } final String packageName = packageNameForGeneratedType(basePackageName, node.getPath()); - final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf); + final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module); genType.addComment(node.getDescription()); genType.setDescription(createDescription(node, genType.getFullyQualifiedName())); genType.setModuleName(module.getName()); @@ -556,7 +554,7 @@ public class BindingGeneratorImpl implements BindingGenerator { processUsesAugments(notification, module); final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(basePackageName, - notification, BindingTypes.DATA_OBJECT); + notification, BindingTypes.DATA_OBJECT, module); notificationInterface.addImplementsType(NOTIFICATION); genCtx.get(module).addChildNodeType(notification, notificationInterface); @@ -704,7 +702,7 @@ public class BindingGeneratorImpl implements BindingGenerator { */ private void groupingToGenType(final String basePackageName, final GroupingDefinition grouping, final Module module) { final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath()); - final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping); + final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping, module); genCtx.get(module).addGroupingType(grouping.getPath(), genType); resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes()); groupingsToGenTypes(module, grouping.getGroupings()); @@ -1204,7 +1202,7 @@ public class BindingGeneratorImpl implements BindingGenerator { for (ChoiceCaseNode caseNode : caseNodes) { if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) { final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath()); - final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode); + final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module); caseTypeBuilder.addImplementsType(refChoiceType); genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder); genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode); @@ -1283,7 +1281,7 @@ public class BindingGeneratorImpl implements BindingGenerator { for (DataSchemaNode caseNode : augmentedNodes) { if (caseNode != null) { final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath()); - final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode); + final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module); caseTypeBuilder.addImplementsType(targetType); SchemaNode parent = null; @@ -1600,8 +1598,9 @@ public class BindingGeneratorImpl implements BindingGenerator { return returnType.toInstance(); } - private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode) { - return addDefaultInterfaceDefinition(packageName, schemaNode, null); + private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode, + final Module module) { + return addDefaultInterfaceDefinition(packageName, schemaNode, null, module); } /** @@ -1628,7 +1627,7 @@ public class BindingGeneratorImpl implements BindingGenerator { * @return generated type builder schemaNode */ private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode, - final Type parent) { + final Type parent, final Module module) { final GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, ""); if (parent == null) { it.addImplementsType(DATA_OBJECT); @@ -1640,6 +1639,7 @@ public class BindingGeneratorImpl implements BindingGenerator { } if (schemaNode instanceof DataNodeContainer) { + groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings()); addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it); } diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java index 7c8586ed8f..e532be5b9e 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java @@ -8,7 +8,6 @@ package org.opendaylight.yangtools.sal.binding.generator.impl; import com.google.common.collect.ImmutableList; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -19,7 +18,6 @@ import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; - import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -29,10 +27,10 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry; @@ -60,9 +58,9 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { public InstanceIdentifier deserialize( final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input) { Class baType = null; - List biArgs = input.getPath(); - List scannedPath = new ArrayList<>(biArgs.size()); - List baArgs = new ArrayList(biArgs.size()); + Iterable biArgs = input.getPathArguments(); + List scannedPath = new ArrayList<>(); + List baArgs = new ArrayList(); for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg : biArgs) { scannedPath.add(biArg.getNodeType()); diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java index 92047d1f22..f72856e1c1 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java @@ -15,7 +15,6 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; - import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collection; @@ -30,7 +29,6 @@ import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; - import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl; import org.opendaylight.yangtools.binding.generator.util.Types; import org.opendaylight.yangtools.concepts.Delegator; @@ -268,7 +266,7 @@ class LazyGeneratedCodecRegistry implements CodecRegistry, SchemaContextListener while (iterator.hasNext()) { QName arg = iterator.next(); DataSchemaNode currentNode = previous.getDataChildByName(arg); - if (currentNode == null && previous instanceof DataNodeContainer) { + if (currentNode == null) { currentNode = searchInChoices(previous, arg); } if (currentNode instanceof DataNodeContainer) { @@ -852,7 +850,7 @@ class LazyGeneratedCodecRegistry implements CodecRegistry, SchemaContextListener if (!parentQName.equals(choiceName)) { // This item is instantiation of choice via uses in other YANG // module - if (choiceName.getNamespace().equals(schema.getQName())) { + if (choiceName.getNamespace().equals(schema.getQName().getNamespace())) { // Original definition of grouping is in same namespace // as original definition of case // so for sure case is introduced via instantiation of diff --git a/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/NestedGroupingCompilationTest.java b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/NestedGroupingCompilationTest.java new file mode 100644 index 0000000000..62190fc498 --- /dev/null +++ b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/NestedGroupingCompilationTest.java @@ -0,0 +1,86 @@ +/* + * 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 + */ +package org.opendaylight.yangtools.sal.java.api.generator.test; + +import static org.junit.Assert.assertTrue; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.BASE_PKG; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.COMPILER_OUTPUT_PATH; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.FS; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.GENERATOR_OUTPUT_PATH; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.NS_TEST; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertFilesCount; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertImplementsIfc; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.cleanUp; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.getSourceFiles; +import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.testCompilation; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashSet; +import java.util.List; +import org.junit.Test; +import org.opendaylight.yangtools.sal.binding.model.api.Type; +import org.opendaylight.yangtools.sal.java.api.generator.GeneratorJavaFile; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * Test correct code generation. + * + */ +public class NestedGroupingCompilationTest extends BaseCompilationTest { + + @Test + public void testListGeneration() throws Exception { + final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "nested-grouping"); + assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir()); + final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "nested-grouping"); + assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir()); + + generateTestSources("/compilation/nested-grouping", sourcesOutputDir); + + // Test if all sources are generated + File parent = new File(sourcesOutputDir, NS_TEST); + File foo = new File(parent, "Foo.java"); + File fooBuilder = new File(parent, "FooBuilder.java"); + File testData = new File(parent, "TestData.java"); + File fooDir = new File(parent, "foo"); + assertTrue(foo.exists()); + assertTrue(fooBuilder.exists()); + assertTrue(testData.exists()); + assertTrue(fooDir.exists()); + assertFilesCount(parent, 4); + + parent = new File(parent, "foo"); + File bar = new File(parent, "Bar.java"); + assertTrue(bar.exists()); + assertFilesCount(parent, 1); + + // Test if sources are compilable + testCompilation(sourcesOutputDir, compiledOutputDir); + + ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() }); + Class fooClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.Foo", true, loader); + Class barClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.foo.Bar", true, loader); + + // Test generated 'foo' + assertTrue(fooClass.isInterface()); + assertImplementsIfc(fooClass, barClass); + + cleanUp(sourcesOutputDir, compiledOutputDir); + } + + private void generateTestSources(String resourceDirPath, File sourcesOutputDir) throws Exception { + final List sourceFiles = getSourceFiles(resourceDirPath); + final SchemaContext context = parser.parseFiles(sourceFiles); + final List types = bindingGenerator.generateTypes(context); + final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types)); + generator.generateToFile(sourcesOutputDir); + } + +} diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/nested-grouping/test.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/nested-grouping/test.yang new file mode 100644 index 0000000000..94cf5e1cba --- /dev/null +++ b/code-generator/binding-java-api-generator/src/test/resources/compilation/nested-grouping/test.yang @@ -0,0 +1,25 @@ +/* + * 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 + */ +module test { + yang-version 1; + namespace "urn:opendaylight:test"; + prefix "t"; + + revision "2013-10-08" { + } + + container foo { + grouping bar { + leaf id { + type int32; + } + } + uses bar; + } + +} diff --git a/code-generator/binding-test-model/pom.xml b/code-generator/binding-test-model/pom.xml new file mode 100644 index 0000000000..106c90439e --- /dev/null +++ b/code-generator/binding-test-model/pom.xml @@ -0,0 +1,67 @@ + + + + + + org.opendaylight.yangtools + binding-generator + 0.6.2-SNAPSHOT + + 4.0.0 + + + + org.opendaylight.yangtools + yang-binding + + + org.opendaylight.yangtools.model + yang-ext + + + + binding-test-model + + + + org.opendaylight.yangtools + yang-maven-plugin + + + + generate-sources + + + + + + org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl + + + target/generated-sources/sal + + + + true + + + + + + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + HEAD + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + diff --git a/code-generator/binding-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java b/code-generator/binding-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java new file mode 100644 index 0000000000..0d3e7e89ce --- /dev/null +++ b/code-generator/binding-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.test.model.util; + +import com.google.common.collect.ImmutableList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUses; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUsesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUsesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.TopBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedListKey; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.Arrays; + +public class ListsBindingUtils { + + private static final InstanceIdentifier TOP_PATH = InstanceIdentifier.create(Top.class); + + private ListsBindingUtils() { + throw new UnsupportedOperationException(); + } + + public static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); + public static final TopLevelListKey TOP_BAR_KEY = new TopLevelListKey("bar"); + public static final ListViaUsesKey USES_ONE_KEY = new ListViaUsesKey("one"); + public static final ListViaUsesKey USES_TWO_KEY = new ListViaUsesKey("two"); + + + public static InstanceIdentifier path(final TopLevelListKey key) { + return TOP_PATH.child(TopLevelList.class, key); + } + + public static InstanceIdentifier path(final TopLevelListKey top,final NestedListKey nested) { + return path(top).child(NestedList.class, nested); + } + + public static InstanceIdentifier path(final TopLevelListKey top,final ListViaUsesKey uses) { + return path(top).augmentation(TreeComplexUsesAugment.class).child(ListViaUses.class, uses); + } + + public static > InstanceIdentifier path(final TopLevelListKey key, final Class augmentation) { + return path(key).augmentation(augmentation); + } + + public static Top top(final TopLevelList... listItems) { + return new TopBuilder().setTopLevelList(Arrays.asList(listItems)).build(); + } + + public static TopLevelList topLevelList(final TopLevelListKey key) { + return new TopLevelListBuilder().setKey(key).build(); + } + + public static TopLevelList topLevelList(final TopLevelListKey key, final TreeComplexUsesAugment augment) { + TopLevelListBuilder builder = new TopLevelListBuilder().setKey(key); + builder.addAugmentation(TreeComplexUsesAugment.class, augment); + return builder.build(); + } + + public static TreeComplexUsesAugment complexUsesAugment(final ListViaUsesKey... keys) { + ImmutableList.Builder listViaUses = ImmutableList. builder(); + for (ListViaUsesKey key : keys) { + listViaUses.add(new ListViaUsesBuilder().setKey(key).build()); + } + return new TreeComplexUsesAugmentBuilder().setListViaUses(listViaUses.build()).build(); + } + + public static TreeLeafOnlyUsesAugment leafOnlyUsesAugment(String leafFromGroupingValue) { + + return new TreeLeafOnlyUsesAugmentBuilder().setLeafFromGrouping(leafFromGroupingValue).build(); + } + +} diff --git a/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-augment-test.yang b/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-augment-test.yang new file mode 100644 index 0000000000..6d155becc7 --- /dev/null +++ b/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-augment-test.yang @@ -0,0 +1,111 @@ +module opendaylight-yangtools-augment-test { + + namespace "urn:opendaylight:params:xml:ns:yang:yangtools:test:augment"; + prefix aug-test; + + import opendaylight-yangtools-binding-test { + prefix test; + } + import yang-ext { + prefix ext; + } + + description + "This module contains a collection of YANG augmentations used for + some test cases."; + + revision 2014-07-09 { + description + "Test model for testing data broker with nested lists."; + } + + grouping leaf-from-grouping { + leaf leaf-from-grouping { + type string; + } + } + + grouping complex-from-grouping { + container container-with-uses { + uses leaf-from-grouping; + } + list list-via-uses { + key "name"; + leaf name { + type string; + } + } + + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-leaf-only-uses-augment; + uses leaf-from-grouping; + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-leaf-only-uses-augment; + uses leaf-from-grouping; + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-complex-uses-augment; + uses complex-from-grouping; + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-complex-uses-augment; + uses complex-from-grouping; + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-leaf-only-augment; + + leaf simple-value { + type string; + } + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-second-leaf-only-augment; + + leaf second-simple-value { + type string; + } + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-leaf-only-augment; + + leaf simple-value { + type string; + } + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-second-leaf-only-augment; + + leaf second-simple-value { + type string; + } + } + + augment "/test:top/test:top-level-list/test:choice-in-list" { + case simple-via-uses { + uses leaf-from-grouping; + } + case complex-via-uses { + uses complex-from-grouping; + } + } + + augment "/test:put-top/test:input/test:top-level-list/test:choice-in-list" { + case simple-via-uses { + uses leaf-from-grouping; + } + case complex-via-uses-with-different-name { + uses complex-from-grouping; + } + } + +} diff --git a/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang b/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang new file mode 100644 index 0000000000..c5e5ce23b7 --- /dev/null +++ b/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang @@ -0,0 +1,86 @@ +module opendaylight-yangtools-binding-test { + + namespace "urn:opendaylight:params:xml:ns:yang:yangtools:test:binding"; + prefix list-test; + + + description + "This module contains a collection of YANG definitions used for + some test cases."; + + revision 2014-07-01 { + description + "Test model for testing data broker with nested lists."; + } + + grouping two-level-list { + list top-level-list { + description + "Top Level List"; + key "name"; + leaf name { + type string; + } + + choice choice-in-list { + case simple-case { + leaf simple { + type string; + } + } + } + + list nested-list { + key "name"; + leaf name { + type string; + } + leaf type { + type string; + mandatory true; + description + "Mandatory type of list."; + } + ordered-by user; + description + "A list of service functions that compose the service chain"; + } + } + leaf-list top-level-leaf-list { + type string; + } + } + + grouping choice { + choice identifier { + case simple { + container simple-id { + leaf id { + type int32; + } + } + } + case extended { + container extended-id { + leaf id { + type string; + } + } + } + } + } + + container top { + uses two-level-list; + } + + container choice-container { + uses choice; + } + + rpc put-top { + input { + uses two-level-list; + } + } +} diff --git a/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java b/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java index cf23c844de..f1864ab1b7 100644 --- a/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java +++ b/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java @@ -14,6 +14,9 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findD import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule; +import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; +import com.google.common.io.BaseEncoding; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; @@ -31,7 +34,6 @@ import java.util.Set; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; - import org.apache.commons.lang3.StringEscapeUtils; import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil; import org.opendaylight.yangtools.binding.generator.util.TypeConstants; @@ -90,10 +92,6 @@ import org.opendaylight.yangtools.yang.model.util.Uint64; import org.opendaylight.yangtools.yang.model.util.Uint8; import org.opendaylight.yangtools.yang.model.util.UnionType; -import com.google.common.base.Preconditions; -import com.google.common.collect.Sets; -import com.google.common.io.BaseEncoding; - public final class TypeProviderImpl implements TypeProvider { private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z"); @@ -810,11 +808,13 @@ public final class TypeProviderImpl implements TypeProvider { final List genTOBuilders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName, typedef, typeDefName, parentNode); GeneratedTOBuilder resultTOBuilder = null; - if (!genTOBuilders.isEmpty()) { - resultTOBuilder = genTOBuilders.remove(0); - for (GeneratedTOBuilder genTOBuilder : genTOBuilders) { - resultTOBuilder.addEnclosingTransferObject(genTOBuilder); - } + if (genTOBuilders.isEmpty()) { + throw new IllegalStateException("No GeneratedTOBuilder objects generated from union " + typedef); + } + + resultTOBuilder = genTOBuilders.remove(0); + for (GeneratedTOBuilder genTOBuilder : genTOBuilders) { + resultTOBuilder.addEnclosingTransferObject(genTOBuilder); } final GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value"); @@ -1062,7 +1062,7 @@ public final class TypeProviderImpl implements TypeProvider { final String packageName = packageNameForGeneratedType(basePackageName, typedef.getPath()); final String typeDefTOName = typedef.getQName().getLocalName(); - if ((packageName != null) && (typedef != null) && (typeDefTOName != null)) { + if ((packageName != null) && (typeDefTOName != null)) { final String genTOName = BindingMapping.getClassName(typeDefTOName); final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTOName); @@ -1300,9 +1300,8 @@ public final class TypeProviderImpl implements TypeProvider { typeDefinitionsConcreteDepth.add(unsortedTypeDefinition); } // keys are in ascending order - Set depths = typeDefinitionsDepths.keySet(); - for (Integer depth : depths) { - sortedTypeDefinition.addAll(typeDefinitionsDepths.get(depth)); + for (Map.Entry>> entry : typeDefinitionsDepths.entrySet()) { + sortedTypeDefinition.addAll(entry.getValue()); } return sortedTypeDefinition; diff --git a/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend b/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend index d8c4959296..f40cbcaa3d 100644 --- a/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend +++ b/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend @@ -975,9 +975,9 @@ class GeneratorImpl { «ENDIF» - «IF !path.path.empty» + «IF path.pathArguments.iterator.hasNext»

XML example

- «nodes.xmlExample(path.path.last.nodeType,path)» + «nodes.xmlExample(path.pathArguments.last.nodeType,path)» «ENDIF» «FOR childNode : containers» @@ -1045,8 +1045,8 @@ class GeneratorImpl { def header(int level,YangInstanceIdentifier name) ''' - - «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR» + + «FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR» ''' @@ -1152,7 +1152,7 @@ class GeneratorImpl { } def CharSequence localLink(YangInstanceIdentifier identifier, CharSequence text) ''' - «text» + «text» ''' @@ -1181,7 +1181,7 @@ class GeneratorImpl { append(currentModule.name) append(":") var previous = false; - for(arg : identifier.path) { + for(arg : identifier.pathArguments) { if(previous) append("/") append(arg.nodeType.localName); previous = true; diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java b/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java index 1208f190f3..1a1052baa1 100644 --- a/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java +++ b/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java @@ -82,13 +82,9 @@ public class YangModuleInfoCompilationTest { testCompilation(sourcesOutputDir, compiledOutputDir); // Create URLClassLoader - File[] roots = File.listRoots(); - URL[] urls = new URL[roots.length + 1]; - for (int i = 0; i < roots.length; i++) { - urls[i] = roots[i].toURI().toURL(); - - } - urls[roots.length] = compiledOutputDir.toURI().toURL(); + URL[] urls = new URL[2]; + urls[0] = compiledOutputDir.toURI().toURL(); + urls[1] = new File(System.getProperty("user.dir")).toURI().toURL(); ClassLoader loader = new URLClassLoader(urls); // Load class @@ -176,13 +172,16 @@ public class YangModuleInfoCompilationTest { private static List getSourceFiles(String path) throws Exception { final URI resPath = YangModuleInfoCompilationTest.class.getResource(path).toURI(); final File sourcesDir = new File(resPath); + final URI currentDir = new File(System.getProperty("user.dir")).toURI(); if (sourcesDir.exists()) { final List sourceFiles = new ArrayList<>(); final File[] fileArray = sourcesDir.listFiles(); if (fileArray == null) { throw new IllegalArgumentException("Unable to locate files in " + sourcesDir); } - sourceFiles.addAll(Arrays.asList(fileArray)); + for (File sourceFile : fileArray) { + sourceFiles.add(new File(currentDir.relativize(sourceFile.toURI()).toString())); + } return sourceFiles; } else { throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")"); diff --git a/code-generator/pom.xml b/code-generator/pom.xml index 4cdf7c23c7..fc239681b5 100644 --- a/code-generator/pom.xml +++ b/code-generator/pom.xml @@ -30,6 +30,7 @@ binding-java-api-generator binding-type-provider maven-sal-api-gen-plugin + binding-test-model binding-data-codec @@ -43,6 +44,11 @@
+ + org.opendaylight.yangtools + binding-test-model + ${project.version} + org.opendaylight.yangtools binding-model-api diff --git a/common/features/pom.xml b/common/features/pom.xml index 4fe4b110c2..a2eed6db1d 100644 --- a/common/features/pom.xml +++ b/common/features/pom.xml @@ -102,6 +102,10 @@ org.opendaylight.yangtools.model ietf-yang-types + + org.opendaylight.yangtools.model + ietf-yang-types-20130715 + org.opendaylight.yangtools.model yang-ext @@ -235,6 +239,10 @@ org.opendaylight.yangtools restconf-common + + org.opendaylight.yangtools + binding-data-codec + org.opendaylight.yangtools.thirdparty xtend-lib-osgi diff --git a/common/features/src/main/resources/features.xml b/common/features/src/main/resources/features.xml index 58b3ab1779..7f94b50c59 100644 --- a/common/features/src/main/resources/features.xml +++ b/common/features/src/main/resources/features.xml @@ -23,6 +23,7 @@ odl-yangtools-binding mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf.inet.types.version} mvn:org.opendaylight.yangtools.model/ietf-yang-types/${ietf.yang.types.version} + mvn:org.opendaylight.yangtools.model/ietf-yang-types-20130715/${ietf.yang.types.20130715.version} mvn:org.opendaylight.yangtools.model/yang-ext/${yang.ext.version} mvn:org.opendaylight.yangtools.model/opendaylight-l2-types/${opendaylight.l2.types.version} mvn:org.opendaylight.yangtools.model/ietf-topology/${ietf.topology.version} diff --git a/common/parent/pom.xml b/common/parent/pom.xml index ec653a59b4..57af4a168e 100644 --- a/common/parent/pom.xml +++ b/common/parent/pom.xml @@ -35,6 +35,7 @@ 2013.10.21.2-SNAPSHOT 2010.09.24.4-SNAPSHOT 2010.09.24.4-SNAPSHOT + 2013.07.15.1-SNAPSHOT 2013.10.19.1-SNAPSHOT 3.0.1 http://nexus.opendaylight.org/content @@ -254,6 +255,11 @@ ietf-yang-types 2010.09.24.4-SNAPSHOT + + org.opendaylight.yangtools.model + ietf-yang-types-20130715 + 2013.07.15.1-SNAPSHOT + org.opendaylight.yangtools.model ietf-restconf @@ -432,6 +438,11 @@ yang-data-operations ${project.version} + + org.opendaylight.yangtools + binding-data-codec + ${project.version} + org.opendaylight.yangtools features-test diff --git a/pom.xml b/pom.xml index 90a3e97e4d..7ad393fbc3 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,8 @@ restconf websocket yang - + benchmarks + diff --git a/restconf/restconf-jaxrs-api/src/main/java/org/opendaylight/yangtools/RestRestconfService.java b/restconf/restconf-jaxrs-api/src/main/java/org/opendaylight/yangtools/RestRestconfService.java index 11083c3129..a3c7146046 100644 --- a/restconf/restconf-jaxrs-api/src/main/java/org/opendaylight/yangtools/RestRestconfService.java +++ b/restconf/restconf-jaxrs-api/src/main/java/org/opendaylight/yangtools/RestRestconfService.java @@ -25,6 +25,8 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; @Path("restconf") public interface RestRestconfService { + public static final String IDENTIFIER = "identifier"; + public static final String INPUT = "input"; public static final String XML = "+xml"; public static final String JSON = "+json"; @@ -45,48 +47,48 @@ public interface RestRestconfService { @Consumes({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public String invokeRpc(@PathParam("identifier") String identifier, @QueryParam("input") CompositeNode payload); + public String invokeRpc(@PathParam(IDENTIFIER) String identifier, @QueryParam(INPUT) CompositeNode payload); @POST @Path("/operations/{identifier}") @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public String invokeRpc(@PathParam("identifier") String identifier); + public String invokeRpc(@PathParam(IDENTIFIER) String identifier); @GET @Path("/config/{identifier:.+}") @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public String readConfigurationData(@PathParam("identifier") String identifier); + public String readConfigurationData(@PathParam(IDENTIFIER) String identifier); @GET @Path("/operational/{identifier:.+}") @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public String readOperationalData(@PathParam("identifier") String identifier); + public String readOperationalData(@PathParam(IDENTIFIER) String identifier); @PUT @Path("/config/{identifier:.+}") @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public Response updateConfigurationData(@PathParam("identifier") String identifier,@QueryParam("input") CompositeNode payload); + public Response updateConfigurationData(@PathParam(IDENTIFIER) String identifier,@QueryParam(INPUT) CompositeNode payload); @POST @Path("/config/{identifier:.+}") @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public Response createConfigurationData(@PathParam("identifier") String identifier, @QueryParam("input") CompositeNode payload); + public Response createConfigurationData(@PathParam(IDENTIFIER) String identifier, @QueryParam(INPUT) CompositeNode payload); @POST @Path("/config") @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public Response createConfigurationData( @QueryParam("input") CompositeNode payload); + public Response createConfigurationData( @QueryParam(INPUT) CompositeNode payload); @DELETE @Path("/config/{identifier:.+}") - public Response deleteConfigurationData(@PathParam("identifier") String identifier); + public Response deleteConfigurationData(@PathParam(IDENTIFIER) String identifier); } diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java index f9f4c5c7b5..bc7474a9f2 100644 --- a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java +++ b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java @@ -16,12 +16,15 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; +import com.google.common.collect.Sets; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -581,4 +584,51 @@ public class BindingReflections { public static Map>, Augmentation> getAugmentations(final Augmentable input) { return AugmentationFieldGetter.getGetter(input.getClass()).getAugmentations(input); } + + /** + * + * Determines if two augmentation classes or case classes represents same data. + *

+ * Two augmentations or cases could be substituted only if and if: + *

    + *
  • Both implements same interfaces
  • + *
  • Both have same children
  • + *
  • If augmentations: Both have same augmentation target class. Target class was generated for data node in grouping.
  • + *
  • If cases: Both are from same choice. Choice class was generated for data node in grouping.
  • + *
+ *

+ * Explanation: Binding Specification reuses classes generated for groupings as part of normal data tree, + * this classes from grouping could be used at various locations and user may not be aware of it + * and may use incorrect case or augmentation in particular subtree (via copy constructors, etc). + * + * @param potential Class which is potential substition + * @param target Class which should be used at particular subtree + * @return true if and only if classes represents same data. + */ + @SuppressWarnings({"rawtypes","unchecked"}) + public static boolean isSubstitutionFor(Class potential, Class target) { + HashSet subImplemented = Sets.newHashSet(potential.getInterfaces()); + HashSet targetImplemented = Sets.newHashSet(target.getInterfaces()); + if(!subImplemented.equals(targetImplemented)) { + return false; + } + if(Augmentation.class.isAssignableFrom(potential) + && !BindingReflections.findAugmentationTarget(potential).equals(BindingReflections.findAugmentationTarget(target))) { + return false; + } + for(Method potentialMethod : potential.getMethods()) { + try { + Method targetMethod = target.getMethod(potentialMethod.getName(), potentialMethod.getParameterTypes()); + if(!potentialMethod.getReturnType().equals(targetMethod.getReturnType())) { + return false; + } + } catch (NoSuchMethodException e) { + // Counterpart method is missing, so classes could not be substituted. + return false; + } catch (SecurityException e) { + throw new IllegalStateException("Could not compare methods",e); + } + } + return true; + } } diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java index dba2e726fa..e9f940a455 100644 --- a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java +++ b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java @@ -31,6 +31,7 @@ import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.util.HashCodeBuilder; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; /** @@ -311,7 +312,7 @@ public final class YangInstanceIdentifier implements Path * This interface itself is used as common parent for actual @@ -339,6 +340,17 @@ public final class YangInstanceIdentifier implements Path getChild(final PathArgument key) { - return Optional.fromNullable(children.get(key)); + Optional explicitNode = Optional.fromNullable(children.get(key)); + if (explicitNode.isPresent()) { + return explicitNode; + } + final NormalizedNodeContainer> castedData = (NormalizedNodeContainer>) getData(); + Optional> value = castedData.getChild(key); + if (value.isPresent()) { + //FIXME: consider caching created Tree Nodes. + //We are safe to not to cache them, since written Tree Nodes are in read only snapshot. + return Optional.of(TreeNodeFactory.createTreeNode(value.get(), getVersion())); + } + return Optional.absent(); } @Override @@ -60,6 +71,26 @@ final class ContainerNode extends AbstractTreeNode { this.children = MapAdaptor.getDefaultInstance().takeSnapshot(parent.children); this.subtreeVersion = parent.getSubtreeVersion(); this.version = parent.getVersion(); + materializeChildVersion(); + } + + /** + * Traverse whole data tree and instantiate children for each data node. Set version of each MutableTreeNode + * accordingly to version in data node. + * + * Use this method if TreeNode is lazy initialized. + */ + private void materializeChildVersion() { + Preconditions.checkState(data instanceof NormalizedNodeContainer); + NormalizedNodeContainer> castedData = (NormalizedNodeContainer>) data; + + for(NormalizedNode childData : castedData.getValue()) { + PathArgument id = childData.getIdentifier(); + + if (!children.containsKey(id)) { + children.put(id, TreeNodeFactory.createTreeNode(childData, version)); + } + } } @Override @@ -97,22 +128,99 @@ final class ContainerNode extends AbstractTreeNode { } } - private static ContainerNode create(final Version version, final NormalizedNode data, - final Iterable> children) { + /** + * Method creates and returns Container root Node and whole subtree for each child node specified in children nodes. + *
+ * Reason why is method used recursively is that for each child in children nodes there is call to + * {@link TreeNodeFactory#createTreeNodeRecursively}. Each call to createTreeNodeRecursively + * calls either {@link #createNormalizedNodeRecursively} or {@link #createOrderedNodeRecursively} + * which depends on type of child node. + *
The root node that is returned holds reference to data node and whole subtree of children also containing references + * to data nodes. + * + * @param version version of indexed data + * @param data reference to data node + * @param children direct children of root node that is being created + * @return Root node with reference to data node and whole subtree of child nodes + */ + private static ContainerNode createNodeRecursively(final Version version, final NormalizedNode data, + final Iterable> children) { final Map map = new HashMap<>(); for (NormalizedNode child : children) { - map.put(child.getIdentifier(), TreeNodeFactory.createTreeNode(child, version)); + map.put(child.getIdentifier(), TreeNodeFactory.createTreeNodeRecursively(child, version)); } return new ContainerNode(data, version, map, version); } - public static ContainerNode create(final Version version, final NormalizedNodeContainer> container) { - return create(version, container, container.getValue()); + /** + * Method creates and returns Normalized Node Container as root and recursively creates whole subtree + * from all of the container child iterables stored in {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer#getValue()} + *
+ * The reason why is this method called recursively is that in background method calls {@link TreeNodeFactory#createTreeNodeRecursively} + * for each child stored in NormalizedNode and after each child is created the method calls again {@link #createNormalizedNodeRecursively} method + * until all of the children are resolved. + * + * @param version version of indexed data + * @param container Normalized Node Container + * @return Normalized Node Container as root and all whole subtree created from container iterables. + */ + public static ContainerNode createNormalizedNodeRecursively(final Version version, + final NormalizedNodeContainer> container) { + return createNodeRecursively(version, container, container.getValue()); + } + + /** + * Method creates and returns Ordered Node Container as root and recursively creates whole subtree + * from all of the container child iterables stored in {@link org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer#getValue()} + *
+ * The reason why is this method called recursively is that in background method calls {@link TreeNodeFactory#createTreeNodeRecursively} + * for each child stored in NormalizedNode and after each child is created the method calls again {@link #createNormalizedNodeRecursively} method + * until all of the children are resolved. + * + * @param version version of indexed data + * @param container Ordered Node Container + * @return Normalized Ordered Container as root and all whole subtree created from container iterables. + */ + public static ContainerNode createOrderedNodeRecursively(final Version version, + final OrderedNodeContainer> container) { + return createNodeRecursively(version, container, container.getValue()); } - public static ContainerNode create(final Version version, final OrderedNodeContainer> container) { - return create(version, container, container.getValue()); + /** + * Creates and returns single instance of Normalized Node Container with provided version and data reference stored in NormalizedNodeContainer. + * + * @param version version of indexed data + * @param container Normalized Node Container + * @return single instance of Normalized node with provided version and data reference stored in NormalizedNodeContainer + */ + public static ContainerNode createNormalizedNode(final Version version, + final NormalizedNodeContainer> container) { + return createNode(version, container); + } + + /** + * Creates and returns single instance of Ordered Node Container with provided version and data reference stored in OrderedNodeContainer. + * + * @param version version of indexed data + * @param container Ordered Node Container + * @return single instance of Ordered Node Container with provided version and data reference stored in OrderedNodeContainer. + */ + public static ContainerNode createOrderedNode(final Version version, + final OrderedNodeContainer> container) { + return createNode(version, container); + } + + /** + * Creates and returns single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode. + * + * @param version version of indexed data + * @param data NormalizedNode data container + * @return single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode. + */ + private static ContainerNode createNode(final Version version, final NormalizedNode data) { + final Map map = new HashMap<>(); + return new ContainerNode(data, version, map, version); } } diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/TreeNodeFactory.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/TreeNodeFactory.java index 656814162f..4f0a2201d7 100644 --- a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/TreeNodeFactory.java +++ b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/TreeNodeFactory.java @@ -28,19 +28,40 @@ public final class TreeNodeFactory { * @param version data node version * @return new AbstractTreeNode instance, covering the data tree provided */ - public static final TreeNode createTreeNode(final NormalizedNode data, final Version version) { + public static final TreeNode createTreeNodeRecursively(final NormalizedNode data, final Version version) { if (data instanceof NormalizedNodeContainer) { @SuppressWarnings("unchecked") NormalizedNodeContainer> container = (NormalizedNodeContainer>) data; - return ContainerNode.create(version, container); + return ContainerNode.createNormalizedNodeRecursively(version, container); } if (data instanceof OrderedNodeContainer) { @SuppressWarnings("unchecked") OrderedNodeContainer> container = (OrderedNodeContainer>) data; - return ContainerNode.create(version, container); + return ContainerNode.createOrderedNodeRecursively(version, container); } return new ValueNode(data, version); } + + /** + * Create a new AbstractTreeNode from a data node. + * + * @param data data node + * @param version data node version + * @return new AbstractTreeNode instance, covering the data tree provided + */ + public static final TreeNode createTreeNode(final NormalizedNode data, final Version version) { + if (data instanceof NormalizedNodeContainer) { + @SuppressWarnings("unchecked") + NormalizedNodeContainer> container = (NormalizedNodeContainer>) data; + return ContainerNode.createNormalizedNode(version, container); + } + if (data instanceof OrderedNodeContainer) { + @SuppressWarnings("unchecked") + OrderedNodeContainer> container = (OrderedNodeContainer>) data; + return ContainerNode.createOrderedNode(version, container); + } + return new ValueNode(data, version); + } } diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java index f51179e6cc..06f661dd1f 100644 --- a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java +++ b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java @@ -8,6 +8,7 @@ package org.opendaylight.yangtools.yang.data.codec.gson; import com.google.gson.stream.JsonReader; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -19,6 +20,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; + import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.yangtools.yang.common.QName; @@ -32,6 +34,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStre import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser; @@ -83,11 +86,10 @@ public class StreamToNormalizedNodeTest { * This is the parsing part */ // This is where we will output the nodes - final NormalizedNodeContainerBuilder> parent = - Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(QName.create("dummy", "2014-12-31", "dummy"))); + NormalizedNodeResult result = new NormalizedNodeResult(); // StreamWriter which attaches NormalizedNode under parent - final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(parent); + final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result); // JSON -> StreamWriter parser try (JsonParserStream handler = JsonParserStream.create(streamWriter, schemaContext)) { @@ -95,14 +97,14 @@ public class StreamToNormalizedNodeTest { } // Finally build the node - final NormalizedNode parsedData = parent.build(); + final NormalizedNode parsedData = result.getResult(); LOG.debug("Parsed NormalizedNodes: {}", parsedData); /* * This is the serialization part. */ // We want to write the first child out - final DataContainerChild firstChild = ((ContainerNode) parsedData).getValue().iterator().next(); + final DataContainerChild firstChild = (DataContainerChild) parsedData; LOG.debug("Serializing first child: {}", firstChild); // String holder diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java index e097771e84..7312c36382 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java @@ -8,9 +8,7 @@ package org.opendaylight.yangtools.yang.data.impl.codec.xml; import java.util.Map; - import javax.annotation.Nonnull; - import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; @@ -50,10 +48,10 @@ public final class XmlUtils { if (pathArgument instanceof NodeIdentifierWithPredicates) { Map predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues(); - for (QName keyValue : predicates.keySet()) { - String predicateValue = String.valueOf(predicates.get(keyValue)); + for (Map.Entry entry : predicates.entrySet()) { + String predicateValue = String.valueOf(entry.getValue()); textContent.append('['); - textContent.append(prefixes.encodeQName(keyValue)); + textContent.append(prefixes.encodeQName(entry.getKey())); textContent.append("='"); textContent.append(predicateValue); textContent.append("']"); diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java index eb6e4bbd8e..84ad453df8 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java @@ -14,12 +14,10 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Collections2; import com.google.common.collect.Maps; import com.google.common.collect.Sets; - import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; - import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; @@ -150,7 +148,7 @@ public final class SchemaUtils { } private static boolean isFromAugment(final DataNodeContainer schema, final DataSchemaNode childSchema) { - if(schema instanceof AugmentationTarget == false) { + if (!(schema instanceof AugmentationTarget)) { return false; } @@ -186,7 +184,7 @@ public final class SchemaUtils { for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) { // If is not augmented child, continue - if (augments.containsKey(child.getQName()) == false) { + if (!(augments.containsKey(child.getQName()))) { continue; } @@ -212,7 +210,7 @@ public final class SchemaUtils { // Choice Node has to map child nodes from all its cases if (schema instanceof ChoiceNode) { for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) schema).getCases()) { - if (augments.containsKey(choiceCaseNode.getQName()) == false) { + if (!(augments.containsKey(choiceCaseNode.getQName()))) { continue; } @@ -257,7 +255,7 @@ public final class SchemaUtils { * */ public static Set getRealSchemasForAugment(final AugmentationTarget targetSchema, final AugmentationSchema augmentSchema) { - if(targetSchema.getAvailableAugmentations().contains(augmentSchema) == false) { + if (!(targetSchema.getAvailableAugmentations().contains(augmentSchema))) { return Collections.emptySet(); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/valid/DataValidationException.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/valid/DataValidationException.java index 493c6ceec0..7a6627eb5e 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/valid/DataValidationException.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/valid/DataValidationException.java @@ -9,7 +9,6 @@ package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid; import java.util.Map; import java.util.Set; - import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; @@ -26,26 +25,26 @@ public class DataValidationException extends RuntimeException { public static void checkLegalChild(final boolean isLegal, final YangInstanceIdentifier.PathArgument child, final DataNodeContainer schema, final Set childNodes, final Set augments) { - if (isLegal == false) { + if (!isLegal) { throw new IllegalChildException(child, schema, childNodes, augments); } } public static void checkLegalChild(final boolean isLegal, final YangInstanceIdentifier.PathArgument child, final DataSchemaNode schema, final Set childNodes) { - if (isLegal == false) { + if (!isLegal) { throw new IllegalChildException(child, schema, childNodes); } } public static void checkLegalChild(final boolean isLegal, final YangInstanceIdentifier.PathArgument child, final ChoiceNode schema) { - if (isLegal == false) { + if (!isLegal) { throw new IllegalChildException(child, schema); } } public static void checkLegalData(final boolean isLegal, final String messageTemplate, final Object... messageAttrs) { - if (isLegal == false) { + if (!isLegal) { throw new DataValidationException(String.format(messageTemplate, messageAttrs)); } } @@ -56,9 +55,6 @@ public class DataValidationException extends RuntimeException { Object expectedValue = nodeId.getKeyValues().get(keyQName); Object actualValue = childNode.getValue(); - if (childNode == null) { - throw new IllegalListKeyException(keyQName, nodeId, actualValue, expectedValue); - } } public static void checkListKey(final DataContainerChild childNode, final QName keyQName, final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeId) { diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeFactory.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeFactory.java index 486c1c2cf5..6c24d4f06c 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeFactory.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeFactory.java @@ -24,7 +24,7 @@ public final class InMemoryDataTreeFactory implements DataTreeFactory { final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME); final NormalizedNode data = Builders.containerBuilder().withNodeIdentifier(root).build(); - return new InMemoryDataTree(TreeNodeFactory.createTreeNode(data, Version.initial()), null); + return new InMemoryDataTree(TreeNodeFactory.createTreeNodeRecursively(data, Version.initial()), null); } /** diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java index e26c32ee5b..de4bcef796 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java @@ -39,7 +39,7 @@ final class InMemoryDataTreeModification implements DataTreeModification { InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final RootModificationApplyOperation resolver) { this.snapshot = Preconditions.checkNotNull(snapshot); this.strategyTree = Preconditions.checkNotNull(resolver).snapshot(); - this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode()); + this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode(), false); /* * We could allocate version beforehand, since Version contract * states two allocated version must be allways different. @@ -141,8 +141,13 @@ final class InMemoryDataTreeModification implements DataTreeModification { ModifiedNode modification = rootNode; // We ensure strategy is present. ModificationApplyOperation operation = resolveModificationStrategy(path); + boolean isOrdered = true; + if (operation instanceof SchemaAwareApplyOperation) { + isOrdered = ((SchemaAwareApplyOperation) operation).isOrdered(); + } + for (PathArgument pathArg : path.getPathArguments()) { - modification = modification.modifyChild(pathArg); + modification = modification.modifyChild(pathArg, isOrdered); } return OperationWithModification.from(operation, modification); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java index 56353350af..27b42cc8fe 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java @@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import com.google.common.base.Optional; import com.google.common.base.Predicate; +import java.util.HashMap; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -48,16 +49,22 @@ final class ModifiedNode implements StoreTreeNode, Identifiable children = new LinkedHashMap<>(); + private final Map children; private final Optional original; private final PathArgument identifier; private ModificationType modificationType = ModificationType.UNMODIFIED; private Optional snapshotCache; private NormalizedNode value; - private ModifiedNode(final PathArgument identifier, final Optional original) { + private ModifiedNode(final PathArgument identifier, final Optional original, boolean isOrdered) { this.identifier = identifier; this.original = original; + + if (isOrdered) { + children = new LinkedHashMap<>(); + } else { + children = new HashMap<>(); + } } /** @@ -119,7 +126,7 @@ final class ModifiedNode implements StoreTreeNode, Identifiable, Identifiable, Identifiable modifications) { @@ -223,6 +233,11 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp entryStrategy = Optional. of(new ValueNodeModificationStrategy.LeafSetEntryModificationStrategy(schema)); } + @Override + boolean isOrdered() { + return true; + } + @SuppressWarnings("rawtypes") @Override protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { @@ -248,6 +263,11 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp entryStrategy = Optional. of(new DataNodeContainerModificationStrategy.ListEntryModificationStrategy(schema)); } + @Override + boolean isOrdered() { + return true; + } + @SuppressWarnings("rawtypes") @Override protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OperationWithModification.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OperationWithModification.java index 511fc322cb..e1df47c7d4 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OperationWithModification.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OperationWithModification.java @@ -61,8 +61,13 @@ final class OperationWithModification { } public OperationWithModification forChild(final PathArgument childId) { - ModifiedNode childMod = modification.modifyChild(childId); - Optional childOp = applyOperation.getChild(childId); - return from(childOp.get(),childMod); + ModificationApplyOperation childOp = applyOperation.getChild(childId).get(); + boolean isOrdered = true; + if (childOp instanceof SchemaAwareApplyOperation) { + isOrdered = ((SchemaAwareApplyOperation) childOp).isOrdered(); + } + ModifiedNode childMod = modification.modifyChild(childId, isOrdered); + + return from(childOp,childMod); } } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java index d0a0bcd33f..d7aa826c23 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java @@ -9,19 +9,24 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; 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.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; import org.opendaylight.yangtools.yang.data.api.schema.tree.IncorrectDataStructureException; import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; +import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.MutableTreeNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.ChoiceNode; @@ -158,7 +163,18 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } } - protected void checkWriteApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional current) throws DataValidationFailedException { + /** + * Checks if write operation can be applied to current TreeNode. + * The operation checks if original tree node to which the modification is going to be applied exists and if + * current node in TreeNode structure exists. + * + * @param path Path from current node in TreeNode + * @param modification modification to apply + * @param current current node in TreeNode for modification to apply + * @throws DataValidationFailedException + */ + protected void checkWriteApplicable(final YangInstanceIdentifier path, final NodeModification modification, + final Optional current) throws DataValidationFailedException { Optional original = modification.getOriginal(); if (original.isPresent() && current.isPresent()) { checkNotConflicting(path, original.get(), current.get()); @@ -176,6 +192,10 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } } + boolean isOrdered() { + return false; + } + @Override public final Optional apply(final ModifiedNode modification, final Optional currentMeta, final Version version) { @@ -234,6 +254,11 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { entryStrategy = Optional. of(new DataNodeContainerModificationStrategy.UnkeyedListItemModificationStrategy(schema)); } + @Override + boolean isOrdered() { + return true; + } + @Override protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { @@ -249,12 +274,65 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { @Override protected TreeNode applyWrite(final ModifiedNode modification, final Optional currentMeta, final Version version) { + final NormalizedNode newValue = modification.getWrittenValue(); + final TreeNode newValueMeta = TreeNodeFactory.createTreeNode(newValue, version); + + if (Iterables.isEmpty(modification.getChildren())) { + return newValueMeta; + } + /* - * FIXME: BUG-1258: This is inefficient: it needlessly creates index nodes for the entire subtree. - * We can determine the depth into which metadata need to be created from the modification - * -- if it does not have children, no need to bother with metadata. + * This is where things get interesting. The user has performed a write and + * then she applied some more modifications to it. So we need to make sense + * of that an apply the operations on top of the written value. We could have + * done it during the write, but this operation is potentially expensive, so + * we have left it out of the fast path. + * + * As it turns out, once we materialize the written data, we can share the + * code path with the subtree change. So let's create an unsealed TreeNode + * and run the common parts on it -- which end with the node being sealed. */ - return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), version); + final MutableTreeNode mutable = newValueMeta.mutable(); + mutable.setSubtreeVersion(version); + + @SuppressWarnings("rawtypes") + final NormalizedNodeContainerBuilder dataBuilder = ImmutableUnkeyedListEntryNodeBuilder + .create((UnkeyedListEntryNode) newValue); + + return mutateChildren(mutable, dataBuilder, version, modification.getChildren()); + } + + /** + * Applies write/remove diff operation for each modification child in modification subtree. + * Operation also sets the Data tree references for each Tree Node (Index Node) in meta (MutableTreeNode) structure. + * + * @param meta MutableTreeNode (IndexTreeNode) + * @param data DataBuilder + * @param nodeVersion Version of TreeNode + * @param modifications modification operations to apply + * @return Sealed immutable copy of TreeNode structure with all Data Node references set. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private TreeNode mutateChildren(final MutableTreeNode meta, final NormalizedNodeContainerBuilder data, + final Version nodeVersion, final Iterable modifications) { + + for (ModifiedNode mod : modifications) { + final PathArgument id = mod.getIdentifier(); + final Optional cm = meta.getChild(id); + + Optional result = resolveChildOperation(id).apply(mod, cm, nodeVersion); + if (result.isPresent()) { + final TreeNode tn = result.get(); + meta.addChild(tn); + data.addChild(tn.getData()); + } else { + meta.removeChild(id); + data.removeChild(id); + } + } + + meta.setData(data.build()); + return meta.seal(); } @Override diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ValueNodeModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ValueNodeModificationStrategy.java index 6979a64f71..3df0c80e95 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ValueNodeModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ValueNodeModificationStrategy.java @@ -62,7 +62,7 @@ abstract class ValueNodeModificationStrategy extends S @Override protected TreeNode applyWrite(final ModifiedNode modification, final Optional currentMeta, final Version version) { - return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), version); + return TreeNodeFactory.createTreeNodeRecursively(modification.getWrittenValue(), version); } @Override diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationMetadataTreeTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationMetadataTreeTest.java index a85acfd1e4..2896675c15 100644 --- a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationMetadataTreeTest.java +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationMetadataTreeTest.java @@ -146,7 +146,7 @@ public class ModificationMetadataTreeTest { @Test public void basicReadWrites() { DataTreeModification modificationTree = new InMemoryDataTreeModification(new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper), + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper), rootOper); Optional> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH); assertTrue(originalBarNode.isPresent()); diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java index bc1f6cef4f..509037fbcc 100644 --- a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java @@ -94,7 +94,7 @@ public class TreeNodeUtilsTest { @Test public void findNodeTestNodeFound() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); Optional node = TreeNodeUtils.findNode(rootNode, OUTER_LIST_1_PATH); assertPresentAndType(node, TreeNode.class); @@ -103,7 +103,7 @@ public class TreeNodeUtilsTest { @Test public void findNodeTestNodeNotFound() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); final YangInstanceIdentifier outerList1InvalidPath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) // @@ -115,7 +115,7 @@ public class TreeNodeUtilsTest { @Test public void findNodeCheckedTestNodeFound() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); TreeNode foundNode = null; try { @@ -129,7 +129,7 @@ public class TreeNodeUtilsTest { @Test public void findNodeCheckedTestNodeNotFound() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); final YangInstanceIdentifier outerList1InvalidPath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) // @@ -145,7 +145,7 @@ public class TreeNodeUtilsTest { @Test public void findClosestOrFirstMatchTestNodeExists() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); Optional expectedNode = TreeNodeUtils.findNode(rootNode, TWO_TWO_PATH); assertPresentAndType(expectedNode, TreeNode.class); @@ -156,7 +156,7 @@ public class TreeNodeUtilsTest { @Test public void findClosestOrFirstMatchTestNodeDoesNotExist() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); final YangInstanceIdentifier outerListInnerListPath = YangInstanceIdentifier.builder(OUTER_LIST_2_PATH) .node(TestModel.INNER_LIST_QNAME) @@ -174,7 +174,7 @@ public class TreeNodeUtilsTest { @Test public void getChildTestChildFound() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); Optional node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode), TestModel.TEST_PATH.getLastPathArgument()); @@ -184,7 +184,7 @@ public class TreeNodeUtilsTest { @Test public void getChildTestChildNotFound() { InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext, - TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper); + TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper); TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode(); Optional node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode), TestModel.OUTER_LIST_PATH.getLastPathArgument()); diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java index e281ea7339..fdaf0c8f70 100644 --- a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java +++ b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java @@ -11,7 +11,6 @@ import java.util.Set; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; @@ -72,7 +71,7 @@ final class ChoiceNodeModification extends Set childrenToProcessFiltered = Sets.newLinkedHashSet(); for (YangInstanceIdentifier.PathArgument childToProcess : childrenToProcess) { // child from other cases, skip - if (childToProcess instanceof AugmentationNode + if (childToProcess instanceof YangInstanceIdentifier.AugmentationIdentifier && SchemaUtils.belongsToCaseAugment(detectedCase, (YangInstanceIdentifier.AugmentationIdentifier) childToProcess) == false) { continue; diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaRepository.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaRepository.java index e8bcc06510..722ac918e0 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaRepository.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaRepository.java @@ -146,7 +146,7 @@ public abstract class AbstractSchemaRepository implements SchemaRepository, Sche } if (m.isEmpty()) { - sources.remove(m); + sources.remove(source.getSourceIdentifier()); } } } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BitsType.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BitsType.java index e89e6572f4..20f8c881a9 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BitsType.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BitsType.java @@ -7,18 +7,16 @@ */ package org.opendaylight.yangtools.yang.model.util; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import java.util.Collections; import java.util.List; - import org.opendaylight.yangtools.yang.common.QName; 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.type.BitsTypeDefinition; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; - /** * The default implementation of Bits Type Definition interface. * @@ -28,7 +26,7 @@ public final class BitsType implements BitsTypeDefinition { private final static QName NAME = BaseTypes.BITS_QNAME; private final SchemaPath path; - private final String description = "The bits built-in type represents a bit set. " + private static final String DESCRIPTION = "The bits built-in type represents a bit set. " + "That is, a bits value is a set of flags identified by small integer position " + "numbers starting at 0. Each bit number has an assigned name."; @@ -129,7 +127,7 @@ public final class BitsType implements BitsTypeDefinition { */ @Override public String getDescription() { - return description; + return DESCRIPTION; } /* @@ -167,7 +165,6 @@ public final class BitsType implements BitsTypeDefinition { final int prime = 31; int result = 1; result = prime * result + ((bits == null) ? 0 : bits.hashCode()); - result = prime * result + ((description == null) ? 0 : description.hashCode()); result = prime * result + NAME.hashCode(); result = prime * result + path.hashCode(); return result; @@ -192,14 +189,6 @@ public final class BitsType implements BitsTypeDefinition { } else if (!bits.equals(other.bits)) { return false; } - if (description == null) { - if (other.description != null) { - return false; - } - } else if (!description.equals(other.description)) { - return false; - } - if (path == null) { if (other.path != null) { return false; @@ -218,7 +207,7 @@ public final class BitsType implements BitsTypeDefinition { builder.append(", path="); builder.append(path); builder.append(", description="); - builder.append(description); + builder.append(DESCRIPTION); builder.append(", reference="); builder.append(REFERENCE); builder.append(", bits="); diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/UnknownType.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/UnknownType.java deleted file mode 100644 index f32c16f8bf..0000000000 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/UnknownType.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * 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 - */ -package org.opendaylight.yangtools.yang.model.util; - -import java.util.Collections; -import java.util.List; - -import org.opendaylight.yangtools.yang.common.QName; -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.type.LengthConstraint; -import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint; -import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; -import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition; - -/** - * Utility implementation of unknown type definition. - * - * Unknown type definition is derived type, for - * which base built-in type is not yet known. This types - * are possible during parsing and resolving of YANG model - * without all requisites already processed. - */ -public final class UnknownType implements UnknownTypeDefinition { - - private final QName name; - private final SchemaPath path; - private final String description; - private final String reference; - private final List lengthStatements; - private final List patterns; - private final List rangeStatements; - private final List extensions; - private final LengthConstraint lengthConstraint; - private final Integer fractionDigits; - - private final Status status; - private final String units; - private final Object defaultValue; - - public static class Builder { - - private final QName name; - private final SchemaPath path; - private String description; - private String reference; - - private List lengthStatements = Collections.emptyList(); - private List patterns = Collections.emptyList(); - private List rangeStatements = Collections.emptyList(); - private List extensions = Collections.emptyList(); - private LengthConstraint lengthConstraint = null; - private Integer fractionDigits = null; - - private Status status = Status.CURRENT; - private String units = ""; - private Object defaultValue = null; - - public Builder(final QName name, final String description, final String reference) { - this.name = name; - this.path = SchemaPath.create(true, name); - this.description = description; - this.reference = reference; - } - - public Builder(final QName name) { - this.name = name; - this.path = SchemaPath.create(true, name); - } - - public Builder description(final String description) { - this.description = description; - return this; - } - - public Builder reference(final String reference) { - this.reference = reference; - return this; - } - - public Builder lengthStatements(final List lengthStatements) { - this.lengthStatements = lengthStatements; - return this; - } - - public Builder patterns(final List patterns) { - this.patterns = patterns; - return this; - } - - public Builder rangeStatements(final List rangeStatements) { - this.rangeStatements = rangeStatements; - return this; - } - - public Builder extensions(final List extensions) { - this.extensions = extensions; - return this; - } - - public Builder lengthConstraint(final LengthConstraint lengthConstraint) { - this.lengthConstraint = lengthConstraint; - return this; - } - - public Builder fractionDigits(final Integer fractionDigits) { - this.fractionDigits = fractionDigits; - return this; - } - - public Builder status(final Status status) { - this.status = status; - return this; - } - - public Builder units(final String units) { - this.units = units; - return this; - } - - public Builder defaultValue(final Object defaultValue) { - this.defaultValue = defaultValue; - return this; - } - - public UnknownTypeDefinition build() { - return new UnknownType(this); - } - } - - private UnknownType(final Builder builder) { - this.name = builder.name; - this.path = builder.path; - this.description = builder.description; - this.reference = builder.reference; - this.lengthStatements = builder.lengthStatements; - this.patterns = builder.patterns; - this.rangeStatements = builder.rangeStatements; - this.extensions = builder.extensions; - this.lengthConstraint = builder.lengthConstraint; - this.status = builder.status; - this.units = builder.units; - this.defaultValue = builder.defaultValue; - this.fractionDigits = builder.fractionDigits; - } - - /* - * (non-Javadoc) - * - * @see - * org.opendaylight.yangtools.yang.model.api.TypeDefinition#getBaseType() - */ - @Override - public UnknownTypeDefinition getBaseType() { - return this; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.TypeDefinition#getUnits() - */ - @Override - public String getUnits() { - return units; - } - - /* - * (non-Javadoc) - * - * @see - * org.opendaylight.yangtools.yang.model.api.TypeDefinition#getDefaultValue - * () - */ - @Override - public Object getDefaultValue() { - return defaultValue; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.SchemaNode#getQName() - */ - @Override - public QName getQName() { - return name; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.SchemaNode#getPath() - */ - @Override - public SchemaPath getPath() { - return path; - } - - /* - * (non-Javadoc) - * - * @see - * org.opendaylight.yangtools.yang.model.api.SchemaNode#getDescription() - */ - @Override - public String getDescription() { - return description; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.SchemaNode#getReference() - */ - @Override - public String getReference() { - return reference; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.SchemaNode#getStatus() - */ - @Override - public Status getStatus() { - return status; - } - - /* - * (non-Javadoc) - * - * @see - * org.opendaylight.yangtools.yang.model.api.SchemaNode#getExtensionSchemaNodes - * () - */ - @Override - public List getUnknownSchemaNodes() { - return extensions; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition - * #getRangeStatements() - */ - @Override - public List getRangeConstraints() { - return rangeStatements; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition - * #getLengthStatements() - */ - @Override - public List getLengthConstraints() { - return lengthStatements; - } - - /* - * (non-Javadoc) - * - * @see org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition - * #getPatterns() - */ - @Override - public List getPatternConstraints() { - return patterns; - } - - @Override - public Integer getFractionDigits() { - return fractionDigits; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((defaultValue == null) ? 0 : defaultValue.hashCode()); - result = prime * result + ((description == null) ? 0 : description.hashCode()); - result = prime * result + ((extensions == null) ? 0 : extensions.hashCode()); - result = prime * result + ((lengthConstraint == null) ? 0 : lengthConstraint.hashCode()); - result = prime * result + ((lengthStatements == null) ? 0 : lengthStatements.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((path == null) ? 0 : path.hashCode()); - result = prime * result + ((patterns == null) ? 0 : patterns.hashCode()); - result = prime * result + ((rangeStatements == null) ? 0 : rangeStatements.hashCode()); - result = prime * result + ((reference == null) ? 0 : reference.hashCode()); - result = prime * result + ((status == null) ? 0 : status.hashCode()); - result = prime * result + ((units == null) ? 0 : units.hashCode()); - 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; - } - UnknownType other = (UnknownType) obj; - if (defaultValue == null) { - if (other.defaultValue != null) { - return false; - } - } else if (!defaultValue.equals(other.defaultValue)) { - return false; - } - if (description == null) { - if (other.description != null) { - return false; - } - } else if (!description.equals(other.description)) { - return false; - } - if (extensions == null) { - if (other.extensions != null) { - return false; - } - } else if (!extensions.equals(other.extensions)) { - return false; - } - if (lengthConstraint == null) { - if (other.lengthConstraint != null) { - return false; - } - } else if (!lengthConstraint.equals(other.lengthConstraint)) { - return false; - } - if (lengthStatements == null) { - if (other.lengthStatements != null) { - return false; - } - } else if (!lengthStatements.equals(other.lengthStatements)) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (path == null) { - if (other.path != null) { - return false; - } - } else if (!path.equals(other.path)) { - return false; - } - if (patterns == null) { - if (other.patterns != null) { - return false; - } - } else if (!patterns.equals(other.patterns)) { - return false; - } - if (rangeStatements == null) { - if (other.rangeStatements != null) { - return false; - } - } else if (!rangeStatements.equals(other.rangeStatements)) { - return false; - } - if (reference == null) { - if (other.reference != null) { - return false; - } - } else if (!reference.equals(other.reference)) { - return false; - } - if (status != other.status) { - return false; - } - if (units == null) { - if (other.units != null) { - return false; - } - } else if (!units.equals(other.units)) { - return false; - } - return true; - } - - @Override - public String toString() { - StringBuilder builder2 = new StringBuilder(); - builder2.append("UnknownType [name="); - builder2.append(name); - builder2.append(", path="); - builder2.append(path); - builder2.append(", description="); - builder2.append(description); - builder2.append(", reference="); - builder2.append(reference); - builder2.append(", lengthStatements="); - builder2.append(lengthStatements); - builder2.append(", patterns="); - builder2.append(patterns); - builder2.append(", rangeStatements="); - builder2.append(rangeStatements); - builder2.append(", extensions="); - builder2.append(extensions); - builder2.append(", lengthConstraint="); - builder2.append(lengthConstraint); - builder2.append(", status="); - builder2.append(status); - builder2.append(", units="); - builder2.append(units); - builder2.append(", defaultValue="); - builder2.append(defaultValue); - builder2.append("]"); - return builder2.toString(); - } - -} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingUtils.java index 6eb400c483..e1792c899f 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingUtils.java @@ -44,7 +44,9 @@ public final class GroupingUtils { * all loaded modules * @param module * current module - * @return grouping with given name if found, null otherwise + * @return grouping with given name, never null + * @throws YangParseException + * if no grouping found */ public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder, final Map> modules, final ModuleBuilder module) { diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java index 2d2b642003..ec7dcd5bba 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java @@ -19,7 +19,6 @@ import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint; import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint; import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; import org.opendaylight.yangtools.yang.model.util.ExtendedType; -import org.opendaylight.yangtools.yang.model.util.UnknownType; import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.util.AbstractTypeAwareBuilder; @@ -68,11 +67,12 @@ public final class TypeDefinitionBuilderImpl extends AbstractTypeAwareBuilder im public TypeDefinition> build() { TypeDefinition result; ExtendedType.Builder typeBuilder; - if ((type == null || type instanceof UnknownType) && typedef == null) { - throw new YangParseException("Unresolved type: '" + qname.getLocalName() + "'."); - } - if (type == null || type instanceof UnknownType) { - type = typedef.build(); + if (type == null) { + if (typedef == null) { + throw new YangParseException("Unresolved type: '" + qname.getLocalName() + "'."); + } else { + type = typedef.build(); + } } typeBuilder = ExtendedType.builder(qname, type, Optional.fromNullable(description), diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedDataNodeContainer.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedDataNodeContainer.java index 30e28d46bd..766b61fbce 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedDataNodeContainer.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedDataNodeContainer.java @@ -26,6 +26,7 @@ public abstract class AbstractDocumentedDataNodeContainer extends AbstractDocume private final Set groupings; private final Set uses; private final Set> typeDefinitions; + private final Set publicChildNodes; protected AbstractDocumentedDataNodeContainer(final AbstractDocumentedDataNodeContainerBuilder data) { super(data); @@ -36,6 +37,7 @@ public abstract class AbstractDocumentedDataNodeContainer extends AbstractDocume groupings = ImmutableSet.copyOf(data.getGroupings()); uses = ImmutableSet.copyOf(data.getUsesNodes()); typeDefinitions = ImmutableSet.copyOf(data.getTypeDefinitions()); + publicChildNodes = ImmutableSet.copyOf(childNodes.values()); } @Override @@ -45,7 +47,7 @@ public abstract class AbstractDocumentedDataNodeContainer extends AbstractDocume @Override public final Set getChildNodes() { - return ImmutableSet.copyOf(childNodes.values()); + return publicChildNodes; } @Override diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java index 933ac6b6d4..83b56314cb 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java @@ -11,17 +11,14 @@ import static com.google.common.base.Preconditions.checkState; import com.google.common.base.CharMatcher; import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Lists; - import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; - import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; @@ -183,13 +180,13 @@ public final class ParserListenerUtils { continue; } /* - * + * * It is safe not to check last argument to be same * grammars enforces that. - * + * * FIXME: Introduce proper escaping and translation of escaped * characters here. - * + * */ sb.append(quoteMatcher.removeFrom(str.substring(1, str.length()-1))); } @@ -378,7 +375,15 @@ public final class ParserListenerUtils { ParseTree child = ctx.getChild(i); if (child instanceof Value_stmtContext) { String valueStr = stringFromNode(child); - value = Integer.valueOf(valueStr); + try { + // yang enum value has same restrictions as JAVA Integer + value = Integer.valueOf(valueStr); + } catch (NumberFormatException e) { + String err = String + .format("Error on enum '%s': the enum value MUST be in the range from -2147483648 to 2147483647, but was: %s", + name, valueStr); + throw new YangParseException(moduleName, ctx.getStart().getLine(), err, e); + } } else if (child instanceof Description_stmtContext) { description = stringFromNode(child); } else if (child instanceof Reference_stmtContext) { @@ -391,10 +396,6 @@ public final class ParserListenerUtils { if (value == null) { value = highestValue + 1; } - if (value < -2147483648 || value > 2147483647) { - throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on enum '" + name - + "': the enum value MUST be in the range from -2147483648 to 2147483647, but was: " + value); - } EnumPairImpl result = new EnumPairImpl(); result.qname = path.getPathTowardsRoot().iterator().next(); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java index 38055d908d..7948158f4d 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java @@ -240,7 +240,7 @@ public final class YangParserImpl implements YangContextParser { if (targetModule == null) { Module result = findModuleFromContext(context, module, prefix, 0); targetModule = new ModuleBuilder(result); - TreeMap map = modules.get(prefix); + TreeMap map = modules.get(targetModule.getNamespace()); if (map == null) { map = new TreeMap<>(); map.put(targetModule.getRevision(), targetModule); @@ -1061,10 +1061,6 @@ public final class YangParserImpl implements YangContextParser { ModuleBuilder module = BuilderUtils.getParentModule(usesNode); final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module); - if (targetGroupingBuilder == null) { - throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '" - + usesNode.getGroupingPath() + "' not found."); - } usesNode.setGrouping(targetGroupingBuilder); } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java index 9f80a1e7f7..46c2f8240d 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java @@ -196,14 +196,11 @@ public abstract class YangModelDependencyInfo { private static YangModelDependencyInfo parseModuleContext(final Module_stmtContext module) { String name = getArgumentString(module); - // String prefix = - // getArgumentString(module.module_header_stmts().prefix_stmt(0)); - String namespace = getArgumentString(module.module_header_stmts().namespace_stmt(0)); String latestRevision = getLatestRevision(module.revision_stmts()); ImmutableSet imports = parseImports(module.linkage_stmts().import_stmt()); ImmutableSet includes = parseIncludes(module.linkage_stmts().include_stmt()); - return new ModuleDependencyInfo(name, latestRevision, namespace, imports, includes); + return new ModuleDependencyInfo(name, latestRevision, imports, includes); } private static ImmutableSet parseImports(final List importStatements) { @@ -265,7 +262,7 @@ public abstract class YangModelDependencyInfo { */ public static final class ModuleDependencyInfo extends YangModelDependencyInfo { - private ModuleDependencyInfo(final String name, final String latestRevision, final String namespace, + private ModuleDependencyInfo(final String name, final String latestRevision, final ImmutableSet imports, final ImmutableSet includes) { super(name, latestRevision, imports, includes); }