Merge "Fix for bug 211, where direct write and read of augmentation was not processed...
authorEd Warnicke <eaw@cisco.com>
Mon, 9 Dec 2013 17:10:49 +0000 (17:10 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 9 Dec 2013 17:10:49 +0000 (17:10 +0000)
13 files changed:
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java
opendaylight/md-sal/sal-binding-dom-it/pom.xml
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend

index a31d3eedd2ee5ba0e08b203fdbb77647ea39e523..b9a4fe87ac80518d054372b5d1056227ea683efb 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.binding.dom.serializer.api;
 
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.Identifier;
 
@@ -14,6 +15,8 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCode
 public interface CodecRegistry {
 
     InstanceIdentifierCodec getInstanceIdentifierCodec();
+    
+    IdentitityCodec<?> getIdentityCodec();
 
     <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> object);
 
@@ -22,6 +25,8 @@ public interface CodecRegistry {
     <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object);
 
     <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object);
+    
+    <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec);
 
     Class<?> getClassForPath(List<QName> names);
 
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java
new file mode 100644 (file)
index 0000000..0c480f5
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface IdentitityCodec<T extends BaseIdentity> extends BindingCodec<QName, Class<T>>{
+
+    @Override
+    public QName serialize(Class<T> input);
+    
+    @Override
+    public Class<T> deserialize(QName input);
+}
index 172fb05292043e49612a8bee700750c6ca68810f..fa2d32a1387d95aa6a65c251279465ca3aaf27f6 100644 (file)
@@ -3,6 +3,7 @@ package org.opendaylight.controller.sal.binding.dom.serializer.impl;
 import java.lang.reflect.Field;
 import java.util.Map;
 
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -15,6 +16,8 @@ public class CodecMapping {
     private static final Logger LOG = LoggerFactory.getLogger(CodecMapping.class);
     
     public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC";
+    public static final String IDENTITYREF_CODEC = "IDENTITYREF_CODEC";
+    
     public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE";
     public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE";
     public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC";
@@ -27,7 +30,22 @@ public class CodecMapping {
                 instanceIdField.set(null, codec);
             }
         } catch (NoSuchFieldException e) {
-           LOG.debug("Instance identifier codec is not needed for {}",obj.getName(),e);
+           LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
+        } catch (SecurityException | IllegalAccessException e) {
+            LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
+        }
+    }
+
+
+    public static void setIdentityRefCodec(Class<?> obj,IdentitityCodec<?> codec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = obj.getField(IDENTITYREF_CODEC);
+            if(obj != null) {
+                instanceIdField.set(null, codec);
+            }
+        } catch (NoSuchFieldException e) {
+           LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
         } catch (SecurityException | IllegalAccessException e) {
             LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
         }
@@ -71,4 +89,18 @@ public class CodecMapping {
                 LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
             }
     }
+    
+    
+    public static BindingCodec<?,?> getAugmentationCodec(Class<? extends BindingCodec<?,?>> dataCodec) {
+            Field instanceIdField;
+            try {
+                instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+                return (BindingCodec<?,?>) instanceIdField.get(null);
+            } catch (NoSuchFieldException e) {
+                LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e);
+            } catch (SecurityException | IllegalAccessException e) {
+                LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
+            }
+            return null;
+    }
 }
