Bug 1906: Fixed bug in Binding leafref to union codec 20/11320/2
authorTony Tkacik <ttkacik@cisco.com>
Wed, 17 Sep 2014 12:45:33 +0000 (14:45 +0200)
committerRobert Varga <rovarga@cisco.com>
Mon, 22 Sep 2014 14:16:38 +0000 (16:16 +0200)
In models, where leafref was used to reference type, incorrect
codec (EncapsulatedValueCodec) was used for all cases with
derived type instead of actual codec. EncapsulatedValueCodec
covered most cases except Union and Bits.

Added special handling for leafref, where type definition
for referenced leaf is fetched and codec is used based
on that notion.

Change-Id: Id790554e1e84bcf01179add4f5327a4e7380ebe1
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
(cherry picked from commit 697925b94246e725412b88151ec097c812a65b39)
Signed-off-by: Robert Varga <rovarga@cisco.com>
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/LeafReferenceTest.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/ModuleContext.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/BindingRuntimeContext.java
code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/binding/rev140701/Int32StringUnionBuilder.java [new file with mode: 0644]
code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-augment-test.yang
code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang

index 881a62bc2e0c0abe4da9baf94c9a5536a9bf0076..11f8d3f5bae2c0e9ead199655c2ee052bd0e5ee8 100644 (file)
@@ -30,6 +30,7 @@ import org.opendaylight.yangtools.binding.data.codec.impl.NodeCodecContext.Codec
 import org.opendaylight.yangtools.concepts.Codec;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
 import org.opendaylight.yangtools.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.BindingMapping;
@@ -53,6 +54,7 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
 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.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -287,6 +289,11 @@ class BindingCodecContext implements CodecContextFactory, Immutable {
             } catch (Exception e) {
                 throw new IllegalStateException("Unable to load codec for " + valueType, e);
             }
+        } else if(rootType instanceof LeafrefTypeDefinition) {
+            Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(valueType);
+            Object schema = typeWithSchema.getValue();
+            Preconditions.checkState(schema instanceof TypeDefinition<?>);
+            return getCodec(valueType, (TypeDefinition<?>) schema);
         }
         return ValueTypeCodec.getCodecFor(valueType, instantiatedType);
     }
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/LeafReferenceTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/LeafReferenceTest.java
new file mode 100644 (file)
index 0000000..ba8c84c
--- /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 static org.junit.Assert.assertEquals;
+
+import java.util.Map.Entry;
+import javassist.ClassPool;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.ThirdParty;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexLeaves;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.TreeComplexLeavesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Int32StringUnion;
+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.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+
+public class LeafReferenceTest extends AbstractBindingRuntimeTest {
+
+    private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<TreeComplexLeaves> BA_TOP_LEVEL_LIST = InstanceIdentifier.builder(Top.class)
+            .child(TopLevelList.class, TOP_FOO_KEY).augmentation(TreeComplexLeaves.class).toInstance();
+
+    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 testCaseWithLeafReferencesType() {
+        TreeComplexLeaves binding = new TreeComplexLeavesBuilder()
+            .setIdentity(ThirdParty.class)
+            .setIdentityRef(ThirdParty.class)
+            .setSimpleType(10)
+            .setSimpleTypeRef(10)
+            .setSchemaUnawareUnion(new Int32StringUnion("foo"))
+            .setSchemaUnawareUnionRef(new Int32StringUnion(10))
+        .build();
+        Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> dom = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, binding);
+        Entry<InstanceIdentifier<?>, DataObject> readed = registry.fromNormalizedNode(dom.getKey(),dom.getValue());
+        TreeComplexLeaves readedAugment = ((TreeComplexLeaves) readed.getValue());
+
+        assertEquals(binding,readedAugment);
+
+    }
+
+
+
+}
index c1fd71df23a3065cebb6206481f52b184f08a986..0b45713b56dbe1da209cfac1bd7b51280bcfb8f7 100644 (file)
@@ -26,7 +26,6 @@ import static org.opendaylight.yangtools.binding.generator.util.Types.typeForCla
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findNodeInSchemaContext;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
-
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -296,7 +295,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 final Type type = ((TypeProviderImpl) typeProvider).generatedTypeForExtendedDefinitionType(typedef,
                         typedef);
                 if (type != null) {
-                    genCtx.get(module).addTypedefType(typedef.getPath(), type);
+                    final ModuleContext ctx = genCtx.get(module);
+                    ctx.addTypedefType(typedef.getPath(), type);
+                    ctx.addTypeToSchema(type,typedef);
                 }
             }
         }
index 0548503d357a9353537007794a002c6b9a8a97d7..8fd13c3cf999807ae8288205505f76a50a139de4 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 
 public final class ModuleContext {
     private GeneratedTypeBuilder moduleNode;
@@ -210,4 +211,8 @@ public final class ModuleContext {
         return Collections.unmodifiableMap(typeToSchema);
     }
 
+    protected void addTypeToSchema(Type type, TypeDefinition<?> typedef) {
+        typeToSchema.put(type, typedef);
+    }
+
 }
index a69e30ea1f437067035f5ffc459a637ad3c1e958..4a3d760172a379497a3e0d5408178285317abbe4 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * 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.generator.util;
 
 import com.google.common.base.Optional;
@@ -8,7 +15,6 @@ import com.google.common.collect.HashBiMap;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Multimap;
-
 import java.util.AbstractMap;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.Collection;
