MDSAL-310 Binding v2 codec - Instance identifier should not reference choice/case. 99/68099/16
authorJie Han <han.jie@zte.com.cn>
Fri, 9 Feb 2018 08:59:18 +0000 (16:59 +0800)
committerJie Han <han.jie@zte.com.cn>
Mon, 27 Aug 2018 01:58:15 +0000 (09:58 +0800)
- Since choice and case are not data tree nodes,
  InstanceIdentifier should not reference choice/case
  as well as YangInstanceIdentifier.

JIRA:MDSAL-310

Change-Id: I881a88bfce337ab3a5d9f2a648cf16ead8214e98
Signed-off-by: Jie Han <han.jie@zte.com.cn>
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ChoiceNodeCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/TreeNodeCodecContext.java [changed mode: 0644->0755]
binding2/mdsal-binding2-dom-codec/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/InstanceIdentifierSerializeDeserializeTest.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/NormalizedNodeSerializeDeserializeTest.java

index ba0c65884541bb1bf2618c997f5345a48368e314..e2c87b5c5036da06e157832067f1a525ceb935bd 100644 (file)
@@ -66,6 +66,8 @@ public class ChoiceNodeCodecContext<D extends TreeNode> extends DataContainerCod
         final Map<Class<?>, DataContainerCodecPrototype<?>> byClassBuilder = new HashMap<>();
         final Map<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClassBuilder = new HashMap<>();
         final Set<Class<?>> potentialSubstitutions = new HashSet<>();
+
+        //TODO: Collect all choice/cases' descendant data children including augmented data nodes.
         // Walks all cases for supplied choice in current runtime context
         for (final Class<?> caze : factory().getRuntimeContext().getCases(getBindingClass())) {
             // We try to load case using exact match thus name
@@ -143,8 +145,35 @@ public class ChoiceNodeCodecContext<D extends TreeNode> extends DataContainerCod
         return Optional.empty();
     }
 
-    Iterable<Class<?>> getCaseChildrenClasses() {
-        return byCaseChildClass.keySet();
+
+    /**
+     * Gets the map of case class and prototype for {@link
+     * org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext}
+     * to catch choice/cases' data child by class.
+     *
+     * @return the map of case class and prototype
+     */
+    public Map<Class<?>, DataContainerCodecPrototype<?>> getClassCaseChildren() {
+        return byCaseChildClass;
+    }
+
+
+    /**
+     * Gets the map of case path argument and prototype for {@link
+     * org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext}
+     * to catch choice/cases' data child by class.
+     *
+     * @return the the map of case path and prototype
+     */
+    public Map<YangInstanceIdentifier.PathArgument, DataContainerCodecPrototype<?>> getYangCaseChildren() {
+        return byYangCaseChild;
+    }
+
+    public DataContainerCodecContext<?, ?> getCaseByChildClass(final @Nonnull Class<? extends TreeNode> type) {
+        final DataContainerCodecPrototype<?> protoCtx =
+            childNonNull(byCaseChildClass.get(type), type, "Class %s is not child of any cases for %s", type,
+                bindingArg());
+        return protoCtx.get();
     }
 
     private DataContainerCodecPrototype<CaseSchemaNode> loadCase(final Class<?> childClass) {
old mode 100644 (file)
new mode 100755 (executable)
index f14cb3b..c5941d5
@@ -32,6 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ChoiceNodeCodecContext;
 import org.opendaylight.mdsal.binding.javav2.generator.api.ClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
 import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
@@ -108,9 +109,17 @@ public abstract class TreeNodeCodecContext<D extends TreeNode, T extends DataNod
             byMethodBuilder.put(childDataObj.getValue(), childProto);
             byStreamClassBuilder.put(childProto.getBindingClass(), childProto);
             byYangBuilder.put(childProto.getYangArg(), childProto);
-            //TODO: get cases in consideration - finish in patches to come
-            //if (childProto.isChoice()) {
+
+            if (childProto.isChoice()) {
+                final ChoiceNodeCodecContext<?> choice = (ChoiceNodeCodecContext<?>) childProto.get();
+                choice.getClassCaseChildren().entrySet().forEach(entry ->
+                    byBindingArgClassBuilder.put(entry.getKey(), childProto));
+
+                choice.getYangCaseChildren().entrySet().forEach(entry ->
+                    byYangBuilder.put(entry.getKey(), childProto));
+            }
         }
+
         this.byMethod = ImmutableSortedMap.copyOfSorted(byMethodBuilder);
         this.byYang = ImmutableMap.copyOf(byYangBuilder);
         this.byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder);