index d0b114e3c37930727146fa6c3cb7a1e191a2ef61..04b8674727ced600871d3e9c44b05657c95d6658 100644 (file)
@@ -13,7 +13,10 @@ class IntermediateMapping {
     
     
     
-    static def Node<?> toNode(Map map) {
+    static def Node<?> toNode(Map<?,?> map) {
+        if(map instanceof Node<?>) {
+            return map as Node<?>;
+        }
         val nodeMap = map as Map<QName,Object>;
         Preconditions.checkArgument(map.size == 1);
         val elem = nodeMap.entrySet.iterator.next;
@@ -22,10 +25,15 @@ class IntermediateMapping {
         toNodeImpl(qname, value);
     }
 
+
     static def dispatch Node<?> toNodeImpl(QName name, List<?> objects) {
         val values = new ArrayList<Node<?>>(objects.size);
         for (obj : objects) {
-            values.add(toNode(obj as Map));
+            if(obj instanceof Node<?>) {
+                values.add(obj as Node<?>);
+            } else if(obj instanceof Map<?,?>) {
+                values.add(toNode(obj as Map<?,?>));
+            }
         }
         return new CompositeNodeTOImpl(name, null, values);
     }
index d33272d6413bfa90628f49a459671eab756ef2d0..39bd0816f50fb63e68bbbdb85ca7cbdce74812b6 100644 (file)
@@ -1,7 +1,9 @@
 package org.opendaylight.controller.sal.binding.dom.serializer.impl;
 
+import java.awt.CompositeContext;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -12,11 +14,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.Set;
 import java.util.WeakHashMap;
 
+import org.apache.commons.lang3.text.translate.AggregateTranslator;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec;
@@ -24,6 +28,7 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName;
 import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils;
@@ -34,6 +39,7 @@ import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -41,6 +47,7 @@ import org.opendaylight.yangtools.yang.binding.Identifier;
 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.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -61,10 +68,12 @@ import static org.opendaylight.controller.sal.binding.dom.serializer.impl.Interm
 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.CycleDetectingLockFactory.WithExplicitOrdering;
 
 public class LazyGeneratedCodecRegistry implements //
@@ -76,27 +85,31 @@ public class LazyGeneratedCodecRegistry implements //
     private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
 
     private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+    private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
 
     private TransformerGenerator generator;
 
     // Concrete class to codecs
-    private Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
-    private Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
-    private Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
-    private Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
-    private Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
-
+    private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, AugmentationCodec<?>> augmentationCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, QName> identityQNames = new WeakHashMap<>();
+    private static final Map<QName, Type> qnamesToIdentityMap = new ConcurrentHashMap<>();
     /** Binding type to encountered classes mapping **/
     @SuppressWarnings("rawtypes")
-    Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
+    private static final Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
 
     @SuppressWarnings("rawtypes")
-    private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
 
     private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
 
-    Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
-    Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+    private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+    private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+    private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
 
     private SchemaContext currentSchema;
 
@@ -115,8 +128,56 @@ public class LazyGeneratedCodecRegistry implements //
 
     @Override
     public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
-        // TODO Auto-generated method stub
-        return null;
+        AugmentationCodec<T> codec = null;
+        @SuppressWarnings("rawtypes")
+        AugmentationCodec potentialCodec = augmentationCodecs.get(object);
+        if (potentialCodec != null) {
+            codec = potentialCodec;
+        } else
+            try {
+                Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
+                        .augmentationTransformerFor(object);
+                BindingCodec<Map<QName, Object>, Object> rawCodec = augmentRawCodec.newInstance();
+                codec = new AugmentationCodecWrapper<T>(rawCodec);
+                augmentationCodecs.put(augmentRawCodec, codec);
+            } catch (InstantiationException e) {
+                LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e);
+            } catch (IllegalAccessException e) {
+                LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e);
+            }
+        Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
+        if (objectSupertype != null) {
+            getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec);
+        } else {
+            LOG.warn("Could not find augmentation target for augmentation {}", object);
+        }
+        return codec;
+    }
+
+    private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
+            final Class<? extends Augmentation<?>> augmentation) {
+        try {
+            Class<? extends Augmentable<?>> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(),
+                    new Callable<Class<? extends Augmentable<?>>>() {
+                        @Override
+                        @SuppressWarnings("unchecked")
+                        public Class<? extends Augmentable<?>> call() throws Exception {
+                            for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) {
+                                if (supertype instanceof ParameterizedType
+                                        && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) {
+                                    ParameterizedType augmentationGeneric = (ParameterizedType) supertype;
+                                    return (Class<? extends Augmentable<?>>) augmentationGeneric
+                                            .getActualTypeArguments()[0];
+                                }
+                            }
+                            return null;
+                        }
+                    });
+            return ret;
+        } catch (Exception e) {
+            LOG.error("Could not find augmentable for {}", augmentation, e);
+            return null;
+        }
     }
 
     @Override
