Merge "Added tests for yang.model.util"
authorRobert Varga <rovarga@cisco.com>
Tue, 2 Sep 2014 12:34:20 +0000 (12:34 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 2 Sep 2014 12:34:20 +0000 (12:34 +0000)
133 files changed:
benchmarks/pom.xml [new file with mode: 0644]
benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/BenchmarkModel.java [new file with mode: 0644]
benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/InMemoryDataTreeBenchmark.java [new file with mode: 0644]
benchmarks/src/main/resources/odl-datastore-test.yang [new file with mode: 0644]
code-generator/binding-data-codec/pom.xml
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnionTypeCodec.java
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AbstractBindingRuntimeTest.java [new file with mode: 0644]
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java [new file with mode: 0644]
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CaseSubstitutionTest.java [new file with mode: 0644]
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierSerializeDeserializeTest.java [new file with mode: 0644]
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierTest.java [new file with mode: 0644]
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NormalizedNodeSerializeDeserializeTest.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTypeBuilderImpl.java
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/NestedGroupingCompilationTest.java [new file with mode: 0644]
code-generator/binding-java-api-generator/src/test/resources/compilation/nested-grouping/test.yang [new file with mode: 0644]
code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang [new file with mode: 0644]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java [new file with mode: 0644]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilder.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java
code-generator/binding-test-model/pom.xml [new file with mode: 0644]
code-generator/binding-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java [new file with mode: 0644]
code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-augment-test.yang [new file with mode: 0644]
code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang [new file with mode: 0644]
code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/TypeProviderImpl.java
code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend
code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java
code-generator/pom.xml
common/features/pom.xml
common/features/src/main/resources/features.xml
common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/ObjectCacheFactory.java
common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/AbstractObjectCache.java
common/parent/pom.xml
common/util/pom.xml
common/util/src/main/java/org/opendaylight/yangtools/util/DurationStatsTracker.java [new file with mode: 0644]
common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/CachedThreadPoolExecutor.java
common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/CountingRejectedExecutionHandler.java [new file with mode: 0644]
common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/FastThreadPoolExecutor.java
common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/ListenerNotificationQueueStats.java [new file with mode: 0644]
common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/QueuedNotificationManager.java
common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/SpecialExecutors.java
common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/TrackingLinkedBlockingQueue.java [new file with mode: 0644]
common/util/src/test/java/org/opendaylight/yangtools/util/DurationStatsTrackerTest.java [new file with mode: 0644]
common/util/src/test/java/org/opendaylight/yangtools/util/concurrent/CountingRejectedExecutionHandlerTest.java [new file with mode: 0644]
common/util/src/test/java/org/opendaylight/yangtools/util/concurrent/ThreadPoolExecutorTest.java
common/util/src/test/java/org/opendaylight/yangtools/util/concurrent/TrackingLinkedBlockingQueueTest.java [new file with mode: 0644]
pom.xml
restconf/restconf-client-impl/src/main/java/org/opendaylight/yangtools/restconf/client/RestListenableEventStreamContext.java
restconf/restconf-jaxrs-api/src/main/java/org/opendaylight/yangtools/RestRestconfService.java
restconf/restconf-util/src/main/java/org/opendaylight/yangtools/restconf/utils/XmlTools.java
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BindingMapping.java
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/NodeModificationBuilder.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/LoggingNormalizedNodeStreamWriter.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/NormalizedNodeWriter.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/ContainerNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/TreeNodeFactory.java
yang/yang-data-codec-gson/pom.xml
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CaseNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ChoiceNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CodecFactory.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CompositeNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ContainerNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringIdentityrefCodec.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListEntryNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListEntryNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/AbstractCodecImpl.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityValuesDTO.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityrefCodecImpl.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/InstanceIdentifierCodecImpl.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/LeafrefCodecImpl.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/ObjectCodec.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestCodecFactory.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestUtil.java [deleted file]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/SchemaContextUtils.java [deleted file]
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java
yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json
yang/yang-data-codec-gson/src/test/resources/complexjson/yang/complexjson.yang
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/TypeDefinitionAwareCodec.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XMLStreamNormalizedNodeStreamWriter.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNodes.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/valid/DataValidationException.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeFactory.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NormalizedNodeContainerModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OperationWithModification.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ValueNodeModificationStrategy.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationMetadataTreeTest.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/TreeNodeUtilsTest.java
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractModuleStringIdentityrefCodec.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractModuleStringInstanceIdentifierCodec.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractNamespaceCodec.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringIdentityrefCodec.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java [new file with mode: 0644]
yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/YangToSourcesProcessor.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaPath.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaRepository.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/Uint16.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/UnionType.java
yang/yang-parser-impl/src/main/antlr/YangParser.g4
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ConstraintsBuilderImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedDataNodeContainer.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ModuleDependencySort.java
yang/yang-parser-impl/src/test/resources/extensions/ext-use.yang

diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml
new file mode 100644 (file)
index 0000000..e80bfee
--- /dev/null
@@ -0,0 +1,59 @@
+<?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>
diff --git a/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/BenchmarkModel.java b/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/BenchmarkModel.java
new file mode 100644 (file)
index 0000000..e8cf728
--- /dev/null
@@ -0,0 +1,44 @@
+package org.opendaylight.yangtools.yang.data.impl.tree;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+/**
+ * @author Lukas Sedlak <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);
+    }
+}
diff --git a/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/InMemoryDataTreeBenchmark.java b/benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/InMemoryDataTreeBenchmark.java
new file mode 100644 (file)
index 0000000..306c14d
--- /dev/null
@@ -0,0 +1,194 @@
+/**
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.tree;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.*;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * Benchmarking of InMemoryDataTree performance.
+ *
+ * JMH is used for microbenchmarking.
+ *
+ * @author Lukas Sedlak <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);
+    }
+}
diff --git a/benchmarks/src/main/resources/odl-datastore-test.yang b/benchmarks/src/main/resources/odl-datastore-test.yang
new file mode 100644 (file)
index 0000000..730ca17
--- /dev/null
@@ -0,0 +1,42 @@
+module odl-datastore-test {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test";
+    prefix "store-test";
+    
+    revision "2014-03-13" {
+        description "Initial revision.";
+    }
+
+    container test {
+        list outer-list {
+            key id;
+            leaf id {
+                type int32;
+            }
+            choice outer-choice {
+                case one {
+                    leaf one {
+                        type string;
+                    }
+                }
+                case two-three {
+                    leaf two {
+                        type string;
+                    }
+                    leaf three {
+                        type string;
+                    }
+               }
+           }
+           list inner-list {
+                key name;
+                leaf name {
+                    type int32;
+                }
+                leaf value {
+                    type string;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
index 80cfe17b79577474ab8d120448007209aca5feef..b8bf7e11ef1f9bcb5e6dc008239c077166c63c83 100644 (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>
@@ -65,9 +66,9 @@
             <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>
 
index b75afa8b5d2b593521c8b4b0a77e021b5966a9c7..3e10492e10c75a4d573c5b06fe52797fee54f454 100644 (file)
@@ -10,6 +10,9 @@ package org.opendaylight.yangtools.binding.data.codec.api;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -18,7 +21,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 /**
  * Serialization service, which provides two-way serialization between
  * Java Binding Data representation and NormalizedNode representation.
- *
  */
 public interface BindingNormalizedNodeSerializer {
 
@@ -28,15 +30,16 @@ public interface BindingNormalizedNodeSerializer {
       * @param binding Binding Instance Identifier
       * @return DOM Instance Identifier
       */
-     YangInstanceIdentifier toYangInstanceIdentifier(InstanceIdentifier<?> binding);
+     YangInstanceIdentifier toYangInstanceIdentifier(@Nonnull InstanceIdentifier<?> binding);
 
      /**
       * Translates supplied YANG Instance Identifier into Binding instance identifier.
       *
       * @param dom YANG Instance Identifier
-      * @return Binding Instance Identifier
+      * @return Binding Instance Identifier, or null if the instance identifier is not
+      *         representable.
       */
-     InstanceIdentifier<?> fromYangInstanceIdentifier(YangInstanceIdentifier dom);
+     @Nullable InstanceIdentifier<?> fromYangInstanceIdentifier(@Nonnull YangInstanceIdentifier dom);
 
      /**
       * Translates supplied Binding Instance Identifier and data into NormalizedNode representation.
@@ -45,7 +48,7 @@ public interface BindingNormalizedNodeSerializer {
       * @param data Data object representing data
       * @return NormalizedNode representation
       */
-     <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.
@@ -54,7 +57,7 @@ public interface BindingNormalizedNodeSerializer {
       * @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.
index 46fd45960f3572affcd4993d08d8b87e6489f9e0..49a834710c47bf04bb6213205fc65e2b88cf968f 100644 (file)
@@ -18,6 +18,7 @@ import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -25,6 +26,9 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.Callable;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
 import org.opendaylight.yangtools.binding.data.codec.impl.NodeCodecContext.CodecContextFactory;
 import org.opendaylight.yangtools.concepts.Codec;
 import org.opendaylight.yangtools.concepts.Immutable;
@@ -52,10 +56,13 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 class BindingCodecContext implements CodecContextFactory, Immutable {
-
+    private static final Logger LOG = LoggerFactory.getLogger(BindingCodecContext.class);
     private static final String GETTER_PREFIX = "get";
+
     private final SchemaRootCodecContext root;
     private final BindingRuntimeContext context;
     private final Codec<YangInstanceIdentifier, InstanceIdentifier<?>> instanceIdentifierCodec =
@@ -72,7 +79,7 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
         return context;
     }
 
-    public Codec<YangInstanceIdentifier, InstanceIdentifier<?>> getInstanceIdentifierCodec() {
+    Codec<YangInstanceIdentifier, InstanceIdentifier<?>> getInstanceIdentifierCodec() {
         return instanceIdentifierCodec;
     }
 
@@ -102,14 +109,27 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
         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
@@ -119,19 +139,13 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
              * Identifier as Item or IdentifiableItem
              */
             if (currentList != null) {
+                Preconditions.checkArgument(currentList == nextNode, "List should be referenced two times in YANG Instance Identifier %s", dom);
 
-                if (currentList == nextNode) {
-
-                    // We entered list, so now we have all information to emit
-                    // list
-                    // path using second list argument.
-                    builder.add(currentList.getBindingPathArgument(domArg));
-                    currentList = null;
-                    currentNode = nextNode;
-                } else {
-                    throw new IllegalArgumentException(
-                            "List should be referenced two times in YANG Instance Identifier");
-                }
+                // We entered list, so now we have all information to emit
+                // list path using second list argument.
+                bindingArguments.add(currentList.getBindingPathArgument(domArg));
+                currentList = null;
+                currentNode = nextNode;
             } else if (nextNode instanceof ListNodeCodecContext) {
                 // We enter list, we do not update current Node yet,
                 // since we need to verify
@@ -141,24 +155,27 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
                 // it is not supported by binding instance identifier.
                 currentNode = nextNode;
             } else if (nextNode instanceof DataContainerCodecContext<?>) {
-                builder.add(((DataContainerCodecContext<?>) nextNode).getBindingPathArgument(domArg));
+                bindingArguments.add(((DataContainerCodecContext<?>) nextNode).getBindingPathArgument(domArg));
                 currentNode = nextNode;
             } else if (nextNode instanceof LeafNodeCodecContext) {
-                Preconditions.checkArgument(builder == null, "Instance Identifier for leaf is not representable.");
-
+                LOG.debug("Instance identifier referencing a leaf is not representable (%s)", dom);
+                return null;
             }
         }
+
         // Algorithm ended in list as whole representation
         // we sill need to emit identifier for list
-
-        if (builder != null) {
-            Preconditions.checkArgument(!(currentNode instanceof ChoiceNodeCodecContext),
-                    "Instance Identifier for choice is not representable.");
-            Preconditions.checkArgument(!(currentNode instanceof CaseNodeCodecContext),
-                    "Instance Identifier for case is not representable.");
+        if (currentNode instanceof ChoiceNodeCodecContext) {
+            LOG.debug("Instance identifier targeting a choice is not representable (%s)", dom);
+            return null;
+        }
+        if (currentNode instanceof CaseNodeCodecContext) {
+            LOG.debug("Instance identifier targeting a case is not representable (%s)", dom);
+            return null;
         }
+
         if (currentList != null) {
-            builder.add(currentList.getBindingPathArgument(null));
+            bindingArguments.add(currentList.getBindingPathArgument(null));
             return currentList;
         }
         return currentNode;
@@ -264,12 +281,11 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
         } else if (rootType instanceof InstanceIdentifierTypeDefinition) {
             return ValueTypeCodec.encapsulatedValueCodecFor(valueType, instanceIdentifierCodec);
         } else if (rootType instanceof UnionTypeDefinition) {
-            Callable<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);
@@ -279,16 +295,16 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
 
         @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);
         }
     }
 
@@ -341,7 +357,7 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
 
     }
 