@@ -188,8 +197,15 @@ public abstract class TreeNodeCodecContext<D extends TreeNode, T extends DataNod
         }
         final DataContainerCodecContext<?, ?> context =
                 childNonNull(ctxProto, argType, "Class %s is not valid child of %s", argType, getBindingClass()).get();
-        //TODO: get cases in consideration - finish in patches to come
-//        if (context instanceof ChoiceNodeCodecContext) {
+
+        if (context instanceof ChoiceNodeCodecContext) {
+            final ChoiceNodeCodecContext<?> choice = (ChoiceNodeCodecContext<?>) context;
+            final DataContainerCodecContext<?, ?> caze = choice.getCaseByChildClass(argType);
+            // FIXME: Instance identifier should not reference choice or case as they're
+            // not data tree nodes.
+            return caze.bindingPathArgumentChild(arg, builder);
+        }
+
         context.addYangPathArgument(arg, builder);
         return context;
     }
@@ -207,6 +223,16 @@ public abstract class TreeNodeCodecContext<D extends TreeNode, T extends DataNod
             childSupplier = byYang.get(arg);
         }
 
+        // FIXME: Since instance identifier does not reference choice or case,
+        // we should search in data children of choice/case
+        if (childSupplier instanceof DataContainerCodecPrototype) {
+            final DataContainerCodecContext<?,T> context = ((DataContainerCodecPrototype) childSupplier).get();
+            if (context instanceof ChoiceNodeCodecContext) {
+                return (NodeCodecContext<D>) childNonNull(((ChoiceNodeCodecContext) context).yangPathArgumentChild(arg),
+                    arg, "Argument %s is not valid child of %s", arg, getSchema());
+            }
+        }
+
         return (NodeCodecContext<D>) childNonNull(childSupplier, arg,
                 "Argument %s is not valid child of %s", arg, getSchema()).get();
     }
diff --git a/binding2/mdsal-binding2-dom-codec/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/InstanceIdentifierSerializeDeserializeTest.java b/binding2/mdsal-binding2-dom-codec/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/InstanceIdentifierSerializeDeserializeTest.java
new file mode 100644 (file)
index 0000000..bc09a07
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 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.mdsal.binding.javav2.dom.codec.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.impl.StreamWriterGenerator;
+import org.opendaylight.mdsal.binding.javav2.runtime.javassist.JavassistUtils;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.data.ChoiceContainer;
+import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.data.choice_container.identifier.simple.SimpleId;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+public class InstanceIdentifierSerializeDeserializeTest extends AbstractBindingRuntimeTest {
+    private static final InstanceIdentifier<SimpleId> BA_SIMPLE_ID = InstanceIdentifier
+            .builder(ChoiceContainer.class).child(SimpleId.class).build();
+
+    private static final QName CHOICE_CONTAINER_QNAME = ChoiceContainer.QNAME;
+    private static final QName SIMPLE_ID_QNAME = SimpleId.QNAME;
+
+
+    private static final YangInstanceIdentifier BI_SIMPLE_ID_PATH = YangInstanceIdentifier
+        .of(CHOICE_CONTAINER_QNAME).node(SIMPLE_ID_QNAME);
+
+    private BindingNormalizedNodeCodecRegistry registry;
+
+    @Override
+    @Before
+    public void setup() {
+        super.setup();
+        final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+        registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+        registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+    }
+
+    @Test
+    public void testYangIIToBindingAwareII() {
+        final InstanceIdentifier<?> instanceIdentifier = registry.fromYangInstanceIdentifier(BI_SIMPLE_ID_PATH);
+        assertEquals(BA_SIMPLE_ID, instanceIdentifier);
+    }
+
+    @Test
+    public void testBindingAwareIIToYangIContainer() {
+        final YangInstanceIdentifier yangInstanceIdentifier = registry.toYangInstanceIdentifier(BA_SIMPLE_ID);
+        assertEquals(BI_SIMPLE_ID_PATH, yangInstanceIdentifier);
+    }
+}
index 363ba73cb33692f5d7ac16633fe05f86086eabf8..531ff349d61d55453acd3675d4076e625a6442cf 100644 (file)
@@ -25,9 +25,12 @@ import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
 import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.data.TreeLeafOnlyUsesAugment;
 import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.dto.TreeLeafOnlyUsesAugmentBuilder;
 import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.grp.LeafFromGrouping;