@@ -165,7 +226,6 @@ public class LazyGeneratedCodecRegistry implements //
         return newWrapper;
     }
 
-    @Override
     @SuppressWarnings("rawtypes")
     public void bindingClassEncountered(Class cls) {
 
@@ -268,9 +328,21 @@ public class LazyGeneratedCodecRegistry implements //
         return newWrapper;
     }
 
+    @Override
+    public IdentitityCodec<?> getIdentityCodec() {
+        return identityRefCodec;
+    }
+
+    @Override
+    public <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec) {
+        bindingClassEncountered(codec);
+        return identityRefCodec;
+    }
+
     @Override
     public void onCodecCreated(Class<?> cls) {
         CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
+        CodecMapping.setIdentityRefCodec(cls, identityRefCodec);
     }
 
     @Override
@@ -316,6 +388,10 @@ public class LazyGeneratedCodecRegistry implements //
 
     public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
         pathToType.putAll(context.getChildNodes());
+        qnamesToIdentityMap.putAll(context.getIdentities());
+        for(Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
+            typeToQname.put(new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),identity.getKey());
+        }
         captureCases(context.getCases(), schemaContext);
     }
 
@@ -324,7 +400,6 @@ public class LazyGeneratedCodecRegistry implements //
             ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
                     .getValue().getName());
 
-            LOG.info("Case path: {} Type : {}", caseNode.getKey(), caseNode.getValue().getFullyQualifiedName());
             pathToType.put(caseNode.getKey(), caseNode.getValue());
 
             ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