@@ -17,7 +23,6 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
@@ -42,6 +47,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -84,6 +90,8 @@ public class BindingRuntimeContext implements Immutable {
         for (ModuleContext ctx : modules.values()) {
             augmentationToSchema.putAll(ctx.getTypeToAugmentation());
             typeToDefiningSchema.putAll(ctx.getTypeToSchema());
+
+            ctx.getTypedefs();
             augmentableToAugmentations.putAll(ctx.getAugmentableToAugmentations());
             choiceToCases.putAll(ctx.getChoiceToCases());
             identities.putAll(ctx.getIdentities());
@@ -223,13 +231,28 @@ public class BindingRuntimeContext implements Immutable {
         return new ReferencedTypeImpl(type.getPackage().getName(), type.getSimpleName());
     }
 
+    /**
+     * Returns schema ({@link DataSchemaNode}, {@link AugmentationSchema} or {@link TypeDefinition})
+     * from which supplied class was generated. Returned schema may be augmented with
+     * additional information, which was not available at compile type
+     * (e.g. third party augmentations).
+     *
+     * @param type Binding Class for which schema should be retrieved.
+     * @return Instance of generated type (definition of Java API), along with
+     *     {@link DataSchemaNode}, {@link AugmentationSchema} or {@link TypeDefinition}
+     *     which was used to generate supplied class.
+     */
     public Entry<GeneratedType, Object> getTypeWithSchema(final Class<?> type) {
         Object schema = typeToDefiningSchema.get(referencedType(type));
         Type definedType = typeToDefiningSchema.inverse().get(schema);
         Preconditions.checkNotNull(schema);
         Preconditions.checkNotNull(definedType);
+        if(definedType instanceof GeneratedTypeBuilder) {
+            return new SimpleEntry<>(((GeneratedTypeBuilder) definedType).toInstance(), schema);
+        }
+        Preconditions.checkArgument(definedType instanceof GeneratedType,"Type {} is not GeneratedType",type);
+        return new SimpleEntry<>((GeneratedType) definedType,schema);
 
-        return new SimpleEntry<>(((GeneratedTypeBuilder) definedType).toInstance(), schema);
     }
 
     public ImmutableMap<Type, Entry<Type, Type>> getChoiceCaseChildren(final DataNodeContainer schema) {
diff --git a/code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/binding/rev140701/Int32StringUnionBuilder.java b/code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/binding/rev140701/Int32StringUnionBuilder.java
new file mode 100644 (file)
index 0000000..7c78c4b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701;
+
+
+/**
+ * The purpose of generated class in src/main/java for Union types is to create new instances of unions from a string representation.
+ * In some cases it is very difficult to automate it since there can be unions such as (uint32 - uint16), or (string - uint32).
+ * The reason behind putting it under src/main/java is:
+ * This class is generated in form of a stub and needs to be finished by the user. This class is generated only once to prevent
+ * loss of user code.
+ */
+public class Int32StringUnionBuilder {
+
+    public static Int32StringUnion getDefaultInstance(final String defaultValue) {
+        try {
+            return new Int32StringUnion(Integer.parseInt(defaultValue));
+        } catch (NumberFormatException e) {
+            return new Int32StringUnion(defaultValue);
+        }
+    }
+
+}
index 7363f38c46ff87e5223cc2f91011d686949c667f..c26559b0714b081b92ea6828a19933c4d0e19d8e 100644 (file)
@@ -19,6 +19,10 @@ module opendaylight-yangtools-augment-test {
         "Test model for testing data broker with nested lists.";
     }
 
+    identity third-party {
+        base test:test-root;
+    }
+
     grouping leaf-from-grouping {
         leaf leaf-from-grouping {
             type string;
@@ -35,7 +39,6 @@ module opendaylight-yangtools-augment-test {
                 type string;
             }
         }
-    
     }
 
     augment "/test:top/test:top-level-list" {
@@ -43,6 +46,36 @@ module opendaylight-yangtools-augment-test {
         uses leaf-from-grouping;
     }
 
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-complex-leaves;
+        leaf simple-type {
+            type int32;
+        }
+        leaf identity {
+            type test:test-identityref;
+        }
+        leaf schema-unaware-union {
+            type test:int32-string-union;
+        }
+
+        leaf simple-type-ref {
+            type leafref {
+                path "../simple-type";
+            }
+        }
+        leaf identity-ref {
+            type leafref {
+                path "../identity";
+            }
+        }
+        leaf schema-unaware-union-ref {
+            type leafref {
+                path "../schema-unaware-union";
+            }
+        }
+    }
+
+
     augment "/test:put-top/test:input/test:top-level-list" {
         ext:augment-identifier rpc-leaf-only-uses-augment;
         uses leaf-from-grouping;
index c5e5ce23b7ae37532a8d5c2e57849e5820376105..8042e3dd8c345c4a8b839f1832879138c7243dda 100644 (file)
@@ -13,6 +13,29 @@ module opendaylight-yangtools-binding-test {
         "Test model for testing data broker with nested lists.";
     }
 
+    typedef int32-string-union {
+        type union {
+            type int32;
+            type string;
+        }
+    }
+
+    identity test-root;
+
+    identity test-one {
+        base test-root;
+    }
+
+    identity test-two {
+        base test-root;
+    }
+
+    typedef test-identityref {
+        type identityref {
+            base test-root;
+        }
+    }
+
     grouping two-level-list {
         list top-level-list {
             description