Merge "Fix xml->CompositeNode transformation for rpc replies for rpcs with no output"
authorTony Tkacik <ttkacik@cisco.com>
Wed, 3 Sep 2014 16:09:06 +0000 (16:09 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 3 Sep 2014 16:09:06 +0000 (16:09 +0000)
13 files changed:
benchmarks/src/main/java/org/opendaylight/yangtools/yang/data/impl/tree/InMemoryDataTreeBenchmark.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java
common/parent/pom.xml
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.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/ListEntryNodeDataWithSchema.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementIdentityrefParser.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/ImmutableMapEntryNodeSchemaAwareBuilder.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractNamespaceCodec.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ListSchemaNodeBuilder.java

index 306c14dc07194530262a7889ccff55049899403f..a9171687cfc29b5aed112cc81651abc9f0817daf 100644 (file)
@@ -141,14 +141,10 @@ public class InMemoryDataTreeBenchmark {
     @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 {
+    public void write100KSingleNodeWithOneInnerItemInOneCommitBenchmark() throws Exception {
         final DataTreeSnapshot snapshot = datastore.takeSnapshot();
         final DataTreeModification modification = snapshot.newModification();
-        for (int outerListKey = 0; outerListKey < reps; ++outerListKey) {
+        for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
             modification.write(OUTER_LIST_100K_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
         }
         datastore.validate(modification);
@@ -159,14 +155,24 @@ public class InMemoryDataTreeBenchmark {
     @Benchmark
     @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
     @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
-    public void twoNodes50KWriteBenchmark() throws Exception {
-        applyWriteTwoNodes(OUTER_LIST_50K);
+    public void write100KSingleNodeWithOneInnerItemInCommitPerWriteBenchmark() throws Exception {
+        final DataTreeSnapshot snapshot = datastore.takeSnapshot();
+        for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
+            final DataTreeModification modification = snapshot.newModification();
+            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);
+        }
     }
 
-    private void applyWriteTwoNodes(final int reps) throws DataValidationFailedException {
+    @Benchmark
+    @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
+    @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
+    public void write50KSingleNodeWithTwoInnerItemsInOneCommitBenchmark() throws Exception {
         final DataTreeSnapshot snapshot = datastore.takeSnapshot();
         final DataTreeModification modification = snapshot.newModification();
-        for (int outerListKey = 0; outerListKey < reps; ++outerListKey) {
+        for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
             modification.write(OUTER_LIST_50K_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
         }
         datastore.validate(modification);
@@ -177,18 +183,42 @@ public class InMemoryDataTreeBenchmark {
     @Benchmark
     @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
     @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
-    public void tenNodes10KWriteBenchmark() throws Exception {
-        applyWriteTenNodes(OUTER_LIST_10K);
+    public void write50KSingleNodeWithTwoInnerItemsInCommitPerWriteBenchmark() throws Exception {
+        final DataTreeSnapshot snapshot = datastore.takeSnapshot();
+        for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
+            final DataTreeModification modification = snapshot.newModification();
+            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);
+        }
     }
 
-    private void applyWriteTenNodes(final int reps) throws DataValidationFailedException {
+    @Benchmark
+    @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
+    @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
+    public void write10KSingleNodeWithTenInnerItemsInOneCommitBenchmark() throws Exception {
         final DataTreeSnapshot snapshot = datastore.takeSnapshot();
         final DataTreeModification modification = snapshot.newModification();
-        for (int outerListKey = 0; outerListKey < reps; ++outerListKey) {
+        for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++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);
     }
+
+    @Benchmark
+    @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
+    @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
+    public void write10KSingleNodeWithTenInnerItemsInCommitPerWriteBenchmark() throws Exception {
+        final DataTreeSnapshot snapshot = datastore.takeSnapshot();
+        for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++outerListKey) {
+            final DataTreeModification modification = snapshot.newModification();
+            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);
+        }
+    }
 }
index 49a834710c47bf04bb6213205fc65e2b88cf968f..dfef41afc0aedd37bac71784384be0b3e816db95 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.yangtools.binding.data.codec.impl;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSortedMap;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -20,6 +19,7 @@ import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -359,7 +359,7 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
 
     private static class IdentifiableItemCodec implements Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> {
 
-        private final ImmutableSortedMap<QName, ValueContext> keyValueContexts;
+        private final Map<QName, ValueContext> keyValueContexts;
         private final ListSchemaNode schema;
         private final Constructor<? extends Identifier<?>> constructor;
         private final Class<?> identifiable;
@@ -368,39 +368,50 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
                 final Class<?> identifiable, final Map<QName, ValueContext> keyValueContexts) {
             this.schema = schema;
             this.identifiable = identifiable;
-            this.keyValueContexts = ImmutableSortedMap.copyOf(keyValueContexts);
             this.constructor = getConstructor(keyClass);
+
+            /*
+             * We need to re-index to make sure we instantiate nodes in the order in which
+             * they are defined.
+             */
+            final Map<QName, ValueContext> keys = new LinkedHashMap<>();
+            for (QName qname : schema.getKeyDefinition()) {
+                keys.put(qname, keyValueContexts.get(qname));
+            }
+            this.keyValueContexts = ImmutableMap.copyOf(keys);
         }
 
         @Override
         public IdentifiableItem<?, ?> deserialize(final NodeIdentifierWithPredicates input) {
-            ArrayList<Object> bindingValues = new ArrayList<>();
-
-            for(QName key: schema.getKeyDefinition()) {
+            final Collection<QName> keys = schema.getKeyDefinition();
+            final ArrayList<Object> bindingValues = new ArrayList<>(keys.size());
+            for (QName key : keys) {
                 Object yangValue = input.getKeyValues().get(key);
                 bindingValues.add(keyValueContexts.get(key).deserialize(yangValue));
             }
+
+            final Identifier<?> identifier;
             try {
-                final Identifier<?> identifier = constructor.newInstance(bindingValues.toArray());
-                @SuppressWarnings({ "rawtypes", "unchecked" })
-                final IdentifiableItem identifiableItem = new IdentifiableItem(identifiable, identifier);
-                return identifiableItem;
+                identifier = constructor.newInstance(bindingValues.toArray());
             } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
-                throw new IllegalStateException(e);
+                throw new IllegalStateException(String.format("Failed to instantiate key class %s", constructor.getDeclaringClass()), e);
             }
+
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            final IdentifiableItem identifiableItem = new IdentifiableItem(identifiable, identifier);
+            return identifiableItem;
         }
 
         @Override
         public NodeIdentifierWithPredicates serialize(final IdentifiableItem<?, ?> input) {
             Object value = input.getKey();
 
-            Map<QName, Object> values = new HashMap<>();
+            Map<QName, Object> values = new LinkedHashMap<>();
             for (Entry<QName, ValueContext> valueCtx : keyValueContexts.entrySet()) {
                 values.put(valueCtx.getKey(), valueCtx.getValue().getAndSerialize(value));
             }
             return new NodeIdentifierWithPredicates(schema.getQName(), values);
         }
-
     }
 
     @SuppressWarnings("unchecked")
index e532be5b9e83689280fbb2469de874174647b45b..aeda45c9904f30634b031f8169e76acc46347e53 100644 (file)
@@ -11,8 +11,8 @@ import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -189,7 +189,6 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     }
 
     private PathArgument serializeIdentifiableItem(final IdentifiableItem<?,?> argument, final QName previousQname) {
-        Map<QName, Object> predicates = new HashMap<>();
         @SuppressWarnings("rawtypes")
         Class type = argument.getType();
         @SuppressWarnings("unchecked")
@@ -202,6 +201,8 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
         ValueWithQName combinedInput = new ValueWithQName(previousQname, argument.getKey());
         @SuppressWarnings("unchecked")
         CompositeNode compositeOutput = keyCodec.serialize(combinedInput);
+
+        final Map<QName, Object> predicates = new LinkedHashMap<>();
         for (Node<?> outputValue : compositeOutput.getValue()) {
             predicates.put(outputValue.getNodeType(), outputValue.getValue());
         }
index 15e887eb44655c77b23cda83d934afe5e5c1bc10..950a6ba9cb0cb81f5e9539f867650389824d9481 100644 (file)
             </plugin>
         </plugins>
     </reporting>
+
+
+    <!-- Note: we can not use variables for these URLs because we need to
+         be able to download the parent pom from the repository the first 
+         time we go to use it (since it is in a different project).
+         To override the settings, use the "mirror" section of the
+         settings.xml. See http://maven.apache.org/settings.html -->
     <repositories>
         <!-- OpenDayLight Repo Mirror -->
         <repository>
             <id>opendaylight-mirror</id>
             <name>opendaylight-mirror</name>
-            <url>${nexusproxy}/groups/public/</url>
+            <url>http://nexus.opendaylight.org/content/groups/public/</url>
             <snapshots>
                 <enabled>false</enabled>
             </snapshots>
         <repository>
             <id>opendaylight-snapshot</id>
             <name>opendaylight-snapshot</name>
-            <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
+            <url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
             <snapshots>
                 <enabled>true</enabled>
             </snapshots>
index e9f940a4555bad2af63797018916240a4209d3a3..84ebdf0f2035f30446e0098220050a80e9e7399d 100644 (file)
@@ -356,6 +356,7 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
     private static abstract class AbstractPathArgument implements PathArgument {
         private static final long serialVersionUID = -4546547994250849340L;
         private final QName nodeType;
+        private volatile transient Integer hash = null;
 
         protected AbstractPathArgument(final QName nodeType) {
             this.nodeType = Preconditions.checkNotNull(nodeType);
@@ -371,11 +372,26 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
             return nodeType.compareTo(o.getNodeType());
         }
 
-        @Override
-        public int hashCode() {
+        protected int hashCodeImpl() {
             return 31 + getNodeType().hashCode();
         }
 
+        @Override
+        public final int hashCode() {
+            Integer ret = hash;
+            if (ret == null) {
+                synchronized (this) {
+                    ret = hash;
+                    if (ret == null) {
+                        ret = hashCodeImpl();
+                        hash = ret;
+                    }
+                }
+            }
+
+            return ret;
+        }
+
         @Override
         public boolean equals(final Object obj) {
             if (this == obj) {
@@ -485,9 +501,9 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         }
 
         @Override
-        public int hashCode() {
+        protected int hashCodeImpl() {
             final int prime = 31;
-            int result = super.hashCode();
+            int result = super.hashCodeImpl();
             result = prime * result;
 
             for (Entry<QName, Object> entry : keyValues.entrySet()) {
@@ -548,9 +564,9 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         }
 
         @Override
-        public int hashCode() {
+        protected int hashCodeImpl() {
             final int prime = 31;
-            int result = super.hashCode();
+            int result = super.hashCodeImpl();
             result = prime * result + ((value == null) ? 0 : YangInstanceIdentifier.hashCode(value));
             return result;
         }
index e2a6cef64179009caed829985dc2f9b0692a323d..f8b0303802e8e2cf63b83afe056ed28340a62d74 100644 (file)
@@ -85,27 +85,16 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
     private final Writer writer;
     private final String indent;
 
-    private URI currentNamespace = null;
     private int currentDepth = 0;
+    private URI currentNamespace;
 
     private JSONNormalizedNodeStreamWriter(final SchemaContext schemaContext,
             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);
+        this(schemaContext, SchemaPath.ROOT, writer, null, indentSize);
     }
 
     private JSONNormalizedNodeStreamWriter(final SchemaContext schemaContext, final SchemaPath path,
-            final Writer writer, final URI initialNs,final int indentSize) {
+            final Writer writer, final URI initialNs, final int indentSize) {
         this.schemaContext = Preconditions.checkNotNull(schemaContext);
         this.writer = Preconditions.checkNotNull(writer);
 
@@ -115,9 +104,10 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         } else {
             indent = null;
         }
-        this.currentNamespace = initialNs;
         this.codecs = CodecFactory.create(schemaContext);
-        this.tracker = SchemaTracker.create(schemaContext,path);
+        this.tracker = SchemaTracker.create(schemaContext, path);
+
+        this.currentNamespace = initialNs;
     }
 
     /**
index 3e877bbfd73c213e32030041660db41c4e37aef1..315ce97e49a863d4cc8bee59ae8f97dac84dcb1d 100644 (file)
@@ -7,17 +7,15 @@
  */
 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.Maps;
 
 import java.io.IOException;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 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;
@@ -26,12 +24,6 @@ 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<>();
 
@@ -60,17 +52,24 @@ class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
 
     @Override
     public void write(final NormalizedNodeStreamWriter writer) throws IOException {
-        final int keyCount = ((ListSchemaNode) getSchema()).getKeyDefinition().size();
-        if (keyCount == 0) {
+        final Collection<QName> keyDef = ((ListSchemaNode) getSchema()).getKeyDefinition();
+        if (keyDef.isEmpty()) {
             writer.startUnkeyedListItem(provideNodeIdentifier(), childSizeHint());
             super.write(writer);
             writer.endNode();
             return;
         }
 
-        Preconditions.checkState(keyCount == qNameToKeys.size(), "Input is missing some of the keys of %s", getSchema().getQName());
+        Preconditions.checkState(keyDef.size() == qNameToKeys.size(), "Input is missing some of the keys of %s", getSchema().getQName());
+
+        // Need to restore schema order...
+        final Map<QName, Object> predicates = new LinkedHashMap<>();
+        for (QName qname : keyDef) {
+            predicates.put(qname, qNameToKeys.get(qname).getValue());
+        }
+
         writer.startMapEntryNode(
-            new NodeIdentifierWithPredicates(getSchema().getQName(), Maps.transformValues(qNameToKeys, VALUE_FUNCTION)),
+            new NodeIdentifierWithPredicates(getSchema().getQName(), predicates),
             childSizeHint());
         super.write(writer);
         writer.endNode();
index fcfaca5ce299c36c17465bebdae18b97bb365912..c6d20e30f0414ba01e103a6d643b4c90647cae41 100644 (file)
@@ -8,9 +8,7 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import com.google.common.base.Preconditions;
-
 import java.net.URI;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.util.AbstractStringIdentityrefCodec;
 import org.opendaylight.yangtools.yang.model.api.Module;
@@ -33,7 +31,7 @@ final class ElementIdentityrefParser extends AbstractStringIdentityrefCodec {
 
     @Override
     protected QName createQName(final String prefix, final String localName) {
-        final String namespace = element.lookupNamespaceURI(prefix);
+        final String namespace = element.lookupNamespaceURI(!prefix.isEmpty() ? prefix : null);
         Preconditions.checkArgument(namespace != null, "Failed to lookup prefix %s", prefix);
 
         final URI ns = URI.create(namespace);
index 73361f1922820c29c38766ce894358ea577efc52..433212bfc46f9a6df118bf30a7bc06eef33247c1 100644 (file)
@@ -60,9 +60,9 @@ public final class ImmutableNodes {
         return leafNode(new NodeIdentifier(name), value);
     }
 
-    public static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder(final QName nodeName,final QName keyName,final Object keyValue) {
+    public static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder(final QName nodeName, final QName keyName, final Object keyValue) {
         return ImmutableMapEntryNodeBuilder.create()
-                .withNodeIdentifier(new NodeIdentifierWithPredicates(nodeName, keyName,keyValue))
+                .withNodeIdentifier(new NodeIdentifierWithPredicates(nodeName, keyName, keyValue))
                 .withChild(leafNode(keyName, keyValue));
     }
 
index c2f81c14a460e0ad753eae1bd98f29fb2ecd2c60..8490e2c0988b09e7d28a5e9eaee97436bd237172 100644 (file)
@@ -7,9 +7,10 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
 
+import com.google.common.base.Preconditions;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 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.schema.DataContainerChild;
@@ -19,9 +20,6 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataN
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-
 public final class ImmutableMapEntryNodeSchemaAwareBuilder extends ImmutableMapEntryNodeBuilder{
 
     private final ListSchemaNode schema;
@@ -55,15 +53,15 @@ public final class ImmutableMapEntryNodeSchemaAwareBuilder extends ImmutableMapE
     private YangInstanceIdentifier.NodeIdentifierWithPredicates constructNodeIdentifier() {
         Collection<QName> keys = schema.getKeyDefinition();
 
-        if(keys.isEmpty()) {
+        if (keys.isEmpty()) {
             keys = childrenQNamesToPaths.keySet();
         }
 
-        final Map<QName, Object> keysToValues = Maps.newHashMap();
+        final Map<QName, Object> keysToValues = new LinkedHashMap<>();
         for (QName key : keys) {
-        final DataContainerChild<?, ?> valueForKey = getChild(childrenQNamesToPaths.get(key));
+            final DataContainerChild<?, ?> valueForKey = getChild(childrenQNamesToPaths.get(key));
             DataValidationException.checkListKey(valueForKey, key, new YangInstanceIdentifier.NodeIdentifierWithPredicates(
-                    schema.getQName(), keysToValues));
+                schema.getQName(), keysToValues));
             keysToValues.put(key, valueForKey.getValue());
         }
 
index 620f46e20462592b1ddcfc7dcd23983629956640..bc6574720f3450879376338df696f09bbb02c750 100644 (file)
@@ -9,13 +9,10 @@ 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 {
@@ -62,17 +59,22 @@ abstract class AbstractNamespaceCodec {
             return null;
         }
 
-        final String prefix = it.next().trim();
-        if (prefix.isEmpty()) {
-            return null;
-        }
 
-        // it is not "prefix:value"
-        if (!it.hasNext()) {
+        final String first = it.next().trim();
+        if (first.isEmpty()) {
             return null;
         }
 
-        final String identifier = it.next().trim();
+        final String identifier;
+        final String prefix;
+        if (it.hasNext()) {
+            // It is "prefix:value"
+            prefix = first;
+            identifier = it.next().trim();
+        } else {
+            prefix = "";
+            identifier = first;
+        }
         if (identifier.isEmpty()) {
             return null;
         }
index 5140f2727df97c0722b2035d7047384233376a4f..e39d819512f45a528cbd784daceb46a5573bf2cd 100644 (file)
@@ -12,8 +12,8 @@ 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.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
@@ -88,7 +88,7 @@ public abstract class AbstractStringInstanceIdentifierCodec extends AbstractName
 
         // predicates
         final Matcher matcher = PREDICATE_PATTERN.matcher(xPathArgument);
-        final Map<QName, Object> predicates = new HashMap<>();
+        final Map<QName, Object> predicates = new LinkedHashMap<>();
         QName currentQName = mainQName;
 
         while (matcher.find()) {
index 994a979b20f1bf2a8822a0b58d9aeb840cf504d2..4e3649c44fc192d76e2c754b531c33beb611a17b 100644 (file)
@@ -91,9 +91,7 @@ public final class ListSchemaNodeBuilder extends AbstractDocumentedDataNodeConta
         instance.userOrdered = userOrdered;
 
         // KEY
-        if (keys == null) {
-            instance.keyDefinition = ImmutableList.of();
-        } else {
+        if (keys != null) {
             keyDefinition = new ArrayList<>();
             for (String key : keys) {
                 DataSchemaNode keyPart = instance.getDataChildByName(key);
@@ -101,9 +99,15 @@ public final class ListSchemaNodeBuilder extends AbstractDocumentedDataNodeConta
                     throw new YangParseException(getModuleName(), getLine(), "Failed to resolve list key for name "
                             + key);
                 }
-                keyDefinition.add(keyPart.getQName());
+
+                final QName qname = keyPart.getQName();
+                if (!keyDefinition.contains(qname)) {
+                    keyDefinition.add(qname);
+                }
             }
             instance.keyDefinition = ImmutableList.copyOf(keyDefinition);
+        } else {
+            instance.keyDefinition = ImmutableList.of();
         }
 
         // ORIGINAL NODE