@@ -371,10 +446,10 @@ public class LazyGeneratedCodecRegistry implements //
             if (path != null && (type = pathToType.get(path)) != null) {
                 ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
                 ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
-                if(partialCodec.getSchema() == null ) {
+                if (partialCodec.getSchema() == null) {
                     partialCodec.setSchema(caseNode);
                 }
-                
+
                 Class<?> caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName());
                 if (caseClass != null) {
                     getCaseCodecFor(caseClass);
@@ -402,7 +477,7 @@ public class LazyGeneratedCodecRegistry implements //
 
     }
 
-    private AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
+    public AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
         AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
         if (ret != null) {
             return ret;
@@ -739,7 +814,7 @@ public class LazyGeneratedCodecRegistry implements //
 
         private final Class augmentableType;
 
-        Map<Class, BindingCodec> rawAugmentationCodecs = new WeakHashMap<>();
+        Map<Class, AugmentationCodec<?>> localAugmentationCodecs = new WeakHashMap<>();
 
         public AugmentableCompositeCodec(Class type) {
             checkArgument(Augmentable.class.isAssignableFrom(type));
@@ -772,53 +847,33 @@ public class LazyGeneratedCodecRegistry implements //
         private List serializeImpl(Map<Class, Augmentation> input) {
             List ret = new ArrayList<>();
             for (Entry<Class, Augmentation> entry : input.entrySet()) {
-                BindingCodec codec = getRawCodecForAugmentation(entry.getKey());
-                List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue()));
-                ret.addAll(output);
+                AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
+                CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
+                ret.addAll(node.getChildren());
             }
             return ret;
         }
 
-        private BindingCodec getRawCodecForAugmentation(Class key) {
-            BindingCodec ret = rawAugmentationCodecs.get(key);
-            if (ret != null) {
-                return ret;
-            }
-            try {
-                Class<? extends BindingCodec> retClass = generator.augmentationTransformerFor(key);
-                ret = retClass.newInstance();
-                rawAugmentationCodecs.put(key, ret);
-                return ret;
-            } catch (InstantiationException e) {
-                LOG.error("Can not instantiate raw augmentation codec {}", key.getSimpleName(), e);
-            } catch (IllegalAccessException e) {
-                LOG.debug("BUG: Constructor for {} is not accessible.", key.getSimpleName(), e);
-            }
-            return null;
+        public synchronized <T extends Augmentation<?>> void addAugmentationCodec(Class<T> augmentationClass,
+                AugmentationCodec<T> value) {
+            localAugmentationCodecs.put(augmentationClass, value);
         }
 
         @Override
         public Map<Class, Augmentation> deserialize(Object input) {
             Map<Class, Augmentation> ret = new HashMap<>();
             if (input instanceof CompositeNode) {
-                for (Entry<Class, BindingCodec> codec : rawAugmentationCodecs.entrySet()) {
-                    Augmentation value = (Augmentation) codec.getValue().deserialize(input);
-                    if (value != null) {
-                        ret.put(codec.getKey(), value);
+                List<Entry<Class, AugmentationCodec<?>>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet());
+                for (Entry<Class, AugmentationCodec<?>> codec : codecs) {
+                    ValueWithQName<?> value = codec.getValue().deserialize((CompositeNode) input);
+                    if (value != null && value.getValue() != null) {
+                        ret.put(codec.getKey(), (Augmentation) value.getValue());
                     }
                 }
             }
             return ret;
         }
 
-        public Map<Class, BindingCodec> getRawAugmentationCodecs() {
-            return rawAugmentationCodecs;
-        }
-
-        public void setRawAugmentationCodecs(Map<Class, BindingCodec> rawAugmentationCodecs) {
-            this.rawAugmentationCodecs = rawAugmentationCodecs;
-        }
-
         public Class getAugmentableType() {
             return augmentableType;
         }
@@ -847,4 +902,82 @@ public class LazyGeneratedCodecRegistry implements //
             return getDelegate().serialize(input);
         }
     }
+
+    private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
+            Delegator<BindingCodec> {
+
+        private BindingCodec delegate;
+
+        public AugmentationCodecWrapper(BindingCodec<Map<QName, Object>, Object> rawCodec) {
+            this.delegate = rawCodec;
+        }
+
+        @Override
+        public BindingCodec getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            @SuppressWarnings("unchecked")
+            List<Map<QName, Object>> rawValues = (List<Map<QName, Object>>) getDelegate().serialize(input);
+            List<Node<?>> serialized = new ArrayList<>(rawValues.size());
+            for (Map<QName, Object> val : rawValues) {
+                serialized.add(toNode(val));
+            }
+            return new CompositeNodeTOImpl(input.getQname(), null, serialized);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            Object rawCodecValue = getDelegate().deserialize((Map<QName, Object>) input);
+            return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
+        }
+    }
+
+    private class IdentityCompositeCodec implements IdentitityCodec {
+
+        @Override
+        public Object deserialize(Object input) {
+            checkArgument(input instanceof QName);
+            return deserialize((QName) input);
+        }
+
+        @Override
+        public Class<?> deserialize(QName input) {
+            Type type = qnamesToIdentityMap.get(input);
+            if(type == null) {
+                return null;
+            }
+            ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+            WeakReference<Class> softref = typeToClass.get(typeref);
+            if(softref == null) {
+                return null;
+            }
+            return softref.get();
+        }
+
+        @Override
+        public QName serialize(Class input) {
+            checkArgument(BaseIdentity.class.isAssignableFrom(input));
+            bindingClassEncountered(input);
+            QName qname = identityQNames.get(input);
+            if(qname != null) {
+                return qname;
+            }
+            ConcreteType typeref = Types.typeForClass(input);
+            qname = typeToQname.get(typeref);
+            if(qname != null) {
+                identityQNames.put(input, qname);
+            }
+            return qname;
+        }
+
+        @Override
+        public Object serialize(Object input) {
+            checkArgument(input instanceof Class);
+            return serialize((Class) input);
+        }
+    }
 }
\ No newline at end of file
index cb25f4da8bb9247845c251ed95b67ee6ffeca4d5..13975cad4c807abc636870f99fbea2a921e4a312 100644 (file)
@@ -37,6 +37,12 @@ import org.opendaylight.controller.sal.binding.impl.connect.dom.DeserializationE
 import java.util.concurrent.Callable
 import org.opendaylight.yangtools.yang.binding.Augmentation
 import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils
+import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
 
 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
 
@@ -112,9 +118,21 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
 
     override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
         Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+        