-    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;
index 9b772bd9dc0f344503d2e3a53c3d98bffef117a6..bfdad3efeb4cb555a22946a035ae460a8592698a 100644 (file)
@@ -16,7 +16,7 @@ import com.google.common.cache.LoadingCache;
 
 import java.io.IOException;
 import java.util.AbstractMap.SimpleEntry;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -34,7 +34,9 @@ import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -74,23 +76,21 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
 
     @Override
     public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
-        List<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
@@ -103,26 +103,51 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         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");
     }
 
@@ -144,8 +169,8 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
 
 
     private static class DeserializeFunction<T> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
-
         private final DataObjectCodecContext<?> ctx;
+
         public DeserializeFunction(final DataObjectCodecContext<?> ctx) {
             super();
             this.ctx = ctx;
@@ -159,8 +184,6 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
             }
             return Optional.absent();
         }
-
-
     }
 
     private class GeneratorLoader extends CacheLoader<Class<? extends DataObject>, DataObjectSerializer> {
index 700476f86bae3d79c3ed8c8d4d6e4315a7bac807..bac768703c24cab5f00e1b13014143f9b5fcf218 100644 (file)
@@ -11,8 +11,13 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
+
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -36,20 +41,50 @@ final class ChoiceNodeCodecContext extends DataContainerCodecContext<ChoiceNode>
         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);
index 32fdf6d80ea597da1c4ec000bcecb880c9564564..5725e186ba0be23d12bf88251e4fc6e79e5daa8d 100644 (file)
@@ -10,12 +10,16 @@ package org.opendaylight.yangtools.binding.data.codec.impl;
 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;
@@ -41,9 +45,17 @@ import org.slf4j.LoggerFactory;
 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;
@@ -56,7 +68,7 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
         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<>();
 
@@ -78,7 +90,7 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
                 }
             }
         }
-        this.byMethod = ImmutableMap.copyOf(byMethodBuilder);
+        this.byMethod = ImmutableSortedMap.copyOfSorted(byMethodBuilder);
         if (Augmentable.class.isAssignableFrom(bindingClass())) {
             try {
                 augmentationGetter = bindingClass().getMethod("getAugmentation", Class.class);
@@ -107,6 +119,29 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
     @Override
     protected DataContainerCodecContext<?> getStreamChild(final Class<?> childClass) {
         DataContainerCodecPrototype<?> childProto = byStreamClass.get(childClass);
+        if (childProto != null) {
+            return childProto.get();
+        }
+
+        if (Augmentation.class.isAssignableFrom(childClass))  {
+            /*
+             * It is potentially mismatched valid augmentation - we look up equivalent augmentation
+             * using reflection and walk all stream child and compare augmenations classes
+             * if they are equivalent.
+             *
+             * FIXME: Cache mapping of mismatched augmentation to real one, to speed up lookup.
+             */
+            Class<?> augTarget = BindingReflections.findAugmentationTarget((Class) childClass);
+            if ((bindingClass().equals(augTarget))) {
+                for (DataContainerCodecPrototype<?> realChild : byStreamClass.values()) {
+                    if (Augmentation.class.isAssignableFrom(realChild.getBindingClass())
+                            && BindingReflections.isSubstitutionFor(childClass,realChild.getBindingClass())) {
+                        childProto = realChild;
+                        break;
+                    }
+                }
+            }
+        }
         Preconditions.checkArgument(childProto != null, " Child %s is not valid child.",childClass);
         return childProto.get();
     }
@@ -243,4 +278,4 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
         return byMethod.keySet();
     }
 
-}
\ No newline at end of file
+}
index 6cbcc5c15680f9ef6a9247030aafa14ece6197f1..f94673c28897baa1eb67d79b12ae18efdb14a017 100644 (file)
@@ -8,13 +8,14 @@
 package org.opendaylight.yangtools.binding.data.codec.impl;
 
 import com.google.common.collect.ImmutableSet;
+
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.Callable;
-import org.opendaylight.yangtools.concepts.Codec;
+
 import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
@@ -34,12 +35,10 @@ final class UnionTypeCodec extends ReflectionBasedCodec {
         }
     }
 
-    @SuppressWarnings("rawtypes")
-    static final Callable<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());
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AbstractBindingRuntimeTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AbstractBindingRuntimeTest.java
new file mode 100644 (file)
index 0000000..a56364c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import org.junit.Before;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public abstract class AbstractBindingRuntimeTest {
+
+    private SchemaContext schemaContext;
+    private BindingRuntimeContext runtimeContext;
+
+    @Before
+    public void setup() {
+        ModuleInfoBackedContext ctx = ModuleInfoBackedContext.create();
+        ctx.addModuleInfos(BindingReflections.loadModuleInfos());
+        schemaContext = ctx.tryToCreateSchemaContext().get();
+        runtimeContext = BindingRuntimeContext.create(ctx, schemaContext);
+
+    }
+
+    public SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
+    public BindingRuntimeContext getRuntimeContext() {
+        return runtimeContext;
+    }
+}
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java
new file mode 100644 (file)
index 0000000..62d913f
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import javassist.ClassPool;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+
+
+public class AugmentationSubstitutionTest extends AbstractBindingRuntimeTest {
+
+    private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<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();
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CaseSubstitutionTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CaseSubstitutionTest.java
new file mode 100644 (file)
index 0000000..a01e12d
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import javassist.ClassPool;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.put.top.input.top.level.list.choice.in.list.ComplexViaUsesWithDifferentNameBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.top.top.level.list.choice.in.list.ComplexViaUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+
+
+public class CaseSubstitutionTest extends AbstractBindingRuntimeTest {
+
+    private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<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();
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierSerializeDeserializeTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierSerializeDeserializeTest.java
new file mode 100644 (file)
index 0000000..67b7d1f
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ *  and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import com.google.common.collect.Iterables;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class InstanceIdentifierSerializeDeserializeTest extends AbstractBindingRuntimeTest{
+    public static final String TOP_LEVEL_LIST_KEY_VALUE = "foo";
+
+    private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<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));
+    }
+}
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/InstanceIdentifierTest.java
new file mode 100644 (file)
index 0000000..e011017
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import javassist.ClassPool;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+
+public class InstanceIdentifierTest extends AbstractBindingRuntimeTest {
+
+    private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<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));
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NormalizedNodeSerializeDeserializeTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NormalizedNodeSerializeDeserializeTest.java
new file mode 100644 (file)
index 0000000..4b08fbe
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ *  and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.ChoiceContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.ChoiceContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.choice.identifier.ExtendedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.choice.identifier.extended.ExtendedIdBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.top;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.topLevelList;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+
+public class NormalizedNodeSerializeDeserializeTest extends AbstractBindingRuntimeTest{
+
+    public static final String TOP_LEVEL_LIST_FOO_KEY_VALUE = "foo";
+    public static final TopLevelListKey TOP_LEVEL_LIST_FOO_KEY = new TopLevelListKey(TOP_LEVEL_LIST_FOO_KEY_VALUE);
+
+    public static final QName TOP_QNAME =
+            QName.create("urn:opendaylight:params:xml:ns:yang:yangtools:test:binding", "2014-07-01", "top");
+    public static final QName TOP_LEVEL_LIST_QNAME = QName.create(TOP_QNAME, "top-level-list");
+    public static final QName TOP_LEVEL_LIST_KEY_QNAME = QName.create(TOP_QNAME, "name");
+    public static final QName TOP_LEVEL_LEAF_LIST_QNAME = QName.create(TOP_QNAME, "top-level-leaf-list");
+    public static final QName NESTED_LIST_QNAME = QName.create(TOP_QNAME, "nested-list");
+    public static final QName NESTED_LIST_KEY_QNAME = QName.create(TOP_QNAME, "name");
+    public static final QName CHOICE_CONTAINER_QNAME =
+            QName.create("urn:opendaylight:params:xml:ns:yang:yangtools:test:binding", "2014-07-01", "choice-container");
+    public static final QName CHOICE_IDENTIFIER_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "identifier");
+    public static final QName CHOICE_IDENTIFIER_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "id");
+    public static final QName SIMPLE_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "simple-id");
+    public static final QName EXTENDED_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "extended-id");
+    private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value");
+
+    private static final InstanceIdentifier<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());
+    }
+}
index befe3e88e02c494e48b287d8089cf2f05eb8fd08..b98c48c9844f0b5067aeae72cd1894b9efd43b9c 100644 (file)
@@ -30,7 +30,6 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findP
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -39,7 +38,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.BindingTypes;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
@@ -310,7 +308,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             return null;
         }
         final String packageName = packageNameForGeneratedType(basePackageName, node.getPath());
