--- /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);
}
}
}
- private class IdentifiableItemCodec implements Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> {
+ private static class IdentifiableItemCodec implements Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> {
private final ImmutableSortedMap<QName, ValueContext> keyValueContexts;
private final ListSchemaNode schema;
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);
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
import java.lang.reflect.Method;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.binding.Augmentable;
abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataContainerCodecContext<T> {
private static final Logger LOG = LoggerFactory.getLogger(DataObjectCodecContext.class);
+ private static final Comparator<Method> METHOD_BY_ALPHABET = new Comparator<Method>() {
+
+ @Override
+ public int compare(final Method o1, final Method o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ };
+
private final ImmutableMap<String, LeafNodeCodecContext> leafChild;
private final ImmutableMap<YangInstanceIdentifier.PathArgument, NodeContextSupplier> byYang;
- private final ImmutableMap<Method, NodeContextSupplier> byMethod;
+ private final ImmutableSortedMap<Method, NodeContextSupplier> byMethod;
private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byStreamClass;
private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byBindingArgClass;
protected final Method augmentationGetter;
Map<Class<?>, Method> clsToMethod = BindingReflections.getChildrenClassToMethod(bindingClass());
Map<YangInstanceIdentifier.PathArgument, NodeContextSupplier> byYangBuilder = new HashMap<>();
- Map<Method, NodeContextSupplier> byMethodBuilder = new HashMap<>();
+ SortedMap<Method, NodeContextSupplier> byMethodBuilder = new TreeMap<>(METHOD_BY_ALPHABET);
Map<Class<?>, DataContainerCodecPrototype<?>> byStreamClassBuilder = new HashMap<>();
Map<Class<?>, DataContainerCodecPrototype<?>> byBindingArgClassBuilder = new HashMap<>();
}
}
}
- this.byMethod = ImmutableMap.copyOf(byMethodBuilder);
+ this.byMethod = ImmutableSortedMap.copyOfSorted(byMethodBuilder);
if (Augmentable.class.isAssignableFrom(bindingClass())) {
try {
augmentationGetter = bindingClass().getMethod("getAugmentation", Class.class);
@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();
}
return byMethod.keySet();
}
-}
\ No newline at end of file
+}
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());
genCtx.get(module).addChildNodeType(node, genType);
groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
processUsesAugments((DataNodeContainer) node, module);
+ if (node.isAddedByUses() || node.isAugmenting())
+ genType.setSuitableForBoxing(false);
}
return genType;
}
+ private boolean hasWhenOrMustConstraints(final SchemaNode node) {
+ boolean hasWhenCondition;
+ boolean hasMustConstraints;
+
+ if (node instanceof ContainerSchemaNode) {
+ ContainerSchemaNode contNode = (ContainerSchemaNode)node;
+ hasWhenCondition = contNode.getConstraints().getWhenCondition() != null;
+ hasMustConstraints = !isNullOrEmpty(contNode.getConstraints().getMustConstraints());
+
+ if (hasWhenCondition || hasMustConstraints)
+ return true;
+ }
+ return false;
+ }
+
private void containerToGenType(final Module module, final String basePackageName,
final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node) {
final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
+
if (genType != null) {
constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType);
resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes());
+
+ final String parentName = parent.getName();
+ final String childOfName = childOf.getName();
+
+ if (parent != null && !parent.getName().contains("Data"))
+ genType.setParentType(parent);
+ genType.setSuitableForBoxing(hasOnlyOneChild(node) && !hasWhenOrMustConstraints(node));
+
+ if (parentName.equals(childOfName))
+ genType.setSuitableForBoxing(false);
}
}
+ private boolean hasOnlyOneChild(final ContainerSchemaNode contNode) {
+ if (!isNullOrEmpty(contNode.getChildNodes()) && contNode.getChildNodes().size() == 1)
+ return true;
+ return false;
+ }
+
private void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder parent,
final GeneratedTypeBuilder childOf, final ListSchemaNode node) {
final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
+
if (genType != null) {
+ if (!parent.getName().equals(childOf) && !parent.getName().contains("Data")) {
+ genType.setParentType(parent);
+ }
constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), Types.listTypeFor(genType));
final List<String> listKeys = listKeys(node);
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());
if (targetTypeBuilder == null) {
throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
}
+ targetTypeBuilder.setSuitableForBoxing(false);
if (!(targetSchemaNode instanceof ChoiceNode)) {
String packageName = augmentPackageName;
constructGetter(parent, choiceNode.getQName().getLocalName(), choiceNode.getDescription(),
choiceTypeBuilder);
choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class));
+ choiceTypeBuilder.setParentType(parent);
genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
generateTypesFromChoiceCases(module, basePackageName, choiceTypeBuilder.toInstance(), choiceNode);
}
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);
}
genTOBuilders.addAll(types);
GeneratedTOBuilder resultTOBuilder = null;
- if (!types.isEmpty()) {
- resultTOBuilder = types.remove(0);
- for (GeneratedTOBuilder genTOBuilder : types) {
- resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
- }
+ if (types.isEmpty()) {
+ throw new IllegalStateException("No GeneratedTOBuilder objects generated from union " + typeDef);
+ }
+ resultTOBuilder = types.remove(0);
+ for (GeneratedTOBuilder genTOBuilder : types) {
+ resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
}
final GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value");
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
return values;
}
+ @Override
+ public boolean isSuitableForBoxing() {
+ return false;
+ }
+
@Override
public List<AnnotationType> getAnnotations() {
return annotations;
public String getModuleName() {
return moduleName;
}
+
}
}
public String getModuleName() {
return moduleName;
}
+
+ @Override
+ public boolean isSuitableForBoxing() {
+ return false;
+ }
}
}
package org.opendaylight.yangtools.binding.generator.util.generated.type.builder;
import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.yangtools.yang.common.QName;
private String reference;
private String moduleName;
private Iterable<QName> schemaPath;
+ private boolean isSuitableForBoxing;
+ private GeneratedTypeBuilder parentType;
public GeneratedTypeBuilderImpl(final String packageName, final String name) {
super(packageName, name);
this.reference = reference;
}
+ @Override
+ public void setSuitableForBoxing(boolean value) {
+ this.isSuitableForBoxing = value;
+ }
+
+ @Override
+ public void setParentType(GeneratedTypeBuilder parent) {
+ this.parentType = parent;
+ }
+
+ @Override
+ public Type getParent() {
+ return this.parentType;
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
private final String reference;
private final String moduleName;
private final Iterable<QName> schemaPath;
+ private final boolean isSuitableForBoxing;
+ private final GeneratedTypeBuilder parentType;
public GeneratedTypeImpl(GeneratedTypeBuilderImpl builder) {
super(builder);
this.reference = builder.reference;
this.moduleName = builder.moduleName;
this.schemaPath = builder.schemaPath;
+ this.isSuitableForBoxing = builder.isSuitableForBoxing;
+ this.parentType = builder.parentType;
}
@Override
public String getModuleName() {
return moduleName;
}
+
+ @Override
+ public boolean isSuitableForBoxing() {
+ return isSuitableForBoxing;
+ }
}
+
}
import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
import org.opendaylight.yangtools.sal.binding.model.api.Type
import org.opendaylight.yangtools.yang.binding.Augmentable
+import org.opendaylight.yangtools.yang.binding.ChildOf
import org.opendaylight.yangtools.yang.binding.DataObject
import org.opendaylight.yangtools.yang.binding.Identifiable
«generateFields(false)»
- «generateAugmentField(true)»
+ «generateAugmentField(false)»
«generateConstructorsFromIfcs(type)»
«generateSetters»
- public «type.name» build() {
- return new «type.name»«IMPL»(this);
- }
+ «generateBuildMethod»
+
+ «generateBuildBoxedMethod»
private static final class «type.name»«IMPL» implements «type.name» {
«generateFields(true)»
- «generateAugmentField(false)»
+ «generateAugmentField(true)»
«generateCopyConstructor(true)»
}
'''
+ def private generateBuildMethod() '''
+ public «type.name» build() {
+ return new «type.name»«IMPL»(this);
+ }
+ '''
+
+ def private generateBuildBoxedMethod() {
+ if(type.suitableForBoxing && type.parentType != null && isContainerAndIsNotList(type)) {
+ val parentTypeBuilder = createParentTypeBuilder()
+ if (countMatches(parentTypeBuilder, "org") < 2) {
+ return '''
+ public «type.parentType.importedName» buildBoxed() {
+ return new «parentTypeBuilder»().set«type.name»(build()).build();
+ }
+ '''
+ }
+ }
+ return ''
+ }
+
+ def private int countMatches(String string, String subString) {
+ if (string.nullOrEmpty || subString.nullOrEmpty) {
+ return 0
+ }
+ var int count = 0;
+ var int idx = 0;
+ while ((idx = string.indexOf(subString, idx)) != -1) {
+ count = count + 1;
+ idx = idx + subString.length();
+ }
+ return count;
+ }
+
+ def private createParentTypeBuilder() {
+ return type.parentType.packageName + "." + type.parentType.importedName + "Builder"
+ }
+
+ def private boolean isContainerAndIsNotList(GeneratedType type) {
+ val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))
+ val implementsChildOf = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(ChildOf), type))
+
+ if (implementsChildOf && !isList) {
+ return true
+ }
+ return false;
+ }
+
/**
* Generate default constructor and constructor for every implemented interface from uses statements.
*/
«ENDIF»
'''
- def private generateAugmentField(boolean init) '''
+ def private generateAugmentField(boolean isPrivate) '''
«IF augmentField != null»
- private «Map.importedName»<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>();
+ «IF isPrivate»private «ENDIF»«Map.importedName»<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>();
«ENDIF»
'''
--- /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
+
+module mod-box {
+ yang-version 1;
+ namespace "urn:opendaylight:mod:box";
+ prefix "box";
+
+ revision 2014-08-05 {
+ }
+
+ container cont1 {
+ choice choice1 {
+ case case1 {
+ container cont2 {
+ leaf leaf1 {
+ type string;
+ }
+ }
+ }
+ }
+ }
+}
--- /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.sal.binding.model.api;
+
+/**
+ * Implementing this interface allows an object to hold information about that if
+ * is generated type suitable for boxing.
+ *
+ * Example:
+ * choice foo-choice {
+ * case foo-case {
+ * container foo {
+ * ...
+ * }
+ * }
+ * }
+ *
+ * Suitable type have to implements ChildOf<T>, where !(T instanceof Identifiable) and
+ * T does not place any structural requirements (must/when) on existence/value Foo.
+ */
+public interface BoxableType {
+
+ /**
+ * Check if generated type is suitable for boxing.
+ *
+ * @return true if generated type is suitable for boxing, false otherwise.
+ */
+ boolean isSuitableForBoxing();
+}
* definitions MUST be public, so there is no need to specify the scope of
* visibility.
*/
-public interface GeneratedType extends Type, DocumentedType {
+public interface GeneratedType extends Type, DocumentedType, BoxableType {
/**
* Returns the parent type if Generated Type is defined as enclosing type,
/**
* Generated Type Builder interface is helper interface for building and
* defining the GeneratedType.
- *
+ *
* @see GeneratedType
*/
public interface GeneratedTypeBuilder extends GeneratedTypeBuilderBase<GeneratedTypeBuilder> {
/**
* Returns the <code>new</code> <i>immutable</i> instance of Generated Type.
- *
+ *
* @return the <code>new</code> <i>immutable</i> instance of Generated Type.
*/
GeneratedType toInstance();
+ /**
+ * Set true if generated type is suitable for boxing, false otherwise.
+ *
+ * @param value
+ */
+ public void setSuitableForBoxing(boolean value);
+
+ /**
+ * Set parent for current generated type.
+ *
+ * @param parent
+ */
+ public void setParentType(GeneratedTypeBuilder parent);
}
package org.opendaylight.yangtools.sal.binding.model.api.type.builder;
import java.util.List;
-
import org.opendaylight.yangtools.sal.binding.model.api.Constant;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.common.QName;
* Name of Enclosing Type
* @return <code>new</code> Instance of Generated Type Builder.
*/
- GeneratedTOBuilder addEnclosingTransferObject(final String name);
+ GeneratedTOBuilder addEnclosingTransferObject(String name);
/**
* Adds new Enclosing Transfer Object <code>genTOBuilder</code> into
* @param genTOBuilder
* Name of Enclosing Type
*/
- T addEnclosingTransferObject(final GeneratedTOBuilder genTOBuilder);
+ T addEnclosingTransferObject(GeneratedTOBuilder genTOBuilder);
/**
* Adds String definition of comment into Method Signature definition. <br>
* @param comment
* Comment String.
*/
- T addComment(final String comment);
+ T addComment(String comment);
/**
* The method creates new AnnotationTypeBuilder containing specified package
* Name of Annotation Type
* @return <code>new</code> instance of Annotation Type Builder.
*/
- AnnotationTypeBuilder addAnnotation(final String packageName, final String name);
+ AnnotationTypeBuilder addAnnotation(String packageName, String name);
boolean isAbstract();
* Type to implement
* @return <code>true</code> if the addition of type is successful.
*/
- T addImplementsType(final Type genType);
+ T addImplementsType(Type genType);
/**
* Adds Constant definition and returns <code>new</code> Constant instance. <br>
* Assigned Value
* @return <code>new</code> Constant instance.
*/
- Constant addConstant(final Type type, final String name, final Object value);
+ Constant addConstant(Type type, String name, Object value);
/**
* Adds new Enumeration definition for Generated Type Builder and returns
* Enumeration Name
* @return <code>new</code> instance of Enumeration Builder.
*/
- EnumBuilder addEnumeration(final String name);
+ EnumBuilder addEnumeration(String name);
List<MethodSignatureBuilder> getMethodDefinitions();
* Name of Method
* @return <code>new</code> instance of Method Signature Builder.
*/
- MethodSignatureBuilder addMethod(final String name);
+ MethodSignatureBuilder addMethod(String name);
/**
* Checks if GeneratedTypeBuilder contains method with name
* @param methodName
* is method name
*/
- boolean containsMethod(final String methodName);
+ boolean containsMethod(String methodName);
List<GeneratedPropertyBuilder> getProperties();
* Name of Property
* @return <code>new</code> instance of Generated Property Builder.
*/
- GeneratedPropertyBuilder addProperty(final String name);
+ GeneratedPropertyBuilder addProperty(String name);
/**
* Check whether GeneratedTOBuilder contains property with name
* of property which existance is checked
* @return true if property <code>name</code> exists in list of properties.
*/
- boolean containsProperty(final String name);
+ boolean containsProperty(String name);
/**
* Set a string that contains a human-readable textual description of type
--- /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;
+ }
+ }
+}
}
typeDefinitionsConcreteDepth.add(unsortedTypeDefinition);
}
- // keys are in ascending order
- for (Map.Entry<Integer, List<TypeDefinition<?>>> entry : typeDefinitionsDepths.entrySet()) {
- sortedTypeDefinition.addAll(entry.getValue());
+
+ // SortedMap guarantees order corresponding to keys in ascending order
+ for (List<TypeDefinition<?>> v : typeDefinitionsDepths.values()) {
+ sortedTypeDefinition.addAll(v);
}
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>
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">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yangtools-parent</artifactId>
- <version>0.6.2-SNAPSHOT</version>
- <relativePath>../parent/pom.xml</relativePath>
- </parent>
- <artifactId>features-yangtools</artifactId>
- <packaging>jar</packaging>
- <properties>
- <features.file>features.xml</features.file>
- </properties>
- <build>
- <resources>
- <resource>
- <directory>src/main/resources</directory>
- <filtering>true</filtering>
- </resource>
- </resources>
- <plugins>
- <plugin>
- <groupId>org.apache.karaf.tooling</groupId>
- <artifactId>karaf-maven-plugin</artifactId>
- <version>${karaf.version}</version>
- <extensions>true</extensions>
- <executions>
- <execution>
- <id>features-create-kar</id>
- <goals>
- <goal>features-create-kar</goal>
- </goals>
- <configuration>
- <featuresFile>${project.build.directory}/classes/${features.file}</featuresFile>
- </configuration>
- </execution>
- </executions>
- <!-- There is no useful configuration for the kar mojo. The features-generate-descriptor mojo configuration may be useful -->
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <executions>
- <execution>
- <id>filter</id>
- <phase>generate-resources</phase>
- <goals>
- <goal>resources</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-artifacts</id>
- <phase>package</phase>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <configuration>
- <artifacts>
- <artifact>
- <file>${project.build.directory}/classes/${features.file}</file>
- <type>xml</type>
- <classifier>features</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <dependenciesToScan>
- <dependency>org.opendaylight.yangtools:features-test</dependency>
- </dependenciesToScan>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>ietf-inet-types</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>ietf-yang-types</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>yang-ext</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>opendaylight-l2-types</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>ietf-topology</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-composite-node</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-operations</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-model-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-model-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-parser-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-parser-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>concepts</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-common</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>object-cache-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>object-cache-guava</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>object-cache-noop</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-spi</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-model-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-type-provider</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-model-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-model-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-parser-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-client-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-client-impl</artifactId>
- </dependency>
- <dependency>
- <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>
- <scope>compile</scope>
- </dependency>
- <!-- test the features.xml -->
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>features-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
+<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">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yangtools-parent</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+ <artifactId>features-yangtools</artifactId>
+ <packaging>jar</packaging>
+ <properties>
+ <features.file>features.xml</features.file>
+ </properties>
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <version>${karaf.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>features-create-kar</id>
+ <goals>
+ <goal>features-create-kar</goal>
+ </goals>
+ <configuration>
+ <featuresFile>${project.build.directory}/classes/${features.file}</featuresFile>
+ </configuration>
+ </execution>
+ </executions>
+ <!-- There is no useful configuration for the kar mojo. The features-generate-descriptor mojo configuration may be useful -->
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>filter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>resources</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/classes/${features.file}</file>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <dependenciesToScan>
+ <dependency>org.opendaylight.yangtools:features-test</dependency>
+ </dependenciesToScan>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <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>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>opendaylight-l2-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-composite-node</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-operations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>concepts</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>object-cache-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>object-cache-guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>object-cache-noop</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-type-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-impl</artifactId>
+ </dependency>
+ <dependency>
+ <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>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+
+ <!-- test the features.xml -->
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>features-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
</project>
<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>
<bundle>mvn:org.opendaylight.yangtools.thirdparty/antlr4-runtime-osgi-nohead/${antlr4.version}</bundle>
<bundle>mvn:commons-io/commons-io/${commons.io.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-data-api/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools/yang-data-composite-node/${project.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-data-impl/${project.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-data-operations/${project.version}</bundle>
- <bundle>mvn:org.opendaylight.yangtools/yang-data-composite-node/${project.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-data-util/${project.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-model-api/${project.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-model-util/${project.version}</bundle>
- <bundle>mvn:org.opendaylight.yangtools/yang-parser-impl/${project.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-parser-api/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools/yang-parser-impl/${project.version}</bundle>
+
+ <!-- GSON-based JSON codec. Can be split out -->
+ <bundle>mvn:com.google.code.gson/gson/${gson.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools/yang-data-codec-gson/${project.version}</bundle>
</feature>
<feature name='odl-yangtools-binding' version='${project.version}' description='OpenDaylight :: Yangtools :: Binding'>
*/
package org.opendaylight.yangtools.objcache;
+import com.google.common.base.Preconditions;
+
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.yangtools.objcache.impl.StaticObjectCacheBinder;
import org.opendaylight.yangtools.objcache.spi.IObjectCacheFactory;
import org.opendaylight.yangtools.objcache.spi.NoopObjectCacheBinder;
-import com.google.common.base.Preconditions;
-
/**
* Point of entry for acquiring an {@link ObjectCache} instance.
*/
public final class ObjectCacheFactory {
- private static IObjectCacheFactory FACTORY;
+ private static volatile IObjectCacheFactory factory;
+ @GuardedBy("this")
private static synchronized IObjectCacheFactory initialize() {
// Double-check under lock
- if (FACTORY != null) {
- return FACTORY;
+ IObjectCacheFactory f = factory;
+ if (f != null) {
+ return f;
}
- IObjectCacheFactory f;
try {
f = StaticObjectCacheBinder.getInstance().getProductCacheFactory();
- FACTORY = f;
+ factory = f;
} catch (NoClassDefFoundError e) {
f = NoopObjectCacheBinder.INSTANCE.getProductCacheFactory();
}
}
public static synchronized void reset() {
- FACTORY = null;
+ factory = null;
}
/**
* @return Object cache instance.
*/
public static ObjectCache getObjectCache(@Nonnull final Class<?> objClass) {
- IObjectCacheFactory f = FACTORY;
+ IObjectCacheFactory f = factory;
if (f == null) {
f = initialize();
}
*/
package org.opendaylight.yangtools.objcache.spi;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.FinalizableReferenceQueue;
+import com.google.common.base.FinalizableSoftReference;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.Cache;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
-
import org.opendaylight.yangtools.concepts.ProductAwareBuilder;
import org.opendaylight.yangtools.objcache.ObjectCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.FinalizableReferenceQueue;
-import com.google.common.base.FinalizableSoftReference;
-import com.google.common.base.Preconditions;
-import com.google.common.cache.Cache;
-
/**
* Abstract object cache implementation. This implementation takes care
* of interacting with the user and manages interaction with the Garbage
* to be on the lookout for WeakKeys, as we cannot pass them
* directly to productEquals().
*/
- if (obj != null && obj instanceof SoftKey) {
+ if (obj instanceof SoftKey) {
obj = ((SoftKey<?>)obj).get();
}
<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>yang-data-impl</artifactId>
<version>0.6.2-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-gson</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-api</artifactId>
<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>
<version>${sonar-jacoco-listeners.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<repository>
<id>opendaylight-mirror</id>
<name>opendaylight-mirror</name>
- <url>http://nexus.opendaylight.org/content/groups/public/</url>
+ <url>${nexusproxy}/groups/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<repository>
<id>opendaylight-snapshot</id>
<name>opendaylight-snapshot</name>
- <url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+ <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<extensions>true</extensions>
<configuration>
<instructions>
- <Export-Package>
- org.opendaylight.yangtools.util,
- org.opendaylight.yangtools.util.concurrent
- </Export-Package>
<Embed-Dependency>java-concurrent-hash-trie-map;inline=true</Embed-Dependency>
</instructions>
</configuration>
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.util;
+
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.google.common.util.concurrent.AtomicDouble;
+
+/**
+ * Class that calculates and tracks time duration statistics.
+ *
+ * @author Thomas Pantelis
+ */
+public class DurationStatsTracker {
+
+ private final AtomicLong totalDurations = new AtomicLong();
+ private final AtomicLong longestDuration = new AtomicLong();
+ private volatile long timeOfLongestDuration;
+ private final AtomicLong shortestDuration = new AtomicLong(Long.MAX_VALUE);
+ private volatile long timeOfShortestDuration;
+ private final AtomicDouble averageDuration = new AtomicDouble();
+
+ /**
+ * Add a duration to track.
+ *
+ * @param duration the duration in nanoseconds.
+ */
+ public void addDuration(long duration) {
+
+ double currentAve = averageDuration.get();
+ long currentTotal = totalDurations.get();
+
+ long newTotal = currentTotal + 1;
+
+ // Calculate moving cumulative average.
+ double newAve = currentAve * currentTotal / newTotal + duration / newTotal;
+
+ averageDuration.compareAndSet(currentAve, newAve);
+ totalDurations.compareAndSet(currentTotal, newTotal);
+
+ long longest = longestDuration.get();
+ if( duration > longest ) {
+ if(longestDuration.compareAndSet( longest, duration )) {
+ timeOfLongestDuration = System.currentTimeMillis();
+ }
+ }
+
+ long shortest = shortestDuration.get();
+ if( duration < shortest ) {
+ if(shortestDuration.compareAndSet( shortest, duration )) {
+ timeOfShortestDuration = System.currentTimeMillis();
+ }
+ }
+ }
+
+ /**
+ * Returns the total number of tracked durations.
+ */
+ public long getTotalDurations() {
+ return totalDurations.get();
+ }
+
+ /**
+ * Returns the longest duration in nanoseconds.
+ */
+ public long getLongestDuration() {
+ return longestDuration.get();
+ }
+
+ /**
+ * Returns the shortest duration in nanoseconds.
+ */
+ public long getShortestDuration() {
+ long shortest = shortestDuration.get();
+ return shortest < Long.MAX_VALUE ? shortest : 0;
+ }
+
+ /**
+ * Returns the average duration in nanoseconds.
+ */
+ public double getAverageDuration() {
+ return averageDuration.get();
+ }
+
+ /**
+ * Returns the time stamp of the longest duration.
+ */
+ public long getTimeOfLongestDuration() {
+ return timeOfLongestDuration;
+ }
+
+ /**
+ * Returns the time stamp of the shortest duration.
+ */
+ public long getTimeOfShortestDuration() {
+ return timeOfShortestDuration;
+ }
+
+ /**
+ * Resets all statistics back to their defaults.
+ */
+ public void reset() {
+ totalDurations.set(0);
+ longestDuration.set(0);
+ timeOfLongestDuration = 0;
+ shortestDuration.set(Long.MAX_VALUE);
+ timeOfShortestDuration = 0;
+ averageDuration.set(0.0);
+ }
+
+ /**
+ * Returns the average duration as a displayable String with units, e.g. "12.34 ms".
+ */
+ public String getDisplayableAverageDuration() {
+ return formatDuration(getAverageDuration(), 0);
+ }
+
+ /**
+ * Returns the shortest duration as a displayable String with units and the date/time at
+ * which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
+ */
+ public String getDisplayableShortestDuration() {
+ return formatDuration(getShortestDuration(), getTimeOfShortestDuration());
+ }
+
+ /**
+ * Returns the longest duration as a displayable String with units and the date/time at
+ * which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
+ */
+ public String getDisplayableLongestDuration() {
+ return formatDuration(getLongestDuration(), getTimeOfLongestDuration());
+ }
+
+ private String formatDuration(double duration, long timeStamp) {
+ TimeUnit unit = chooseUnit((long)duration);
+ double value = duration / NANOSECONDS.convert(1, unit);
+ return timeStamp > 0 ?
+ String.format("%.4g %s at %3$tD %3$tT", value, abbreviate(unit), new Date(timeStamp)) :
+ String.format("%.4g %s", value, abbreviate(unit));
+ }
+
+ private static TimeUnit chooseUnit(long nanos) {
+ if(SECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return SECONDS;
+ }
+
+ if(MILLISECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return MILLISECONDS;
+ }
+
+ if(MICROSECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return MICROSECONDS;
+ }
+
+ return NANOSECONDS;
+ }
+
+ private static String abbreviate(TimeUnit unit) {
+ switch(unit) {
+ case NANOSECONDS:
+ return "ns";
+ case MICROSECONDS:
+ return "\u03bcs"; // μs
+ case MILLISECONDS:
+ return "ms";
+ case SECONDS:
+ return "s";
+ default:
+ return "";
+ }
+ }
+}
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Preconditions;
private static final long IDLE_TIMEOUT_IN_SEC = 60L;
- private final AtomicLong largestBackingQueueSize = new AtomicLong( 0 );
-
private final ExecutorQueue executorQueue;
private final String threadPrefix;
executorQueue = (ExecutorQueue)super.getQueue();
rejectedTaskHandler = new RejectedTaskHandler(
- executorQueue.getBackingQueue(), largestBackingQueueSize );
+ executorQueue.getBackingQueue(), CountingRejectedExecutionHandler.newAbortPolicy() );
super.setRejectedExecutionHandler( rejectedTaskHandler );
}
@Override
public void setRejectedExecutionHandler( RejectedExecutionHandler handler ) {
+ Preconditions.checkNotNull( handler );
rejectedTaskHandler.setDelegateRejectedExecutionHandler( handler );
}
+ @Override
+ public RejectedExecutionHandler getRejectedExecutionHandler(){
+ return rejectedTaskHandler.getDelegateRejectedExecutionHandler();
+ }
+
@Override
public BlockingQueue<Runnable> getQueue(){
return executorQueue.getBackingQueue();
}
public long getLargestQueueSize() {
- return largestBackingQueueSize.get();
+ return ((TrackingLinkedBlockingQueue<?>)executorQueue.getBackingQueue()).getLargestQueueSize();
}
protected ToStringHelper addToStringAttributes( ToStringHelper toStringHelper ) {
private final LinkedBlockingQueue<Runnable> backingQueue;
ExecutorQueue( int maxBackingQueueSize ) {
- backingQueue = new LinkedBlockingQueue<>( maxBackingQueueSize );
+ backingQueue = new TrackingLinkedBlockingQueue<>( maxBackingQueueSize );
}
LinkedBlockingQueue<Runnable> getBackingQueue() {
private static class RejectedTaskHandler implements RejectedExecutionHandler {
private final LinkedBlockingQueue<Runnable> backingQueue;
- private final AtomicLong largestBackingQueueSize;
private volatile RejectedExecutionHandler delegateRejectedExecutionHandler;
RejectedTaskHandler( LinkedBlockingQueue<Runnable> backingQueue,
- AtomicLong largestBackingQueueSize ) {
+ RejectedExecutionHandler delegateRejectedExecutionHandler ) {
this.backingQueue = backingQueue;
- this.largestBackingQueueSize = largestBackingQueueSize;
+ this.delegateRejectedExecutionHandler = delegateRejectedExecutionHandler;
}
void setDelegateRejectedExecutionHandler(
- RejectedExecutionHandler delegateRejectedExecutionHandler ){
+ RejectedExecutionHandler delegateRejectedExecutionHandler ) {
this.delegateRejectedExecutionHandler = delegateRejectedExecutionHandler;
}
+ RejectedExecutionHandler getDelegateRejectedExecutionHandler(){
+ return delegateRejectedExecutionHandler;
+ }
+
@Override
public void rejectedExecution( Runnable task, ThreadPoolExecutor executor ) {
if( executor.isShutdown() ) {
}
if( !backingQueue.offer( task ) ) {
- if( delegateRejectedExecutionHandler != null ) {
- delegateRejectedExecutionHandler.rejectedExecution( task, executor );
- } else {
- throw new RejectedExecutionException(
- "All threads are in use and the queue is full" );
- }
- }
-
- largestBackingQueueSize.incrementAndGet();
- long size = backingQueue.size();
- long largest = largestBackingQueueSize.get();
- if( size > largest ) {
- largestBackingQueueSize.compareAndSet( largest, size );
+ delegateRejectedExecutionHandler.rejectedExecution( task, executor );
}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.util.concurrent;
+
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.opendaylight.yangtools.util.ExecutorServiceUtil;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * A RejectedExecutionHandler that delegates to a backing RejectedExecutionHandler and counts the
+ * number of rejected tasks.
+ *
+ * @author Thomas Pantelis
+ */
+public class CountingRejectedExecutionHandler implements RejectedExecutionHandler {
+
+ private final RejectedExecutionHandler delegate;
+ private final AtomicLong rejectedTaskCounter = new AtomicLong();
+
+ /**
+ * Constructor.
+ *
+ * @param delegate the backing RejectedExecutionHandler.
+ */
+ public CountingRejectedExecutionHandler( RejectedExecutionHandler delegate ) {
+ this.delegate = Preconditions.checkNotNull( delegate );
+ }
+
+ @Override
+ public void rejectedExecution( Runnable task, ThreadPoolExecutor executor ) {
+ rejectedTaskCounter.incrementAndGet();
+ delegate.rejectedExecution( task, executor );
+ }
+
+ /**
+ * Returns the rejected task count.
+ */
+ public long getRejectedTaskCount(){
+ return rejectedTaskCounter.get();
+ }
+
+ /**
+ * Returns s counting handler for rejected tasks that runs the rejected task directly in the
+ * calling thread of the execute method, unless the executor has been shut down, in which case
+ * the task is discarded.
+ */
+ public static CountingRejectedExecutionHandler newCallerRunsPolicy() {
+ return new CountingRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy() );
+ }
+
+ /**
+ * Returns a counting handler for rejected tasks that throws a RejectedExecutionException.
+ */
+ public static CountingRejectedExecutionHandler newAbortPolicy() {
+ return new CountingRejectedExecutionHandler( new ThreadPoolExecutor.AbortPolicy() );
+ }
+
+ /**
+ * Returns a counting handler for rejected tasks that that blocks on the
+ * {@link ThreadPoolExecutor}'s backing queue until it can add the task to the queue.
+ */
+ public static CountingRejectedExecutionHandler newCallerWaitsPolicy() {
+ return new CountingRejectedExecutionHandler( ExecutorServiceUtil.waitInQueueExecutionHandler() );
+ }
+}
package org.opendaylight.yangtools.util.concurrent;
-import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
// reached, subsequent tasks will be queued. If the queue is full, tasks will be rejected.
super( maximumPoolSize, maximumPoolSize, keepAliveTime, unit,
- new LinkedBlockingQueue<Runnable>( maximumQueueSize ) );
+ new TrackingLinkedBlockingQueue<Runnable>( maximumQueueSize ) );
this.threadPrefix = threadPrefix;
this.maximumQueueSize = maximumQueueSize;
// Need to specifically configure core threads to timeout.
allowCoreThreadTimeOut( true );
}
+
+ setRejectedExecutionHandler( CountingRejectedExecutionHandler.newAbortPolicy() );
+ }
+
+ public long getLargestQueueSize() {
+ return ((TrackingLinkedBlockingQueue<?>)getQueue()).getLargestQueueSize();
}
protected ToStringHelper addToStringAttributes( ToStringHelper toStringHelper ) {
.add( "Largest Thread Pool Size", getLargestPoolSize() )
.add( "Max Thread Pool Size", getMaximumPoolSize() )
.add( "Current Queue Size", getQueue().size() )
+ .add( "Largest Queue Size", getLargestQueueSize() )
.add( "Max Queue Size", maximumQueueSize )
.add( "Active Thread Count", getActiveCount() )
.add( "Completed Task Count", getCompletedTaskCount() )
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.util.concurrent;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * Class used by the {@link QueuedNotificationManager} that contains a snapshot of notification
+ * queue statistics for a listener.
+ *
+ * @author Thomas Pantelis
+ * @see QueuedNotificationManager
+ */
+public class ListenerNotificationQueueStats {
+
+ private final String listenerClassName;
+ private final int currentQueueSize;
+
+ @ConstructorProperties({"listenerClassName","currentQueueSize"})
+ public ListenerNotificationQueueStats( String listenerClassName, int currentQueueSize ) {
+ this.listenerClassName = listenerClassName;
+ this.currentQueueSize = currentQueueSize;
+ }
+
+ /**
+ * Returns the name of the listener class.
+ */
+ public String getListenerClassName(){
+ return listenerClassName;
+ }
+
+ /**
+ * Returns the current notification queue size.
+ */
+ public int getCurrentQueueSize(){
+ return currentQueueSize;
+ }
+}
package org.opendaylight.yangtools.util.concurrent;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
}
}
+ /**
+ * Returns {@link ListenerNotificationQueueStats} instances for each current listener
+ * notification task in progress.
+ */
+ public List<ListenerNotificationQueueStats> getListenerNotificationQueueStats() {
+ List<ListenerNotificationQueueStats> statsList = new ArrayList<>( listenerCache.size() );
+ for( NotificationTask task: listenerCache.values() ) {
+ statsList.add( new ListenerNotificationQueueStats(
+ task.listenerKey.getListener().getClass().getName(),
+ task.notificationQueue.size() ) );
+ }
+
+ return statsList ;
+ }
+
+ /**
+ * Returns the maximum listener queue capacity.
+ */
+ public int getMaxQueueCapacity(){
+ return maxQueueCapacity;
+ }
+
+ /**
+ * Returns the {@link Executor} to used for notification tasks.
+ */
+ public Executor getExecutor(){
+ return executor;
+ }
+
/**
* Used as the listenerCache map key. We key by listener reference identity hashCode/equals.
* Since we don't know anything about the listener class implementations and we're mixing
package org.opendaylight.yangtools.util.concurrent;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
FastThreadPoolExecutor executor =
new FastThreadPoolExecutor( maximumPoolSize, maximumQueueSize, threadPrefix );
- executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy() );
+ executor.setRejectedExecutionHandler( CountingRejectedExecutionHandler.newCallerRunsPolicy() );
return executor;
}
CachedThreadPoolExecutor executor =
new CachedThreadPoolExecutor( maximumPoolSize, maximumQueueSize, threadPrefix );
- executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy() );
+ executor.setRejectedExecutionHandler( CountingRejectedExecutionHandler.newCallerRunsPolicy() );
return executor;
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.util.concurrent;
+
+import java.util.Collection;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+
+/**
+ * A {@link LinkedBlockingQueue} that tracks the largest queue size for debugging.
+ *
+ * @author Thomas Pantelis
+ *
+ * @param <E> the element t.ype
+ */
+public class TrackingLinkedBlockingQueue<E> extends LinkedBlockingQueue<E> {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Holds largestQueueSize, this long field should be only accessed
+ * using {@value #LARGEST_QUEUE_SIZE_UPDATER}
+ */
+ private volatile long largestQueueSize = 0;
+
+ @SuppressWarnings("rawtypes")
+ private static AtomicLongFieldUpdater<TrackingLinkedBlockingQueue> LARGEST_QUEUE_SIZE_UPDATER = AtomicLongFieldUpdater.newUpdater(TrackingLinkedBlockingQueue.class, "largestQueueSize");
+
+ /**
+ * @see LinkedBlockingQueue#LinkedBlockingQueue
+ */
+ public TrackingLinkedBlockingQueue() {
+ super();
+ }
+
+ /**
+ * @see LinkedBlockingQueue#LinkedBlockingQueue(Collection)
+ */
+ public TrackingLinkedBlockingQueue( Collection<? extends E> c ) {
+ super(c);
+ }
+
+ /**
+ * @see LinkedBlockingQueue#LinkedBlockingQueue(int)
+ */
+ public TrackingLinkedBlockingQueue( int capacity ) {
+ super(capacity);
+ }
+
+ /**
+ * Returns the largest queue size.
+ */
+ public long getLargestQueueSize(){
+ return largestQueueSize;
+ }
+
+ @Override
+ public boolean offer( E e, long timeout, TimeUnit unit ) throws InterruptedException {
+ if( super.offer( e, timeout, unit ) ) {
+ updateLargestQueueSize();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean offer( E e ) {
+ if( super.offer( e ) ) {
+ updateLargestQueueSize();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void put( E e ) throws InterruptedException {
+ super.put( e );
+ updateLargestQueueSize();
+ }
+
+ @Override
+ public boolean add( E e ) {
+ boolean result = super.add( e );
+ updateLargestQueueSize();
+ return result;
+ }
+
+ @Override
+ public boolean addAll( Collection<? extends E> c ) {
+ try {
+ return super.addAll( c );
+ } finally {
+ updateLargestQueueSize();
+ }
+ }
+
+ private void updateLargestQueueSize() {
+ long size = size();
+ long largest = largestQueueSize;
+ if( size > largest ) {
+ LARGEST_QUEUE_SIZE_UPDATER.compareAndSet(this, largest, size );
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for DurationStatsTracker.
+ *
+ * @author Thomas Pantelis
+ */
+public class DurationStatsTrackerTest {
+
+ @Test
+ public void test() {
+
+ DurationStatsTracker tracker = new DurationStatsTracker();
+
+ tracker.addDuration(10000);
+ assertEquals("getTotalDurations", 1, tracker.getTotalDurations());
+ assertEquals("getAverageDuration", 10000.0, tracker.getAverageDuration(), 0.1);
+ assertEquals("getLongestDuration", 10000, tracker.getLongestDuration());
+ assertEquals("getShortestDuration", 10000, tracker.getShortestDuration());
+
+ tracker.addDuration(30000);
+ assertEquals("getTotalDurations", 2, tracker.getTotalDurations());
+ assertEquals("getAverageDuration", 20000.0, tracker.getAverageDuration(), 0.1);
+ assertEquals("getLongestDuration", 30000, tracker.getLongestDuration());
+ assertEquals("getShortestDuration", 10000, tracker.getShortestDuration());
+
+ verifyDisplayableString("getDisplayableAverageDuration",
+ tracker.getDisplayableAverageDuration(), "20.0");
+ verifyDisplayableString("getDisplayableLongestDuration",
+ tracker.getDisplayableLongestDuration(), "30.0");
+ verifyDisplayableString("getDisplayableShortestDuration",
+ tracker.getDisplayableShortestDuration(), "10.0");
+
+ tracker.addDuration(10000);
+ assertEquals("getTotalDurations", 3, tracker.getTotalDurations());
+ assertEquals("getAverageDuration", 16666.0, tracker.getAverageDuration(), 1.0);
+ assertEquals("getLongestDuration", 30000, tracker.getLongestDuration());
+ assertEquals("getShortestDuration", 10000, tracker.getShortestDuration());
+
+ tracker.addDuration(5000);
+ assertEquals("getTotalDurations", 4, tracker.getTotalDurations());
+ assertEquals("getAverageDuration", 13750.0, tracker.getAverageDuration(), 1.0);
+ assertEquals("getLongestDuration", 30000, tracker.getLongestDuration());
+ assertEquals("getShortestDuration", 5000, tracker.getShortestDuration());
+
+ tracker.reset();
+ assertEquals("getTotalDurations", 0, tracker.getTotalDurations());
+ assertEquals("getAverageDuration", 0.0, tracker.getAverageDuration(), 0.1);
+ assertEquals("getLongestDuration", 0, tracker.getLongestDuration());
+ assertEquals("getShortestDuration", 0, tracker.getShortestDuration());
+
+ tracker.addDuration(10000);
+ assertEquals("getTotalDurations", 1, tracker.getTotalDurations());
+ assertEquals("getAverageDuration", 10000.0, tracker.getAverageDuration(), 0.1);
+ assertEquals("getLongestDuration", 10000, tracker.getLongestDuration());
+ assertEquals("getShortestDuration", 10000, tracker.getShortestDuration());
+ }
+
+ private void verifyDisplayableString(String name, String actual, String expPrefix) {
+ assertEquals(name + " starts with " + expPrefix + ". Actual: " + actual,
+ true, actual.startsWith(expPrefix));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.Test;
+import org.opendaylight.yangtools.util.ExecutorServiceUtil;
+import org.opendaylight.yangtools.util.concurrent.ThreadPoolExecutorTest.Task;
+
+/**
+ * Unit tests for CountingRejectedExecutionHandler.
+ *
+ * @author Thomas Pantelis
+ */
+public class CountingRejectedExecutionHandlerTest {
+
+ private ThreadPoolExecutor executor;
+
+ @After
+ public void tearDown() {
+ if( executor != null ) {
+ executor.shutdownNow();
+ }
+ }
+
+ @Test
+ public void testCallerRunsPolicyHandler() throws InterruptedException {
+
+ int nTasks = 5;
+ CountDownLatch tasksRunLatch = new CountDownLatch( 1 );
+ CountDownLatch blockLatch = new CountDownLatch( 1 );
+
+ executor = new ThreadPoolExecutor( 1, 1, 0, TimeUnit.SECONDS,
+ ExecutorServiceUtil.offerFailingBlockingQueue( new LinkedBlockingQueue<Runnable>() ) );
+
+ CountingRejectedExecutionHandler countingHandler =
+ CountingRejectedExecutionHandler.newCallerRunsPolicy();
+ executor.setRejectedExecutionHandler( countingHandler );
+
+ executor.execute( new Task( tasksRunLatch, blockLatch ) );
+
+ for( int i = 0; i < nTasks - 1; i++ ) {
+ executor.execute( new Task( null, null, null, null, 0 ) );
+ }
+
+ assertEquals( "getRejectedTaskCount", nTasks - 1, countingHandler.getRejectedTaskCount() );
+
+ blockLatch.countDown();
+
+ assertEquals( "Tasks complete", true, tasksRunLatch.await( 5, TimeUnit.SECONDS ) );
+ }
+
+ @Test
+ public void testAbortPolicyHandler() throws InterruptedException {
+
+ int nTasks = 5;
+ CountDownLatch tasksRunLatch = new CountDownLatch( 1 );
+ CountDownLatch blockLatch = new CountDownLatch( 1 );
+
+ executor = new ThreadPoolExecutor( 1, 1, 0, TimeUnit.SECONDS,
+ ExecutorServiceUtil.offerFailingBlockingQueue( new LinkedBlockingQueue<Runnable>() ) );
+
+ CountingRejectedExecutionHandler countingHandler =
+ CountingRejectedExecutionHandler.newAbortPolicy();
+ executor.setRejectedExecutionHandler( countingHandler );
+
+ executor.execute( new Task( tasksRunLatch, blockLatch ) );
+
+ for( int i = 0; i < nTasks - 1; i++ ) {
+ try {
+ executor.execute( new Task( null, null, null, null, 0 ) );
+ fail( "Expected RejectedExecutionException" );
+ } catch( RejectedExecutionException e ) {
+ // Expected
+ }
+ }
+
+ assertEquals( "getRejectedTaskCount", nTasks - 1, countingHandler.getRejectedTaskCount() );
+
+ blockLatch.countDown();
+
+ assertEquals( "Tasks complete", true, tasksRunLatch.await( 5, TimeUnit.SECONDS ) );
+ }
+}
System.out.println();
}
- private static class Task implements Runnable {
+ static class Task implements Runnable {
final CountDownLatch tasksRunLatch;
+ final CountDownLatch blockLatch;
final ConcurrentMap<Thread, AtomicLong> taskCountPerThread;
final AtomicReference<AssertionError> threadError;
final String expThreadPrefix;
this.threadError = threadError;
this.expThreadPrefix = expThreadPrefix;
this.delay = delay;
+ blockLatch = null;
+ }
+
+ Task( CountDownLatch tasksRunLatch, CountDownLatch blockLatch ) {
+ this.tasksRunLatch = tasksRunLatch;
+ this.blockLatch = blockLatch;
+ this.taskCountPerThread = null;
+ this.threadError = null;
+ this.expThreadPrefix = null;
+ this.delay = 0;
}
@Override
public void run() {
try {
- if( delay > 0 ) {
- try {
+ try {
+ if( delay > 0 ) {
TimeUnit.MICROSECONDS.sleep( delay );
- } catch( InterruptedException e ) {}
- }
+ } else if( blockLatch != null ) {
+ blockLatch.await();
+ }
+ } catch( InterruptedException e ) {}
if( expThreadPrefix != null ) {
assertEquals( "Thread name starts with " + expThreadPrefix, true,
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for TrackingLinkedBlockingQueue.
+ *
+ * @author Thomas Pantelis
+ */
+public class TrackingLinkedBlockingQueueTest {
+
+ @Test
+ public void testOffer() throws InterruptedException {
+
+ TrackingLinkedBlockingQueue<String> queue = new TrackingLinkedBlockingQueue<>( 2 );
+
+ assertEquals( "offer", true, queue.offer( "1" ) );
+ assertEquals( "getLargestQueueSize", 1, queue.getLargestQueueSize() );
+ assertEquals( "size", 1, queue.size() );
+
+ assertEquals( "offer", true, queue.offer( "2", 1, TimeUnit.MILLISECONDS ) );
+ assertEquals( "getLargestQueueSize", 2, queue.getLargestQueueSize() );
+ assertEquals( "size", 2, queue.size() );
+
+ assertEquals( "offer", false, queue.offer( "3" ) );
+ assertEquals( "getLargestQueueSize", 2, queue.getLargestQueueSize() );
+ assertEquals( "size", 2, queue.size() );
+
+ assertEquals( "offer", false, queue.offer( "4", 1, TimeUnit.MILLISECONDS ) );
+ assertEquals( "getLargestQueueSize", 2, queue.getLargestQueueSize() );
+ assertEquals( "size", 2, queue.size() );
+ }
+
+ @Test
+ public void testPut() throws InterruptedException {
+
+ TrackingLinkedBlockingQueue<String> queue = new TrackingLinkedBlockingQueue<>();
+
+ queue.put( "1" );
+ assertEquals( "getLargestQueueSize", 1, queue.getLargestQueueSize() );
+ assertEquals( "size", 1, queue.size() );
+
+ queue.put( "2" );
+ assertEquals( "getLargestQueueSize", 2, queue.getLargestQueueSize() );
+ assertEquals( "size", 2, queue.size() );
+ }
+
+ @Test
+ public void testAdd() {
+
+ TrackingLinkedBlockingQueue<String> queue = new TrackingLinkedBlockingQueue<>( 2 );
+
+ assertEquals( "add", true, queue.add( "1" ) );
+ assertEquals( "getLargestQueueSize", 1, queue.getLargestQueueSize() );
+ assertEquals( "size", 1, queue.size() );
+
+ assertEquals( "add", true, queue.add( "2" ) );
+ assertEquals( "getLargestQueueSize", 2, queue.getLargestQueueSize() );
+ assertEquals( "size", 2, queue.size() );
+
+ try {
+ queue.add( "3" );
+ fail( "Expected IllegalStateException" );
+ } catch( IllegalStateException e ) {
+ // Expected
+ assertEquals( "getLargestQueueSize", 2, queue.getLargestQueueSize() );
+ assertEquals( "size", 2, queue.size() );
+ }
+ }
+
+ @Test
+ public void testAddAll() {
+
+ TrackingLinkedBlockingQueue<String> queue = new TrackingLinkedBlockingQueue<>( 3 );
+
+ queue.addAll( Arrays.asList( "1", "2" ) );
+ assertEquals( "getLargestQueueSize", 2, queue.getLargestQueueSize() );
+ assertEquals( "size", 2, queue.size() );
+
+ try {
+ queue.addAll( Arrays.asList( "3", "4" ) );
+ fail( "Expected IllegalStateException" );
+ } catch( IllegalStateException e ) {
+ // Expected
+ assertEquals( "getLargestQueueSize", 3, queue.getLargestQueueSize() );
+ assertEquals( "size", 3, queue.size() );
+ }
+ }
+}
<module>restconf</module>
<module>websocket</module>
<module>yang</module>
- <!-- module>third-party</module -->
+ <module>benchmarks</module>
+ <!-- module>third-party</module -->
</modules>
<build>
}
try {
this.listenerCallbackMethod.invoke(message);
- } catch (IllegalAccessException e) {
- throw new IllegalStateException(e.getMessage());
- } catch (InvocationTargetException e) {
- throw new IllegalStateException(e.getMessage());
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException("Failed to invoke callback", e);
}
}
@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);
}
restModule.setName(eElement.getElementsByTagName("name").item(0).getTextContent());
restModule.setNamespace(eElement.getElementsByTagName("namespace").item(0).getTextContent());
restModule.setRevision(eElement.getElementsByTagName("revision").item(0).getTextContent());
- } catch (NullPointerException npe){
- throw new IllegalStateException("Incomplete module data in xml.");
+ } catch (NullPointerException e) {
+ throw new IllegalStateException("Incomplete module data in xml.", e);
}
return restModule;
}
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
+
import java.text.SimpleDateFormat;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
throw new UnsupportedOperationException("Utility class should not be instantiated");
}
- public static final String getRootPackageName(final QName module) {
+ public static String getRootPackageName(final QName module) {
return getRootPackageName(module.getModule());
}
- public static final String getRootPackageName(final QNameModule module) {
+ public static String getRootPackageName(final QNameModule module) {
checkArgument(module != null, "Module must not be null");
checkArgument(module.getRevision() != null, "Revision must not be null");
checkArgument(module.getNamespace() != null, "Namespace must not be null");
return builder.toString();
}
- public static final String getMethodName(final QName name) {
+ public static String getMethodName(final QName name) {
checkArgument(name != null, "Name should not be null.");
return getMethodName(name.getLocalName());
}
- public static final String getClassName(final String localName) {
+ public static String getClassName(final String localName) {
checkArgument(localName != null, "Name should not be null.");
return toFirstUpper(toCamelCase(localName));
}
- public static final String getMethodName(final String yangIdentifier) {
+ public static String getMethodName(final String yangIdentifier) {
checkArgument(yangIdentifier != null,"Identifier should not be null");
return toFirstLower(toCamelCase(yangIdentifier));
}
- public static final String getClassName(final QName name) {
+ public static String getClassName(final QName name) {
checkArgument(name != null, "Name should not be null.");
return toFirstUpper(toCamelCase(name.getLocalName()));
}
return potential;
}
- private static final String toCamelCase(final String rawString) {
+ private static String toCamelCase(final String rawString) {
checkArgument(rawString != null, "String should not be null");
Iterable<String> components = CAMEL_SPLITTER.split(rawString);
StringBuilder builder = new StringBuilder();
return checkNumericPrefix(builder.toString());
}
- private static final String checkNumericPrefix(final String rawString) {
+ private static String checkNumericPrefix(final String rawString) {
if (rawString == null || rawString.isEmpty()) {
return rawString;
}
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;
+ }
}
@Deprecated
public interface NodeModificationBuilder {
- abstract Node<?> getMutableEquivalent(Node<?> originalNode);
+ Node<?> getMutableEquivalent(Node<?> originalNode);
- abstract CompositeNode buildDiffTree();
+ CompositeNode buildDiffTree();
- abstract void mergeNode(MutableCompositeNode alteredNode);
+ void mergeNode(MutableCompositeNode alteredNode);
- abstract void removeNode(MutableCompositeNode deadNode);
+ void removeNode(MutableCompositeNode deadNode);
- abstract void removeNode(MutableSimpleNode<?> deadNode);
+ void removeNode(MutableSimpleNode<?> deadNode);
- abstract void deleteNode(MutableSimpleNode<?> deadNode);
+ void deleteNode(MutableSimpleNode<?> deadNode);
- abstract void deleteNode(MutableCompositeNode deadNode);
+ void deleteNode(MutableCompositeNode deadNode);
- abstract void replaceNode(MutableCompositeNode replacementNode);
+ void replaceNode(MutableCompositeNode replacementNode);
- abstract void replaceNode(MutableSimpleNode<?> replacementNode);
+ void replaceNode(MutableSimpleNode<?> replacementNode);
- abstract void addNode(MutableCompositeNode newNode);
+ void addNode(MutableCompositeNode newNode);
- abstract void addNode(MutableSimpleNode<?> newNode);
+ void addNode(MutableSimpleNode<?> newNode);
}
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();
package org.opendaylight.yangtools.yang.data.api.schema.stream;
import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * A {@link NormalizedNodeStreamWriter} which logs the events into a {@link Logger}.
+ */
@Beta
-public class LoggingNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
+public final class LoggingNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
private static final Logger LOG = LoggerFactory.getLogger(LoggingNormalizedNodeStreamWriter.class);
private static final int DEFAULT_INDENT_SIZE = 2;
- private final int indentSize = DEFAULT_INDENT_SIZE;
- private int currentIndent = 0;
+
+ private final Deque<String> indent = new ArrayDeque<>();
+ private final String indentStr;
+
+ public LoggingNormalizedNodeStreamWriter() {
+ this(DEFAULT_INDENT_SIZE);
+ }
+
+ public LoggingNormalizedNodeStreamWriter(final int indentSize) {
+ this.indentStr = Strings.repeat(" ", indentSize);
+ indent.push("");
+ }
private String ind() {
- return Strings.repeat(" ", currentIndent);
+ return indent.peek();
}
private void decIndent() {
- Preconditions.checkState(currentIndent >= 0, "Unexpected indentation %s", currentIndent);
- currentIndent -= indentSize;
+ indent.pop();
}
private void incIndent() {
- currentIndent += indentSize;
+ indent.push(ind() + indentStr);
}
@Override
- public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IllegalStateException {
+ public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) {
LOG.debug("{}{}[](no key)", ind(), name);
incIndent();
}
@Override
- public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+ public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
LOG.debug("{}{}(no key)", ind(), name);
incIndent();
}
@Override
- public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+ public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) {
}
@Override
- public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+ public void startMapNode(final NodeIdentifier name, final int childSizeHint) {
LOG.debug("{}{}(key)", ind(), name);
incIndent();
}
@Override
- public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
- throws IllegalArgumentException {
+ public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) {
LOG.debug("{}{}[](key)", ind(), identifier);
incIndent();
}
@Override
- public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+ public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
LOG.debug("{}{}(leaf-list)", ind(), name);
incIndent();
}
@Override
- public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+ public void startContainerNode(final NodeIdentifier name, final int childSizeHint) {
LOG.debug("{}{}(container)", ind(), name);
incIndent();
}
@Override
- public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+ public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) {
LOG.debug("{}{}(choice)", ind(), name);
incIndent();
}
@Override
- public void startAugmentationNode(final AugmentationIdentifier identifier) throws IllegalArgumentException {
+ public void startAugmentationNode(final AugmentationIdentifier identifier) {
LOG.debug("{}{}(augmentation)", ind(), identifier);
incIndent();
}
@Override
- public void leafSetEntryNode(final Object value) throws IllegalArgumentException {
+ public void leafSetEntryNode(final Object value) {
LOG.debug("{}{}({}) ", ind(), value, value.getClass().getSimpleName());
}
@Override
- public void leafNode(final NodeIdentifier name, final Object value) throws IllegalArgumentException {
+ public void leafNode(final NodeIdentifier name, final Object value) {
LOG.debug("{}{}(leaf({}))=", ind(), name, value.getClass().getSimpleName(), value);
}
}
@Override
- public void anyxmlNode(final NodeIdentifier name, final Object value) throws IllegalArgumentException {
+ public void anyxmlNode(final NodeIdentifier name, final Object value) {
LOG.debug("{}{}(anyxml)=", ind(), name, value);
}
@Override
- public void flush() throws IOException {
+ public void flush() {
LOG.trace("<<FLUSH>>");
}
@Override
- public void close() throws IOException {
+ public void close() {
LOG.debug("<<END-OF-STREAM>>");
}
}
\ No newline at end of file
import java.io.Flushable;
import java.io.IOException;
+import javax.xml.stream.XMLStreamReader;
+
import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
/**
- * This is an experimental
+ * This is an experimental iterator over a {@link NormalizedNode}. This is essentially
+ * the opposite of a {@link XMLStreamReader} -- unlike instantiating an iterator over
+ * the backing data, this encapsulates a {@link NormalizedNodeStreamWriter} and allows
+ * us to write multiple nodes.
*/
@Beta
public final class NormalizedNodeWriter implements Closeable, Flushable {
this.writer = Preconditions.checkNotNull(writer);
}
+ /**
+ * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
+ *
+ * @param writer Backend writer
+ * @return A new instance.
+ */
public static NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer) {
return new NormalizedNodeWriter(writer);
}
+ /**
+ * Iterate over the provided {@link NormalizedNode} and emit write
+ * events to the encapsulated {@link NormalizedNodeStreamWriter}.
+ *
+ * @param node Node
+ * @return
+ * @throws IOException when thrown from the backing writer.
+ */
public NormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
if (wasProcessedAsCompositeNode(node)) {
return this;
@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);
+ }
}
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-impl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-util</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-parser-impl</artifactId>
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+/**
+ * Utility abstract class for tracking parser state, as needed by StAX-like parser.
+ */
+@Beta
abstract class AbstractNodeDataWithSchema {
-
private final DataSchemaNode schema;
- public AbstractNodeDataWithSchema(final DataSchemaNode schema) {
- this.schema = schema;
+ protected AbstractNodeDataWithSchema(final DataSchemaNode schema) {
+ this.schema = Preconditions.checkNotNull(schema);
}
+ /**
+ * Return the associated schema node.
+ * @return
+ */
public final DataSchemaNode getSchema() {
return schema;
}
- protected abstract void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException;
+ /**
+ * Emit this node's events into the specified writer.
+ *
+ * @param writer Target writer
+ * @throws IOException reported when thrown by the writer.
+ */
+ public abstract void write(final NormalizedNodeStreamWriter writer) throws IOException;
- protected NodeIdentifier provideNodeIdentifier() {
+ protected final NodeIdentifier provideNodeIdentifier() {
return new NodeIdentifier(schema.getQName());
}
if (getClass() != obj.getClass()) {
return false;
}
- AbstractNodeDataWithSchema other = (AbstractNodeDataWithSchema) obj;
- if (schema == null) {
- if (other.schema != null) {
- return false;
- }
- } else if (!schema.equals(other.schema)) {
- return false;
- }
-
- return true;
+ final AbstractNodeDataWithSchema other = (AbstractNodeDataWithSchema) obj;
+ return schema.equals(other.schema);
}
}
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
-// FIXME: should be changed according to format of value
- nnStreamWriter.anyxmlNode(provideNodeIdentifier(), getValue());
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ // FIXME: should be changed according to format of value
+ writer.anyxmlNode(provideNodeIdentifier(), getValue());
}
}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
-
-import java.io.IOException;
-
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
class CaseNodeDataWithSchema extends CompositeNodeDataWithSchema {
super(schema);
}
- @Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- super.writeToStream(nnStreamWriter);
- }
}
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
-import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
-
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
}
@Override
- public CompositeNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
+ protected CompositeNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
CaseNodeDataWithSchema newChild = new CaseNodeDataWithSchema((ChoiceCaseNode) schema);
caseNodeDataWithSchema = newChild;
addCompositeChild(newChild);
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- nnStreamWriter.startChoiceNode(provideNodeIdentifier(), UNKNOWN_SIZE);
- super.writeToStream(nnStreamWriter);
- nnStreamWriter.endNode();
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ writer.startChoiceNode(provideNodeIdentifier(), childSizeHint());
+ super.write(writer);
+ writer.endNode();
}
}
--- /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.yang.data.codec.gson;
+
+import com.google.common.annotations.Beta;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
+import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is implementation-internal and subject to change. Please do not use it.
+ */
+@Beta
+final class CodecFactory {
+ private static final Logger LOG = LoggerFactory.getLogger(CodecFactory.class);
+ private static final Codec<?, ?> LEAFREF_DEFAULT_CODEC = new LeafrefCodec<String>() {
+ @Override
+ public String serialize(final Object data) {
+ return String.valueOf(data);
+ }
+
+ @Override
+ public Object deserialize(final String data) {
+ return data;
+ }
+ };
+ private static final Codec<?, ?> NULL_CODEC = new Codec<Object, Object>() {
+ @Override
+ public Object deserialize(final Object input) {
+ return null;
+ }
+
+ @Override
+ public Object serialize(final Object input) {
+ return null;
+ }
+ };
+
+
+ private static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
+ TypeDefinition<?> superType = type;
+ while (superType.getBaseType() != null) {
+ superType = superType.getBaseType();
+ }
+ return superType;
+ }
+
+ private final LoadingCache<TypeDefinition<?>, Codec<?, ?>> codecs =
+ CacheBuilder.newBuilder().softValues().build(new CacheLoader<TypeDefinition<?>, Codec<?, ?>>() {
+ @Override
+ public Codec<?, ?> load(final TypeDefinition<?> key) throws Exception {
+ final TypeDefinition<?> type = resolveBaseTypeFrom(key);
+
+ if (type instanceof InstanceIdentifierType) {
+ return iidCodec;
+ }
+ if (type instanceof IdentityrefType) {
+ return idrefCodec;
+ }
+ if (type instanceof LeafrefTypeDefinition) {
+ return LEAFREF_DEFAULT_CODEC;
+ }
+
+ final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codec = TypeDefinitionAwareCodec.from(type);
+ if (codec == null) {
+ LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName().getLocalName());
+ return NULL_CODEC;
+ }
+
+ return codec;
+ }
+ });
+
+ private final Codec<?, ?> iidCodec;
+ private final Codec<?, ?> idrefCodec;
+
+ private CodecFactory(final SchemaContext context) {
+ iidCodec = new JSONStringInstanceIdentifierCodec(context);
+ idrefCodec = new JSONStringIdentityrefCodec(context);
+ }
+
+ public static CodecFactory create(final SchemaContext context) {
+ return new CodecFactory(context);
+ }
+
+ @SuppressWarnings("unchecked")
+ public final Codec<Object, Object> codecFor(final TypeDefinition<?> typeDefinition) {
+ return (Codec<Object, Object>) codecs.getUnchecked(typeDefinition);
+ }
+}
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
+
+import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+/**
+ * A node which is composed of multiple simpler nodes.
+ */
class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
+ private static final Function<DataSchemaNode, QName> QNAME_FUNCTION = new Function<DataSchemaNode, QName>() {
+ @Override
+ public QName apply(@Nonnull final DataSchemaNode input) {
+ return input.getQName();
+ }
+ };
/**
* nodes which were added to schema via augmentation and are present in data input
*/
- protected Map<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationsToChild = new HashMap<>();
+ private final Multimap<AugmentationSchema, AbstractNodeDataWithSchema> augmentationsToChild = ArrayListMultimap.create();
/**
- * remaining data nodes (which aren't added via augment). Every of them should have the same QName
+ * remaining data nodes (which aren't added via augment). Every of one them should have the same QName.
*/
- protected List<AbstractNodeDataWithSchema> childs = new ArrayList<>();
+ private final List<AbstractNodeDataWithSchema> children = new ArrayList<>();
public CompositeNodeDataWithSchema(final DataSchemaNode schema) {
super(schema);
}
- public AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
- SimpleNodeDataWithSchema newChild = null;
- if (schema instanceof LeafSchemaNode) {
- newChild = new LeafNodeDataWithSchema(schema);
- } else if (schema instanceof AnyXmlSchemaNode) {
- newChild = new AnyXmlNodeDataWithSchema(schema);
+ public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
+ Preconditions.checkArgument(!schemas.isEmpty(), "Expecting at least one schema");
+
+ // Pop the first node...
+ final DataSchemaNode schema = schemas.pop();
+ if (schemas.isEmpty()) {
+ // Simple, direct node
+ return addChild(schema);
}
- if (newChild != null) {
+ // The choice/case mess, reuse what we already popped
+ final DataSchemaNode choiceCandidate = schema;
+ Preconditions.checkArgument(choiceCandidate instanceof ChoiceNode,
+ "Expected node of type ChoiceNode but was %s", choiceCandidate.getClass().getSimpleName());
+ final ChoiceNode choiceNode = (ChoiceNode) choiceCandidate;
- AugmentationSchema augSchema = null;
- if (schema.isAugmenting()) {
- augSchema = findCorrespondingAugment(getSchema(), schema);
- }
- if (augSchema != null) {
- addChildToAugmentation(augSchema, newChild);
- } else {
- addChild(newChild);
- }
- return newChild;
- }
- return null;
- }
+ final DataSchemaNode caseCandidate = schemas.pop();
+ Preconditions.checkArgument(caseCandidate instanceof ChoiceCaseNode,
+ "Expected node of type ChoiceCaseNode but was %s", caseCandidate.getClass().getSimpleName());
+ final ChoiceCaseNode caseNode = (ChoiceCaseNode) caseCandidate;
- private void addChildToAugmentation(final AugmentationSchema augSchema, final AbstractNodeDataWithSchema newChild) {
- List<AbstractNodeDataWithSchema> childsInAugment = augmentationsToChild.get(augSchema);
- if (childsInAugment == null) {
- childsInAugment = new ArrayList<>();
- augmentationsToChild.put(augSchema, childsInAugment);
+ AugmentationSchema augSchema = null;
+ if (choiceCandidate.isAugmenting()) {
+ augSchema = findCorrespondingAugment(getSchema(), choiceCandidate);
}
- childsInAugment.add(newChild);
- }
- public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
- if (schemas.size() == 1) {
- final DataSchemaNode childDataSchemaNode = schemas.pop();
- return addChild(childDataSchemaNode);
+ // looking for existing choice
+ final Collection<AbstractNodeDataWithSchema> childNodes;
+ if (augSchema != null) {
+ childNodes = augmentationsToChild.get(augSchema);
} else {
- DataSchemaNode choiceCandidate = schemas.pop();
- DataSchemaNode caseCandidate = schemas.pop();
- ChoiceNode choiceNode = null;
- ChoiceCaseNode caseNode = null;
- if (choiceCandidate instanceof ChoiceNode) {
- choiceNode = (ChoiceNode) choiceCandidate;
- } else {
- throw new IllegalArgumentException("Awaited node of type ChoiceNode but was "
- + choiceCandidate.getClass().getSimpleName());
- }
-
- if (caseCandidate instanceof ChoiceCaseNode) {
- caseNode = (ChoiceCaseNode) caseCandidate;
- } else {
- throw new IllegalArgumentException("Awaited node of type ChoiceCaseNode but was "
- + caseCandidate.getClass().getSimpleName());
- }
-
- AugmentationSchema augSchema = null;
- if (choiceCandidate.isAugmenting()) {
- augSchema = findCorrespondingAugment(getSchema(), choiceCandidate);
- }
+ childNodes = children;
+ }
- // looking for existing choice
- List<AbstractNodeDataWithSchema> childNodes = Collections.emptyList();
- if (augSchema != null) {
- childNodes = augmentationsToChild.get(augSchema);
- } else {
- childNodes = childs;
- }
+ CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
+ if (caseNodeDataWithSchema == null) {
+ ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
+ addChild(choiceNodeDataWithSchema);
+ caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
+ }
- CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
- if (caseNodeDataWithSchema == null) {
- ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
- addChild(choiceNodeDataWithSchema);
- caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
- }
+ return caseNodeDataWithSchema.addChild(schemas);
+ }
- return caseNodeDataWithSchema.addChild(schemas);
+ private AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
+ SimpleNodeDataWithSchema newChild = null;
+ if (schema instanceof LeafSchemaNode) {
+ newChild = new LeafNodeDataWithSchema(schema);
+ } else if (schema instanceof AnyXmlSchemaNode) {
+ newChild = new AnyXmlNodeDataWithSchema(schema);
+ } else {
+ return null;
}
+ AugmentationSchema augSchema = null;
+ if (schema.isAugmenting()) {
+ augSchema = findCorrespondingAugment(getSchema(), schema);
+ }
+ if (augSchema != null) {
+ augmentationsToChild.put(augSchema, newChild);
+ } else {
+ addChild(newChild);
+ }
+ return newChild;
}
- private CaseNodeDataWithSchema findChoice(final List<AbstractNodeDataWithSchema> childNodes, final DataSchemaNode choiceCandidate,
+ private CaseNodeDataWithSchema findChoice(final Collection<AbstractNodeDataWithSchema> childNodes, final DataSchemaNode choiceCandidate,
final DataSchemaNode caseCandidate) {
- if (childNodes == null) {
- return null;
- }
- for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
- if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
- && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
- CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
- if (casePrevious.getSchema().getQName() != caseCandidate.getQName()) {
- throw new IllegalArgumentException("Data from case " + caseCandidate.getQName()
- + " are specified but other data from case " + casePrevious.getSchema().getQName()
- + " were specified erlier. Data aren't from the same case.");
+ if (childNodes != null) {
+ for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
+ if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
+ && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
+ CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
+
+ Preconditions.checkArgument(casePrevious.getSchema().getQName().equals(caseCandidate.getQName()),
+ "Data from case %s are specified but other data from case %s were specified erlier. Data aren't from the same case.",
+ caseCandidate.getQName(), casePrevious.getSchema().getQName());
+
+ return casePrevious;
}
- return casePrevious;
}
}
return null;
}
- public AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
+ AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
CompositeNodeDataWithSchema newChild;
if (schema instanceof ListSchemaNode) {
newChild = new ListNodeDataWithSchema(schema);
return newChild;
}
- public void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
+ void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
AugmentationSchema augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
if (augSchema != null) {
- addChildToAugmentation(augSchema, newChild);
+ augmentationsToChild.put(augSchema, newChild);
} else {
addChild(newChild);
}
}
public void addChild(final AbstractNodeDataWithSchema newChild) {
- childs.add(newChild);
+ children.add(newChild);
+ }
+
+ /**
+ * Return a hint about how may children we are going to generate.
+ * @return Size of currently-present node list.
+ */
+ protected final int childSizeHint() {
+ return children.size();
}
/**
* Tries to find in {@code parent} which is dealed as augmentation target node with QName as {@code child}. If such
* node is found then it is returned, else null.
*/
- protected AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) {
+ AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) {
if (parent instanceof AugmentationTarget) {
for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName());
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- for (AbstractNodeDataWithSchema child : childs) {
- child.writeToStream(nnStreamWriter);
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ for (AbstractNodeDataWithSchema child : children) {
+ child.write(writer);
}
- for (Entry<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.entrySet()) {
-
- final List<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
-
+ for (Entry<AugmentationSchema, Collection<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.asMap().entrySet()) {
+ final Collection<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
if (!childsFromAgumentation.isEmpty()) {
- nnStreamWriter.startAugmentationNode(toAugmentationIdentifier(augmentationToChild));
+ writer.startAugmentationNode(toAugmentationIdentifier(augmentationToChild.getKey()));
for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
- nodeDataWithSchema.writeToStream(nnStreamWriter);
+ nodeDataWithSchema.write(writer);
}
- nnStreamWriter.endNode();
+ writer.endNode();
}
}
}
- private static AugmentationIdentifier toAugmentationIdentifier(
- final Entry<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationToChild) {
- Collection<DataSchemaNode> nodes = augmentationToChild.getKey().getChildNodes();
- Set<QName> nodesQNames = new HashSet<>();
- for (DataSchemaNode node : nodes) {
- nodesQNames.add(node.getQName());
- }
-
- return new AugmentationIdentifier(nodesQNames);
+ private static AugmentationIdentifier toAugmentationIdentifier(final AugmentationSchema schema) {
+ final Collection<QName> qnames = Collections2.transform(schema.getChildNodes(), QNAME_FUNCTION);
+ return new AugmentationIdentifier(ImmutableSet.copyOf(qnames));
}
-
}
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
-import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
-
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- nnStreamWriter.startContainerNode(provideNodeIdentifier(), UNKNOWN_SIZE);
- super.writeToStream(nnStreamWriter);
- nnStreamWriter.endNode();
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ writer.startContainerNode(provideNodeIdentifier(), childSizeHint());
+ super.write(writer);
+ writer.endNode();
}
}
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.gson.stream.JsonWriter;
-
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayDeque;
import java.util.Deque;
-
+import org.opendaylight.yangtools.concepts.Codec;
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.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.SchemaTracker;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
/**
* This implementation will create JSON output as output stream.
private final Deque<TypeInfo> stack = new ArrayDeque<>();
private final SchemaContext schemaContext;
+ private final CodecFactory codecs;
+ private final SchemaTracker tracker;
private final Writer writer;
private final String indent;
this.writer = Preconditions.checkNotNull(writer);
Preconditions.checkArgument(indentSize >= 0, "Indent size must be non-negative");
+ if (indentSize != 0) {
+ indent = Strings.repeat(" ", indentSize);
+ } else {
+ indent = null;
+ }
+
+ this.codecs = CodecFactory.create(schemaContext);
+ this.tracker = SchemaTracker.create(schemaContext);
+ }
+ private JSONNormalizedNodeStreamWriter(final SchemaContext schemaContext, final SchemaPath path,
+ final Writer writer, final int indentSize) {
+ this.schemaContext = Preconditions.checkNotNull(schemaContext);
+ this.writer = Preconditions.checkNotNull(writer);
+
+ Preconditions.checkArgument(indentSize >= 0, "Indent size must be non-negative");
if (indentSize != 0) {
indent = Strings.repeat(" ", indentSize);
} else {
indent = null;
}
+
+ this.codecs = CodecFactory.create(schemaContext);
+ this.tracker = SchemaTracker.create(schemaContext,path);
}
/**
return new JSONNormalizedNodeStreamWriter(schemaContext, writer, 0);
}
+ /**
+ * Create a new stream writer, which writes to the specified {@link Writer}.
+ *
+ * @param schemaContext Schema context
+ * @param writer Output writer
+ * @return A stream writer instance
+ */
+ public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, SchemaPath path,final Writer writer) {
+ return new JSONNormalizedNodeStreamWriter(schemaContext, path, writer, 0);
+ }
+
/**
* Create a new stream writer, which writes to the specified output stream.
*
@Override
public void leafNode(final NodeIdentifier name, final Object value) throws IOException {
+ final LeafSchemaNode schema = tracker.leafNode(name);
+ final Codec<Object, Object> codec = codecs.codecFor(schema.getType());
+
separateElementFromPreviousElement();
writeJsonIdentifier(name);
currentNamespace = stack.peek().getNamespace();
- writeValue(value.toString());
+ writeValue(String.valueOf(codec.serialize(value)));
separateNextSiblingsWithComma();
}
@Override
public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ tracker.startLeafSet(name);
+
separateElementFromPreviousElement();
stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
writeJsonIdentifier(name);
@Override
public void leafSetEntryNode(final Object value) throws IOException {
+ final LeafListSchemaNode schema = tracker.leafSetEntryNode();
+ final Codec<Object, Object> codec = codecs.codecFor(schema.getType());
+
separateElementFromPreviousElement();
- writeValue(value.toString());
+ writeValue(String.valueOf(codec.serialize(value)));
separateNextSiblingsWithComma();
}
@Override
public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ tracker.startContainerNode(name);
+
separateElementFromPreviousElement();
stack.push(new TypeInfo(NodeType.OBJECT, name.getNodeType().getNamespace()));
writeJsonIdentifier(name);
@Override
public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ tracker.startList(name);
+
separateElementFromPreviousElement();
stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
writeJsonIdentifier(name);
@Override
public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ tracker.startListItem(name);
+
stack.push(new TypeInfo(NodeType.OBJECT, name.getNodeType().getNamespace()));
separateElementFromPreviousElement();
writeStartObject();
@Override
public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ tracker.startList(name);
+
separateElementFromPreviousElement();
stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
writeJsonIdentifier(name);
@Override
public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
throws IOException {
- stack.push(new TypeInfo(NodeType.OBJECT, identifier.getNodeType().getNamespace()));
+ tracker.startListItem(identifier);
separateElementFromPreviousElement();
+ stack.push(new TypeInfo(NodeType.OBJECT, identifier.getNodeType().getNamespace()));
+
+
writeStartObject();
indentRight();
}
@Override
public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ tracker.startListItem(name);
+
stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
separateElementFromPreviousElement();
writeJsonIdentifier(name);
@Override
public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+ tracker.startChoiceNode(name);
handleInvisibleNode(name.getNodeType().getNamespace());
}
@Override
public void startAugmentationNode(final AugmentationIdentifier identifier) throws IllegalArgumentException {
+ tracker.startAugmentationNode(identifier);
handleInvisibleNode(currentNamespace);
}
@Override
public void anyxmlNode(final NodeIdentifier name, final Object value) throws IOException {
+ final AnyXmlSchemaNode schema = tracker.anyxmlNode(name);
+ // FIXME: should have a codec based on this :)
+
separateElementFromPreviousElement();
writeJsonIdentifier(name);
currentNamespace = stack.peek().getNamespace();
@Override
public void endNode() throws IOException {
- switch (stack.peek().getType()) {
+ tracker.endNode();
+
+ final TypeInfo t = stack.pop();
+ switch (t.getType()) {
case LIST:
indentLeft();
newLine();
default:
break;
}
- stack.pop();
+
currentNamespace = stack.isEmpty() ? null : stack.peek().getNamespace();
separateNextSiblingsWithComma();
}
--- /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.yang.data.codec.gson;
+
+import com.google.common.base.Preconditions;
+
+import java.net.URI;
+
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringIdentityrefCodec;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class JSONStringIdentityrefCodec extends AbstractModuleStringIdentityrefCodec {
+ private final SchemaContext context;
+
+ JSONStringIdentityrefCodec(final SchemaContext context) {
+ this.context = Preconditions.checkNotNull(context);
+ }
+
+ @Override
+ protected Module moduleForPrefix(final String prefix) {
+ return context.findModuleByName(prefix, null);
+ }
+
+ @Override
+ protected String prefixForNamespace(final URI namespace) {
+ final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
+ return module == null ? null : module.getName();
+ }
+
+}
--- /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.yang.data.codec.gson;
+
+import com.google.common.base.Preconditions;
+
+import java.net.URI;
+
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class JSONStringInstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec {
+ private final SchemaContext context;
+
+ JSONStringInstanceIdentifierCodec(final SchemaContext context) {
+ this.context = Preconditions.checkNotNull(context);
+ }
+
+ @Override
+ protected Module moduleForPrefix(final String prefix) {
+ return context.findModuleByName(prefix, null);
+ }
+
+ @Override
+ protected String prefixForNamespace(final URI namespace) {
+ final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
+ return module == null ? null : module.getName();
+ }
+}
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterators;
import com.google.gson.JsonIOException;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;
import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
import com.google.gson.stream.MalformedJsonException;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.net.URI;
-import java.security.InvalidParameterException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Set;
-import org.opendaylight.yangtools.concepts.Codec;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.RestCodecFactory;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.RestUtil;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.RestUtil.PrefixMapingFromJson;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.SchemaContextUtils;
import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
/**
* This class parses JSON elements from a GSON JsonReader. It disallows multiple elements of the same name unlike the
*/
@Beta
public final class JsonParserStream implements Closeable, Flushable {
- private static final Splitter COLON_SPLITTER = Splitter.on(':');
-
private final Deque<URI> namespaces = new ArrayDeque<>();
private final NormalizedNodeStreamWriter writer;
- private final SchemaContextUtils utils;
- private final RestCodecFactory codecs;
+ private final CodecFactory codecs;
private final SchemaContext schema;
private JsonParserStream(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext) {
this.schema = Preconditions.checkNotNull(schemaContext);
- this.utils = SchemaContextUtils.create(schemaContext);
this.writer = Preconditions.checkNotNull(writer);
- this.codecs = RestCodecFactory.create(utils);
+ this.codecs = CodecFactory.create(schemaContext);
}
public static JsonParserStream create(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext) {
isEmpty = false;
CompositeNodeDataWithSchema compositeNodeDataWithSchema = new CompositeNodeDataWithSchema(schema);
read(reader, compositeNodeDataWithSchema);
- compositeNodeDataWithSchema.writeToStream(writer);
+ compositeNodeDataWithSchema.write(writer);
return this;
// return read(reader);
}
}
- public void read(final JsonReader in, final AbstractNodeDataWithSchema parent) throws IOException {
+ private final void setValue(final AbstractNodeDataWithSchema parent, final String value) {
+ Preconditions.checkArgument(parent instanceof SimpleNodeDataWithSchema, "Node %s is not a simple type", parent);
+
+ final Object translatedValue = translateValueByType(value, parent.getSchema());
+ ((SimpleNodeDataWithSchema) parent).setValue(translatedValue);
+ }
- final JsonToken peek = in.peek();
- Optional<String> value = Optional.absent();
- switch (peek) {
+ public void read(final JsonReader in, final AbstractNodeDataWithSchema parent) throws IOException {
+ switch (in.peek()) {
case STRING:
case NUMBER:
- value = Optional.of(in.nextString());
+ setValue(parent, in.nextString());
break;
case BOOLEAN:
- value = Optional.of(Boolean.toString(in.nextBoolean()));
+ setValue(parent, Boolean.toString(in.nextBoolean()));
break;
case NULL:
in.nextNull();
- value = Optional.of((String) null);
- break;
- default:
+ setValue(parent, null);
break;
- }
- if (value.isPresent()) {
- final Object translatedValue = translateValueByType(value.get(), parent.getSchema());
- ((SimpleNodeDataWithSchema) parent).setValue(translatedValue);
- }
-
- switch (peek) {
case BEGIN_ARRAY:
in.beginArray();
while (in.hasNext()) {
case NAME:
case END_OBJECT:
case END_ARRAY:
+ break;
}
}
return value;
}
- final Object inputValue;
- if (typeDefinition instanceof IdentityrefTypeDefinition) {
- inputValue = valueAsIdentityRef(value);
- } else if (typeDefinition instanceof InstanceIdentifierTypeDefinition) {
- inputValue = valueAsInstanceIdentifier(value);
- } else {
- inputValue = value;
- }
-
- // FIXME: extract this as a cacheable context?
- final Codec<Object, Object> codec = codecs.codecFor(typeDefinition);
- if (codec == null) {
- return null;
- }
- return codec.deserialize(inputValue);
+ return codecs.codecFor(typeDefinition).deserialize(value);
}
private static TypeDefinition<? extends Object> typeDefinition(final DataSchemaNode node) {
return baseType;
}
- private static Object valueAsInstanceIdentifier(final String value) {
- // it could be instance-identifier Built-In Type
- if (!value.isEmpty() && value.charAt(0) == '/') {
- IdentityValuesDTO resolvedValue = RestUtil.asInstanceIdentifier(value, new PrefixMapingFromJson());
- if (resolvedValue != null) {
- return resolvedValue;
- }
- }
- throw new InvalidParameterException("Value for instance-identifier doesn't have correct format");
- }
-
- private static IdentityValuesDTO valueAsIdentityRef(final String value) {
- // it could be identityref Built-In Type
- URI namespace = getNamespaceFor(value);
- if (namespace != null) {
- return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null, value);
- }
- throw new InvalidParameterException("Value for identityref has to be in format moduleName:localName.");
- }
-
- private static URI getNamespaceFor(final String jsonElementName) {
- final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
-
- // The string needs to me in form "moduleName:localName"
- if (it.hasNext()) {
- final String maybeURI = it.next();
- if (Iterators.size(it) == 1) {
- return URI.create(maybeURI);
- }
- }
-
- return null;
- }
-
- private static String getLocalNameFor(final String jsonElementName) {
- final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
-
- // The string needs to me in form "moduleName:localName"
- final String ret = Iterators.get(it, 1, null);
- return ret != null && !it.hasNext() ? ret : jsonElementName;
- }
-
private void removeNamespace() {
namespaces.pop();
}
}
private NamespaceAndName resolveNamespace(final String childName) {
- int lastIndexOfColon = childName.lastIndexOf(":");
+ int lastIndexOfColon = childName.lastIndexOf(':');
String moduleNamePart = null;
String nodeNamePart = null;
URI namespace = null;
if (lastIndexOfColon != -1) {
moduleNamePart = childName.substring(0, lastIndexOfColon);
nodeNamePart = childName.substring(lastIndexOfColon + 1);
- namespace = utils.findNamespaceByModuleName(moduleNamePart);
+
+ final Module m = schema.findModuleByName(moduleNamePart, null);
+ namespace = m == null ? null : m.getNamespace();
} else {
nodeNamePart = childName;
}
}
/**
- * Returns stack of schema nodes via which it was necessary to prass to get schema node with specified
+ * Returns stack of schema nodes via which it was necessary to pass to get schema node with specified
* {@code childName} and {@code namespace}
*
* @param dataSchemaNode
* @param childName
* @param namespace
- * @return stack of schema nodes via which it was passed through. If found schema node is dirrect child then stack
- * contains only one node. If it is found under choice and case then stack should conains 2*n+1 element
+ * @return stack of schema nodes via which it was passed through. If found schema node is direct child then stack
+ * contains only one node. If it is found under choice and case then stack should contains 2*n+1 element
* (where n is number of choices through it was passed)
*/
private Deque<DataSchemaNode> findSchemaNodeByNameAndNamespace(final DataSchemaNode dataSchemaNode,
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- nnStreamWriter.leafSetEntryNode(getValue());
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ writer.leafSetEntryNode(getValue());
}
}
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
-import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
-
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- nnStreamWriter.startLeafSet(provideNodeIdentifier(), UNKNOWN_SIZE);
- super.writeToStream(nnStreamWriter);
- nnStreamWriter.endNode();
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ writer.startLeafSet(provideNodeIdentifier(), childSizeHint());
+ super.write(writer);
+ writer.endNode();
}
}
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- nnStreamWriter.leafNode(provideNodeIdentifier(), getValue());
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ writer.leafNode(provideNodeIdentifier(), getValue());
}
}
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
-import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.annotation.Nonnull;
+
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
+ private static final Function<SimpleNodeDataWithSchema, Object> VALUE_FUNCTION = new Function<SimpleNodeDataWithSchema, Object>() {
+ @Override
+ public Object apply(@Nonnull final SimpleNodeDataWithSchema input) {
+ return input.getValue();
+ }
+ };
private final Map<QName, SimpleNodeDataWithSchema> qNameToKeys = new HashMap<>();
@Override
public void addChild(final AbstractNodeDataWithSchema newChild) {
- DataSchemaNode childSchema = newChild.getSchema();
+ final DataSchemaNode childSchema = newChild.getSchema();
if (childSchema instanceof LeafSchemaNode && isPartOfKey((LeafSchemaNode) childSchema)) {
qNameToKeys.put(childSchema.getQName(), (SimpleNodeDataWithSchema)newChild);
}
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- int keyCount = ((ListSchemaNode) getSchema()).getKeyDefinition().size();
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ final int keyCount = ((ListSchemaNode) getSchema()).getKeyDefinition().size();
if (keyCount == 0) {
- nnStreamWriter.startUnkeyedListItem(provideNodeIdentifier(), UNKNOWN_SIZE);
- super.writeToStream(nnStreamWriter);
- nnStreamWriter.endNode();
- } else if (keyCount == qNameToKeys.size()) {
- nnStreamWriter.startMapEntryNode(provideNodeIdentifierWithPredicates(), UNKNOWN_SIZE);
- super.writeToStream(nnStreamWriter);
- nnStreamWriter.endNode();
- } else {
- throw new IllegalStateException("Some of keys of " + getSchema().getQName() + " are missing in input.");
+ writer.startUnkeyedListItem(provideNodeIdentifier(), childSizeHint());
+ super.write(writer);
+ writer.endNode();
+ return;
}
- }
-
- private NodeIdentifierWithPredicates provideNodeIdentifierWithPredicates() {
- Map<QName, Object> qNameToPredicateValues = new HashMap<>();
- for (SimpleNodeDataWithSchema simpleNodeDataWithSchema : qNameToKeys.values()) {
- qNameToPredicateValues.put(simpleNodeDataWithSchema.getSchema().getQName(), simpleNodeDataWithSchema.getValue());
- }
-
- return new NodeIdentifierWithPredicates(getSchema().getQName(), qNameToPredicateValues);
+ Preconditions.checkState(keyCount == qNameToKeys.size(), "Input is missing some of the keys of %s", getSchema().getQName());
+ writer.startMapEntryNode(
+ new NodeIdentifierWithPredicates(getSchema().getQName(), Maps.transformValues(qNameToKeys, VALUE_FUNCTION)),
+ childSizeHint());
+ super.write(writer);
+ writer.endNode();
}
-
}
*/
package org.opendaylight.yangtools.yang.data.codec.gson;
-import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
-
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
}
@Override
- protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
- if (!((ListSchemaNode) getSchema()).getKeyDefinition().isEmpty()) {
- nnStreamWriter.startMapNode(provideNodeIdentifier(), UNKNOWN_SIZE);
+ public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+ if (((ListSchemaNode) getSchema()).getKeyDefinition().isEmpty()) {
+ writer.startUnkeyedList(provideNodeIdentifier(), childSizeHint());
} else {
- nnStreamWriter.startUnkeyedList(provideNodeIdentifier(), UNKNOWN_SIZE);
+ writer.startMapNode(provideNodeIdentifier(), childSizeHint());
}
- super.writeToStream(nnStreamWriter);
- nnStreamWriter.endNode();
+ super.write(writer);
+ writer.endNode();
}
}
+++ /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.yang.data.codec.gson.helpers;
-
-import com.google.common.base.Preconditions;
-
-import java.net.URI;
-
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-abstract class AbstractCodecImpl {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractCodecImpl.class);
- private final SchemaContextUtils schema;
-
- protected AbstractCodecImpl(final SchemaContextUtils schema) {
- this.schema = Preconditions.checkNotNull(schema);
- }
-
- protected final SchemaContextUtils getSchema() {
- return schema;
- }
-
- protected final Module getModuleByNamespace(final String namespace) {
- URI validNamespace = resolveValidNamespace(namespace);
-
- Module module = schema.findModuleByNamespace(validNamespace);
- if (module == null) {
- LOG.info("Module for namespace " + validNamespace + " wasn't found.");
- return null;
- }
- return module;
- }
-
- protected final URI resolveValidNamespace(final String namespace) {
- URI validNamespace = schema.findNamespaceByModuleName(namespace);
- if (validNamespace == null) {
- validNamespace = URI.create(namespace);
- }
-
- return validNamespace;
- }
-}
+++ /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.yang.data.codec.gson.helpers;
-
-import com.google.common.annotations.Beta;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This class is implementation-internal and subject to change. Please do not use it.
- */
-@Beta
-public final class IdentityValuesDTO {
-
- private final List<IdentityValue> elementData = new ArrayList<>();
- private final String originValue;
-
- public IdentityValuesDTO(final String namespace, final String value, final String prefix, final String originValue) {
- elementData.add(new IdentityValue(namespace, value, prefix));
- this.originValue = originValue;
- }
-
- public IdentityValuesDTO(final String originValue) {
- this.originValue = originValue;
- }
-
- public IdentityValuesDTO() {
- originValue = null;
- }
-
- public void add(final String namespace, final String value, final String prefix) {
- elementData.add(new IdentityValue(namespace, value, prefix));
- }
-
- public void add(final IdentityValue identityValue) {
- elementData.add(identityValue);
- }
-
- public List<IdentityValue> getValuesWithNamespaces() {
- return Collections.unmodifiableList(elementData);
- }
-
- @Override
- public String toString() {
- return elementData.toString();
- }
-
- public String getOriginValue() {
- return originValue;
- }
-
- public static final class IdentityValue {
-
- private final String namespace;
- private final String value;
- private final String prefix;
- private List<Predicate> predicates;
-
- public IdentityValue(final String namespace, final String value, final String prefix) {
- this.namespace = namespace;
- this.value = value;
- this.prefix = prefix;
- }
-
- public String getNamespace() {
- return namespace;
- }
-
- public String getValue() {
- return value;
- }
-
- public String getPrefix() {
- return prefix;
- }
-
- public List<Predicate> getPredicates() {
- if (predicates == null) {
- return Collections.emptyList();
- }
- return Collections.unmodifiableList(predicates);
- }
-
- public void setPredicates(final List<Predicate> predicates) {
- this.predicates = predicates;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (namespace != null) {
- sb.append(namespace);
- }
- if (prefix != null) {
- sb.append("(").append(prefix).append(")");
- }
- if (value != null) {
- sb.append(" - ").append(value);
- }
- if (predicates != null && !predicates.isEmpty()) {
- for (Predicate predicate : predicates) {
- sb.append("[");
- predicate.toString();
- sb.append("]");
- }
- }
- return sb.toString();
- }
-
- }
-
- public static final class Predicate {
-
- private final IdentityValue name;
- private final String value;
-
- public Predicate(final IdentityValue name, final String value) {
- super();
- this.name = name;
- this.value = value;
- }
-
- public IdentityValue getName() {
- return name;
- }
-
- public String getValue() {
- return value;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (name != null) {
- sb.append(name.toString());
- }
- if (value != null) {
- sb.append("=").append(value);
- }
- return sb.toString();
- }
-
- public boolean isLeafList() {
- return name == null ? true : false;
- }
-
- }
-}
+++ /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.yang.data.codec.gson.helpers;
-
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.codec.IdentityrefCodec;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.IdentityValue;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class IdentityrefCodecImpl extends AbstractCodecImpl implements IdentityrefCodec<IdentityValuesDTO> {
- private static final Logger LOG = LoggerFactory.getLogger(IdentityrefCodecImpl.class);
-
- IdentityrefCodecImpl(final SchemaContextUtils schema) {
- super(schema);
- }
-
- @Override
- public IdentityValuesDTO serialize(final QName data) {
- return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), data.getPrefix(), null);
- }
-
- @Override
- public QName deserialize(final IdentityValuesDTO data) {
- IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
- Module module = getModuleByNamespace(valueWithNamespace.getNamespace());
- if (module == null) {
- LOG.info("Module was not found for namespace {}", valueWithNamespace.getNamespace());
- LOG.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace));
- return null;
- }
-
- return QName.create(module.getNamespace(), module.getRevision(), valueWithNamespace.getValue());
- }
-
-}
\ No newline at end of file
+++ /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.yang.data.codec.gson.helpers;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-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.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.IdentityValue;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.Predicate;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class InstanceIdentifierCodecImpl extends AbstractCodecImpl implements InstanceIdentifierCodec<IdentityValuesDTO> {
- private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
-
- InstanceIdentifierCodecImpl(final SchemaContextUtils schema) {
- super(schema);
- }
-
- @Override
- public IdentityValuesDTO serialize(final YangInstanceIdentifier data) {
- IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO();
- for (PathArgument pathArgument : data.getPathArguments()) {
- IdentityValue identityValue = qNameToIdentityValue(pathArgument.getNodeType());
- if (pathArgument instanceof NodeIdentifierWithPredicates && identityValue != null) {
- List<Predicate> predicates = keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument)
- .getKeyValues());
- identityValue.setPredicates(predicates);
- } else if (pathArgument instanceof NodeWithValue && identityValue != null) {
- List<Predicate> predicates = new ArrayList<>();
- String value = String.valueOf(((NodeWithValue) pathArgument).getValue());
- predicates.add(new Predicate(null, value));
- identityValue.setPredicates(predicates);
- }
- identityValuesDTO.add(identityValue);
- }
- return identityValuesDTO;
- }
-
- @Override
- public YangInstanceIdentifier deserialize(final IdentityValuesDTO data) {
- List<PathArgument> result = new ArrayList<PathArgument>();
- IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
- Module module = getModuleByNamespace(valueWithNamespace.getNamespace());
- if (module == null) {
- LOG.info("Module by namespace '{}' of first node in instance-identiefier was not found.",
- valueWithNamespace.getNamespace());
- LOG.info("Instance-identifier will be translated as NULL for data - {}",
- String.valueOf(valueWithNamespace.getValue()));
- return null;
- }
-
- DataNodeContainer parentContainer = module;
- List<IdentityValue> identities = data.getValuesWithNamespaces();
- for (int i = 0; i < identities.size(); i++) {
- IdentityValue identityValue = identities.get(i);
- URI validNamespace = resolveValidNamespace(identityValue.getNamespace());
- DataSchemaNode node = getSchema().findInstanceDataChildByNameAndNamespace(
- parentContainer, identityValue.getValue(), validNamespace);
- if (node == null) {
- LOG.info("'{}' node was not found in {}", identityValue, parentContainer.getChildNodes());
- LOG.info("Instance-identifier will be translated as NULL for data - {}",
- String.valueOf(identityValue.getValue()));
- return null;
- }
- QName qName = node.getQName();
- PathArgument pathArgument = null;
- if (identityValue.getPredicates().isEmpty()) {
- pathArgument = new NodeIdentifier(qName);
- } else {
- if (node instanceof LeafListSchemaNode) { // predicate is value of leaf-list entry
- Predicate leafListPredicate = identityValue.getPredicates().get(0);
- if (!leafListPredicate.isLeafList()) {
- LOG.info("Predicate's data is not type of leaf-list. It should be in format \".='value'\"");
- LOG.info("Instance-identifier will be translated as NULL for data - {}",
- String.valueOf(identityValue.getValue()));
- return null;
- }
- pathArgument = new NodeWithValue(qName, leafListPredicate.getValue());
- } else if (node instanceof ListSchemaNode) { // predicates are keys of list
- DataNodeContainer listNode = (DataNodeContainer) node;
- Map<QName, Object> predicatesMap = new HashMap<>();
- for (Predicate predicate : identityValue.getPredicates()) {
- validNamespace = resolveValidNamespace(predicate.getName().getNamespace());
- DataSchemaNode listKey = getSchema()
- .findInstanceDataChildByNameAndNamespace(listNode, predicate.getName().getValue(),
- validNamespace);
- predicatesMap.put(listKey.getQName(), predicate.getValue());
- }
- pathArgument = new NodeIdentifierWithPredicates(qName, predicatesMap);
- } else {
- LOG.info("Node {} is not List or Leaf-list.", node);
- LOG.info("Instance-identifier will be translated as NULL for data - {}",
- String.valueOf(identityValue.getValue()));
- return null;
- }
- }
- result.add(pathArgument);
- if (i < identities.size() - 1) { // last element in instance-identifier can be other than
- // DataNodeContainer
- if (node instanceof DataNodeContainer) {
- parentContainer = (DataNodeContainer) node;
- } else {
- LOG.info("Node {} isn't instance of DataNodeContainer", node);
- LOG.info("Instance-identifier will be translated as NULL for data - {}",
- String.valueOf(identityValue.getValue()));
- return null;
- }
- }
- }
-
- return result.isEmpty() ? null : YangInstanceIdentifier.create(result);
- }
-
- private static List<Predicate> keyValuesToPredicateList(final Map<QName, Object> keyValues) {
- List<Predicate> result = new ArrayList<>(keyValues.size());
- for (Map.Entry<QName, Object> e : keyValues.entrySet()) {
- result.add(new Predicate(qNameToIdentityValue(e.getKey()), String.valueOf(e.getValue())));
- }
- return result;
- }
-
- private static IdentityValue qNameToIdentityValue(final QName qName) {
- if (qName != null) {
- // FIXME: the prefix here is completely arbitrary
- return new IdentityValue(qName.getNamespace().toString(), qName.getLocalName(), qName.getPrefix());
- }
- return null;
- }
-}
+++ /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.yang.data.codec.gson.helpers;
-
-import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec;
-
-class LeafrefCodecImpl implements LeafrefCodec<String> {
-
- @Override
- public String serialize(final Object data) {
- return String.valueOf(data);
- }
-
- @Override
- public Object deserialize(final String data) {
- return data;
- }
-
-}
\ No newline at end of file
+++ /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.yang.data.codec.gson.helpers;
-
-import org.opendaylight.yangtools.concepts.Codec;
-import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-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.LeafrefTypeDefinition;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@SuppressWarnings("rawtypes")
-final class ObjectCodec extends AbstractCodecImpl implements Codec<Object, Object> {
- public static final Codec LEAFREF_DEFAULT_CODEC = new LeafrefCodecImpl();
- private static final Logger LOG = LoggerFactory.getLogger(RestCodecFactory.class);
- private final Codec instanceIdentifier;
- private final Codec identityrefCodec;
- private final TypeDefinition<?> type;
-
- ObjectCodec(final SchemaContextUtils schema, final TypeDefinition<?> typeDefinition) {
- super(schema);
- type = RestUtil.resolveBaseTypeFrom(typeDefinition);
- if (type instanceof IdentityrefTypeDefinition) {
- identityrefCodec = new IdentityrefCodecImpl(schema);
- } else {
- identityrefCodec = null;
- }
- if (type instanceof InstanceIdentifierTypeDefinition) {
- instanceIdentifier = new InstanceIdentifierCodecImpl(schema);
- } else {
- instanceIdentifier = null;
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Object deserialize(final Object input) {
- try {
- if (type instanceof IdentityrefTypeDefinition) {
- if (input instanceof IdentityValuesDTO) {
- return identityrefCodec.deserialize(input);
- }
- LOG.debug("Value is not instance of IdentityrefTypeDefinition but is {}. Therefore NULL is used as translation of - {}",
- input == null ? "null" : input.getClass(), String.valueOf(input));
- return null;
- } else if (type instanceof LeafrefTypeDefinition) {
- if (input instanceof IdentityValuesDTO) {
- return LEAFREF_DEFAULT_CODEC.deserialize(((IdentityValuesDTO) input).getOriginValue());
- }
- return LEAFREF_DEFAULT_CODEC.deserialize(input);
- } else if (type instanceof InstanceIdentifierTypeDefinition) {
- if (input instanceof IdentityValuesDTO) {
- return instanceIdentifier.deserialize(input);
- }
- LOG.info(
- "Value is not instance of InstanceIdentifierTypeDefinition but is {}. Therefore NULL is used as translation of - {}",
- input == null ? "null" : input.getClass(), String.valueOf(input));
- return null;
- } else {
- TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
- .from(type);
- if (typeAwarecodec != null) {
- if (input instanceof IdentityValuesDTO) {
- return typeAwarecodec.deserialize(((IdentityValuesDTO) input).getOriginValue());
- }
- return typeAwarecodec.deserialize(String.valueOf(input));
- } else {
- LOG.debug("Codec for type \"" + type.getQName().getLocalName()
- + "\" is not implemented yet.");
- return null;
- }
- }
- } catch (ClassCastException e) {
- // TODO remove this catch when everyone use codecs
- LOG.error("ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input),
- e);
- return null;
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Object serialize(final Object input) {
- try {
- if (type instanceof IdentityrefTypeDefinition) {
- return identityrefCodec.serialize(input);
- } else if (type instanceof LeafrefTypeDefinition) {
- return LEAFREF_DEFAULT_CODEC.serialize(input);
- } else if (type instanceof InstanceIdentifierTypeDefinition) {
- return instanceIdentifier.serialize(input);
- } else {
- TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
- .from(type);
- if (typeAwarecodec != null) {
- return typeAwarecodec.serialize(input);
- } else {
- LOG.debug("Codec for type \"" + type.getQName().getLocalName()
- + "\" is not implemented yet.");
- return null;
- }
- }
- } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs
- LOG.error(
- "ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input),
- e);
- return input;
- }
- }
-
-}
\ No newline at end of file
+++ /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.yang.data.codec.gson.helpers;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-import org.opendaylight.yangtools.concepts.Codec;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-
-/**
- * This class is implementation-internal and subject to change. Please do not use it.
- */
-@Beta
-public final class RestCodecFactory {
- private final SchemaContextUtils utils;
-
- private RestCodecFactory(final SchemaContextUtils utils) {
- this.utils = Preconditions.checkNotNull(utils);
- }
-
- public static RestCodecFactory create(final SchemaContextUtils utils) {
- return new RestCodecFactory(utils);
- }
-
- public final Codec<Object, Object> codecFor(final TypeDefinition<?> typeDefinition) {
- // FIXME: implement loadingcache
- return new ObjectCodec(utils, typeDefinition);
- }
-}
+++ /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.yang.data.codec.gson.helpers;
-
-
-import com.google.common.annotations.Beta;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.xml.stream.events.StartElement;
-
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.IdentityValue;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.Predicate;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-
-/**
- * This class is implementation-internal and subject to change. Please do not use it.
- */
-@Beta
-public final class RestUtil {
-
- // FIXME: BUG-1275: this is code duplicates data.impl.codec
-
- public static final String SQUOTE = "'";
- public static final String DQUOTE = "\"";
- private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
-
- public final static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
- TypeDefinition<?> superType = type;
- while (superType.getBaseType() != null) {
- superType = superType.getBaseType();
- }
- return superType;
- }
-
- public static IdentityValuesDTO asInstanceIdentifier(final String value, final PrefixesMaping prefixMap) {
- String valueTrimmed = value.trim();
- if (!valueTrimmed.startsWith("/")) {
- return null;
- }
- String[] xPathParts = valueTrimmed.split("/");
- if (xPathParts.length < 2) { // must be at least "/pr:node"
- return null;
- }
- IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value);
- for (int i = 1; i < xPathParts.length; i++) {
- String xPathPartTrimmed = xPathParts[i].trim();
-
- String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
- IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
- if (identityValue == null) {
- return null;
- }
-
- List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
- if (predicates == null) {
- return null;
- }
- identityValue.setPredicates(predicates);
-
- identityValuesDTO.add(identityValue);
- }
- return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO;
- }
-
- private static String getIdAndPrefixAsStr(final String pathPart) {
- int predicateStartIndex = pathPart.indexOf("[");
- return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
- }
-
- private static IdentityValue toIdentity(final String xPathPart, final PrefixesMaping prefixMap) {
- String xPathPartTrimmed = xPathPart.trim();
- if (xPathPartTrimmed.isEmpty()) {
- return null;
- }
- String[] prefixAndIdentifier = xPathPartTrimmed.split(":");
- // it is not "prefix:value"
- if (prefixAndIdentifier.length != 2) {
- return null;
- }
- String prefix = prefixAndIdentifier[0].trim();
- String identifier = prefixAndIdentifier[1].trim();
- if (prefix.isEmpty() || identifier.isEmpty()) {
- return null;
- }
- String namespace = prefixMap.getNamespace(prefix);
- return new IdentityValue(namespace, identifier, namespace.equals(prefix) ? null : prefix);
- }
-
- private static List<Predicate> toPredicates(final String predicatesStr, final PrefixesMaping prefixMap) {
- List<Predicate> result = new ArrayList<>();
- List<String> predicates = new ArrayList<>();
- Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
- while (matcher.find()) {
- predicates.add(matcher.group(1).trim());
- }
- for (String predicate : predicates) {
- int indexOfEqualityMark = predicate.indexOf("=");
- if (indexOfEqualityMark != -1) {
- String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1));
- if (predicate.startsWith(".")) { // it is leaf-list
- if (predicateValue == null) {
- return null;
- }
- result.add(new Predicate(null, predicateValue));
- } else {
- IdentityValue identityValue = toIdentity(predicate.substring(0, indexOfEqualityMark), prefixMap);
- if (identityValue == null || predicateValue == null) {
- return null;
- }
- result.add(new Predicate(identityValue, predicateValue));
- }
- }
- }
- return result;
- }
-
- private static String toPredicateValue(final String predicatedValue) {
- String predicatedValueTrimmed = predicatedValue.trim();
- if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE))
- && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) {
- return predicatedValueTrimmed.substring(1, predicatedValueTrimmed.length() - 1);
- }
- return null;
- }
-
- public interface PrefixesMaping {
- public String getNamespace(String prefix);
- }
-
- public static class PrefixMapingFromXml implements PrefixesMaping {
- StartElement startElement = null;
-
- public PrefixMapingFromXml(final StartElement startElement) {
- this.startElement = startElement;
- }
-
- @Override
- public String getNamespace(final String prefix) {
- return startElement.getNamespaceContext().getNamespaceURI(prefix);
- }
- }
-
- public static class PrefixMapingFromJson implements PrefixesMaping {
-
- @Override
- public String getNamespace(final String prefix) {
- return prefix;
- }
- }
-
-}
+++ /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.yang.data.codec.gson.helpers;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
-/**
- * This class is implementation-internal and subject to change. Please do not use it.
- */
-@Beta
-public final class SchemaContextUtils {
- private final SchemaContext schemaContext;
-
- private SchemaContextUtils(final SchemaContext schemaContext) {
- this.schemaContext = Preconditions.checkNotNull(schemaContext);
- }
-
- public static SchemaContextUtils create(final SchemaContext schemaContext) {
- return new SchemaContextUtils(schemaContext);
- }
-
- public URI findNamespaceByModuleName(final String moduleName) {
- final Module module = this.findModuleByName(moduleName);
- return module == null ? null : module.getNamespace();
- }
-
-
- public Module findModuleByName(final String moduleName) {
- checkPreconditions();
- Preconditions.checkArgument(moduleName != null && !moduleName.isEmpty());
- return schemaContext.findModuleByName(moduleName, null);
- }
-
- public Module findModuleByNamespace(final URI namespace) {
- this.checkPreconditions();
- Preconditions.checkArgument(namespace != null);
- return schemaContext.findModuleByNamespaceAndRevision(namespace, null);
- }
-
- private void checkPreconditions() {
- if (schemaContext == null) {
- throw new IllegalStateException("Schema context isn't set.");
- }
- }
-
- public DataSchemaNode findInstanceDataChildByNameAndNamespace(final DataNodeContainer container, final String name,
- final URI namespace) {
- Preconditions.<URI> checkNotNull(namespace);
-
- final List<DataSchemaNode> potentialSchemaNodes = findInstanceDataChildrenByName(container, name);
-
- Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
- @Override
- public boolean apply(final DataSchemaNode node) {
- return Objects.equal(node.getQName().getNamespace(), namespace);
- }
- };
-
- Iterable<DataSchemaNode> result = Iterables.filter(potentialSchemaNodes, filter);
- return Iterables.getFirst(result, null);
- }
-
- public List<DataSchemaNode> findInstanceDataChildrenByName(final DataNodeContainer container, final String name) {
- Preconditions.<DataNodeContainer> checkNotNull(container);
- Preconditions.<String> checkNotNull(name);
-
- List<DataSchemaNode> instantiatedDataNodeContainers = new ArrayList<DataSchemaNode>();
- collectInstanceDataNodeContainers(instantiatedDataNodeContainers, container, name);
- return instantiatedDataNodeContainers;
- }
-
- private void collectInstanceDataNodeContainers(final List<DataSchemaNode> potentialSchemaNodes,
- final DataNodeContainer container, final String name) {
-
- Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
- @Override
- public boolean apply(final DataSchemaNode node) {
- return Objects.equal(node.getQName().getLocalName(), name);
- }
- };
-
- Iterable<DataSchemaNode> nodes = Iterables.filter(container.getChildNodes(), filter);
-
- // Can't combine this loop with the filter above because the filter is
- // lazily-applied by Iterables.filter.
- for (final DataSchemaNode potentialNode : nodes) {
- if (isInstantiatedDataSchema(potentialNode)) {
- potentialSchemaNodes.add(potentialNode);
- }
- }
-
- Iterable<ChoiceNode> choiceNodes = Iterables.filter(container.getChildNodes(), ChoiceNode.class);
- Iterable<Set<ChoiceCaseNode>> map = Iterables.transform(choiceNodes, CHOICE_FUNCTION);
-
- final Iterable<ChoiceCaseNode> allCases = Iterables.<ChoiceCaseNode> concat(map);
- for (final ChoiceCaseNode caze : allCases) {
- collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name);
- }
- }
-
- public boolean isInstantiatedDataSchema(final DataSchemaNode node) {
- return node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode
- || node instanceof ContainerSchemaNode || node instanceof ListSchemaNode
- || node instanceof AnyXmlSchemaNode;
- }
-
- private final Function<ChoiceNode, Set<ChoiceCaseNode>> CHOICE_FUNCTION = new Function<ChoiceNode, Set<ChoiceCaseNode>>() {
- @Override
- public Set<ChoiceCaseNode> apply(final ChoiceNode node) {
- return node.getCases();
- }
- };
-
-}
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.Ignore;
import org.junit.Test;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.stream.LoggingNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
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.builder.api.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
*
* @throws IOException
*/
+ @Ignore
@Test
public void immutableNormalizedNodeStreamWriterDemonstration() throws IOException {
/*
* 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
"anyxml-in-data":"foo"
}
],
-
+
"lf13-any":{
"anyxml-in-data":"foo"
},
-
+
"lf14-any":"anyxml data",
-
+
"lflst11":["lflst11 value1","lflst11 value2"],
-
+
"lst11":[
- {
+ {
"key111":"key111 value",
"lf112":"/complexjson:cont1/complexjson:lflst11",
"lf113":"lf113 value",
"lf111":"lf111 value"
}
- ],
+ ],
"lf11" : "453",
"lf12_1" : "lf12 value",
- "lf13" : "lf13 value",
+ "lf13" : "lf13 value",
"complexjson-augmentation:lf15_11" : "lf15_11 value from augmentation",
"complexjson-augmentation:lf15_12" : "lf15_12 value from augmentation",
"lf15_11" : "one two",
"lf15_12" : "complexjson:lf11",
"lf15_21" : "lf15_21 value",
- "lf17" : "lf17 value",
-
+ "lf17" : "lf17 value",
+
"lst12":[
{
"lf121":"lf121 value"
}
]
}
-}
\ No newline at end of file
+}
namespace "ns:complex:json";
prefix cj;
- revision "2014-08-11" {
+ revision "2014-08-11" {
}
-
-
+
+
identity ident;
-
+
container cont1 {
-
+
anyxml lf12-any;
anyxml lf13-any;
anyxml lf14-any;
-
+
leaf lf11 {
type int32;
}
-
+
leaf-list lflst11 {
type string;
}
-
+
list lst11 {
key "key111 lf111";
leaf key111 {
type string;
}
}
-
+
list lst12 {
leaf lf121 {
type string;
type string;
}
}
-
-
+
+
choice choc11 {
case c11A {
leaf lf13 {
}
}
}
-
-
+
augment "/cont1/choc12" {
case c12B {
leaf lf17 {
type string;
}
}
- }
-
-
+ }
+
augment "/cont1" {
container cont11 {
leaf lf111 {
type string;
}
- }
+ }
}
-
+
augment "/cont1" {
leaf lf12_1 {
- type string;
- }
+ type string;
+ }
leaf lf12_2 {
type string;
}
}
-
+
augment "/cont1" {
leaf lf12_3 {
- type string;
- }
+ type string;
+ }
}
-
-
+
augment "/cont1/choc11" {
case c11B {
leaf lf14_1 {
- type string;
- }
+ type string;
+ }
}
}
-
+
augment "/cont1/choc11" {
case c11C {
leaf lf14_2 {
- type string;
- }
+ type string;
+ }
}
}
-
+
augment "/cont1/choc11/c11A" {
leaf lf15_11 {
- type bits {
- bit one;
- bit two;
- bit three;
- }
- }
+ type bits {
+ bit one;
+ bit two;
+ bit three;
+ }
+ }
leaf lf15_12 {
- type identityref {
- base ident;
- }
- }
-
+ type identityref {
+ base ident;
+ }
+ }
+
}
-
+
augment "/cont1/choc11/c11A" {
leaf lf15_21 {
- type string;
- }
+ type string;
+ }
}
}
import org.opendaylight.yangtools.yang.binding.BindingCodec;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-public interface InstanceIdentifierCodec extends BindingCodec<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier,InstanceIdentifier<?>> {
-
+public interface InstanceIdentifierCodec extends BindingCodec<YangInstanceIdentifier, InstanceIdentifier<?>> {
@Override
- org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier serialize(InstanceIdentifier<?> input);
+ YangInstanceIdentifier serialize(InstanceIdentifier<?> input);
@Override
- InstanceIdentifier<?> deserialize(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input);
+ InstanceIdentifier<?> deserialize(YangInstanceIdentifier input);
}
--- /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.yang.data.impl.codec;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashSet;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.yang.common.QName;
+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.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for tracking the underlying state of the underlying
+ * schema node.
+ */
+@Beta
+public final class SchemaTracker {
+ private static final Logger LOG = LoggerFactory.getLogger(SchemaTracker.class);
+ private final Deque<Object> schemaStack = new ArrayDeque<>();
+ private final DataNodeContainer root;
+
+ private SchemaTracker(final SchemaContext context, final SchemaPath path) {
+ DataNodeContainer current = Preconditions.checkNotNull(context);
+ for (QName qname : path.getPathFromRoot()) {
+ final DataSchemaNode child = current.getDataChildByName(qname);
+ Preconditions.checkArgument(child instanceof DataNodeContainer);
+ current = (DataNodeContainer) child;
+ }
+
+ this.root = current;
+ }
+
+ /**
+ * Create a new writer with the specified context as its root.
+ *
+ * @param writer Output {@link XMLStreamWriter}
+ * @param context Associated {@link SchemaContext}.
+ * @return A new {@link NormalizedNodeStreamWriter}
+ */
+ public static SchemaTracker create(final SchemaContext context) {
+ return create(context, SchemaPath.ROOT);
+ }
+
+ /**
+ * Create a new writer with the specified context and rooted in the specified schema path
+ *
+ * @param writer Output {@link XMLStreamWriter}
+ * @param context Associated {@link SchemaContext}.
+ *
+ * @return A new {@link NormalizedNodeStreamWriter}
+ */
+ public static SchemaTracker create(final SchemaContext context, final SchemaPath path) {
+ return new SchemaTracker(context, path);
+ }
+
+ public Object getParent() {
+ if (schemaStack.isEmpty()) {
+ return root;
+ }
+ return schemaStack.peek();
+ }
+
+ private SchemaNode getSchema(final PathArgument name) {
+ final Object parent = getParent();
+ SchemaNode schema = null;
+ final QName qname = name.getNodeType();
+ if(parent instanceof DataNodeContainer) {
+ schema = ((DataNodeContainer)parent).getDataChildByName(qname);
+
+ } else if(parent instanceof ChoiceNode) {
+ for(ChoiceCaseNode caze : ((ChoiceNode) parent).getCases()) {
+ DataSchemaNode potential = caze.getDataChildByName(qname);
+ if(potential != null) {
+ schema = potential;
+ break;
+ }
+ }
+ } else {
+ throw new IllegalStateException("Unsupported schema type "+ parent.getClass() +" on stack.");
+ }
+ Preconditions.checkArgument(schema != null, "Could not find schema for node %s in %s", qname, parent);
+ return schema;
+ }
+
+ public void startList(final NodeIdentifier name) {
+ final SchemaNode schema = getSchema(name);
+ Preconditions.checkArgument(schema instanceof ListSchemaNode, "Node %s is not a list", schema.getPath());
+ schemaStack.push(schema);
+ }
+
+ public void startListItem(final PathArgument name) throws IOException {
+ final Object schema = getParent();
+ Preconditions.checkArgument(schema instanceof ListSchemaNode, "List item is not appropriate");
+ schemaStack.push(schema);
+ }
+
+ public LeafSchemaNode leafNode(final NodeIdentifier name) throws IOException {
+ final SchemaNode schema = getSchema(name);
+
+ Preconditions.checkArgument(schema instanceof LeafSchemaNode, "Node %s is not a leaf", schema.getPath());
+ return (LeafSchemaNode) schema;
+ }
+
+ public SchemaNode startLeafSet(final NodeIdentifier name) {
+ final SchemaNode schema = getSchema(name);
+
+ Preconditions.checkArgument(schema instanceof LeafListSchemaNode, "Node %s is not a leaf-list", schema.getPath());
+ schemaStack.push(schema);
+ return schema;
+ }
+
+ public LeafListSchemaNode leafSetEntryNode() {
+ final Object parent = getParent();
+
+ Preconditions.checkArgument(parent instanceof LeafListSchemaNode, "Not currently in a leaf-list");
+ return (LeafListSchemaNode) parent;
+ }
+
+ public SchemaNode startChoiceNode(final NodeIdentifier name) {
+ LOG.debug("Enter choice {}", name);
+ final SchemaNode schema = getSchema(name);
+
+ Preconditions.checkArgument(schema instanceof ChoiceNode, "Node %s is not a choice", schema.getPath());
+ schemaStack.push(schema);
+ return schema;
+ }
+
+ public SchemaNode startContainerNode(final NodeIdentifier name) {
+ LOG.debug("Enter container {}", name);
+ final SchemaNode schema = getSchema(name);
+
+ Preconditions.checkArgument(schema instanceof ContainerSchemaNode, "Node %s is not a container", schema.getPath());
+ schemaStack.push(schema);
+ return schema;
+ }
+
+ public AugmentationSchema startAugmentationNode(final AugmentationIdentifier identifier) {
+ LOG.debug("Enter augmentation {}", identifier);
+ final Object parent = getParent();
+
+ Preconditions.checkArgument(parent instanceof AugmentationTarget, "Augmentation not allowed under %s", parent);
+ Preconditions.checkArgument(parent instanceof DataNodeContainer, "Augmentation allowed only in DataNodeContainer",parent);
+ final AugmentationSchema schema = SchemaUtils.findSchemaForAugment((AugmentationTarget) parent, identifier.getPossibleChildNames());
+ HashSet<DataSchemaNode> realChildSchemas = new HashSet<>();
+ for(DataSchemaNode child : schema.getChildNodes()) {
+ realChildSchemas.add(((DataNodeContainer) parent).getDataChildByName(child.getQName()));
+ }
+ AugmentationSchema resolvedSchema = new AugmentationSchemaProxy(schema, realChildSchemas);
+ schemaStack.push(resolvedSchema);
+ return resolvedSchema;
+ }
+
+ public AnyXmlSchemaNode anyxmlNode(final NodeIdentifier name) {
+ final SchemaNode schema = getSchema(name);
+
+ Preconditions.checkArgument(schema instanceof AnyXmlSchemaNode, "Node %s is not anyxml", schema.getPath());
+ return (AnyXmlSchemaNode)schema;
+ }
+
+ public Object endNode() {
+ return schemaStack.pop();
+ }
+}
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.io.BaseEncoding;
-
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import javax.xml.bind.DatatypeConverter;
-
import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
return 8;
} else {
String formatedMessage = String.format("Incorrect lexical representation of integer value: %s."
- + "\nAn integer value can be defined as: "
- + "\n - a decimal number,"
- + "\n - a hexadecimal number (prefix 0x),"
- + "\n - an octal number (prefix 0)."
- + "\nSigned values are allowed. Spaces between digits are NOT allowed.", integer);
+ + "%nAn integer value can be defined as: "
+ + "%n - a decimal number,"
+ + "%n - a hexadecimal number (prefix 0x),"
+ + "%n - an octal number (prefix 0)."
+ + "%nSigned values are allowed. Spaces between digits are NOT allowed.", integer);
throw new NumberFormatException(formatedMessage);
}
}
@Override
public String deserialize(final String stringRepresentation) {
- return stringRepresentation == null ? "" :stringRepresentation;
+ return stringRepresentation == null ? "" : stringRepresentation;
}
@Override
public String serialize(final String data) {
- return data == null ? "" : data.toString();
+ return data == null ? "" : data;
}
};
--- /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.yang.data.impl.codec.xml;
+
+import com.google.common.base.Preconditions;
+
+import java.io.IOException;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+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.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.SchemaTracker;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+/**
+ * A {@link NormalizedNodeStreamWriter} which translates the events into an
+ * {@link XMLStreamWriter}, resulting in a RFC 6020 XML encoding.
+ */
+public final class XMLStreamNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
+ private static final XmlStreamUtils UTILS = XmlStreamUtils.create(XmlUtils.DEFAULT_XML_CODEC_PROVIDER);
+
+ private final XMLStreamWriter writer;
+ private final SchemaTracker tracker;
+
+ private XMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer, final SchemaContext context, final SchemaPath path) {
+ this.writer = Preconditions.checkNotNull(writer);
+ this.tracker = SchemaTracker.create(context, path);
+ }
+
+ /**
+ * Create a new writer with the specified context as its root.
+ *
+ * @param writer Output {@link XMLStreamWriter}
+ * @param context Associated {@link SchemaContext}.
+ * @return A new {@link NormalizedNodeStreamWriter}
+ */
+ public static NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context) {
+ return create( writer, context, SchemaPath.ROOT);
+ }
+
+ /**
+ * Create a new writer with the specified context and rooted in the specified schema path
+ *
+ * @param writer Output {@link XMLStreamWriter}
+ * @param context Associated {@link SchemaContext}.
+ *
+ * @return A new {@link NormalizedNodeStreamWriter}
+ */
+ public static NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context, final SchemaPath path) {
+ final Boolean repairing = (Boolean) writer.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
+ Preconditions.checkArgument(repairing == true, "XML Stream Writer has to be repairing namespaces");
+ return new XMLStreamNormalizedNodeStreamWriter(writer, context, path);
+ }
+
+ private void writeElement(final QName qname, final TypeDefinition<?> type, final Object value) throws IOException {
+ final String ns = qname.getNamespace().toString();
+
+ try {
+ if (value != null) {
+ writer.writeStartElement(ns, qname.getLocalName());
+ UTILS.writeValue(writer, type, value);
+ writer.writeEndElement();
+ } else {
+ writer.writeEmptyElement(ns, qname.getLocalName());
+ }
+ } catch (XMLStreamException e) {
+ throw new IOException("Failed to emit element", e);
+ }
+ }
+
+ private void startElement(final QName qname) throws IOException {
+ try {
+ writer.writeStartElement(qname.getNamespace().toString(), qname.getLocalName());
+ } catch (XMLStreamException e) {
+ throw new IOException("Failed to start element", e);
+ }
+ }
+
+ private void startList(final NodeIdentifier name) {
+ tracker.startList(name);
+ }
+
+ private void startListItem(final PathArgument name) throws IOException {
+ tracker.startListItem(name);
+ startElement(name.getNodeType());
+ }
+
+ @Override
+ public void leafNode(final NodeIdentifier name, final Object value) throws IOException {
+ final LeafSchemaNode schema = tracker.leafNode(name);
+
+ writeElement(schema.getQName(), schema.getType(), value);
+ }
+
+ @Override
+ public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
+ tracker.startLeafSet(name);
+ }
+
+ @Override
+ public void leafSetEntryNode(final Object value) throws IOException {
+ final LeafListSchemaNode schema = tracker.leafSetEntryNode();
+ writeElement(schema.getQName(), schema.getType(), value);
+ }
+
+ @Override
+ public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ final SchemaNode schema = tracker.startContainerNode(name);
+ startElement(schema.getQName());
+ }
+
+ @Override
+ public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
+ startList(name);
+ }
+
+ @Override
+ public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
+ startListItem(name);
+ }
+
+ @Override
+ public void startMapNode(final NodeIdentifier name, final int childSizeHint) {
+ startList(name);
+ }
+
+ @Override
+ public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) throws IOException {
+ startListItem(identifier);
+ }
+
+ @Override
+ public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) {
+ startList(name);
+ }
+
+ @Override
+ public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) {
+ tracker.startChoiceNode(name);
+ }
+
+ @Override
+ public void startAugmentationNode(final AugmentationIdentifier identifier) {
+ tracker.startAugmentationNode(identifier);
+ }
+
+ @Override
+ public void anyxmlNode(final NodeIdentifier name, final Object value) throws IOException {
+ final AnyXmlSchemaNode schema = tracker.anyxmlNode(name);
+ final QName qname = schema.getQName();
+ final String ns = qname.getNamespace().toString();
+
+ try {
+ if (value != null) {
+ writer.writeStartElement(ns, qname.getLocalName());
+ UTILS.writeValue(writer, (Node<?>)value, schema);
+ writer.writeEndElement();
+ } else {
+ writer.writeEmptyElement(ns, qname.getLocalName());
+ }
+ } catch (XMLStreamException e) {
+ throw new IOException("Failed to emit element", e);
+ }
+ }
+
+ @Override
+ public void endNode() throws IOException {
+ final Object schema = tracker.endNode();
+
+ try {
+ if (schema instanceof ListSchemaNode) {
+ // For lists, we only emit end element on the inner frame
+ final Object parent = tracker.getParent();
+ if (parent == schema) {
+ writer.writeEndElement();
+ }
+ } else if (schema instanceof ContainerSchemaNode) {
+ // Emit container end element
+ writer.writeEndElement();
+ }
+ } catch (XMLStreamException e) {
+ throw new IOException("Failed to end element", e);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ writer.close();
+ } catch (XMLStreamException e) {
+ throw new IOException("Failed to close writer", e);
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ writer.flush();
+ } catch (XMLStreamException e) {
+ throw new IOException("Failed to flush writer", e);
+ }
+ }
+}
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("']");
throw new UnsupportedOperationException("Utilities class should not be instantiated");
}
- public static final CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder() {
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder() {
return ImmutableMapNodeBuilder.create();
}
- public static final CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder(final QName name) {
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder(final QName name) {
return ImmutableMapNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(name));
}
* @param value Value of leaf node
* @return Leaf node with supplied identifier and value
*/
- public static final <T> LeafNode<T> leafNode(final NodeIdentifier name,final T value) {
+ public static <T> LeafNode<T> leafNode(final NodeIdentifier name,final T value) {
return ImmutableLeafNodeBuilder.<T>create()
.withNodeIdentifier(name)
.withValue(value)
}
/**
- *
* Construct immutable leaf node
*
* @param name QName which will be used as node identifier
* @param value Value of leaf node.
* @return Leaf node with supplied identifier and value
*/
- public static final <T> LeafNode<T> leafNode(final QName name,final T value) {
+ public static <T> LeafNode<T> leafNode(final QName name,final T value) {
return leafNode(new NodeIdentifier(name), value);
}
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;
--- /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.yang.data.util;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+@Beta
+public abstract class AbstractModuleStringIdentityrefCodec extends AbstractStringIdentityrefCodec {
+ /**
+ * Resolve a string prefix into the corresponding module.
+ *
+ * @param prefix
+ * @return module mapped to prefix, or null if the module cannot be resolved
+ */
+ protected abstract Module moduleForPrefix(@Nonnull String prefix);
+
+ @Override
+ protected final QName createQName(final String prefix, final String localName) {
+ final Module module = moduleForPrefix(prefix);
+ Preconditions.checkArgument(module != null, "Failed to lookup prefix %s", prefix);
+ return QName.create(module.getQNameModule(), localName);
+ }
+}
--- /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.yang.data.util;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+/**
+ * Extension of {@link AbstractStringInstanceIdentifierCodec}, which instantiates
+ * QNames by first resolving the namespace and then looking the target namespace
+ * in the list of currently-subscribed modules.
+ */
+@Beta
+public abstract class AbstractModuleStringInstanceIdentifierCodec extends AbstractStringInstanceIdentifierCodec {
+ /**
+ * Resolve a string prefix into the corresponding module.
+ *
+ * @param prefix
+ * @return module mapped to prefix, or null if the module cannot be resolved
+ */
+ protected abstract Module moduleForPrefix(@Nonnull String prefix);
+
+ @Override
+ protected final QName createQName(final String prefix, final String localName) {
+ final Module module = moduleForPrefix(prefix);
+ Preconditions.checkArgument(module != null, "Failed to lookup prefix %s", prefix);
+ return QName.create(module.getQNameModule(), localName);
+ }
+}
--- /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.yang.data.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+
+import java.net.URI;
+import java.util.Iterator;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+abstract class AbstractNamespaceCodec {
+ private static final Splitter COLON_SPLITTER = Splitter.on(':');
+
+ /**
+ * Return string prefix for a particular namespace, allocating a new one if necessary.
+ *
+ * @param namespace Namespace to map
+ * @return Allocated unique prefix, or null if the prefix cannot be mapped.
+ */
+ protected abstract @Nullable String prefixForNamespace(final @Nonnull URI namespace);
+
+ /**
+ * Create a QName for a prefix and local name.
+ *
+ * @param prefix Prefix for namespace
+ * @param localName local name
+ * @return QName
+ * @throws IllegalArgumentException if the prefix cannot be resolved
+ */
+ protected abstract @Nullable QName createQName(final @Nonnull String prefix, final @Nonnull String localName);
+
+ private static String getIdAndPrefixAsStr(final String pathPart) {
+ int predicateStartIndex = pathPart.indexOf('[');
+ return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
+ }
+
+ protected final StringBuilder appendQName(final StringBuilder sb, final QName qname) {
+ final String prefix = prefixForNamespace(qname.getNamespace());
+ Preconditions.checkArgument(prefix != null, "Failed to map QName {}", qname);
+ sb.append(prefix);
+ sb.append(':');
+ sb.append(qname.getLocalName());
+ return sb;
+ }
+
+ protected final QName parseQName(final String str) {
+ final String xPathPartTrimmed = getIdAndPrefixAsStr(str).trim();
+ final Iterator<String> it = COLON_SPLITTER.split(xPathPartTrimmed).iterator();
+
+ // Empty string
+ if (!it.hasNext()) {
+ return null;
+ }
+
+ final String prefix = it.next().trim();
+ if (prefix.isEmpty()) {
+ return null;
+ }
+
+ // it is not "prefix:value"
+ if (!it.hasNext()) {
+ return null;
+ }
+
+ final String identifier = it.next().trim();
+ if (identifier.isEmpty()) {
+ return null;
+ }
+
+ return createQName(prefix, identifier);
+ }
+}
--- /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.yang.data.util;
+
+import com.google.common.annotations.Beta;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.codec.IdentityrefCodec;
+
+/**
+ * Abstract utility class for representations which encode Identityref as a
+ * prefix:name tuple. Typical uses are RESTCONF/JSON (module:name) and XML (prefix:name).
+ */
+@Beta
+public abstract class AbstractStringIdentityrefCodec extends AbstractNamespaceCodec implements IdentityrefCodec<String> {
+ @Override
+ public String serialize(final QName data) {
+ return appendQName(new StringBuilder(), data).toString();
+ }
+
+ @Override
+ public QName deserialize(final String data) {
+ return parseQName(data);
+ }
+}
--- /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.yang.data.util;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
+
+/**
+ * Abstract utility class for representations which encode {@link YangInstanceIdentifier} as a
+ * prefix:name tuple. Typical uses are RESTCONF/JSON (module:name) and XML (prefix:name).
+ */
+@Beta
+public abstract class AbstractStringInstanceIdentifierCodec extends AbstractNamespaceCodec implements InstanceIdentifierCodec<String> {
+ private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
+ private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+
+ @Override
+ public final String serialize(final YangInstanceIdentifier data) {
+ StringBuilder sb = new StringBuilder();
+ for (PathArgument arg : data.getPathArguments()) {
+ sb.append('/');
+ appendQName(sb, arg.getNodeType());
+
+ if (arg instanceof NodeIdentifierWithPredicates) {
+ for (Map.Entry<QName, Object> entry : ((NodeIdentifierWithPredicates) arg).getKeyValues().entrySet()) {
+ sb.append('[');
+ appendQName(sb, entry.getKey());
+ sb.append("='");
+ sb.append(String.valueOf(entry.getValue()));
+ sb.append("']");
+ }
+ } else if (arg instanceof NodeWithValue) {
+ sb.append("[.='");
+ sb.append(((NodeWithValue) arg).getValue());
+ sb.append("']");
+ }
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public final YangInstanceIdentifier deserialize(final String data) {
+ Preconditions.checkNotNull(data, "Data may not be null");
+
+ final Iterator<String> xPathParts = SLASH_SPLITTER.split(data).iterator();
+
+ // must be at least "/pr:node"
+ if (!xPathParts.hasNext() || !xPathParts.next().isEmpty() || !xPathParts.hasNext()) {
+ return null;
+ }
+
+ List<PathArgument> result = new ArrayList<>();
+ while (xPathParts.hasNext()) {
+ String xPathPartTrimmed = xPathParts.next().trim();
+
+ PathArgument pathArgument = toPathArgument(xPathPartTrimmed);
+ if (pathArgument != null) {
+ result.add(pathArgument);
+ }
+ }
+ return YangInstanceIdentifier.create(result);
+ }
+
+ private PathArgument toPathArgument(final String xPathArgument) {
+ final QName mainQName = parseQName(xPathArgument);
+
+ // predicates
+ final Matcher matcher = PREDICATE_PATTERN.matcher(xPathArgument);
+ final Map<QName, Object> predicates = new HashMap<>();
+ QName currentQName = mainQName;
+
+ while (matcher.find()) {
+ final String predicateStr = matcher.group(1).trim();
+ final int indexOfEqualityMark = predicateStr.indexOf('=');
+ if (indexOfEqualityMark != -1) {
+ final String predicateValue = toPredicateValue(predicateStr.substring(indexOfEqualityMark + 1));
+ if (predicateValue == null) {
+ return null;
+ }
+
+ if (predicateStr.charAt(0) != '.') {
+ // target is not a leaf-list
+ currentQName = parseQName(predicateStr.substring(0, indexOfEqualityMark));
+ if (currentQName == null) {
+ return null;
+ }
+ }
+ predicates.put(currentQName, predicateValue);
+ }
+ }
+
+ if (predicates.isEmpty()) {
+ return new YangInstanceIdentifier.NodeIdentifier(mainQName);
+ } else {
+ return new YangInstanceIdentifier.NodeIdentifierWithPredicates(mainQName, predicates);
+ }
+ }
+
+ private static String toPredicateValue(final String predicatedValue) {
+ final String predicatedValueTrimmed = predicatedValue.trim();
+ if (predicatedValue.isEmpty()) {
+ return null;
+ }
+
+ switch (predicatedValueTrimmed.charAt(0)) {
+ case '"':
+ return trimIfEndIs(predicatedValueTrimmed, '"');
+ case '\'':
+ return trimIfEndIs(predicatedValueTrimmed, '\'');
+ default:
+ return null;
+ }
+ }
+
+ private static String trimIfEndIs(final String str, final char end) {
+ final int l = str.length() - 1;
+ if (str.charAt(l) != end) {
+ return null;
+ }
+
+ return str.substring(1, l);
+ }
+}
private final MavenProject project;
private final boolean inspectDependencies;
private final BuildContext buildContext;
- private YangProvider yangProvider;
+ private final YangProvider yangProvider;
@VisibleForTesting
YangToSourcesProcessor(Log log, File yangFilesRootDir, File[] excludedFiles, List<CodeGeneratorArg> codeGenerators,
static class YangProvider {
-
-
void addYangsToMetaInf(Log log, MavenProject project, File yangFilesRootDir, File[] excludedFiles)
throws MojoFailureException {
// copy project's src/main/yang/*.yang to target/generated-sources/yang/META-INF/yang/*.yang
+
File generatedYangDir = new File(project.getBasedir(), CodeGeneratorArg.YANG_GENERATED_DIR);
+ addYangsToMetaInf(log, project, yangFilesRootDir, excludedFiles, generatedYangDir);
+
+ // Also copy to the actual build output dir if different than "target". When running in
+ // Eclipse this can differ (eg "target-ide").
+
+ File actualGeneratedYangDir = new File(project.getBuild().getDirectory(),
+ CodeGeneratorArg.YANG_GENERATED_DIR.replace("target" + File.separator, ""));
+ if(!actualGeneratedYangDir.equals(generatedYangDir)) {
+ addYangsToMetaInf(log, project, yangFilesRootDir, excludedFiles, actualGeneratedYangDir);
+ }
+ }
+
+ private void addYangsToMetaInf(Log log, MavenProject project, File yangFilesRootDir,
+ File[] excludedFiles, File generatedYangDir)
+ throws MojoFailureException {
File withMetaInf = new File(generatedYangDir, META_INF_YANG_STRING);
withMetaInf.mkdirs();
org.apache.commons.io.FileUtils.copyFile(file, new File(withMetaInf, file.getName()));
}
} catch (IOException e) {
- String message = "Unable to list yang files into resource folder";
- log.warn(message, e);
- throw new MojoFailureException(message, e);
+ log.warn(String.format("Failed to generate files into root %s", yangFilesRootDir), e);
+ throw new MojoFailureException("Unable to list yang files into resource folder", e);
}
setResource(generatedYangDir, project);
* Cached legacy path, filled-in when {@link #getPath()} or {@link #getPathTowardsRoot()}
* is invoked.
*/
- private ImmutableList<QName> legacyPath;
+ private volatile ImmutableList<QName> legacyPath;
private ImmutableList<QName> getLegacyPath() {
- if (legacyPath == null) {
- legacyPath = ImmutableList.copyOf(getPathTowardsRoot()).reverse();
+ ImmutableList<QName> ret = legacyPath;
+ if (ret == null) {
+ synchronized (this) {
+ ret = legacyPath;
+ if (ret == null) {
+ ret = ImmutableList.copyOf(getPathTowardsRoot()).reverse();
+ legacyPath = ret;
+ }
+ }
}
- return legacyPath;
+ return ret;
}
/**
}
if (m.isEmpty()) {
- sources.remove(m);
+ sources.remove(source.getSourceIdentifier());
}
}
}
public static final int MAX_VALUE = 65535;
private static final String DESCRIPTION = "uint16 represents integer values between 0 and 65535, inclusively.";
- private static Uint16 INSTANCE = new Uint16();
+ private static final Uint16 INSTANCE = new Uint16();
private Uint16() {
super(BaseTypes.UINT16_QNAME, DESCRIPTION, MAX_VALUE, "");
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((types == null) ? 0 : types.hashCode());
+ result = prime * result + types.hashCode();
return result;
}
builder.append(BaseTypes.UNION_QNAME);
builder.append(" (types=[");
for (TypeDefinition<?> td : types) {
- builder.append(", " + td.getQName().getLocalName());
+ builder.append(", " ).append(td.getQName().getLocalName());
}
- builder.append("]");
+ builder.append(']');
return builder.toString();
}
ANYXML_KEYWORD | IDENTIFIER) string? (SEMICOLON | (LEFT_BRACE (unknown_statement | identifier_stmt)* RIGHT_BRACE)*);
stmtend : (SEMICOLON) | (LEFT_BRACE identifier_stmt? RIGHT_BRACE);
+
+/* DO NOT replace stmtsep in rest of grammar with identifier_stmt!!! It might seems as code duplicity here, but this one is necessary.
+ Body of identifier_stmt generated from this grammar in YangParserListener is implemented in YangParserListenerImpl.
+ To ensure that all of the identifier_stmts will be resolved correctly the YangParserListenerImpl contains code that handles
+ specifcly identifier_stmts -> i.e. transforms identifier_stmt into QName. The stmtsep is used for parsing extension statements
+ placed outside of body_stmt.
+ */
stmtsep : IDENTIFIER string? (stmtend | (LEFT_BRACE unknown_statement* RIGHT_BRACE));
deviate_replace_stmt : DEVIATE_KEYWORD string /* REPLACE_KEYWORD */ (SEMICOLON | (LEFT_BRACE (identifier_stmt |type_stmt | units_stmt | default_stmt | config_stmt | mandatory_stmt | min_elements_stmt | max_elements_stmt )* RIGHT_BRACE));
deviate_delete_stmt : DEVIATE_KEYWORD string /* DELETE_KEYWORD */ (SEMICOLON | (LEFT_BRACE (identifier_stmt |units_stmt | must_stmt | unique_stmt | default_stmt )* RIGHT_BRACE));
data_def_stmt : container_stmt | leaf_stmt | leaf_list_stmt | list_stmt | choice_stmt | anyxml_stmt | uses_stmt;
body_stmts : (( identifier_stmt| extension_stmt | feature_stmt | identity_stmt | typedef_stmt | grouping_stmt | data_def_stmt | augment_stmt | rpc_stmt | notification_stmt | deviation_stmt) )*;
revision_stmts : (revision_stmt )* (stmtsep)*;
-linkage_stmts : (import_stmt stmtsep? | include_stmt stmtsep?)*;
-meta_stmts : (organization_stmt stmtsep? | contact_stmt stmtsep? | description_stmt stmtsep? | reference_stmt stmtsep?)*;
-submodule_header_stmts : (yang_version_stmt stmtsep? | belongs_to_stmt stmtsep?)+ ;
-module_header_stmts : (yang_version_stmt stmtsep? | namespace_stmt stmtsep? | prefix_stmt stmtsep?)+ ;
+linkage_stmts : (import_stmt stmtsep* | include_stmt stmtsep*)*;
+meta_stmts : (organization_stmt stmtsep* | contact_stmt stmtsep* | description_stmt stmtsep* | reference_stmt stmtsep*)*;
+submodule_header_stmts : (yang_version_stmt stmtsep* | belongs_to_stmt stmtsep*)+ ;
+module_header_stmts : (yang_version_stmt stmtsep* | namespace_stmt stmtsep* | prefix_stmt stmtsep*)+ ;
submodule_stmt : SUBMODULE_KEYWORD string LEFT_BRACE submodule_header_stmts linkage_stmts meta_stmts revision_stmts body_stmts RIGHT_BRACE;
-module_stmt : MODULE_KEYWORD string LEFT_BRACE stmtsep? module_header_stmts linkage_stmts meta_stmts revision_stmts body_stmts RIGHT_BRACE;
\ No newline at end of file
+module_stmt : MODULE_KEYWORD string LEFT_BRACE stmtsep* module_header_stmts linkage_stmts meta_stmts revision_stmts body_stmts RIGHT_BRACE;
\ No newline at end of file
} else if (!mustConstraints.equals(other.mustConstraints)) {
return false;
}
- if (mandatory != other.mandatory) {
+ if (!mandatory.equals(other.mandatory)) {
return false;
}
if (minElements == null) {
* 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) {
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 final Function<Node, Module> TOPOLOGY_FUNCTION = new Function<TopologicalSort.Node, Module>() {
@Override
public Module apply(final TopologicalSort.Node input) {
+ if (input == null) {
+ return null;
+ }
ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference();
return moduleOrModuleBuilder.getModule();
}
@Override
public ModuleBuilder apply(final TopologicalSort.Node input) {
// Cast to ModuleBuilder from Node and return
+ if (input == null) {
+ return null;
+ }
ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference();
return moduleOrModuleBuilder.getModuleBuilder();
}
@Override
public ModuleBuilder apply(final TopologicalSort.Node input) {
+ if (input == null) {
+ return null;
+ }
ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference();
if (moduleOrModuleBuilder.isModuleBuilder()) {
return moduleOrModuleBuilder.getModuleBuilder();
module ext-use {
+ ext:id "http://opendaylight.org";
yang-version 1;
+ ext:id "http://opendaylight.org";
+
+ ext:id2 "73354";
+ ext:name "test-name";
+
namespace "urn:simple.extension.use";
+ ext:id "http://opendaylight.org";
+
+ ext:name "test-name";
+
prefix "ext-use";
+ ext:id "http://opendaylight.org";
+ ext:name "test-name";
import ext-typedef { prefix "ext"; }