+        try {
         val key = toDataDom(entry.key)
-        val data = toCompositeNodeImpl(entry.value);
+        var CompositeNode data;
+        if(Augmentation.isAssignableFrom(entry.key.targetType)) {
+            data = toCompositeNodeImpl(key,entry.value);
+        } else {
+          data = toCompositeNodeImpl(entry.value);
+        }
         return new SimpleEntry(key, data);
+        
+        } catch (Exception e) {
+            LOG.error("Error during serialization for {}.", entry.key,e);
+            throw e;
+        }
     }
 
     private def CompositeNode toCompositeNodeImpl(DataObject object) {
@@ -124,6 +142,26 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         val ret = codec.serialize(new ValueWithQName(null, object));
         return ret as CompositeNode;
     }
+    
+    
+    private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
+       
+        //val cls = object.implementedInterface;
+        //waitForSchema(cls);
+        val last = identifier.path.last;
+        val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
+        val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
+        if(last instanceof NodeIdentifierWithPredicates) {
+            val predicates = last as NodeIdentifierWithPredicates;
+            val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
+            for(predicate : predicates.keyValues.entrySet) {
+                newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
+            }
+            newNodes.addAll(ret.children);
+            return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
+        }
+        return ret as CompositeNode;
+    }
 
     private def void waitForSchema(Class<? extends DataContainer> class1) {
         if(Augmentation.isAssignableFrom(class1)) {
index 0316614aa1269a93eb8d6aa3f7d2e3fd2a4438a7..b2d25af8850bd5b40a369e136baf710d9e669735 100644 (file)
@@ -91,6 +91,8 @@ class TransformerGenerator {
 
     @Property
     var GeneratorListener listener;
+    
+    public static val CLASS_TYPE = Types.typeForClass(Class);
 
     public new(ClassPool pool) {
         classPool = pool;
@@ -269,6 +271,7 @@ class TransformerGenerator {
             val ctCls = createClass(inputType.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 staticQNameField(node.QName);
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
@@ -351,6 +354,7 @@ class TransformerGenerator {
                 staticQNameField(node.QName);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
@@ -409,6 +413,7 @@ class TransformerGenerator {
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 staticQNameField(node.QName);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
@@ -459,6 +464,7 @@ class TransformerGenerator {
                 staticQNameField(node.augmentationQName);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
@@ -466,7 +472,7 @@ class TransformerGenerator {
                         {
                             //System.out.println("Qname " + $1);
                             //System.out.println("Value " + $2);
-                            «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+                            «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName());
                             java.util.List _childNodes = new java.util.ArrayList();
                             «type.resolvedName» value = («type.resolvedName») $2;
                             «FOR child : node.childNodes»
@@ -540,6 +546,7 @@ class TransformerGenerator {
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 //staticQNameField(inputType);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 staticField(it, CLASS_TO_CASE_MAP, Map)
                 staticField(it, COMPOSITE_TO_CASE, Map)
                 //staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
@@ -828,6 +835,7 @@ class TransformerGenerator {
                 if (hasYangBinding) {
                     implementsType(BINDING_CODEC)
                     staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
                     implementsType(BindingDeserializer.asCtClass)
                 }
                 method(Object, "toDomValue", Object) [
@@ -1020,10 +1028,10 @@ class TransformerGenerator {
 
     private def dispatch String deserializeValue(Type type, String domParameter) {
         if (INSTANCE_IDENTIFIER.equals(type)) {
-
             return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
+        } else if (CLASS_TYPE.equals(type)) {
+            return '''(«Class.name») «IDENTITYREF_CODEC».deserialize(«domParameter»)'''
         }
-
         return '''(«type.resolvedName») «domParameter»'''
 
     }
@@ -1192,6 +1200,8 @@ class TransformerGenerator {
     private def dispatch serializeValue(Type signature, String property) {
         if (INSTANCE_IDENTIFIER == signature) {
             return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
+        }else if (CLASS_TYPE.equals(signature)) {
+            return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)'''
         }
         return '''«property»''';
     }
index 5f3189f7d2a196593ec2c903c1a2eb717c488ac5..9eff29f8cc4e256f6d9c3163cb551650e226b02f 100644 (file)
@@ -22,6 +22,8 @@ import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
 import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcError;
@@ -61,8 +63,22 @@ public class BindingIndependentDataServiceConnector implements //
     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
         try {
             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
+            
+            
             CompositeNode result = biDataService.readOperationalData(biPath);
+            Class<? extends DataObject> targetType = path.getTargetType();
+            
+            if(Augmentation.class.isAssignableFrom(targetType)) {
+                path = mappingService.fromDataDom(biPath);
+                Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
+                DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
+                if(parentTo instanceof Augmentable<?>) {
+                    return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
+                }
+                
+            }
             return mappingService.dataObjectFromDataDom(path, result);
+            
         } catch (DeserializationException e) {
             throw new IllegalStateException(e);
         }
@@ -116,7 +132,7 @@ public class BindingIndependentDataServiceConnector implements //
                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
                 target.putConfigurationData(baKey, baData);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+                LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
             }
         }
         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
@@ -127,7 +143,7 @@ public class BindingIndependentDataServiceConnector implements //
                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
                 target.putOperationalData(baKey, baData);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+                LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
             }
         }
         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
@@ -136,7 +152,7 @@ public class BindingIndependentDataServiceConnector implements //
                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
                 target.removeConfigurationData(baEntry);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry, e);
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
             }
         }
         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
@@ -145,7 +161,7 @@ public class BindingIndependentDataServiceConnector implements //
                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
                 target.removeOperationalData(baEntry);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e);
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
             }
         }
         return target;
index 9a143d3f008f5843ce36676f16afc5a293bf6143..6525fa078ed991ed26bed4e9491b79b4dd4ebe95 100644 (file)
@@ -49,7 +49,7 @@
     </build>
 
     <dependencies>
-    <dependency>
+        <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-broker-impl</artifactId>
             <version>1.0-SNAPSHOT</version>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+            <version>1.7.2</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java
new file mode 100644 (file)
index 0000000..96d0361
--- /dev/null
@@ -0,0 +1,176 @@
+package org.opendaylight.controller.sal.binding.test.bugfix;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import static org.junit.Assert.*;
+
+public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener {
+
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final String NODE_ID = "openflow:1";
+
+    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+
+    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+            NODE_ID);
+
+    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+            .toInstance();
+
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
+            .builder(NODES_INSTANCE_ID_BA) //
+            .child(Node.class, NODE_KEY).toInstance();
+    
+    
+    private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier//
+            .builder(NODES_INSTANCE_ID_BA) //
+            .child(Node.class, NODE_KEY) //
+            .augmentation(FlowCapableNode.class) //
+            .child(SupportedActions.class)
+            .toInstance();
+    
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .toInstance();
+    private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
+
+    
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+                    .node(Nodes.QNAME) //
+                    .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+                    .node(SUPPORTED_ACTIONS_QNAME) //
+                    .toInstance();
+    
+    private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
+
+    
+    
+    /**
+     * Test for Bug 148
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void putNodeAndAugmentation() throws Exception {
+
+        baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
+        
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setId(new NodeId(NODE_ID));
+        nodeBuilder.setKey(NODE_KEY);
+        DataModificationTransaction baseTransaction = baDataService.beginTransaction();
+        baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
+        RpcResult<TransactionStatus> result = baseTransaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        assertNotNull(receivedChangeEvent);
+        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+        assertNotNull(node);
+        assertEquals(NODE_KEY, node.getKey());
+        
+        FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
+        fnub.setHardware("Hardware Foo");
+        fnub.setManufacturer("Manufacturer Foo");
+        fnub.setSerialNumber("Serial Foo");
+        fnub.setDescription("Description Foo");
+        fnub.setSoftware("JUnit emulated");
+        FlowCapableNode fnu = fnub.build();
+        InstanceIdentifier<FlowCapableNode> augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance();
+        DataModificationTransaction augmentedTransaction = baDataService.beginTransaction();
+        augmentedTransaction.putOperationalData(augmentIdentifier, fnu);
+        
+        result = augmentedTransaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        
+        Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+        assertNotNull(node);
+        assertEquals(NODE_KEY, augmentedNode.getKey());
+        System.out.println("Before assertion");
+        assertNotNull(augmentedNode.getAugmentation(FlowCapableNode.class));
+        FlowCapableNode readedAugmentation = augmentedNode.getAugmentation(FlowCapableNode.class);
+        assertEquals(fnu.getDescription(), readedAugmentation.getDescription());
+        assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+        testNodeRemove();
+    }
+
+    
+    private void testNodeRemove() throws Exception {
+        DataModificationTransaction transaction = baDataService.beginTransaction();
+        transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
+        RpcResult<TransactionStatus> result = transaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+        assertNull(node);
+    }
+
+    private void verifyNodes(Nodes nodes,Node original) {
+        assertNotNull(nodes);
+        assertNotNull(nodes.getNode());
+        assertEquals(1, nodes.getNode().size());
+        Node readedNode = nodes.getNode().get(0);
+        assertEquals(original.getId(), readedNode.getId());
+        assertEquals(original.getKey(), readedNode.getKey());
+        
+        FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
+        FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
+        assertNotNull(fnu);
+        assertEquals(fnu.getDescription(), readedAugment.getDescription());
+        assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
+        
+    }
+
+    private void assertBindingIndependentVersion(
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) {
+        CompositeNode node = biDataService.readOperationalData(nodeId);
+        assertNotNull(node);
+    }
+
+    private Nodes checkForNodes() {
+        return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+    }
+    
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        receivedChangeEvent = change;
+    }
+
+}
index 7fe5f0c5bea91336c103ce3f6224ed6986d9c545..7111501b5392e174d25b16d456da6493cdfe3d77 100644 (file)
@@ -116,6 +116,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest {
     
     @Test
     public void simpleModifyOperation() throws Exception {
+        assertNull(biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI));
         
         registerCommitHandler();
         
@@ -123,7 +124,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest {
         DataModificationTransaction biTransaction = biDataService.beginTransaction();
         biTransaction.putConfigurationData(FLOW_INSTANCE_ID_BI, domflow);
         RpcResult<TransactionStatus> biResult = biTransaction.commit().get();
-        
+        assertEquals(TransactionStatus.COMMITED, biResult.getResult());
         assertNotNull(modificationCapture);
         Flow flow = (Flow) modificationCapture.getCreatedConfigurationData().get(FLOW_INSTANCE_ID_BA);
         assertNotNull(flow);
index 1b0fda41ca723d67f640de2418ebd6e33e153751..df6b58c8971331b74c89418a6e1ee039e1fcdf10 100644 (file)
@@ -9,9 +9,12 @@ import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.common.RpcResult
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.slf4j.LoggerFactory
 
 class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
 
+
+    val static LOG = LoggerFactory.getLogger(BrokerFacade)
     val static BrokerFacade INSTANCE = new BrokerFacade
 
     @Property
@@ -38,11 +41,13 @@ class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
 
     override readConfigurationData(InstanceIdentifier path) {
         checkPreconditions
+        LOG.info("Read Configuration via Restconf: {}",path)
         return dataService.readConfigurationData(path);
     }
 
     override readOperationalData(InstanceIdentifier path) {
         checkPreconditions
+        LOG.info("Read Operational via Restconf: {}",path)
         return dataService.readOperationalData(path);
     }
 
index 602e8b92425ea9d1ab26bd784893f7ff3a3a9ba1..fed56fe297a8ed9cc929437329701799ce06ccfb 100644 (file)
@@ -33,6 +33,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
 
 import static com.google.common.base.Preconditions.*
 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
 
 class ControllerContext implements SchemaServiceListener {
 
@@ -291,7 +292,16 @@ class ControllerContext implements SchemaServiceListener {
         checkArgument(node instanceof LeafSchemaNode);
         val urlDecoded = URLDecoder.decode(uriValue);
         val typedef = (node as LeafSchemaNode).type;
-        val decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+        var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+        if(decoded == null) {
+            var baseType = typedef
+            while (baseType.baseType != null) {
+                baseType = baseType.baseType;
+            }
+            if(baseType instanceof IdentityrefTypeDefinition) {
+                decoded = toQName(urlDecoded)
+            }
+        }
         map.put(node.QName, decoded);
     }