-        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf);
+        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module);
         genType.addComment(node.getDescription());
         genType.setDescription(createDescription(node, genType.getFullyQualifiedName()));
         genType.setModuleName(module.getName());
@@ -320,23 +318,61 @@ public class BindingGeneratorImpl implements BindingGenerator {
             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);
@@ -556,7 +592,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 processUsesAugments(notification, module);
 
                 final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(basePackageName,
-                        notification, BindingTypes.DATA_OBJECT);
+                        notification, BindingTypes.DATA_OBJECT, module);
                 notificationInterface.addImplementsType(NOTIFICATION);
                 genCtx.get(module).addChildNodeType(notification, notificationInterface);
 
@@ -704,7 +740,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      */
     private void groupingToGenType(final String basePackageName, final GroupingDefinition grouping, final Module module) {
         final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath());
-        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping);
+        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping, module);
         genCtx.get(module).addGroupingType(grouping.getPath(), genType);
         resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes());
         groupingsToGenTypes(module, grouping.getGroupings());
@@ -858,6 +894,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         if (targetTypeBuilder == null) {
             throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
         }
+        targetTypeBuilder.setSuitableForBoxing(false);
 
         if (!(targetSchemaNode instanceof ChoiceNode)) {
             String packageName = augmentPackageName;
@@ -1158,6 +1195,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             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);
         }
@@ -1204,7 +1242,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         for (ChoiceCaseNode caseNode : caseNodes) {
             if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
-                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
+                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module);
                 caseTypeBuilder.addImplementsType(refChoiceType);
                 genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
                 genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
@@ -1283,7 +1321,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         for (DataSchemaNode caseNode : augmentedNodes) {
             if (caseNode != null) {
                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
-                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
+                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module);
                 caseTypeBuilder.addImplementsType(targetType);
 
                 SchemaNode parent = null;
@@ -1600,8 +1638,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return returnType.toInstance();
     }
 
-    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
-        return addDefaultInterfaceDefinition(packageName, schemaNode, null);
+    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+            final Module module) {
+        return addDefaultInterfaceDefinition(packageName, schemaNode, null, module);
     }
 
     /**
@@ -1628,7 +1667,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @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);
@@ -1640,6 +1679,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
 
         if (schemaNode instanceof DataNodeContainer) {
+            groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
             addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it);
         }
 
@@ -1918,11 +1958,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
             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");
index 7c8586ed8f5af71ceab4b88bda76f082c0f4fd94..e532be5b9e83689280fbb2469de874174647b45b 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.yangtools.sal.binding.generator.impl;
 
 import com.google.common.collect.ImmutableList;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -19,7 +18,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
-
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -29,10 +27,10 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
@@ -60,9 +58,9 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     public InstanceIdentifier<? 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());
index 92047d1f22c6547d284c8a29453eb5274a9408ab..f72856e1c11b540c2c6d855ef26b0ab7455a209e 100644 (file)
@@ -15,7 +15,6 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
-
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -30,7 +29,6 @@ import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.binding.generator.util.Types;
 import org.opendaylight.yangtools.concepts.Delegator;
@@ -268,7 +266,7 @@ class LazyGeneratedCodecRegistry implements CodecRegistry, SchemaContextListener
         while (iterator.hasNext()) {
             QName arg = iterator.next();
             DataSchemaNode currentNode = previous.getDataChildByName(arg);
-            if (currentNode == null && previous instanceof DataNodeContainer) {
+            if (currentNode == null) {
                 currentNode = searchInChoices(previous, arg);
             }
             if (currentNode instanceof DataNodeContainer) {
@@ -852,7 +850,7 @@ class LazyGeneratedCodecRegistry implements CodecRegistry, SchemaContextListener
             if (!parentQName.equals(choiceName)) {
                 // This item is instantiation of choice via uses in other YANG
                 // module
-                if (choiceName.getNamespace().equals(schema.getQName())) {
+                if (choiceName.getNamespace().equals(schema.getQName().getNamespace())) {
                     // Original definition of grouping is in same namespace
                     // as original definition of case
                     // so for sure case is introduced via instantiation of
index cb7f50549e537e6a24f11e5407f35082b8f970ae..ae80a51da4b19351b95b5de666504cb80549f881 100644 (file)
@@ -342,6 +342,11 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
             return values;
         }
 
+        @Override
+        public boolean isSuitableForBoxing() {
+            return false;
+        }
+
         @Override
         public List<AnnotationType> getAnnotations() {
             return annotations;
@@ -518,5 +523,6 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
         public String getModuleName() {
             return moduleName;
         }
+
     }
 }
index 270b04ac81161374d337fe03f012d96691939920..8d1bcea0e80be00fd1ccc4bc9923747474b6f076 100644 (file)
@@ -337,5 +337,10 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
         public String getModuleName() {
             return moduleName;
         }
+
+        @Override
+        public boolean isSuitableForBoxing() {
+            return false;
+        }
     }
 }
index 92c5629eab8861674bb2532957d4ab0bb9239256..5b14461dbbd8d029d5af60a323b3c84a2a6d5beb 100644 (file)
@@ -8,6 +8,7 @@
 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;
 
@@ -18,6 +19,8 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
     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);
@@ -49,6 +52,21 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         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();
@@ -86,6 +104,8 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         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);
@@ -94,6 +114,8 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
             this.reference = builder.reference;
             this.moduleName = builder.moduleName;
             this.schemaPath = builder.schemaPath;
+            this.isSuitableForBoxing = builder.isSuitableForBoxing;
+            this.parentType = builder.parentType;
         }
 
         @Override
@@ -115,5 +137,11 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         public String getModuleName() {
             return moduleName;
         }
+
+        @Override
+        public boolean isSuitableForBoxing() {
+            return isSuitableForBoxing;
+        }
     }
+
 }
index 286b5f06b17017a6c01fe9ad678db612a65af16b..66b72cf9e62647a475bc359744bff63b7386f67a 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
 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
 
@@ -213,7 +214,7 @@ class BuilderTemplate extends BaseTemplate {
 
             Â«generateFields(false)»
 
-            Â«generateAugmentField(true)»
+            Â«generateAugmentField(false)»
 
             Â«generateConstructorsFromIfcs(type)»
 
@@ -225,9 +226,9 @@ class BuilderTemplate extends BaseTemplate {
 
             Â«generateSetters»
 
-            public Â«type.name» build() {
-                return new Â«type.name»«IMPL»(this);
-            }
+            Â«generateBuildMethod»
+
+            Â«generateBuildBoxedMethod»
 
             private static final class Â«type.name»«IMPL» implements Â«type.name» {
 
@@ -235,7 +236,7 @@ class BuilderTemplate extends BaseTemplate {
 
                 Â«generateFields(true)»
 
-                Â«generateAugmentField(false)»
+                Â«generateAugmentField(true)»
 
                 Â«generateCopyConstructor(true)»
 
@@ -251,6 +252,53 @@ class BuilderTemplate extends BaseTemplate {
         }
     '''
 
+    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.
      */