+import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.data.ChoiceContainer;
 import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.data.Top;
+import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.data.choice_container.identifier.simple.SimpleId;
 import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.data.top.TopLevelList;
 import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.dto.TopBuilder;
+import org.opendaylight.mdsal.gen.javav2.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.dto.choice_container.identifier.simple.SimpleIdBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
@@ -46,6 +49,14 @@ public class NormalizedNodeSerializeDeserializeTest extends AbstractBindingRunti
     private static final QName AUGMENTED_INT_QNAME = QName.create(TopLevelList.QNAME, "augmented-int");
     private static final QName SIMPLE_VALUE_QNAME = QName.create(LeafFromGrouping.QNAME, "simple-value");
     private static final QName SIMPLE_TYPE_QNAME = QName.create(LeafFromGrouping.QNAME, "simple-type");
+    private static final QName CHOICE_CONTAINER_QNAME = ChoiceContainer.QNAME;
+    private static final QName SIMPLE_ID_QNAME = SimpleId.QNAME;
+    private static final QName SIMPLE_LEAF_ID_QNAME = QName.create(SimpleId.QNAME, "id");
+
+    private static final InstanceIdentifier<SimpleId> BA_SIMPLE_ID = InstanceIdentifier
+        .builder(ChoiceContainer.class).child(SimpleId.class).build();
+    private static final YangInstanceIdentifier BI_SIMPLE_ID_PATH = YangInstanceIdentifier
+        .of(CHOICE_CONTAINER_QNAME).node(SIMPLE_ID_QNAME);
 
     @Before
     public void setup() {
@@ -122,4 +133,29 @@ public class NormalizedNodeSerializeDeserializeTest extends AbstractBindingRunti
         assertEquals(topBindingData(), entry.getValue());
     }
 
+    private static SimpleId simpleIdBindingData() {
+        return new SimpleIdBuilder().setId(10).build();
+    }
+
+    private static ContainerNode simpleIdNormailziedData() {
+        return ImmutableContainerNodeBuilder.create()
+            .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SIMPLE_ID_QNAME))
+            .withChild(leafNode(SIMPLE_LEAF_ID_QNAME, 10))
+            .build();
+    }
+
+    @Test
+    public void testChoiceDataToNormalizedNode() {
+        final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry =
+            registry.toNormalizedNode(BA_SIMPLE_ID, simpleIdBindingData());
+        assertEquals(simpleIdNormailziedData(), entry.getValue());
+    }
+
+    @Test
+    public void testChoiceDataFromNormalizedNode() {
+        final Entry<InstanceIdentifier<?>, TreeNode> entry =
+            registry.fromNormalizedNode(BI_SIMPLE_ID_PATH, simpleIdNormailziedData());
+        assertEquals(simpleIdBindingData(), entry.getValue());
+    }
+
 }
\ No newline at end of file