--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yangtools-parent</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ <relativePath>../common/parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>benchmarks</artifactId>
+
+ <properties>
+ <yangtools.version>0.6.2-SNAPSHOT</yangtools.version>
+ <yang.maven.plugin.version>0.6.2-SNAPSHOT</yang.maven.plugin.version>
+ <java.source.version>1.7</java.source.version>
+ <java.target.version>1.7</java.target.version>
+ <jmh.version>0.9.7</jmh.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-core</artifactId>
+ <version>${jmh.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-generator-annprocess</artifactId>
+ <version>${jmh.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.source.version}</source>
+ <target>${java.source.version}</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+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 <lsedlak@cisco.com>
+ */
+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<Module> modules = parser.parseYangModelsFromStreams(Collections.singletonList(
+ getDatastoreBenchmarkInputStream()));
+ return parser.resolveSchemaContext(modules);
+ }
+}
--- /dev/null
+/**
+ * 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 <lsedlak@cisco.com>
+ *
+ * @see <a href="http://openjdk.java.net/projects/code-tools/jmh/">JMH</a>
+ */
+@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<MapEntryNode, MapNode> 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);
+ }
+}
--- /dev/null
+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
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>
-
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-test-model</artifactId>
+ <scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
+ <dependency><groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
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;
/**
* Serialization service, which provides two-way serialization between
* Java Binding Data representation and NormalizedNode representation.
- *
*/
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.
* @param data Data object representing data
* @return NormalizedNode representation
*/
- <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(InstanceIdentifier<T> path, T data);
+ <T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode<?,?>> toNormalizedNode(InstanceIdentifier<T> path, T data);
/**
* Translates supplied YANG Instance Identifier and NormalizedNode into Binding data.
* @param data NormalizedNode representing data
* @return DOM Instance Identifier
*/
- Entry<InstanceIdentifier<?>,DataObject> fromNormalizedNode(YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+ @Nullable Entry<InstanceIdentifier<?>,DataObject> fromNormalizedNode(@Nonnull YangInstanceIdentifier path, NormalizedNode<?, ?> data);
/**
* Returns map view which contains translated set of entries to normalized nodes.
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;
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;
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<YangInstanceIdentifier, InstanceIdentifier<?>> instanceIdentifierCodec =
return context;
}
- public Codec<YangInstanceIdentifier, InstanceIdentifier<?>> getInstanceIdentifierCodec() {
+ Codec<YangInstanceIdentifier, InstanceIdentifier<?>> getInstanceIdentifierCodec() {
return instanceIdentifierCodec;
}
return currentNode;
}
- public NodeCodecContext getCodecContextNode(final YangInstanceIdentifier dom,
- final List<InstanceIdentifier.PathArgument> 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<InstanceIdentifier.PathArgument> 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
* 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
// 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;
} else if (rootType instanceof InstanceIdentifierTypeDefinition) {
return ValueTypeCodec.encapsulatedValueCodecFor(valueType, instanceIdentifierCodec);
} else if (rootType instanceof UnionTypeDefinition) {
- Callable<UnionTypeCodec> loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType,
- getInstanceIdentifierCodec(), getIdentityCodec());
+ Callable<UnionTypeCodec> 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);
@Override
public YangInstanceIdentifier serialize(final InstanceIdentifier<?> input) {
- List<YangInstanceIdentifier.PathArgument> domArgs = new LinkedList<>();
+ List<YangInstanceIdentifier.PathArgument> domArgs = new ArrayList<>();
getCodecContextNode(input, domArgs);
return YangInstanceIdentifier.create(domArgs);
}
@Override
public InstanceIdentifier<?> deserialize(final YangInstanceIdentifier input) {
- List<InstanceIdentifier.PathArgument> builder = new LinkedList<>();
- getCodecContextNode(input, builder);
- return InstanceIdentifier.create(builder);
+ final List<InstanceIdentifier.PathArgument> builder = new ArrayList<>();
+ final NodeCodecContext codec = getCodecContextNode(input, builder);
+ return codec == null ? null : InstanceIdentifier.create(builder);
}
}
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;
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;
@Override
public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
- List<YangInstanceIdentifier.PathArgument> 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 <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> 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<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path, domWriter);
// We get serializer which reads binding data and uses Binding To Normalized Node writer to write result
return new SimpleEntry<YangInstanceIdentifier,NormalizedNode<?,?>>(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<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data) {
- List<PathArgument> builder = new LinkedList<>();
- if(isBindingRepresentable(data)) {
- DataObject lazyObj = (DataObject) codecContext.getCodecContextNode(path, builder).dataFromNormalizedNode(data);
- InstanceIdentifier<?> bindingPath = InstanceIdentifier.create(builder);
- return new SimpleEntry<InstanceIdentifier<?>, DataObject>(bindingPath,lazyObj);
+ public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ if (!isBindingRepresentable(data)) {
+ return null;
}
- return null;
+
+ final List<PathArgument> 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<InstanceIdentifier<?>, DataObject>(bindingPath, lazyObj);
}
@Override
- public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(
- final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
+ public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
throw new UnsupportedOperationException("Not implemented yet");
}
private static class DeserializeFunction<T> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
-
private final DataObjectCodecContext<?> ctx;
+
public DeserializeFunction(final DataObjectCodecContext<?> ctx) {
super();
this.ctx = ctx;
}
return Optional.absent();
}
-
-
}
private class GeneratorLoader extends CacheLoader<Class<? extends DataObject>, DataObjectSerializer> {
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;
Map<YangInstanceIdentifier.PathArgument, DataContainerCodecPrototype<?>> byYangCaseChildBuilder = new HashMap<>();
Map<Class<?>, DataContainerCodecPrototype<?>> byClassBuilder = new HashMap<>();
Map<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClassBuilder = new HashMap<>();
-
+ Set<Class<?>> 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<ChoiceCaseNode> 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<? extends DataObject> 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<Class<?>, 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<Class<?>, 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);
@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();
}
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;
}
}
- @SuppressWarnings("rawtypes")
- static final Callable<UnionTypeCodec> loader(final Class<?> unionCls,final UnionTypeDefinition unionType, final Codec instanceIdentifier, final Codec identity) {
+ static final Callable<UnionTypeCodec> loader(final Class<?> unionCls, final UnionTypeDefinition unionType) {
return new Callable<UnionTypeCodec>() {
-
@Override
- public UnionTypeCodec call() throws Exception {
+ public UnionTypeCodec call() throws NoSuchMethodException, SecurityException {
Set<UnionValueOptionContext> values = new HashSet<>();
for(TypeDefinition<?> subtype : unionType.getTypes()) {
String methodName = "get" + BindingMapping.getClassName(subtype.getQName());
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier.builder(Top.class)
+ .child(TopLevelList.class, TOP_FOO_KEY).toInstance();
+ private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST
+ .augmentation(TreeLeafOnlyAugment.class);
+ private static final InstanceIdentifier<TreeComplexUsesAugment> 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.<ListViaUses>emptyList())
+ .build();
+ }
+
+}
--- /dev/null
+/*
+ * 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<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier.builder(Top.class)
+ .child(TopLevelList.class, TOP_FOO_KEY).toInstance();
+ private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST
+ .augmentation(TreeLeafOnlyAugment.class);
+ private static final InstanceIdentifier<TreeComplexUsesAugment> 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.<ListViaUses>emptyList())
+ .build();
+ }
+
+}
--- /dev/null
+/*
+ * 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<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
+ .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).toInstance();
+ private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY =
+ BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class);
+ private static final InstanceIdentifier<TreeComplexUsesAugment> 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));
+ }
+}
--- /dev/null
+/*
+ * 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<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier.builder(Top.class)
+ .child(TopLevelList.class, TOP_FOO_KEY).toInstance();
+ private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST
+ .augmentation(TreeLeafOnlyAugment.class);
+ private static final InstanceIdentifier<TreeComplexUsesAugment> 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));
+ }
+
+}
--- /dev/null
+/*
+ * 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<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
+ .builder(Top.class).child(TopLevelList.class, TOP_LEVEL_LIST_FOO_KEY).toInstance();
+ private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY =
+ BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class);
+ private static final InstanceIdentifier<TreeComplexUsesAugment> 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<YangInstanceIdentifier, NormalizedNode<?, ?>> 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<InstanceIdentifier<?>, DataObject> entry = registry.fromNormalizedNode(BI_TOP_PATH, topNormalized);
+ assertEquals(top(), entry.getValue());
+ }
+
+ @Test
+ public void listWithKeysToNormalized() {
+ Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> 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<InstanceIdentifier<?>, 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<YangInstanceIdentifier, NormalizedNode<?, ?>> entry =
+ registry.toNormalizedNode(BA_TREE_LEAF_ONLY, new TreeLeafOnlyAugmentBuilder().setSimpleValue("simpleValue").build());
+ Set<QName> 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<QName> 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<InstanceIdentifier<?>, 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<String> topLevelLeafList = new ArrayList<>();
+ topLevelLeafList.add("foo");
+ Top top = new TopBuilder().setTopLevelLeafList(topLevelLeafList).build();
+
+ Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> 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<InstanceIdentifier<?>, DataObject> entry = registry.fromNormalizedNode(BI_TOP_PATH, topWithLeafList);
+ List<String> 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<YangInstanceIdentifier, NormalizedNode<?, ?>> 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<InstanceIdentifier<?>, 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<TopLevelList> ii = BA_TOP_LEVEL_LIST;
+ List<NestedList> 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<YangInstanceIdentifier, NormalizedNode<?, ?>> 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<TopLevelList> ii = BA_TOP_LEVEL_LIST;
+
+ Map.Entry<InstanceIdentifier<?>, DataObject> entry = registry.fromNormalizedNode(BI_TOP_LEVEL_LIST_FOO_PATH, foo);
+ List<NestedList> 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());
+ }
+}
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;
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;
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());
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);
*/
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());
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);
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;
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);
}
/**
* @return generated type builder <code>schemaNode</code>
*/
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);
}
if (schemaNode instanceof DataNodeContainer) {
+ groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it);
}
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;
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;
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;
public InstanceIdentifier<? extends Object> deserialize(
final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input) {
Class<?> baType = null;
- List<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> biArgs = input.getPath();
- List<QName> scannedPath = new ArrayList<>(biArgs.size());
- List<InstanceIdentifier.PathArgument> baArgs = new ArrayList<InstanceIdentifier.PathArgument>(biArgs.size());
+ Iterable<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> biArgs = input.getPathArguments();
+ List<QName> scannedPath = new ArrayList<>();
+ List<InstanceIdentifier.PathArgument> baArgs = new ArrayList<InstanceIdentifier.PathArgument>();
for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg : biArgs) {
scannedPath.add(biArg.getNodeType());
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;
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;
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) {
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
--- /dev/null
+/*
+ * 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<File> sourceFiles = getSourceFiles(resourceDirPath);
+ final SchemaContext context = parser.parseFiles(sourceFiles);
+ final List<Type> types = bindingGenerator.generateTypes(context);
+ final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
+ generator.generateToFile(sourcesOutputDir);
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>yang-ext</artifactId>
+ </dependency>
+ </dependencies>
+
+ <artifactId>binding-test-model</artifactId>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <outputBaseDir>
+ target/generated-sources/sal
+ </outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+</project>
--- /dev/null
+/*
+ * 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> 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<TopLevelList> path(final TopLevelListKey key) {
+ return TOP_PATH.child(TopLevelList.class, key);
+ }
+
+ public static InstanceIdentifier<NestedList> path(final TopLevelListKey top,final NestedListKey nested) {
+ return path(top).child(NestedList.class, nested);
+ }
+
+ public static InstanceIdentifier<ListViaUses> path(final TopLevelListKey top,final ListViaUsesKey uses) {
+ return path(top).augmentation(TreeComplexUsesAugment.class).child(ListViaUses.class, uses);
+ }
+
+ public static <T extends DataObject & Augmentation<TopLevelList>> InstanceIdentifier<T> path(final TopLevelListKey key, final Class<T> 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> listViaUses = ImmutableList.<ListViaUses> 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();
+ }
+
+}
--- /dev/null
+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;
+ }
+ }
+
+}
--- /dev/null
+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;
+ }
+ }
+}
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;
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;
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");
final List<GeneratedTOBuilder> 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");
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);
typeDefinitionsConcreteDepth.add(unsortedTypeDefinition);
}
// keys are in ascending order
- Set<Integer> depths = typeDefinitionsDepths.keySet();
- for (Integer depth : depths) {
- sortedTypeDefinition.addAll(typeDefinitionsDepths.get(depth));
+ for (Map.Entry<Integer, List<TypeDefinition<?>>> entry : typeDefinitionsDepths.entrySet()) {
+ sortedTypeDefinition.addAll(entry.getValue());
}
return sortedTypeDefinition;
</ul>
«ENDIF»
- «IF !path.path.empty»
+ «IF path.pathArguments.iterator.hasNext»
<h3>XML example</h3>
- «nodes.xmlExample(path.path.last.nodeType,path)»
+ «nodes.xmlExample(path.pathArguments.last.nodeType,path)»
</h3>
«ENDIF»
«FOR childNode : containers»
def header(int level,YangInstanceIdentifier name) '''
- <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
- «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
+ <h«level» id="«FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
+ «FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
</h«level»>
'''
}
def CharSequence localLink(YangInstanceIdentifier identifier, CharSequence text) '''
- <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
+ <a href="#«FOR cmp : identifier.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
'''
append(currentModule.name)
append(":")
var previous = false;
- for(arg : identifier.path) {
+ for(arg : identifier.pathArguments) {
if(previous) append("/")
append(arg.nodeType.localName);
previous = true;
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
private static List<File> 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<File> 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() + ")");
<module>binding-java-api-generator</module>
<module>binding-type-provider</module>
<module>maven-sal-api-gen-plugin</module>
+ <module>binding-test-model</module>
<module>binding-data-codec</module>
</modules>
</dependency>
<!-- Local Dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-test-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>binding-model-api</artifactId>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-yang-types</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-yang-types-20130715</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>yang-ext</artifactId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-common</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-data-codec</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>xtend-lib-osgi</artifactId>
<feature version='${project.version}'>odl-yangtools-binding</feature>
<bundle>mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf.inet.types.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types/${ietf.yang.types.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types-20130715/${ietf.yang.types.20130715.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools.model/yang-ext/${yang.ext.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools.model/opendaylight-l2-types/${opendaylight.l2.types.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools.model/ietf-topology/${ietf.topology.version}</bundle>
<ietf.topology.version>2013.10.21.2-SNAPSHOT</ietf.topology.version>
<ietf.inet.types.version>2010.09.24.4-SNAPSHOT</ietf.inet.types.version>
<ietf.yang.types.version>2010.09.24.4-SNAPSHOT</ietf.yang.types.version>
+ <ietf.yang.types.20130715.version>2013.07.15.1-SNAPSHOT</ietf.yang.types.20130715.version>
<ietf.restconf.version>2013.10.19.1-SNAPSHOT</ietf.restconf.version>
<karaf.version>3.0.1</karaf.version>
<nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
<artifactId>ietf-yang-types</artifactId>
<version>2010.09.24.4-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-yang-types-20130715</artifactId>
+ <version>2013.07.15.1-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-restconf</artifactId>
<artifactId>yang-data-operations</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-data-codec</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>features-test</artifactId>
<module>restconf</module>
<module>websocket</module>
<module>yang</module>
- <!-- module>third-party</module -->
+ <module>benchmarks</module>
+ <!-- module>third-party</module -->
</modules>
<build>
@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";
@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);
}
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;
public static Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Augmentable<?> input) {
return AugmentationFieldGetter.getGetter(input.getClass()).getAugmentations(input);
}
+
+ /**
+ *
+ * Determines if two augmentation classes or case classes represents same data.
+ * <p>
+ * Two augmentations or cases could be substituted only if and if:
+ * <ul>
+ * <li>Both implements same interfaces</li>
+ * <li>Both have same children</li>
+ * <li>If augmentations: Both have same augmentation target class. Target class was generated for data node in grouping.</li>
+ * <li>If cases: Both are from same choice. Choice class was generated for data node in grouping.</li>
+ * </ul>
+ * <p>
+ * <b>Explanation:</b> 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<Class> subImplemented = Sets.newHashSet(potential.getInterfaces());
+ HashSet<Class> 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;
+ }
}
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;
/**
/**
* Path argument / component of InstanceIdentifier
*
- * Path argument uniquelly identifies node in data tree on particular
+ * Path argument uniquely identifies node in data tree on particular
* level.
* <p>
* This interface itself is used as common parent for actual
* @return Node type
*/
QName getNodeType();
+
+ /**
+ * Return the string representation of this object for use in context
+ * provided by a previous object. This method can be implemented in
+ * terms of {@link #toString()}, but implementations are encourage to
+ * reuse any context already emitted by the previous object.
+ *
+ * @param previous Previous path argument
+ * @return String representation
+ */
+ String toRelativeString(PathArgument previous);
}
private static abstract class AbstractPathArgument implements PathArgument {
public String toString() {
return getNodeType().toString();
}
+
+ @Override
+ public String toRelativeString(final PathArgument previous) {
+ if (previous instanceof AbstractPathArgument) {
+ final QNameModule mod = ((AbstractPathArgument)previous).getNodeType().getModule();
+ if (getNodeType().getModule().equals(mod)) {
+ return getNodeType().getLocalName();
+ }
+ }
+
+ return getNodeType().toString();
+ }
}
/**
public String toString() {
return super.toString() + '[' + keyValues + ']';
}
+
+ @Override
+ public String toRelativeString(final PathArgument previous) {
+ return super.toRelativeString(previous) + '[' + keyValues + ']';
+ }
}
/**
public String toString() {
return super.toString() + '[' + value + ']';
}
+
+ @Override
+ public String toRelativeString(final PathArgument previous) {
+ return super.toRelativeString(previous) + '[' + value + ']';
+ }
}
/**
}
/**
- *
* Returns set of all possible child nodes
*
* @return set of all possible child nodes.
return sb.toString();
}
+ @Override
+ public String toRelativeString(final PathArgument previous) {
+ return toString();
+ }
+
@Override
public boolean equals(final Object o) {
if (this == o) {
synchronized (this) {
ret = toStringCache;
if (ret == null) {
- final StringBuilder builder = new StringBuilder('/');
- boolean first = true;
+ final StringBuilder builder = new StringBuilder("/");
+ PathArgument prev = null;
for (PathArgument argument : getPathArguments()) {
- if (first) {
- first = false;
- } else {
+ if (prev != null) {
builder.append('/');
}
- builder.append(argument.toString());
+ builder.append(argument.toRelativeString(prev));
+ prev = argument;
}
ret = builder.toString();
@Override
public Optional<TreeNode> getChild(final PathArgument key) {
- return Optional.fromNullable(children.get(key));
+ Optional<TreeNode> explicitNode = Optional.fromNullable(children.get(key));
+ if (explicitNode.isPresent()) {
+ return explicitNode;
+ }
+ final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
+ Optional<NormalizedNode<?, ?>> 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
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<?, ?, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
+
+ for(NormalizedNode<?, ?> childData : castedData.getValue()) {
+ PathArgument id = childData.getIdentifier();
+
+ if (!children.containsKey(id)) {
+ children.put(id, TreeNodeFactory.createTreeNode(childData, version));
+ }
+ }
}
@Override
}
}
- private static ContainerNode create(final Version version, final NormalizedNode<?, ?> data,
- final Iterable<NormalizedNode<?, ?>> children) {
+ /**
+ * Method creates and returns Container root Node and whole subtree for each child node specified in children nodes.
+ * <br>
+ * Reason why is method used recursively is that for each child in children nodes there is call to
+ * {@link TreeNodeFactory#createTreeNodeRecursively}. Each call to <code>createTreeNodeRecursively</code>
+ * calls either {@link #createNormalizedNodeRecursively} or {@link #createOrderedNodeRecursively}
+ * which depends on type of child node.
+ * <br> 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<NormalizedNode<?, ?>> children) {
final Map<PathArgument, TreeNode> 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<?, ?, NormalizedNode<?, ?>> 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()}
+ * <br>
+ * 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<?, ?, NormalizedNode<?, ?>> 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()}
+ * <br>
+ * 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<NormalizedNode<?, ?>> container) {
+ return createNodeRecursively(version, container, container.getValue());
}
- public static ContainerNode create(final Version version, final OrderedNodeContainer<NormalizedNode<?, ?>> 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<?, ?, NormalizedNode<?, ?>> 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<NormalizedNode<?, ?>> 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<PathArgument, TreeNode> map = new HashMap<>();
+ return new ContainerNode(data, version, map, version);
}
}
* @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<?, ?, NormalizedNode<?, ?>> container = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
- return ContainerNode.create(version, container);
+ return ContainerNode.createNormalizedNodeRecursively(version, container);
}
if (data instanceof OrderedNodeContainer<?>) {
@SuppressWarnings("unchecked")
OrderedNodeContainer<NormalizedNode<?, ?>> container = (OrderedNodeContainer<NormalizedNode<?, ?>>) 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<?, ?, NormalizedNode<?, ?>> container = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
+ return ContainerNode.createNormalizedNode(version, container);
+ }
+ if (data instanceof OrderedNodeContainer<?>) {
+ @SuppressWarnings("unchecked")
+ OrderedNodeContainer<NormalizedNode<?, ?>> container = (OrderedNodeContainer<NormalizedNode<?, ?>>) data;
+ return ContainerNode.createOrderedNode(version, container);
+ }
+ return new ValueNode(data, version);
+ }
}
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;
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;
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;
* This is the parsing part
*/
// This is where we will output the nodes
- final NormalizedNodeContainerBuilder<NodeIdentifier, ?, ?, ? extends NormalizedNode<?, ?>> 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)) {
}
// 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<? extends PathArgument, ?> firstChild = ((ContainerNode) parsedData).getValue().iterator().next();
+ final DataContainerChild<? extends PathArgument, ?> firstChild = (DataContainerChild<? extends PathArgument, ?>) parsedData;
LOG.debug("Serializing first child: {}", firstChild);
// String holder
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;
if (pathArgument instanceof NodeIdentifierWithPredicates) {
Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
- for (QName keyValue : predicates.keySet()) {
- String predicateValue = String.valueOf(predicates.get(keyValue));
+ for (Map.Entry<QName, Object> 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("']");
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;
}
private static boolean isFromAugment(final DataNodeContainer schema, final DataSchemaNode childSchema) {
- if(schema instanceof AugmentationTarget == false) {
+ if (!(schema instanceof AugmentationTarget)) {
return false;
}
for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) {
// If is not augmented child, continue
- if (augments.containsKey(child.getQName()) == false) {
+ if (!(augments.containsKey(child.getQName()))) {
continue;
}
// 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;
}
*
*/
public static Set<DataSchemaNode> getRealSchemasForAugment(final AugmentationTarget targetSchema, final AugmentationSchema augmentSchema) {
- if(targetSchema.getAvailableAugmentations().contains(augmentSchema) == false) {
+ if (!(targetSchema.getAvailableAugmentations().contains(augmentSchema))) {
return Collections.emptySet();
}
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;
public static void checkLegalChild(final boolean isLegal, final YangInstanceIdentifier.PathArgument child, final DataNodeContainer schema,
final Set<QName> childNodes, final Set<YangInstanceIdentifier.AugmentationIdentifier> 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<QName> 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));
}
}
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) {
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);
}
/**
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.
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);
}
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;
}
};
- private final Map<PathArgument, ModifiedNode> children = new LinkedHashMap<>();
+ private final Map<PathArgument, ModifiedNode> children;
private final Optional<TreeNode> original;
private final PathArgument identifier;
private ModificationType modificationType = ModificationType.UNMODIFIED;
private Optional<TreeNode> snapshotCache;
private NormalizedNode<?, ?> value;
- private ModifiedNode(final PathArgument identifier, final Optional<TreeNode> original) {
+ private ModifiedNode(final PathArgument identifier, final Optional<TreeNode> original, boolean isOrdered) {
this.identifier = identifier;
this.original = original;
+
+ if (isOrdered) {
+ children = new LinkedHashMap<>();
+ } else {
+ children = new HashMap<>();
+ }
}
/**
* @return {@link org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ModifiedNode} for specified child, with {@link #getOriginal()}
* containing child metadata if child was present in original data.
*/
- public ModifiedNode modifyChild(final PathArgument child) {
+ public ModifiedNode modifyChild(final PathArgument child, boolean isOrdered) {
clearSnapshot();
if (modificationType == ModificationType.UNMODIFIED) {
updateModificationType(ModificationType.SUBTREE_MODIFIED);
currentMetadata = Optional.absent();
}
- ModifiedNode newlyCreated = new ModifiedNode(child, currentMetadata);
+ ModifiedNode newlyCreated = new ModifiedNode(child, currentMetadata, isOrdered);
children.put(child, newlyCreated);
return newlyCreated;
}
+ modificationType + ", childModification=" + children + "]";
}
- public static ModifiedNode createUnmodified(final TreeNode metadataTree) {
- return new ModifiedNode(metadataTree.getIdentifier(), Optional.of(metadataTree));
+ public static ModifiedNode createUnmodified(final TreeNode metadataTree, boolean isOrdered) {
+ return new ModifiedNode(metadataTree.getIdentifier(), Optional.of(metadataTree), isOrdered);
}
}
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<ModifiedNode> modifications) {
entryStrategy = Optional.<ModificationApplyOperation> of(new ValueNodeModificationStrategy.LeafSetEntryModificationStrategy(schema));
}
+ @Override
+ boolean isOrdered() {
+ return true;
+ }
+
@SuppressWarnings("rawtypes")
@Override
protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
entryStrategy = Optional.<ModificationApplyOperation> of(new DataNodeContainerModificationStrategy.ListEntryModificationStrategy(schema));
}
+ @Override
+ boolean isOrdered() {
+ return true;
+ }
+
@SuppressWarnings("rawtypes")
@Override
protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
}
public OperationWithModification forChild(final PathArgument childId) {
- ModifiedNode childMod = modification.modifyChild(childId);
- Optional<ModificationApplyOperation> 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);
}
}
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;
}
}
- protected void checkWriteApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> 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<TreeNode> current) throws DataValidationFailedException {
Optional<TreeNode> original = modification.getOriginal();
if (original.isPresent() && current.isPresent()) {
checkNotConflicting(path, original.get(), current.get());
}
}
+ boolean isOrdered() {
+ return false;
+ }
+
@Override
public final Optional<TreeNode> apply(final ModifiedNode modification,
final Optional<TreeNode> currentMeta, final Version version) {
entryStrategy = Optional.<ModificationApplyOperation> of(new DataNodeContainerModificationStrategy.UnkeyedListItemModificationStrategy(schema));
}
+ @Override
+ boolean isOrdered() {
+ return true;
+ }
+
@Override
protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
final Version version) {
@Override
protected TreeNode applyWrite(final ModifiedNode modification,
final Optional<TreeNode> 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<ModifiedNode> modifications) {
+
+ for (ModifiedNode mod : modifications) {
+ final PathArgument id = mod.getIdentifier();
+ final Optional<TreeNode> cm = meta.getChild(id);
+
+ Optional<TreeNode> 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
@Override
protected TreeNode applyWrite(final ModifiedNode modification,
final Optional<TreeNode> currentMeta, final Version version) {
- return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), version);
+ return TreeNodeFactory.createTreeNodeRecursively(modification.getWrittenValue(), version);
}
@Override
@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<NormalizedNode<?, ?>> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH);
assertTrue(originalBarNode.isPresent());
@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<TreeNode> node = TreeNodeUtils.findNode(rootNode, OUTER_LIST_1_PATH);
assertPresentAndType(node, TreeNode.class);
@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) //
@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 {
@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) //
@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<TreeNode> expectedNode = TreeNodeUtils.findNode(rootNode, TWO_TWO_PATH);
assertPresentAndType(expectedNode, TreeNode.class);
@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)
@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<TreeNode> node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode),
TestModel.TEST_PATH.getLastPathArgument());
@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<TreeNode> node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode),
TestModel.OUTER_LIST_PATH.getLastPathArgument());
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;
Set<YangInstanceIdentifier.PathArgument> 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;
}
if (m.isEmpty()) {
- sources.remove(m);
+ sources.remove(source.getSourceIdentifier());
}
}
}
*/
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 <code>default</code> implementation of Bits Type Definition interface.
*
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.";
*/
@Override
public String getDescription() {
- return description;
+ return DESCRIPTION;
}
/*
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;
} 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;
builder.append(", path=");
builder.append(path);
builder.append(", description=");
- builder.append(description);
+ builder.append(DESCRIPTION);
builder.append(", reference=");
builder.append(REFERENCE);
builder.append(", bits=");
+++ /dev/null
-/*
- * 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<LengthConstraint> lengthStatements;
- private final List<PatternConstraint> patterns;
- private final List<RangeConstraint> rangeStatements;
- private final List<UnknownSchemaNode> 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<LengthConstraint> lengthStatements = Collections.emptyList();
- private List<PatternConstraint> patterns = Collections.emptyList();
- private List<RangeConstraint> rangeStatements = Collections.emptyList();
- private List<UnknownSchemaNode> 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<LengthConstraint> lengthStatements) {
- this.lengthStatements = lengthStatements;
- return this;
- }
-
- public Builder patterns(final List<PatternConstraint> patterns) {
- this.patterns = patterns;
- return this;
- }
-
- public Builder rangeStatements(final List<RangeConstraint> rangeStatements) {
- this.rangeStatements = rangeStatements;
- return this;
- }
-
- public Builder extensions(final List<UnknownSchemaNode> 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<UnknownSchemaNode> getUnknownSchemaNodes() {
- return extensions;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition
- * #getRangeStatements()
- */
- @Override
- public List<RangeConstraint> getRangeConstraints() {
- return rangeStatements;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition
- * #getLengthStatements()
- */
- @Override
- public List<LengthConstraint> getLengthConstraints() {
- return lengthStatements;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition
- * #getPatterns()
- */
- @Override
- public List<PatternConstraint> 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();
- }
-
-}
* 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<URI, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
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;
public TypeDefinition<? extends 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),
private final Set<GroupingDefinition> groupings;
private final Set<UsesNode> uses;
private final Set<TypeDefinition<?>> typeDefinitions;
+ private final Set<DataSchemaNode> publicChildNodes;
protected AbstractDocumentedDataNodeContainer(final AbstractDocumentedDataNodeContainerBuilder data) {
super(data);
groupings = ImmutableSet.copyOf(data.getGroupings());
uses = ImmutableSet.copyOf(data.getUsesNodes());
typeDefinitions = ImmutableSet.copyOf(data.getTypeDefinitions());
+ publicChildNodes = ImmutableSet.copyOf(childNodes.values());
}
@Override
@Override
public final Set<DataSchemaNode> getChildNodes() {
- return ImmutableSet.copyOf(childNodes.values());
+ return publicChildNodes;
}
@Override
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;
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)));
}
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) {
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();
if (targetModule == null) {
Module result = findModuleFromContext(context, module, prefix, 0);
targetModule = new ModuleBuilder(result);
- TreeMap<Date, ModuleBuilder> map = modules.get(prefix);
+ TreeMap<Date, ModuleBuilder> map = modules.get(targetModule.getNamespace());
if (map == null) {
map = new TreeMap<>();
map.put(targetModule.getRevision(), targetModule);
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);
}
}
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<ModuleImport> imports = parseImports(module.linkage_stmts().import_stmt());
ImmutableSet<ModuleImport> 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<ModuleImport> parseImports(final List<Import_stmtContext> importStatements) {
*/
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<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
super(name, latestRevision, imports, includes);
}