@@ -421,9 +469,9 @@ class BuilderTemplate extends BaseTemplate {
         Â«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»
     '''
 
diff --git a/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/NestedGroupingCompilationTest.java b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/NestedGroupingCompilationTest.java
new file mode 100644 (file)
index 0000000..62190fc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.sal.java.api.generator.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.BASE_PKG;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.COMPILER_OUTPUT_PATH;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.FS;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.GENERATOR_OUTPUT_PATH;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.NS_TEST;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertFilesCount;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.assertImplementsIfc;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.cleanUp;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.getSourceFiles;
+import static org.opendaylight.yangtools.sal.java.api.generator.test.CompilationTestUtils.testCompilation;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashSet;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.java.api.generator.GeneratorJavaFile;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Test correct code generation.
+ *
+ */
+public class NestedGroupingCompilationTest extends BaseCompilationTest {
+
+    @Test
+    public void testListGeneration() throws Exception {
+        final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "nested-grouping");
+        assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
+        final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "nested-grouping");
+        assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
+
+        generateTestSources("/compilation/nested-grouping", sourcesOutputDir);
+
+        // Test if all sources are generated
+        File parent = new File(sourcesOutputDir, NS_TEST);
+        File foo = new File(parent, "Foo.java");
+        File fooBuilder = new File(parent, "FooBuilder.java");
+        File testData = new File(parent, "TestData.java");
+        File fooDir = new File(parent, "foo");
+        assertTrue(foo.exists());
+        assertTrue(fooBuilder.exists());
+        assertTrue(testData.exists());
+        assertTrue(fooDir.exists());
+        assertFilesCount(parent, 4);
+
+        parent = new File(parent, "foo");
+        File bar = new File(parent, "Bar.java");
+        assertTrue(bar.exists());
+        assertFilesCount(parent, 1);
+
+        // Test if sources are compilable
+        testCompilation(sourcesOutputDir, compiledOutputDir);
+
+        ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
+        Class<?> fooClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.Foo", true, loader);
+        Class<?> barClass = Class.forName(BASE_PKG + ".urn.opendaylight.test.rev131008.foo.Bar", true, loader);
+
+        // Test generated 'foo'
+        assertTrue(fooClass.isInterface());
+        assertImplementsIfc(fooClass, barClass);
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
+    private void generateTestSources(String resourceDirPath, File sourcesOutputDir) throws Exception {
+        final List<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);
+    }
+
+}
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/nested-grouping/test.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/nested-grouping/test.yang
new file mode 100644 (file)
index 0000000..94cf5e1
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+module test {
+    yang-version 1;
+    namespace "urn:opendaylight:test";
+    prefix "t";
+
+    revision "2013-10-08" {
+    }
+
+    container foo {
+        grouping bar {
+            leaf id {
+                type int32;
+            }
+        }
+        uses bar;
+    }
+
+}
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang
new file mode 100644 (file)
index 0000000..1334298
--- /dev/null
@@ -0,0 +1,21 @@
+
+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;
+                                       }
+                               }
+                       }
+           }
+       }
+}
diff --git a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java
new file mode 100644 (file)
index 0000000..258c53d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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();
+}
index 0e9b51ee741f42bb5952961421d046c7c52efa2a..ef2fdcdd7e6d4e942526937a670a28c5828dccf3 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  * 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,
index 9756bd209250b207e0689bc841fd1ce5bc185903..ea2ab258e06f12a06e7c2bf8f9ea71bf021f7f39 100644 (file)
@@ -12,16 +12,29 @@ import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
 /**
  * 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);
 }
index 628029f02869760998d3f33618832b2f70a428c2..70d0856fb70420784dfd897385a0cf72a9ecae37 100644 (file)
@@ -8,7 +8,6 @@
 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;
@@ -30,7 +29,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            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
@@ -49,7 +48,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      * @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>
@@ -59,7 +58,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      * @param comment
      *            Comment String.
      */
-    T addComment(final String comment);
+    T addComment(String comment);
 
     /**
      * The method creates new AnnotationTypeBuilder containing specified package
@@ -74,7 +73,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            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();
 
@@ -96,7 +95,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            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>
@@ -113,7 +112,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            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
@@ -128,7 +127,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            Enumeration Name
      * @return <code>new</code> instance of Enumeration Builder.
      */
-    EnumBuilder addEnumeration(final String name);
+    EnumBuilder addEnumeration(String name);
 
     List<MethodSignatureBuilder> getMethodDefinitions();
 
@@ -146,7 +145,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            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
@@ -155,7 +154,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      * @param methodName
      *            is method name
      */
-    boolean containsMethod(final String methodName);
+    boolean containsMethod(String methodName);
 
     List<GeneratedPropertyBuilder> getProperties();
 
@@ -169,7 +168,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            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
@@ -179,7 +178,7 @@ public interface GeneratedTypeBuilderBase<T extends GeneratedTypeBuilderBase<T>>
      *            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
diff --git a/code-generator/binding-test-model/pom.xml b/code-generator/binding-test-model/pom.xml
new file mode 100644 (file)
index 0000000..106c904
--- /dev/null
@@ -0,0 +1,67 @@
+<?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>
diff --git a/code-generator/binding-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java b/code-generator/binding-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java
new file mode 100644 (file)
index 0000000..0d3e7e8
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.test.model.util;
+
+import com.google.common.collect.ImmutableList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeLeafOnlyUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.complex.from.grouping.ListViaUsesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.top.level.list.NestedListKey;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Arrays;
+
+public class ListsBindingUtils {
+
+    private static final InstanceIdentifier<Top> 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();
+    }
+
+}
diff --git a/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-augment-test.yang b/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-augment-test.yang
new file mode 100644 (file)
index 0000000..6d155be
--- /dev/null
@@ -0,0 +1,111 @@
+module opendaylight-yangtools-augment-test {
+
+    namespace "urn:opendaylight:params:xml:ns:yang:yangtools:test:augment";
+    prefix aug-test;
+
+    import opendaylight-yangtools-binding-test {
+        prefix test;
+    }
+    import yang-ext {
+        prefix ext;
+    }
+
+    description
+        "This module contains a collection of YANG augmentations used for
+        some test cases.";
+
+    revision 2014-07-09 {
+        description
+        "Test model for testing data broker with nested lists.";
+    }
+
+    grouping leaf-from-grouping {
+        leaf leaf-from-grouping {
+            type string;
+        }
+    }
+
+    grouping complex-from-grouping {
+        container container-with-uses {
+            uses leaf-from-grouping;
+        }
+        list list-via-uses {
+            key "name";
+            leaf name {
+                type string;
+            }
+        }
+    
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-leaf-only-uses-augment;
+        uses leaf-from-grouping;
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-leaf-only-uses-augment;
+        uses leaf-from-grouping;
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-complex-uses-augment;
+        uses complex-from-grouping;
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-complex-uses-augment;
+        uses complex-from-grouping;
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-leaf-only-augment;
+
+        leaf simple-value {
+            type string;
+        }
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-second-leaf-only-augment;
+
+        leaf second-simple-value {
+            type string;
+        }
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-leaf-only-augment;
+
+        leaf simple-value {
+            type string;
+        }
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-second-leaf-only-augment;
+
+        leaf second-simple-value {
+            type string;
+        }
+    }
+
+    augment "/test:top/test:top-level-list/test:choice-in-list" {
+        case simple-via-uses {
+            uses leaf-from-grouping;
+        }
+        case complex-via-uses {
+            uses complex-from-grouping;
+        }
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list/test:choice-in-list" {
+        case simple-via-uses {
+            uses leaf-from-grouping;
+        }
+        case complex-via-uses-with-different-name {
+            uses complex-from-grouping;
+        }
+    }
+
+}
diff --git a/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang b/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang
new file mode 100644 (file)
index 0000000..c5e5ce2
--- /dev/null
@@ -0,0 +1,86 @@
+module opendaylight-yangtools-binding-test {
+
+    namespace "urn:opendaylight:params:xml:ns:yang:yangtools:test:binding";
+    prefix list-test;
+
+
+    description
+        "This module contains a collection of YANG definitions used for
+        some test cases.";
+
+    revision 2014-07-01 {
+        description
+        "Test model for testing data broker with nested lists.";
+    }
+
+    grouping two-level-list {
+        list top-level-list {
+            description
+                "Top Level List";
+            key "name";
+            leaf name {
+                type string;
+            }
+
+            choice choice-in-list {
+                case simple-case {
+                    leaf simple {
+                        type string;
+                    }
+                }
+            }
+
+            list nested-list {
+                key "name";
+                leaf name {
+                    type string;
+                }
+                leaf type {
+                    type string;
+                    mandatory true;
+                    description
+                        "Mandatory type of list.";
+                }
+                ordered-by user;
+                description
+                    "A list of service functions that compose the service chain";
+            }
+        }
+        leaf-list top-level-leaf-list {
+            type string;
+        }
+    }
+
+    grouping choice {
+        choice identifier {
+            case simple {
+                container simple-id {
+                    leaf id {
+                        type int32;
+                    }
+                }
+            }
+            case extended {
+                container extended-id {
+                    leaf id {
+                        type string;
+                    }
+                }
+            }
+        }
+    }
+
+    container top {
+        uses two-level-list;
+    }
+
+    container choice-container {
+        uses choice;
+    }
+
+    rpc put-top {
+        input {
+            uses two-level-list;
+        }
+    }
+}
index f1864ab1b7e5af44810b1dd9a07d5d1e81e52d6a..d48046a48b23bc76cb174d92fe70b0e9d68f686d 100644 (file)
@@ -1299,9 +1299,10 @@ public final class TypeProviderImpl implements TypeProvider {
             }
             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;
index d8c49592965f0cb1f62654aed4bff87894c0269e..f40cbcaa3dff249ad6cc8443028d380853fa8485 100644 (file)
@@ -975,9 +975,9 @@ class GeneratorImpl {
             </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»
@@ -1045,8 +1045,8 @@ class GeneratorImpl {
 
 
     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»>
     '''
 
@@ -1152,7 +1152,7 @@ class GeneratorImpl {
     }
 
     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>
     '''
 
 
@@ -1181,7 +1181,7 @@ class GeneratorImpl {
         append(currentModule.name)
         append(":")
         var previous = false;
-        for(arg : identifier.path) {
+        for(arg : identifier.pathArguments) {
             if(previous) append("/")
             append(arg.nodeType.localName);
             previous = true;
index 1208f190f376519a18f54fd406c469c9b94f3671..1a1052baa14838f604e6d1d6a068d785911ea126 100644 (file)
@@ -82,13 +82,9 @@ public class YangModuleInfoCompilationTest {
         testCompilation(sourcesOutputDir, compiledOutputDir);
 
         // Create URLClassLoader
-        File[] roots = File.listRoots();
-        URL[] urls = new URL[roots.length + 1];
-        for (int i = 0; i < roots.length; i++) {
-            urls[i] = roots[i].toURI().toURL();
-
-        }
-        urls[roots.length] = compiledOutputDir.toURI().toURL();
+        URL[] urls = new URL[2];
+        urls[0] = compiledOutputDir.toURI().toURL();
+        urls[1] = new File(System.getProperty("user.dir")).toURI().toURL();
         ClassLoader loader = new URLClassLoader(urls);
 
         // Load class
@@ -176,13 +172,16 @@ public class YangModuleInfoCompilationTest {
     private static List<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() + ")");
index 4cdf7c23c78e0349ef6e162d16a98cf76dd548a1..fc239681b50fbf6de3dfabd9397fd4c634b01481 100644 (file)
@@ -30,6 +30,7 @@
         <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>
index a3de6e5b7832a94e6cc4e3ac11d797e515ed075d..46c91492d06b1553f59ec5af433aaeb9985da0c0 100644 (file)
  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>
index 58b3ab177983771a58cd2878e76ca9b56dc175d8..45f1a8de1bec4c3f71a5f4ff46a9e54b9af46b32 100644 (file)
@@ -23,6 +23,7 @@
         <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'>
index dd3e53bbd0225119116a4ed0180620d3a2a11352..a18f6edc17039b72c7ea0fab6943775a7b546179 100644 (file)
@@ -7,30 +7,32 @@
  */
 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();
         }
@@ -39,7 +41,7 @@ public final class ObjectCacheFactory {
     }
 
     public static synchronized void reset() {
-        FACTORY = null;
+        factory = null;
     }
 
     /**
@@ -50,7 +52,7 @@ public final class ObjectCacheFactory {
      * @return Object cache instance.
      */
     public static ObjectCache getObjectCache(@Nonnull final Class<?> objClass) {
-        IObjectCacheFactory f = FACTORY;
+        IObjectCacheFactory f = factory;
         if (f == null) {
             f = initialize();
         }
index aeef1ee5cfbbcb28e9f27948bf960587fbb67649..3e09e967ca8fdd86765cb4f9343bc3e1fae1ad8d 100644 (file)
@@ -7,20 +7,18 @@
  */
 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
@@ -53,7 +51,7 @@ public abstract class AbstractObjectCache implements ObjectCache {
              * 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();
             }
 
index 76a2e108758cf89682fafd6efd46cbcd4975a98e..15e887eb44655c77b23cda83d934afe5e5c1bc10 100644 (file)
@@ -35,6 +35,7 @@
         <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>
index 5d185efe517345ac63c832837e7f3db06dd3e7c4..f3502891baa6b585d5460ef3f2300ed2d65d88f8 100644 (file)
                 <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>
diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/DurationStatsTracker.java b/common/util/src/main/java/org/opendaylight/yangtools/util/DurationStatsTracker.java
new file mode 100644 (file)
index 0000000..45ebd01
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * 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 "";
+        }
+    }
+}
index 4936efaba132fa150d60fa3c316975f6d81b6746..a7dd4af009e06457925d305483c1bcb048455c62 100644 (file)
@@ -14,8 +14,6 @@ import java.util.concurrent.RejectedExecutionHandler;
 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;
@@ -33,8 +31,6 @@ public class CachedThreadPoolExecutor extends ThreadPoolExecutor {
 
     private static final long IDLE_TIMEOUT_IN_SEC = 60L;
 
-    private final AtomicLong largestBackingQueueSize = new AtomicLong( 0 );
-
     private final ExecutorQueue executorQueue;
 
     private final String threadPrefix;
@@ -76,22 +72,28 @@ public class CachedThreadPoolExecutor extends ThreadPoolExecutor {
         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 ) {
@@ -129,7 +131,7 @@ public class CachedThreadPoolExecutor extends ThreadPoolExecutor {
         private final LinkedBlockingQueue<Runnable> backingQueue;
 
         ExecutorQueue( int maxBackingQueueSize ) {
-            backingQueue = new LinkedBlockingQueue<>( maxBackingQueueSize );
+            backingQueue = new TrackingLinkedBlockingQueue<>( maxBackingQueueSize );
         }
 
         LinkedBlockingQueue<Runnable> getBackingQueue() {
@@ -189,20 +191,23 @@ public class CachedThreadPoolExecutor extends ThreadPoolExecutor {
     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() ) {
@@ -210,19 +215,7 @@ public class CachedThreadPoolExecutor extends ThreadPoolExecutor {
             }
 
             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 );
             }
         }
     }
diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/CountingRejectedExecutionHandler.java b/common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/CountingRejectedExecutionHandler.java
new file mode 100644 (file)
index 0000000..ab010c9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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() );
+    }
+}
index b7549eb24e7fc602293bce054ba5ed069ecc6c1f..bf92ca5d9b47037a2366429ec8007b9fd176a2d0 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.yangtools.util.concurrent;
 
-import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
@@ -70,7 +69,7 @@ public class FastThreadPoolExecutor extends ThreadPoolExecutor {
         // 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;
@@ -82,6 +81,12 @@ public class FastThreadPoolExecutor extends ThreadPoolExecutor {
             // 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 ) {
@@ -96,6 +101,7 @@ public class FastThreadPoolExecutor extends ThreadPoolExecutor {
                 .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() )
diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/ListenerNotificationQueueStats.java b/common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/ListenerNotificationQueueStats.java
new file mode 100644 (file)
index 0000000..a8edd9a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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;
+    }
+}
index a939840d6255497b47a9356d5f8b133b52c61290..27c81a1ee1969436c03a1405a81544c32109e6e0 100644 (file)
@@ -8,7 +8,9 @@
 
 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;
@@ -182,6 +184,35 @@ public class QueuedNotificationManager<L,N> implements NotificationManager<L,N>
         }
     }
 
+    /**
+     * 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
index 0548d7a09142cf8195e377c778b1776756ff4889..110ac1eedab6e39bcce03955ef2ee471b143cc8e 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.yangtools.util.concurrent;
 
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -74,7 +73,7 @@ public final class SpecialExecutors {
 
         FastThreadPoolExecutor executor =
                 new FastThreadPoolExecutor( maximumPoolSize, maximumQueueSize, threadPrefix );
-        executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy() );
+        executor.setRejectedExecutionHandler( CountingRejectedExecutionHandler.newCallerRunsPolicy() );
         return executor;
     }
 
@@ -130,7 +129,7 @@ public final class SpecialExecutors {
 
         CachedThreadPoolExecutor executor =
                 new CachedThreadPoolExecutor( maximumPoolSize, maximumQueueSize, threadPrefix );
-        executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy() );
+        executor.setRejectedExecutionHandler( CountingRejectedExecutionHandler.newCallerRunsPolicy() );
         return executor;
     }
 
diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/TrackingLinkedBlockingQueue.java b/common/util/src/main/java/org/opendaylight/yangtools/util/concurrent/TrackingLinkedBlockingQueue.java
new file mode 100644 (file)
index 0000000..38b5d90
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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 );
+        }
+    }
+}
diff --git a/common/util/src/test/java/org/opendaylight/yangtools/util/DurationStatsTrackerTest.java b/common/util/src/test/java/org/opendaylight/yangtools/util/DurationStatsTrackerTest.java
new file mode 100644 (file)
index 0000000..70d63df
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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));
+    }
+}
diff --git a/common/util/src/test/java/org/opendaylight/yangtools/util/concurrent/CountingRejectedExecutionHandlerTest.java b/common/util/src/test/java/org/opendaylight/yangtools/util/concurrent/CountingRejectedExecutionHandlerTest.java
new file mode 100644 (file)
index 0000000..42c939a
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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 ) );
+    }
+}
index 8270e45d357ca6fffd6ecdb407d84d37115155cc..4d280536a1c865b4896d764b235f69d442e86cd2 100644 (file)
@@ -148,8 +148,9 @@ public class ThreadPoolExecutorTest {
         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;
@@ -162,16 +163,28 @@ public class ThreadPoolExecutorTest {
             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,
diff --git a/common/util/src/test/java/org/opendaylight/yangtools/util/concurrent/TrackingLinkedBlockingQueueTest.java b/common/util/src/test/java/org/opendaylight/yangtools/util/concurrent/TrackingLinkedBlockingQueueTest.java
new file mode 100644 (file)
index 0000000..e1119c3
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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() );
+        }
+    }
+}
diff --git a/pom.xml b/pom.xml
index 90a3e97e4d01e74a1229dea69696d54e90a0b03e..7ad393fbc312e5dcc184b7c9d8f7f77f9b17a0c3 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,8 @@
         <module>restconf</module>
         <module>websocket</module>
         <module>yang</module>
-        <!-- module>third-party</module -->
+        <module>benchmarks</module>
+      <!-- module>third-party</module -->
     </modules>
 
     <build>
index ce0ca2cc88917383ecb9be8aa48ece17e2eaa05e..a14ea33b5f0adb484635d26b00d3517100b33d03 100644 (file)
@@ -160,10 +160,8 @@ public class RestListenableEventStreamContext<L extends NotificationListener> im
         }
         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);
         }
     }
 
index 11083c31299cc07d27baca8fd4ed8e694ad3481f..a3c7146046a55a951cfcb99ab1de388632f9d13e 100644 (file)
@@ -25,6 +25,8 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 @Path("restconf")
 public interface RestRestconfService {
 
+    public static final String IDENTIFIER = "identifier";
+    public static final String INPUT = "input";
     public static final String XML = "+xml";
     public static final String JSON = "+json";
 
@@ -45,48 +47,48 @@ public interface RestRestconfService {
     @Consumes({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML,
             Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
             MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public String invokeRpc(@PathParam("identifier") String identifier, @QueryParam("input") CompositeNode payload);
+    public String invokeRpc(@PathParam(IDENTIFIER) String identifier, @QueryParam(INPUT) CompositeNode payload);
 
     @POST
     @Path("/operations/{identifier}")
     @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML,
             Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
             MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public String invokeRpc(@PathParam("identifier") String identifier);
+    public String invokeRpc(@PathParam(IDENTIFIER) String identifier);
 
     @GET
     @Path("/config/{identifier:.+}")
     @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
             MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public String readConfigurationData(@PathParam("identifier") String identifier);
+    public String readConfigurationData(@PathParam(IDENTIFIER) String identifier);
 
     @GET
     @Path("/operational/{identifier:.+}")
     @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
             MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public String readOperationalData(@PathParam("identifier") String identifier);
+    public String readOperationalData(@PathParam(IDENTIFIER) String identifier);
 
     @PUT
     @Path("/config/{identifier:.+}")
     @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
             MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public Response updateConfigurationData(@PathParam("identifier") String identifier,@QueryParam("input") CompositeNode payload);
+    public Response updateConfigurationData(@PathParam(IDENTIFIER) String identifier,@QueryParam(INPUT) CompositeNode payload);
 
     @POST
     @Path("/config/{identifier:.+}")
     @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
             MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public Response createConfigurationData(@PathParam("identifier") String identifier, @QueryParam("input") CompositeNode payload);
+    public Response createConfigurationData(@PathParam(IDENTIFIER) String identifier, @QueryParam(INPUT) CompositeNode payload);
 
     @POST
     @Path("/config")
     @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
             MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public Response createConfigurationData( @QueryParam("input") CompositeNode payload);
+    public Response createConfigurationData( @QueryParam(INPUT) CompositeNode payload);
 
     @DELETE
     @Path("/config/{identifier:.+}")
-    public Response deleteConfigurationData(@PathParam("identifier") String identifier);
+    public Response deleteConfigurationData(@PathParam(IDENTIFIER) String identifier);
 
 
 }
index 05b95be0e37b656a888d3b40cd3c3fa5035a1ef4..9ca3a2345bc05bcb4809a016e12b9fa6e40cc377 100644 (file)
@@ -152,8 +152,8 @@ public final class XmlTools {
             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;
     }
index 2966fb982fcb7a7cac76965d2e1c01b1e6df53a2..d628de016c44354fd721b5ba3f9a094799795d87 100644 (file)
@@ -12,10 +12,12 @@ import static com.google.common.base.Preconditions.checkArgument;
 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;
 
@@ -66,11 +68,11 @@ public final class BindingMapping {
         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");
@@ -132,22 +134,22 @@ public final class BindingMapping {
         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()));
     }
@@ -160,7 +162,7 @@ public final class BindingMapping {
         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();
@@ -170,7 +172,7 @@ public final class BindingMapping {
         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;
         }
index f9f4c5c7b547774e3e4567a326d2192541d7fbc1..bc7474a9f2cb765796063f07e8c9cd65dc2b5e96 100644 (file)
@@ -16,12 +16,15 @@ import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Sets;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -581,4 +584,51 @@ public class BindingReflections {
     public static Map<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;
+    }
 }
index b8b6d14d1b84a4fc1d8320290105f27005590209..fc86f71e13e17655ea74879622ce19da588d2e5d 100644 (file)
@@ -16,26 +16,26 @@ package org.opendaylight.yangtools.yang.data.api;
 @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);
 
 }
index dba2e726fa3d04bca68e2b806f20e1a74242bb9d..e9f940a4555bad2af63797018916240a4209d3a3 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.concepts.Path;
 import org.opendaylight.yangtools.util.HashCodeBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 
 /**
@@ -311,7 +312,7 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
     /**
      * 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
@@ -339,6 +340,17 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
          * @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 {
@@ -380,6 +392,18 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         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();
+        }
     }
 
     /**
@@ -498,6 +522,11 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         public String toString() {
             return super.toString() + '[' + keyValues + ']';
         }
+
+        @Override
+        public String toRelativeString(final PathArgument previous) {
+            return super.toRelativeString(previous) + '[' + keyValues + ']';
+        }
     }
 
     /**
@@ -539,6 +568,11 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         public String toString() {
             return super.toString() + '[' + value + ']';
         }
+
+        @Override
+        public String toRelativeString(final PathArgument previous) {
+            return super.toRelativeString(previous) + '[' + value + ']';
+        }
     }
 
     /**
@@ -590,7 +624,6 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         }
 
         /**
-         *
          * Returns set of all possible child nodes
          *
          * @return set of all possible child nodes.
@@ -606,6 +639,11 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
             return sb.toString();
         }
 
+        @Override
+        public String toRelativeString(final PathArgument previous) {
+            return toString();
+        }
+
         @Override
         public boolean equals(final Object o) {
             if (this == o) {
@@ -736,15 +774,14 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
             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();
index 83a8c33180b1733a7d5a4fb1ca10612cc8e30fa3..d8a8edf611487f5e81d74a134d3e643bea0d16fc 100644 (file)
@@ -1,10 +1,10 @@
 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;
@@ -12,87 +12,98 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 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);
     }
 
@@ -103,17 +114,17 @@ public class LoggingNormalizedNodeStreamWriter implements NormalizedNodeStreamWr
     }
 
     @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
index a0068c303ace91862932b2aaec02233dd70d5204..b0c05243ea143b3d612626b143f28089329a00e3 100644 (file)
@@ -16,6 +16,8 @@ import java.io.Closeable;
 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;
@@ -31,7 +33,10 @@ import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
 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 {
@@ -41,10 +46,24 @@ 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;
index 6b9e36eb7a72aad68ed5874c3fb4adfc94f19639..588b884d8a9edf563af6d6b88d8977a56d7d68d0 100644 (file)
@@ -41,7 +41,18 @@ final class ContainerNode extends AbstractTreeNode {
 
     @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
@@ -60,6 +71,26 @@ final class ContainerNode extends AbstractTreeNode {
             this.children = MapAdaptor.getDefaultInstance().takeSnapshot(parent.children);
             this.subtreeVersion = parent.getSubtreeVersion();
             this.version = parent.getVersion();
+            materializeChildVersion();
+        }
+
+        /**
+         * Traverse whole data tree and instantiate children for each data node. Set version of each MutableTreeNode
+         * accordingly to version in data node.
+         *
+         * Use this method if TreeNode is lazy initialized.
+         */
+        private void materializeChildVersion() {
+            Preconditions.checkState(data instanceof NormalizedNodeContainer);
+            NormalizedNodeContainer<?, ?, 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
@@ -97,22 +128,99 @@ final class ContainerNode extends AbstractTreeNode {
         }
     }
 
-    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);
     }
 }
index 656814162f21d4a54c39900f7a4c6d64d09fbd26..4f0a2201d7c58aa59770e80099c1b68bd4608871 100644 (file)
@@ -28,19 +28,40 @@ public final class TreeNodeFactory {
      * @param version data node version
      * @return new AbstractTreeNode instance, covering the data tree provided
      */
-    public static final TreeNode createTreeNode(final NormalizedNode<?, ?> data, final Version version) {
+    public static final TreeNode createTreeNodeRecursively(final NormalizedNode<?, ?> data, final Version version) {
         if (data instanceof NormalizedNodeContainer<?, ?, ?>) {
             @SuppressWarnings("unchecked")
             NormalizedNodeContainer<?, ?, 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);
+    }
 }
index c8e17199064fc3766dc5ad80428badb0f8e3e4aa..6947a8121147cd5d05de5f73d7b11fdc620d738b 100644 (file)
             <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>
index 3284df2cdd3b8a8fe51b54740c8c5a3fcdd96e04..fd0d95072211ef0d65d8eb385c625c6ada2ae711 100644 (file)
@@ -7,27 +7,43 @@
  */
 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());
     }
 
@@ -50,16 +66,8 @@ abstract class AbstractNodeDataWithSchema {
         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);
     }
 
 }
index aaef749ffa181596fdbbe01dfdfec0f19bcabec6..2c674d6e46e80bae8d9337ef4d5435b62af3e608 100644 (file)
@@ -19,8 +19,8 @@ class AnyXmlNodeDataWithSchema extends SimpleNodeDataWithSchema {
     }
 
     @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());
     }
 }
index e3fdaede26492f5c07b7ab83eb1c7725bb9dcb0f..67e3c59389719edae7701e6a20c04700f58a1b85 100644 (file)
@@ -6,10 +6,6 @@
  * 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 {
@@ -18,8 +14,4 @@ class CaseNodeDataWithSchema extends CompositeNodeDataWithSchema {
         super(schema);
     }
 
-    @Override
-    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
-        super.writeToStream(nnStreamWriter);
-    }
 }
index 39c1589053ae594692b5bcd16e65b1a27d3a6829..6f840bb3d67ab96ee89829b69a9eadd7f247c66e 100644 (file)
@@ -7,8 +7,6 @@
  */
 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;
@@ -30,7 +28,7 @@ class ChoiceNodeDataWithSchema extends CompositeNodeDataWithSchema {
     }
 
     @Override
-    public CompositeNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
+    protected CompositeNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
         CaseNodeDataWithSchema newChild = new CaseNodeDataWithSchema((ChoiceCaseNode) schema);
         caseNodeDataWithSchema = newChild;
         addCompositeChild(newChild);
@@ -42,10 +40,10 @@ class ChoiceNodeDataWithSchema extends CompositeNodeDataWithSchema {
     }
 
     @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();
     }
 
 }
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CodecFactory.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CodecFactory.java
new file mode 100644 (file)
index 0000000..dba5ed7
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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);
+    }
+}
index 83d715cefe20f973d7a466d2d2d741529bb110e4..c2997a84d74814feae68fec7fc76adc9122e66b7 100644 (file)
@@ -7,17 +7,21 @@
  */
 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;
@@ -33,124 +37,117 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 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);
@@ -165,10 +162,10 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         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);
         }
@@ -180,14 +177,22 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
     }
 
     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());
@@ -200,35 +205,26 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
     }
 
     @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));
     }
-
 }
index c49d71b6fcf027ab013aeca3c509dd8c3bb9b5e9..b473e9e8a19c7ae1334186f5da1ffc5d60f9abe7 100644 (file)
@@ -7,8 +7,6 @@
  */
 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;
@@ -21,10 +19,10 @@ class ContainerNodeDataWithSchema extends CompositeNodeDataWithSchema {
     }
 
     @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();
     }
 
 }
index 16428cd477e1af4a03f26207f80ded9d0be1cd5e..c1a4c31d43f1c1b21146fd1dd87f84ff2ae556d9 100644 (file)
@@ -10,19 +10,23 @@ package org.opendaylight.yangtools.yang.data.codec.gson;
 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.
@@ -68,6 +72,8 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     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;
 
@@ -80,12 +86,30 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         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);
     }
 
     /**
@@ -99,6 +123,17 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         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.
      *
@@ -113,15 +148,20 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     @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);
@@ -131,13 +171,18 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     @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);
@@ -147,6 +192,8 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     @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);
@@ -156,6 +203,8 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     @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();
@@ -164,6 +213,8 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     @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);
@@ -174,14 +225,19 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
     @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);
@@ -191,16 +247,21 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     @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();
@@ -210,7 +271,10 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
 
     @Override
     public void endNode() throws IOException {
-        switch (stack.peek().getType()) {
+        tracker.endNode();
+
+        final TypeInfo t = stack.pop();
+        switch (t.getType()) {
         case LIST:
             indentLeft();
             newLine();
@@ -224,7 +288,7 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         default:
             break;
         }
-        stack.pop();
+
         currentNamespace = stack.isEmpty() ? null : stack.peek().getNamespace();
         separateNextSiblingsWithComma();
     }
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringIdentityrefCodec.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringIdentityrefCodec.java
new file mode 100644 (file)
index 0000000..66d5523
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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();
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..fc1322f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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();
+    }
+}
index 18232ff77ec4d0e971cf21df382322d0e6c922e2..65c234aae4b87dfef3c87fd3662cf34fd2c660d2 100644 (file)
@@ -10,13 +10,10 @@ package org.opendaylight.yangtools.yang.data.codec.gson;
 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;
@@ -24,24 +21,16 @@ import java.io.EOFException;
 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;
@@ -49,10 +38,9 @@ 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.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
@@ -60,19 +48,15 @@ import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefi
  */
 @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) {
@@ -90,7 +74,7 @@ public final class JsonParserStream implements Closeable, Flushable {
             isEmpty = false;
             CompositeNodeDataWithSchema compositeNodeDataWithSchema = new CompositeNodeDataWithSchema(schema);
             read(reader, compositeNodeDataWithSchema);
-            compositeNodeDataWithSchema.writeToStream(writer);
+            compositeNodeDataWithSchema.write(writer);
 
             return this;
             // return read(reader);
@@ -114,31 +98,26 @@ public final class JsonParserStream implements Closeable, Flushable {
         }
     }
 
-    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()) {
@@ -189,6 +168,7 @@ public final class JsonParserStream implements Closeable, Flushable {
         case NAME:
         case END_OBJECT:
         case END_ARRAY:
+            break;
         }
     }
 
@@ -198,21 +178,7 @@ public final class JsonParserStream implements Closeable, Flushable {
             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) {
@@ -235,48 +201,6 @@ public final class JsonParserStream implements Closeable, Flushable {
         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();
     }
@@ -294,14 +218,16 @@ public final class JsonParserStream implements Closeable, Flushable {
     }
 
     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;
         }
@@ -315,14 +241,14 @@ public final class JsonParserStream implements Closeable, Flushable {
     }
 
     /**
-     * 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,
index e53367c637ae44ff68dae1ba2c14603eddfa03d1..7063be6753b9b308ab40ec904e4483730a6e610c 100644 (file)
@@ -18,7 +18,7 @@ class LeafListEntryNodeDataWithSchema extends SimpleNodeDataWithSchema {
     }
 
     @Override
-    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
-        nnStreamWriter.leafSetEntryNode(getValue());
+    public void write(final NormalizedNodeStreamWriter writer) throws IOException {
+        writer.leafSetEntryNode(getValue());
     }
 }
index 8b23acdb9fb05421415ba96d36c0862661e32466..20a607d5fe6c1ea31c6b374bd1a2fb314eba90fb 100644 (file)
@@ -7,8 +7,6 @@
  */
 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;
@@ -20,9 +18,9 @@ class LeafListNodeDataWithSchema extends CompositeNodeDataWithSchema {
     }
 
     @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();
     }
 }
index c63422af7313491b8b7067ffac8b2b33c5551c89..fc8c814c3f4d987852e9e03f609702aea33fc0ea 100644 (file)
@@ -19,8 +19,8 @@ class LeafNodeDataWithSchema extends SimpleNodeDataWithSchema {
     }
 
     @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());
     }
 
 }
index b08add8a36d033e345e655d21d6ac60b70228d87..3e877bbfd73c213e32030041660db41c4e37aef1 100644 (file)
@@ -7,13 +7,17 @@
  */
 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;
@@ -22,6 +26,12 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 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<>();
 
@@ -31,7 +41,7 @@ class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
 
     @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);
         }
@@ -49,29 +59,20 @@ class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
     }
 
     @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();
     }
-
 }
index 612c386e23a99cd248930f89f722156c647afd9a..d21cd9a77a01000a9e48cb3b941899e68dc7d06f 100644 (file)
@@ -7,8 +7,6 @@
  */
 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;
@@ -22,14 +20,14 @@ class ListNodeDataWithSchema extends CompositeNodeDataWithSchema {
     }
 
     @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();
     }
 
 }
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/AbstractCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/AbstractCodecImpl.java
deleted file mode 100644 (file)
index 407d866..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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;
-    }
-}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityValuesDTO.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityValuesDTO.java
deleted file mode 100644 (file)
index 30ba2a0..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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;
-        }
-
-    }
-}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityrefCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityrefCodecImpl.java
deleted file mode 100644 (file)
index a8c8b8d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/InstanceIdentifierCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/InstanceIdentifierCodecImpl.java
deleted file mode 100644 (file)
index 455bdf4..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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;
-    }
-}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/LeafrefCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/LeafrefCodecImpl.java
deleted file mode 100644 (file)
index c6d8baf..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/ObjectCodec.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/ObjectCodec.java
deleted file mode 100644 (file)
index abe7cd2..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestCodecFactory.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestCodecFactory.java
deleted file mode 100644 (file)
index 94bba92..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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);
-    }
-}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestUtil.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestUtil.java
deleted file mode 100644 (file)
index c3d002c..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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;
-        }
-    }
-
-}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/SchemaContextUtils.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/SchemaContextUtils.java
deleted file mode 100644 (file)
index 5e8f6f1..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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();
-        }
-    };
-
-}
index f51179e6cc02cbd3dee149f836d153c28f5a5730..534b3bdb445759685121c033e4b1a2b15375b326 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.gson.stream.JsonReader;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -19,10 +20,10 @@ import java.net.URI;
 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;
@@ -30,9 +31,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 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;
@@ -77,17 +77,17 @@ public class StreamToNormalizedNodeTest {
      *
      * @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)) {
@@ -95,14 +95,14 @@ public class StreamToNormalizedNodeTest {
         }
 
         // Finally build the node
-        final NormalizedNode<?, ?> parsedData = parent.build();
+        final NormalizedNode<?, ?> parsedData = result.getResult();
         LOG.debug("Parsed NormalizedNodes: {}", parsedData);
 
         /*
          * This is the serialization part.
          */
         // We want to write the first child out
-        final DataContainerChild<? 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
index 8ecaa37e4f8c8e08053f923f45055b5679e58140..fd4538833bd40457a225437a51e3a0e3692bafa6 100644 (file)
@@ -5,37 +5,37 @@
                 "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
+}
index 6c07d656da72db9ee21844da7576e4599a7d9e26..de0858d667ab14e80b48796722370f1215362e14 100644 (file)
@@ -2,26 +2,26 @@ module complexjson {
     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 {
@@ -37,7 +37,7 @@ module complexjson {
                 type string;
             }
         }
-        
+
         list lst12 {
             leaf lf121 {
                 type string;
@@ -46,8 +46,8 @@ module complexjson {
                 type string;
             }
         }
-        
-    
+
+
         choice choc11 {
             case c11A {
                 leaf lf13 {
@@ -64,77 +64,74 @@ module complexjson {
             }
         }
     }
-    
-    
+
     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;
+        }
     }
 
 }
index 5f85b4f0a2813b68445e268943ebd2582298fdfc..de7949b212d000fcff297c32ff09f4d3751ddcd1 100644 (file)
@@ -9,12 +9,12 @@ package org.opendaylight.yangtools.yang.data.impl.codec;
 
 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);
 }
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java
new file mode 100644 (file)
index 0000000..4a8232e
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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();
+    }
+}
index 2628df2419f54a17f4e74234074c16b9674f739b..e735b28d61ec1192ad8383430dc21b3d0a06d337 100644 (file)
@@ -25,15 +25,12 @@ import com.google.common.base.Strings;
 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;
@@ -97,11 +94,11 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
                     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);
                 }
             }
@@ -344,12 +341,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
 
         @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;
         }
     };
 
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XMLStreamNormalizedNodeStreamWriter.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XMLStreamNormalizedNodeStreamWriter.java
new file mode 100644 (file)
index 0000000..c244867
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * 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);
+        }
+    }
+}
index e097771e84a3fd5e59e428322074e03e7b964eb8..7312c363829832466c593d488f6bac31f7356621 100644 (file)
@@ -8,9 +8,7 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import java.util.Map;
-
 import javax.annotation.Nonnull;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -50,10 +48,10 @@ public final class XmlUtils {
             if (pathArgument instanceof NodeIdentifierWithPredicates) {
                 Map<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("']");
index fc5c20e6fde66e21fa0c6e9159dfadbf0b1dfc80..73361f1922820c29c38766ce894358ea577efc52 100644 (file)
@@ -27,11 +27,11 @@ public final class ImmutableNodes {
         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));
     }
 
@@ -42,7 +42,7 @@ public final class ImmutableNodes {
      * @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)
@@ -50,14 +50,13 @@ public final class ImmutableNodes {
     }
 
     /**
-     *
      * 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);
     }
 
index 493c6ceec0055628c3ac77aa4a469edab5b542e6..7a6627eb5e444dddfd9dd385def15f2fcd8cbc24 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid;
 
 import java.util.Map;
 import java.util.Set;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
@@ -26,26 +25,26 @@ public class DataValidationException extends RuntimeException {
 
     public static void checkLegalChild(final boolean isLegal, final YangInstanceIdentifier.PathArgument child, final DataNodeContainer schema,
             final Set<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));
         }
     }
@@ -56,9 +55,6 @@ public class DataValidationException extends RuntimeException {
 
         Object expectedValue = nodeId.getKeyValues().get(keyQName);
         Object actualValue = childNode.getValue();
-        if (childNode == null) {
-            throw new IllegalListKeyException(keyQName, nodeId, actualValue, expectedValue);
-        }
     }
 
     public static void checkListKey(final DataContainerChild<?, ?> childNode, final QName keyQName, final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeId) {
index 486c1c2cf5569641e6de28df1ea444f67925c998..6c24d4f06c84d3c63baf0e4f1ffe9d42716e66fe 100644 (file)
@@ -24,7 +24,7 @@ public final class InMemoryDataTreeFactory implements DataTreeFactory {
         final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME);
         final NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(root).build();
 
-        return new InMemoryDataTree(TreeNodeFactory.createTreeNode(data, Version.initial()), null);
+        return new InMemoryDataTree(TreeNodeFactory.createTreeNodeRecursively(data, Version.initial()), null);
     }
 
     /**
index e26c32ee5b03bfc01edd2ec64698a66911797bd0..de4bcef79666b6002ede5051ed2064a763838843 100644 (file)
@@ -39,7 +39,7 @@ final class InMemoryDataTreeModification implements DataTreeModification {
     InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final RootModificationApplyOperation resolver) {
         this.snapshot = Preconditions.checkNotNull(snapshot);
         this.strategyTree = Preconditions.checkNotNull(resolver).snapshot();
-        this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode());
+        this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode(), false);
         /*
          * We could allocate version beforehand, since Version contract
          * states two allocated version must be allways different.
@@ -141,8 +141,13 @@ final class InMemoryDataTreeModification implements DataTreeModification {
         ModifiedNode modification = rootNode;
         // We ensure strategy is present.
         ModificationApplyOperation operation = resolveModificationStrategy(path);
+        boolean isOrdered = true;
+        if (operation instanceof SchemaAwareApplyOperation) {
+            isOrdered = ((SchemaAwareApplyOperation) operation).isOrdered();
+        }
+
         for (PathArgument pathArg : path.getPathArguments()) {
-            modification = modification.modifyChild(pathArg);
+            modification = modification.modifyChild(pathArg, isOrdered);
         }
         return OperationWithModification.from(operation, modification);
     }
index 56353350af803bcf1553bc35476d93e63e7f38a4..27b42cc8fe55116e8a979f8602cf87cd0acc84cb 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
+import java.util.HashMap;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -48,16 +49,22 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
         }
     };
 
-    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<>();
+        }
     }
 
     /**
@@ -119,7 +126,7 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
      * @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);
@@ -137,7 +144,7 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
             currentMetadata = Optional.absent();
         }
 
-        ModifiedNode newlyCreated = new ModifiedNode(child, currentMetadata);
+        ModifiedNode newlyCreated = new ModifiedNode(child, currentMetadata, isOrdered);
         children.put(child, newlyCreated);
         return newlyCreated;
     }
@@ -217,7 +224,7 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
                 + 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);
     }
 }
index 6667076fb40d0f647658ffd302d95d19426136d7..03b7c3ee23d8eb76033e644d2d79a8a173f0ec04 100644 (file)
@@ -108,6 +108,16 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
         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) {
@@ -223,6 +233,11 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
             entryStrategy = Optional.<ModificationApplyOperation> of(new ValueNodeModificationStrategy.LeafSetEntryModificationStrategy(schema));
         }
 
+        @Override
+        boolean isOrdered() {
+            return true;
+        }
+
         @SuppressWarnings("rawtypes")
         @Override
         protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
@@ -248,6 +263,11 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
             entryStrategy = Optional.<ModificationApplyOperation> of(new DataNodeContainerModificationStrategy.ListEntryModificationStrategy(schema));
         }
 
+        @Override
+        boolean isOrdered() {
+            return true;
+        }
+
         @SuppressWarnings("rawtypes")
         @Override
         protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
index 511fc322cbd8b2b402ec50c56798fcd13b9828a2..e1df47c7d4df2d20ad65e7caf2860b77726801b0 100644 (file)
@@ -61,8 +61,13 @@ final class OperationWithModification {
     }
 
     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);
     }
 }
index d0a0bcd33fe9d7d82df72dedd2700be4fc3f62e7..d7aa826c236f4c375ca9e1bd6c3dccf3f5dd7d42 100644 (file)
@@ -9,19 +9,24 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.IncorrectDataStructureException;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.MutableTreeNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
@@ -158,7 +163,18 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         }
     }
 
-    protected void checkWriteApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional<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());
@@ -176,6 +192,10 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         }
     }
 
+    boolean isOrdered() {
+        return false;
+    }
+
     @Override
     public final Optional<TreeNode> apply(final ModifiedNode modification,
             final Optional<TreeNode> currentMeta, final Version version) {
@@ -234,6 +254,11 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
             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) {
@@ -249,12 +274,65 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         @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
index 6979a64f717c15d708f9d950fe0f93f99eff561a..3df0c80e959eef38d79d91e1ad45e28a20894d28 100644 (file)
@@ -62,7 +62,7 @@ abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends S
     @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
index a85acfd1e4c30f377fd768a1e7893e703f1bb477..2896675c156a0ddc5c2be0612d140dad75ed9c26 100644 (file)
@@ -146,7 +146,7 @@ public class ModificationMetadataTreeTest {
     @Test
     public void basicReadWrites() {
         DataTreeModification modificationTree = new InMemoryDataTreeModification(new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper),
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper),
                 rootOper);
         Optional<NormalizedNode<?, ?>> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH);
         assertTrue(originalBarNode.isPresent());
index bc1f6cef4f50f835268179cf855b7093f63d7778..509037fbccc05915712c3fcd141f5658d079bd2e 100644 (file)
@@ -94,7 +94,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void findNodeTestNodeFound() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         Optional<TreeNode> node = TreeNodeUtils.findNode(rootNode, OUTER_LIST_1_PATH);
         assertPresentAndType(node, TreeNode.class);
@@ -103,7 +103,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void findNodeTestNodeNotFound() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         final YangInstanceIdentifier outerList1InvalidPath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
                 .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) //
@@ -115,7 +115,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void findNodeCheckedTestNodeFound() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         TreeNode foundNode = null;
         try {
@@ -129,7 +129,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void findNodeCheckedTestNodeNotFound() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         final YangInstanceIdentifier outerList1InvalidPath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
                 .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) //
@@ -145,7 +145,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void findClosestOrFirstMatchTestNodeExists() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         Optional<TreeNode> expectedNode = TreeNodeUtils.findNode(rootNode, TWO_TWO_PATH);
         assertPresentAndType(expectedNode, TreeNode.class);
@@ -156,7 +156,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void findClosestOrFirstMatchTestNodeDoesNotExist() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         final YangInstanceIdentifier outerListInnerListPath = YangInstanceIdentifier.builder(OUTER_LIST_2_PATH)
                 .node(TestModel.INNER_LIST_QNAME)
@@ -174,7 +174,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void getChildTestChildFound() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         Optional<TreeNode> node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode),
                 TestModel.TEST_PATH.getLastPathArgument());
@@ -184,7 +184,7 @@ public class TreeNodeUtilsTest {
     @Test
     public void getChildTestChildNotFound() {
         InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
-                TreeNodeFactory.createTreeNode(createDocumentOne(), Version.initial()), rootOper);
+                TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
         TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
         Optional<TreeNode> node = TreeNodeUtils.getChild(Optional.fromNullable(rootNode),
                 TestModel.OUTER_LIST_PATH.getLastPathArgument());
index e281ea73393ef8c6c03636649eda5d6d7c873d49..fdaf0c8f702513899a84586cac99bf2a0a25aabf 100644 (file)
@@ -11,7 +11,6 @@ import java.util.Set;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
@@ -72,7 +71,7 @@ final class ChoiceNodeModification extends
         Set<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;
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractModuleStringIdentityrefCodec.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractModuleStringIdentityrefCodec.java
new file mode 100644 (file)
index 0000000..dc04682
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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);
+    }
+}
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractModuleStringInstanceIdentifierCodec.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractModuleStringInstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..7e61841
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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);
+    }
+}
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractNamespaceCodec.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractNamespaceCodec.java
new file mode 100644 (file)
index 0000000..620f46e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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);
+    }
+}
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringIdentityrefCodec.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringIdentityrefCodec.java
new file mode 100644 (file)
index 0000000..6e15067
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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);
+    }
+}
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..5140f27
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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);
+    }
+}
index 809353a4d7f8d60ff5b78b9365e72b7d833c4917..d3de2502a121179c927c2b29ffb4c1a04f0c8a4e 100644 (file)
@@ -49,7 +49,7 @@ class YangToSourcesProcessor {
     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,
@@ -180,13 +180,27 @@ class YangToSourcesProcessor {
 
     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();
@@ -197,9 +211,8 @@ class YangToSourcesProcessor {
                     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);
index 7bae5f0f57daf182827fbcedbc5d045689ef62f7..56d240aed1ac426e4fd8ebd30ca4e87a9e09f446 100644 (file)
@@ -92,14 +92,21 @@ public abstract class SchemaPath implements Immutable {
      * 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;
     }
 
     /**
index e8bcc0651039413b7c4fa95cb00917e8ff2a95f9..722ac918e08c995d391546d085fcf6b4aa36b95b 100644 (file)
@@ -146,7 +146,7 @@ public abstract class AbstractSchemaRepository implements SchemaRepository, Sche
             }
 
             if (m.isEmpty()) {
-                sources.remove(m);
+                sources.remove(source.getSourceIdentifier());
             }
         }
     }
index d557449220a153d725772905490748b080c8fe35..5c233df5ad9c761a1b344ebca0c38e0a006e572a 100644 (file)
@@ -19,7 +19,7 @@ public final class Uint16 extends AbstractUnsignedInteger implements Immutable {
     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, "");
index 41e91351aff53d514fa943b1db15b1c163683c69..ec8edd3411763f3f14ac18885fdd70aced4c8fab 100644 (file)
@@ -90,7 +90,7 @@ public final class UnionType implements UnionTypeDefinition {
     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;
     }
 
@@ -119,9 +119,9 @@ public final class UnionType implements UnionTypeDefinition {
         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();
     }
 
index c1b004dfd289baf1dbb6839b733cfe3a65ed23bd..3484b79fc342ad072c911e170fd1aed653c7a15e 100644 (file)
@@ -34,6 +34,13 @@ unknown_statement : (YIN_ELEMENT_KEYWORD | YANG_VERSION_KEYWORD | WHEN_KEYWORD |
                     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));
@@ -133,9 +140,9 @@ yang_version_stmt : YANG_VERSION_KEYWORD string stmtend;
 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
index 52f8acdb3c7e027f9406e3aa29b7077b88a3760d..11fcb347d43a3398703bb3252bd18b4845e9dc23 100644 (file)
@@ -288,7 +288,7 @@ public final class ConstraintsBuilderImpl implements ConstraintsBuilder {
             } else if (!mustConstraints.equals(other.mustConstraints)) {
                 return false;
             }
-            if (mandatory != other.mandatory) {
+            if (!mandatory.equals(other.mandatory)) {
                 return false;
             }
             if (minElements == null) {
index 6eb400c483ce7b622b1504ee87ace10c1912db93..e1792c899f7fc1af26caf0c5f4559a3864cd94f3 100644 (file)
@@ -44,7 +44,9 @@ public final class GroupingUtils {
      *            all loaded modules
      * @param module
      *            current module
-     * @return grouping with given name if found, null otherwise
+     * @return grouping with given name, never null
+     * @throws YangParseException
+     *             if no grouping found
      */
     public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
             final Map<URI, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
index 30e28d46bde7c04ae1b2e1be768fb34a6f67f2b7..766b61fbce1605e094f920187822eeecc9d186e5 100644 (file)
@@ -26,6 +26,7 @@ public abstract class AbstractDocumentedDataNodeContainer extends AbstractDocume
     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);
@@ -36,6 +37,7 @@ public abstract class AbstractDocumentedDataNodeContainer extends AbstractDocume
         groupings = ImmutableSet.copyOf(data.getGroupings());
         uses = ImmutableSet.copyOf(data.getUsesNodes());
         typeDefinitions = ImmutableSet.copyOf(data.getTypeDefinitions());
+        publicChildNodes = ImmutableSet.copyOf(childNodes.values());
     }
 
     @Override
@@ -45,7 +47,7 @@ public abstract class AbstractDocumentedDataNodeContainer extends AbstractDocume
 
     @Override
     public final Set<DataSchemaNode> getChildNodes() {
-        return ImmutableSet.copyOf(childNodes.values());
+        return publicChildNodes;
     }
 
     @Override
index 933ac6b6d4f17f489efb3fa878ea868bbf7bfb94..83b56314cb93de7f7fbfd603e66d05b3966b5037 100644 (file)
@@ -11,17 +11,14 @@ import static com.google.common.base.Preconditions.checkState;
 
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.Lists;
-
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.TerminalNode;
@@ -183,13 +180,13 @@ public final class ParserListenerUtils {
                 continue;
             }
             /*
-             * 
+             *
              * It is safe not to check last argument to be same
              * grammars enforces that.
-             * 
+             *
              * FIXME: Introduce proper escaping and translation of escaped
              * characters here.
-             * 
+             *
              */
             sb.append(quoteMatcher.removeFrom(str.substring(1, str.length()-1)));
         }
@@ -378,7 +375,15 @@ public final class ParserListenerUtils {
             ParseTree child = ctx.getChild(i);
             if (child instanceof Value_stmtContext) {
                 String valueStr = stringFromNode(child);
-                value = Integer.valueOf(valueStr);
+                try {
+                    // yang enum value has same restrictions as JAVA Integer
+                    value = Integer.valueOf(valueStr);
+                } catch (NumberFormatException e) {
+                    String err = String
+                            .format("Error on enum '%s': the enum value MUST be in the range from -2147483648 to 2147483647, but was: %s",
+                                    name, valueStr);
+                    throw new YangParseException(moduleName, ctx.getStart().getLine(), err, e);
+                }
             } else if (child instanceof Description_stmtContext) {
                 description = stringFromNode(child);
             } else if (child instanceof Reference_stmtContext) {
@@ -391,10 +396,6 @@ public final class ParserListenerUtils {
         if (value == null) {
             value = highestValue + 1;
         }
-        if (value < -2147483648 || value > 2147483647) {
-            throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on enum '" + name
-                    + "': the enum value MUST be in the range from -2147483648 to 2147483647, but was: " + value);
-        }
 
         EnumPairImpl result = new EnumPairImpl();
         result.qname = path.getPathTowardsRoot().iterator().next();
index 38055d908df31608a5a3d100c8976fc69f0c182c..7948158f4dee6b277493d8d2451395d3ee6b3d19 100644 (file)
@@ -240,7 +240,7 @@ public final class YangParserImpl implements YangContextParser {
                     if (targetModule == null) {
                         Module result = findModuleFromContext(context, module, prefix, 0);
                         targetModule = new ModuleBuilder(result);
-                        TreeMap<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);
@@ -1061,10 +1061,6 @@ public final class YangParserImpl implements YangContextParser {
             ModuleBuilder module = BuilderUtils.getParentModule(usesNode);
             final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
                     module);
-            if (targetGroupingBuilder == null) {
-                throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
-                        + usesNode.getGroupingPath() + "' not found.");
-            }
             usesNode.setGrouping(targetGroupingBuilder);
         }
     }
index f7e270ea1d5badf84ef605c51a93da8422739e9d..05dbd2e1b7f1d7f0b4ba454e94138a257e59e396 100644 (file)
@@ -46,6 +46,9 @@ public final class ModuleDependencySort {
     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();
         }
@@ -65,6 +68,9 @@ public final class ModuleDependencySort {
         @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();
         }
@@ -95,6 +101,9 @@ public final class ModuleDependencySort {
 
             @Override
             public ModuleBuilder apply(final TopologicalSort.Node input) {
+                if (input == null) {
+                    return null;
+                }
                 ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference();
                 if (moduleOrModuleBuilder.isModuleBuilder()) {
                     return moduleOrModuleBuilder.getModuleBuilder();
index f36fc15b073439b90d48e3bf4bdb6922d0b5b83d..01c1dd97247b51f645c6bd9812d50a4c509c71ad 100644 (file)
@@ -1,7 +1,19 @@
 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"; }