Fix for Bug 144, Bug 147, 148 - improved codec 81/2781/13
authorTony Tkacik <ttkacik@cisco.com>
Fri, 15 Nov 2013 14:43:43 +0000 (15:43 +0100)
committerEd Warnicke <eaw@cisco.com>
Tue, 19 Nov 2013 16:33:05 +0000 (10:33 -0600)
  - Added defensive locking mechanism to class generation code
  - Provider's and Consumer's crossing boundatories between
    brokers are blocked util their YANG schema is ready and processed.
  - Added set of APIs to make generated codec contracts and interactions
    more explicit.
  - Extracted augmentation serialization / deserialization to sepparate
    generated codec (one codec per augmentation type).
  - Fixed NPE

Change-Id: I299924e911f63aba1fdeca3debeb8cc80f66f5ac
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
36 files changed:
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.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 [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java [new file with mode: 0644]
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/NotificationBrokerImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/MappingServiceImpl.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java [deleted file]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java [new file with mode: 0644]

index 5b11ec7..b6dcde1 100644 (file)
@@ -8,7 +8,6 @@ import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeC
 import java.util.Set
 import java.util.HashMap
 import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import static org.opendaylight.controller.sal.binding.codegen.impl.XtendHelper.*
 import org.opendaylight.yangtools.yang.binding.DataContainer
 import org.opendaylight.yangtools.yang.binding.RpcImplementation
 
index 19737b8..802e7ac 100644 (file)
@@ -10,10 +10,15 @@ import javassist.Modifier
 import javassist.NotFoundException
 import javassist.LoaderClassPath
 import javassist.ClassClassPath
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
 
 class JavassistUtils {
 
     ClassPool classPool
+    
+    @Property
+    val Lock lock = new ReentrantLock();
 
     new(ClassPool pool) {
         classPool = pool;
@@ -49,12 +54,14 @@ class JavassistUtils {
     }
 
     def CtClass createClass(String fqn, ClassGenerator cls) {
+        
         val target = classPool.makeClass(fqn);
         cls.process(target);
         return target;
     }
 
     def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
+        
         val target = classPool.makeClass(fqn);
         target.implementsType(superInterface);
         cls.process(target);
@@ -76,6 +83,13 @@ class JavassistUtils {
         addField(field);
         return field;
     }
+    
+    def CtField staticField(CtClass it, String name, Class<?> returnValue) {
+        val field = new CtField(returnValue.asCtClass, name, it);
+        field.modifiers = Modifier.PUBLIC + Modifier.STATIC
+        addField(field);
+        return field;
+    }
 
     def get(ClassPool pool, Class<?> cls) {
         try {
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java
new file mode 100644 (file)
index 0000000..cdddec7
--- /dev/null
@@ -0,0 +1,15 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface AugmentationCodec<A extends Augmentation<?>> extends DomCodec<A> {
+
+    
+    @Override
+    public CompositeNode serialize(ValueWithQName<A> input);
+    
+    @Override
+    public ValueWithQName<A> deserialize(Node<?> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java
new file mode 100644 (file)
index 0000000..d545b72
--- /dev/null
@@ -0,0 +1,16 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface ChoiceCaseCodec<C extends DataContainer> extends DataContainerCodec<C> {
+
+    @Override
+    public CompositeNode serialize(ValueWithQName<C> input);
+    
+    @Override
+    public ValueWithQName<C> deserialize(Node<?> input);
+    
+    public boolean isAcceptable(Node<?> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java
new file mode 100644 (file)
index 0000000..21bb1cf
--- /dev/null
@@ -0,0 +1,12 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface ChoiceCodec<C> extends DomCodec<C> {
+
+    @Override
+    public Node<?> serialize(ValueWithQName<C> input);
+    
+    @Override
+    public ValueWithQName<C> deserialize(Node<?> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java
new file mode 100644 (file)
index 0000000..1a02ea1
--- /dev/null
@@ -0,0 +1,32 @@
+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.DataContainer;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
+
+
+public interface CodecRegistry {
+
+    InstanceIdentifierCodec getInstanceIdentifierCodec();
+
+    <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> object);
+
+    <T extends Identifiable<?>> IdentifierCodec<?> getIdentifierCodecForIdentifiable(Class<T> object);
+
+    <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object);
+
+    <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object);
+
+    Class<?> getClassForPath(List<QName> names);
+
+    IdentifierCodec<?> getKeyCodecForPath(List<QName> names);
+    
+    
+    void bindingClassEncountered(Class<?> cls);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java
new file mode 100644 (file)
index 0000000..683faaf
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface DataContainerCodec<T extends DataContainer> extends  DomCodec<T> {
+
+
+    @Override
+    public ValueWithQName<T> deserialize(Node<?> input);
+    
+    @Override
+    public CompositeNode serialize(ValueWithQName<T> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java
new file mode 100644 (file)
index 0000000..76969ab
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface DomCodec<I> extends BindingCodec<Node<?>, ValueWithQName<I>>{
+    
+    
+    @Override
+    public Node<?> serialize(ValueWithQName<I> input);
+    
+    
+    @Override
+    public ValueWithQName<I> deserialize(Node<?> input);
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java
new file mode 100644 (file)
index 0000000..933b884
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface IdentifierCodec<I extends Identifier<?>> extends DomCodec<I> {
+
+    @Override
+    public ValueWithQName<I> deserialize(Node<?> input);
+    
+    @Override
+    public CompositeNode serialize(ValueWithQName<I> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..7fbb79d
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface InstanceIdentifierCodec extends BindingCodec<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier,InstanceIdentifier<?>> {
+
+    @Override
+    public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier serialize(InstanceIdentifier<?> input);
+    
+    @Override
+    public InstanceIdentifier<?> deserialize(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java
new file mode 100644 (file)
index 0000000..442df01
--- /dev/null
@@ -0,0 +1,72 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+public class ValueWithQName<V> implements Entry<QName, V>{
+    
+    final QName qname;
+    final V value;
+    
+    public ValueWithQName(QName qname, V value) {
+        super();
+        this.qname = qname;
+        this.value = value;
+    }
+
+    public QName getQname() {
+        return qname;
+    }
+
+    public V getValue() {
+        return value;
+    }
+    
+    @Override
+    public QName getKey() {
+        return qname;
+    }
+    
+    @Override
+    public V setValue(V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        @SuppressWarnings("rawtypes")
+        ValueWithQName other = (ValueWithQName) obj;
+        if (qname == null) {
+            if (other.qname != null)
+                return false;
+        } else if (!qname.equals(other.qname))
+            return false;
+        if (value == null) {
+            if (other.value != null) {
+                return false;
+            }
+        } else if (!value.equals(other.value)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java
new file mode 100644 (file)
index 0000000..c2b5635
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+public interface BindingClassListener {
+
+    void onBindingClassCaptured(Class<?> cls);
+    
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java
new file mode 100644 (file)
index 0000000..19e9961
--- /dev/null
@@ -0,0 +1,79 @@
+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.InstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public class CodecMapping {
+
+    public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_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";
+    
+    public static void setIdentifierCodec(Class obj,InstanceIdentifierCodec codec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = obj.getField(INSTANCE_IDENTIFIER_CODEC);
+            instanceIdField.set(null, codec);
+        } catch (NoSuchFieldException e) {
+           // NOOP
+        } catch (SecurityException e) {
+            // NOOP
+        } catch (IllegalAccessException e) {
+            // NOOp
+        }
+    }
+
+    public static void setClassToCaseMap(Class<? extends BindingCodec> codec,
+            Map<Class,BindingCodec> classToCaseRawCodec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = codec.getField(CLASS_TO_CASE_MAP);
+            instanceIdField.set(null, classToCaseRawCodec);
+        } catch (NoSuchFieldException e) {
+           // NOOP
+        } catch (SecurityException e) {
+            // NOOP
+        } catch (IllegalAccessException e) {
+            // NOOp
+        }
+        
+        
+    }
+
+    public static void setCompositeNodeToCaseMap(Class<? extends BindingCodec> codec,
+            Map<CompositeNode,BindingCodec> compositeToCase) {
+        Field instanceIdField;
+        try {
+            instanceIdField = codec.getField(COMPOSITE_TO_CASE);
+            instanceIdField.set(null, compositeToCase);
+        } catch (NoSuchFieldException e) {
+           // NOOP
+        } catch (SecurityException e) {
+            // NOOP
+        } catch (IllegalAccessException e) {
+            // NOOp
+        }
+    }
+
+    public static void setAugmentationCodec(Class<? extends BindingCodec<Map<QName, Object>, Object>> dataCodec,
+            BindingCodec augmentableCodec) {
+            Field instanceIdField;
+            try {
+                instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+                instanceIdField.set(null, augmentableCodec);
+            } catch (NoSuchFieldException e) {
+               // NOOP
+            } catch (SecurityException e) {
+                // NOOP
+            } catch (IllegalAccessException e) {
+                // NOOp
+            }
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java
new file mode 100644 (file)
index 0000000..048dc3a
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+public class CodecTypeUtils {
+
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static IdentifiableItem<?, ?> newIdentifiableItem(Class<?> type, Object key) {
+        Class<? extends Identifiable<?>> identifiableType = (Class<? extends Identifiable<?>>) type;
+        Identifier<? extends Identifiable<?>> identifier = (Identifier<? extends Identifiable<?>>) key;
+        return new IdentifiableItem(identifiableType,identifier);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java
new file mode 100644 (file)
index 0000000..3f74c9e
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface GeneratorListener {
+
+    
+    
+    void onCodecCreated(Class<?> codec);
+    void onValueCodecCreated(Class<?> valueClass,Class<?> valueCodec);
+    void onChoiceCodecCreated(Class<?> choiceClass,Class<? extends BindingCodec<Map<QName, Object>,Object>> choiceCodec);
+    void onCaseCodecCreated(Class<?> choiceClass,Class<? extends BindingCodec<Map<QName, Object>,Object>> choiceCodec);
+    public abstract void onDataContainerCodecCreated(Class<?> dataClass, Class<?  extends BindingCodec<Map<QName, Object>,Object>> dataCodec);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend
new file mode 100644 (file)
index 0000000..fd02fde
--- /dev/null
@@ -0,0 +1,123 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
+import java.util.Map
+import java.util.WeakHashMap
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName
+import java.util.HashMap
+import org.slf4j.LoggerFactory
+import java.util.List
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+
+class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
+    
+    private static val LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl);
+    val CodecRegistry codecRegistry;
+    
+    val Map<Class<?>,QName> classToQName = new WeakHashMap;
+    
+    
+    public new(CodecRegistry registry) {
+        codecRegistry = registry;
+    }
+    
+    
+    override deserialize(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input) {
+        var Class<?> baType = null
+        val biArgs = input.path
+        val scannedPath = new ArrayList<QName>(biArgs.size);
+        val baArgs = new ArrayList<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>(biArgs.size)
+        for(biArg : biArgs) {
+            scannedPath.add(biArg.nodeType);
+            val baArg = deserializePathArgument(biArg,scannedPath)
+            baArgs.add(baArg)
+            baType = baArg?.type
+        }
+        val ret = new InstanceIdentifier(baArgs,baType as Class<? extends DataObject>);
+        return ret;
+    }
+    
+    private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifier argument,List<QName> processedPath) {
+        val Class cls = codecRegistry.getClassForPath(processedPath);
+        return new Item(cls);
+    }
+    
+    
+    private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifierWithPredicates argument,List<QName> processedPath) {
+        val Class type = codecRegistry.getClassForPath(processedPath);
+        val IdentifierCodec codec = codecRegistry.getIdentifierCodecForIdentifiable(type);
+        val value = codec.deserialize(argument.toCompositeNode())?.value;
+        return CodecTypeUtils.newIdentifiableItem(type,value);
+    }
+    
+    def CompositeNode toCompositeNode(NodeIdentifierWithPredicates predicates) {
+        val keyValues = predicates.keyValues.entrySet;
+        val values = new ArrayList<Node<?>>(keyValues.size)
+        for(keyValue : keyValues) {
+            values.add(new SimpleNodeTOImpl(keyValue.key,null,keyValue.value))
+        }
+        return new CompositeNodeTOImpl(predicates.nodeType,null,values);
+    }
+    
+    override serialize(InstanceIdentifier input) {
+        val pathArgs = input.path as List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>
+        var QName previousQName = null;
+        val components = new ArrayList<PathArgument>(pathArgs.size);
+        for(baArg : pathArgs) { 
+            codecRegistry.bindingClassEncountered(baArg.type);
+            val biArg = serializePathArgument(baArg,previousQName);
+            previousQName = biArg.nodeType;
+            components.add(biArg);
+        }
+        return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(components);
+    }
+    
+    private def dispatch PathArgument serializePathArgument(Item argument, QName previousQname) {
+        val type = argument.type;
+        val qname = resolveQname(type);
+        if(previousQname == null) {
+            return new NodeIdentifier(qname);
+        }
+        return new NodeIdentifier(QName.create(previousQname,qname.localName));
+    }
+    
+    private def dispatch PathArgument serializePathArgument(IdentifiableItem argument, QName previousQname) {
+        val Map<QName,Object> predicates = new HashMap();
+        val type = argument.type;
+        val keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type);
+        val qname = resolveQname(type);
+        val combinedInput =  new ValueWithQName(previousQname,argument.key)
+        val compositeOutput = keyCodec.serialize(combinedInput as ValueWithQName);
+        for(outputValue :compositeOutput.value) {
+            predicates.put(outputValue.nodeType,outputValue.value);
+        }
+        if(previousQname == null) {
+            return new NodeIdentifierWithPredicates(qname,predicates);
+        }
+        return new NodeIdentifierWithPredicates(QName.create(previousQname,qname.localName),predicates);
+    }
+    
+    def resolveQname(Class class1) {
+        val qname = classToQName.get(class1);
+        if(qname !== null) {
+            return qname;
+        }
+        val qnameField = class1.getField("QNAME");
+        val qnameValue = qnameField.get(null) as QName;
+        classToQName.put(class1,qnameValue);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend
new file mode 100644 (file)
index 0000000..d0b114e
--- /dev/null
@@ -0,0 +1,40 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl
+
+import org.opendaylight.yangtools.yang.data.api.Node
+import java.util.Map
+import org.opendaylight.yangtools.yang.common.QName
+import java.util.List
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import com.google.common.base.Preconditions
+
+class IntermediateMapping {
+    
+    
+    
+    static def Node<?> toNode(Map map) {
+        val nodeMap = map as Map<QName,Object>;
+        Preconditions.checkArgument(map.size == 1);
+        val elem = nodeMap.entrySet.iterator.next;
+        val qname = elem.key;
+        val value = elem.value;
+        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));
+        }
+        return new CompositeNodeTOImpl(name, null, values);
+    }
+
+    static def dispatch Node<?> toNodeImpl(QName name, Map<QName, Object> object) {
+        throw new UnsupportedOperationException("Unsupported node hierarchy.");
+    }
+
+    static def dispatch Node<?> toNodeImpl(QName name, Object object) {
+        return new SimpleNodeTOImpl(name, null, object);
+    } 
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java
new file mode 100644 (file)
index 0000000..e8e4c43
--- /dev/null
@@ -0,0 +1,779 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+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;
+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.InstanceIdentifierCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName;
+import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener;
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+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.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+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.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.*;
+import static org.opendaylight.controller.sal.binding.dom.serializer.impl.IntermediateMapping.*;
+
+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.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+
+public class LazyGeneratedCodecRegistry implements //
+        CodecRegistry, //
+        SchemaServiceListener, //
+        GeneratorListener {
+
+    private final static Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class);
+    private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
+
+    private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+
+    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<>();
+
+    /** Binding type to encountered classes mapping **/
+    @SuppressWarnings("rawtypes")
+    Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
+
+    @SuppressWarnings("rawtypes")
+    private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseNodes = new ConcurrentHashMap<>();
+
+    private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
+
+    Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+
+    private SchemaContext currentSchema;
+
+    public TransformerGenerator getGenerator() {
+        return generator;
+    }
+
+    public void setGenerator(TransformerGenerator generator) {
+        this.generator = generator;
+    }
+
+    @Override
+    public InstanceIdentifierCodec getInstanceIdentifierCodec() {
+        return instanceIdentifierCodec;
+    }
+
+    @Override
+    public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Class<?> getClassForPath(List<QName> names) {
+        DataSchemaNode node = getSchemaNode(names);
+        SchemaPath path = node.getPath();
+        GeneratedTypeBuilder type = pathToType.get(path);
+        ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+        @SuppressWarnings("rawtypes")
+        WeakReference<Class> weakRef = typeToClass.get(typeref);
+        return weakRef.get();
+    }
+
+    @Override
+    public IdentifierCodec<?> getKeyCodecForPath(List<QName> names) {
+        @SuppressWarnings("unchecked")
+        Class<? extends Identifiable<?>> cls = (Class<? extends Identifiable<?>>) getClassForPath(names);
+        return getIdentifierCodecForIdentifiable(cls);
+    }
+
+    @Override
+    public <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> type) {
+        @SuppressWarnings("unchecked")
+        DataContainerCodec<T> ret = (DataContainerCodec<T>) containerCodecs.get(type);
+        if (ret != null) {
+            return ret;
+        }
+        Class<? extends BindingCodec<Map<QName, Object>, Object>> newType = generator.transformerFor(type);
+        BindingCodec<Map<QName, Object>, Object> rawCodec = newInstanceOf(newType);
+        DataContainerCodecImpl<T> newWrapper = new DataContainerCodecImpl<>(rawCodec);
+        containerCodecs.put(type, newWrapper);
+        return newWrapper;
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public void bindingClassEncountered(Class cls) {
+        ConcreteType typeRef = Types.typeForClass(cls);
+        WeakReference<Class> weakRef = new WeakReference<>(cls);
+        typeToClass.put(typeRef, weakRef);
+    }
+
+    private DataSchemaNode getSchemaNode(List<QName> path) {
+        QName firstNode = path.get(0);
+        DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(),
+                firstNode.getRevision());
+        Iterator<QName> iterator = path.iterator();
+        while (iterator.hasNext()) {
+            QName arg = iterator.next();
+            DataSchemaNode currentNode = previous.getDataChildByName(arg);
+            if (currentNode == null && previous instanceof DataNodeContainer) {
+                currentNode = searchInChoices(previous, arg);
+            }
+            if (currentNode instanceof DataNodeContainer) {
+                previous = (DataNodeContainer) currentNode;
+            } else if (currentNode instanceof LeafSchemaNode || currentNode instanceof LeafListSchemaNode) {
+                checkState(!iterator.hasNext(), "Path tries to nest inside leaf node.");
+                return currentNode;
+            }
+        }
+        return (DataSchemaNode) previous;
+    }
+
+    private DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) {
+        Set<DataSchemaNode> children = node.getChildNodes();
+        for (DataSchemaNode child : children) {
+            if (child instanceof ChoiceNode) {
+                ChoiceNode choiceNode = (ChoiceNode) child;
+                DataSchemaNode potential = searchInCases(choiceNode, arg);
+                if (potential != null) {
+                    return potential;
+                }
+            }
+        }
+        return null;
+    }
+
+    private DataSchemaNode searchInCases(ChoiceNode choiceNode, QName arg) {
+        Set<ChoiceCaseNode> cases = choiceNode.getCases();
+        for (ChoiceCaseNode caseNode : cases) {
+            DataSchemaNode node = caseNode.getDataChildByName(arg);
+            if (node != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private <T> T newInstanceOf(Class<?> newType) {
+        try {
+            @SuppressWarnings("unchecked")
+            T ret = (T) newType.newInstance();
+            return ret;
+        } catch (InstantiationException e) {
+            throw new IllegalStateException(e);
+        } catch (IllegalAccessException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public <T extends Identifiable<?>> IdentifierCodec<?> getIdentifierCodecForIdentifiable(Class<T> type) {
+        IdentifierCodec<?> obj = identifierCodecs.get(type);
+        if (obj != null) {
+            return obj;
+        }
+        Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
+                .keyTransformerForIdentifiable(type);
+        BindingCodec<Map<QName, Object>, Object> newInstance;
+        newInstance = newInstanceOf(newCodec);
+        IdentifierCodecImpl<?> newWrapper = new IdentifierCodecImpl<>(newInstance);
+        identifierCodecs.put(type, newWrapper);
+        return newWrapper;
+    }
+
+    @Override
+    public void onCodecCreated(Class<?> cls) {
+        CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
+    }
+
+    @Override
+    public <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object) {
+        @SuppressWarnings("unchecked")
+        IdentifierCodec<T> obj = (IdentifierCodec<T>) identifierCodecs.get(object);
+        if (obj != null) {
+            return obj;
+        }
+        Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
+                .keyTransformerForIdentifier(object);
+        BindingCodec<Map<QName, Object>, Object> newInstance;
+        newInstance = newInstanceOf(newCodec);
+        IdentifierCodecImpl<T> newWrapper = new IdentifierCodecImpl<>(newInstance);
+        identifierCodecs.put(object, newWrapper);
+        return newWrapper;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public ChoiceCaseCodecImpl getCaseCodecFor(Class caseClass) {
+        ChoiceCaseCodecImpl<?> potential = caseCodecs.get(caseClass);
+        if (potential != null) {
+            return potential;
+        }
+        ConcreteType typeref = Types.typeForClass(caseClass);
+        ChoiceCaseCodecImpl caseCodec = typeToCaseNodes.get(typeref);
+
+        @SuppressWarnings("unchecked")
+        Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.schema);
+        BindingCodec newInstance = newInstanceOf(newCodec);
+        caseCodec.setDelegate(newInstance);
+        caseCodecs.put(caseClass, caseCodec);
+
+        for (Entry<Class<?>, ChoiceCodecImpl<?>> choice : choiceCodecs.entrySet()) {
+            if (choice.getKey().isAssignableFrom(caseClass)) {
+                choice.getValue().cases.put(caseClass, caseCodec);
+            }
+        }
+        return caseCodec;
+    }
+
+    public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
+        pathToType.putAll(context.getChildNodes());
+
+        captureCases(context.getCases(), schemaContext);
+    }
+
+    private void captureCases(Map<SchemaPath, GeneratedTypeBuilder> cases, SchemaContext module) {
+        for (Entry<SchemaPath, GeneratedTypeBuilder> caseNode : cases.entrySet()) {
+            ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
+                    .getValue().getName());
+            ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
+            @SuppressWarnings("rawtypes")
+            ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node);
+            typeToCaseNodes.putIfAbsent(typeref, value);
+        }
+    }
+
+    @Override
+    public void onGlobalContextUpdated(SchemaContext context) {
+        currentSchema = context;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public void onChoiceCodecCreated(Class<?> choiceClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
+        ChoiceCodec<?> oldCodec = choiceCodecs.get(choiceClass);
+        checkState(oldCodec == null);
+        BindingCodec<Map<QName, Object>, Object> delegate = newInstanceOf(choiceCodec);
+        ChoiceCodecImpl<?> newCodec = new ChoiceCodecImpl(delegate);
+        choiceCodecs.put(choiceClass, newCodec);
+        CodecMapping.setClassToCaseMap(choiceCodec, (Map<Class, BindingCodec>) classToCaseRawCodec);
+        CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase());
+
+    }
+
+    @Override
+    public void onValueCodecCreated(Class<?> valueClass, Class<?> valueCodec) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onCaseCodecCreated(Class<?> choiceClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onDataContainerCodecCreated(Class<?> dataClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> dataCodec) {
+        if (Augmentable.class.isAssignableFrom(dataClass)) {
+            AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass);
+            CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec);
+        }
+
+    }
+
+    private AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
+        AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
+        if (ret != null) {
+            return ret;
+        }
+        ret = new AugmentableCompositeCodec(dataClass);
+        augmentableCodecs.put(dataClass, ret);
+        return ret;
+    }
+
+    private static abstract class IntermediateCodec<T> implements //
+            DomCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
+
+        private final BindingCodec<Map<QName, Object>, Object> delegate;
+
+        @Override
+        public BindingCodec<Map<QName, Object>, Object> getDelegate() {
+            return delegate;
+        }
+
+        public IntermediateCodec(BindingCodec<Map<QName, Object>, Object> delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Node<?> serialize(ValueWithQName<T> input) {
+            Map<QName, Object> intermediateOutput = delegate.serialize(input);
+            return toNode(intermediateOutput);
+        }
+    }
+
+    private static class IdentifierCodecImpl<T extends Identifier<?>> //
+            extends IntermediateCodec<T> //
+            implements IdentifierCodec<T> {
+
+        public IdentifierCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            QName qname = input.getNodeType();
+            @SuppressWarnings("unchecked")
+            T value = (T) getDelegate().deserialize((Map<QName, Object>) input);
+            return new ValueWithQName<T>(qname, value);
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            return (CompositeNode) super.serialize(input);
+        }
+    }
+
+    private static class DataContainerCodecImpl<T extends DataContainer> //
+            extends IntermediateCodec<T> //
+            implements DataContainerCodec<T> {
+
+        public DataContainerCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            if (input == null) {
+                return null;
+            }
+            QName qname = input.getNodeType();
+            @SuppressWarnings("unchecked")
+            T value = (T) getDelegate().deserialize((Map<QName, Object>) input);
+            return new ValueWithQName<T>(qname, value);
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            return (CompositeNode) super.serialize(input);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
+            Delegator<BindingCodec> {
+        private final boolean augmenting;
+        private BindingCodec delegate;
+
+        private final Set<String> validNames;
+        private final Set<QName> validQNames;
+        private ChoiceCaseNode schema;
+
+        public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) {
+            this.delegate = NOT_READY_CODEC;
+            this.schema = caseNode;
+            validNames = new HashSet<>();
+            validQNames = new HashSet<>();
+            for (DataSchemaNode node : caseNode.getChildNodes()) {
+                QName qname = node.getQName();
+                validQNames.add(qname);
+                validNames.add(qname.getLocalName());
+            }
+            augmenting = caseNode.isAugmenting();
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        public BindingCodec getDelegate() {
+            return delegate;
+        }
+
+        public void setDelegate(BindingCodec delegate) {
+            this.delegate = delegate;
+        }
+
+        public ChoiceCaseNode getSchema() {
+            return schema;
+        }
+
+        @Override
+        public boolean isAcceptable(Node<?> input) {
+            if (false == (input instanceof CompositeNode)) {
+                if (augmenting) {
+                    return checkAugmenting((CompositeNode) input);
+                } else {
+                    return checkLocal((CompositeNode) input);
+                }
+            }
+            return false;
+        }
+
+        private boolean checkLocal(CompositeNode input) {
+            QName parent = input.getNodeType();
+            for (Node<?> childNode : input.getChildren()) {
+                QName child = childNode.getNodeType();
+                if (false == Objects.equals(parent.getNamespace(), child.getNamespace())) {
+                    continue;
+                }
+                if (false == Objects.equals(parent.getRevision(), child.getRevision())) {
+                    continue;
+                }
+                if (validNames.contains(child.getLocalName())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean checkAugmenting(CompositeNode input) {
+            for (Node<?> child : input.getChildren()) {
+                if (validQNames.contains(child.getNodeType())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private static class ChoiceCodecImpl<T> implements ChoiceCodec<T> {
+
+        private final BindingCodec<Map<QName, Object>, Object> delegate;
+
+        @SuppressWarnings("rawtypes")
+        private final Map<Class, ChoiceCaseCodecImpl<?>> cases = new WeakHashMap<>();
+
+        private final CaseCompositeNodeMapFacade CompositeToCase;
+
+        public ChoiceCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+            this.delegate = delegate;
+            this.CompositeToCase = new CaseCompositeNodeMapFacade(cases);
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        @Override
+        public Node<?> serialize(ValueWithQName<T> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        public CaseCompositeNodeMapFacade getCompositeToCase() {
+            return CompositeToCase;
+        }
+
+        public Map<Class, ChoiceCaseCodecImpl<?>> getCases() {
+            return cases;
+        }
+
+        public BindingCodec<Map<QName, Object>, Object> getDelegate() {
+            return delegate;
+        }
+
+    }
+
+    @SuppressWarnings("rawtypes")
+    private class CaseClassMapFacade extends MapFacadeBase {
+
+        @Override
+        public Set<java.util.Map.Entry<Class, BindingCodec<Object, Object>>> entrySet() {
+            return null;
+        }
+
+        @Override
+        public BindingCodec get(Object key) {
+            if (key instanceof Class) {
+                Class cls = (Class) key;
+                bindingClassEncountered(cls);
+                ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls);
+                return caseCodec.getDelegate();
+            }
+            return null;
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static class CaseCompositeNodeMapFacade extends MapFacadeBase<CompositeNode> {
+
+        final Map<Class, ChoiceCaseCodecImpl<?>> choiceCases;
+
+        public CaseCompositeNodeMapFacade(Map<Class, ChoiceCaseCodecImpl<?>> choiceCases) {
+            this.choiceCases = choiceCases;
+        }
+
+        @Override
+        public Set<java.util.Map.Entry<CompositeNode, BindingCodec>> entrySet() {
+            return null;
+        }
+
+        @Override
+        public BindingCodec get(Object key) {
+            if (false == (key instanceof CompositeNode)) {
+                return null;
+            }
+            for (java.util.Map.Entry<Class, ChoiceCaseCodecImpl<?>> entry : choiceCases.entrySet()) {
+                ChoiceCaseCodecImpl<?> codec = entry.getValue();
+                if (codec.isAcceptable((CompositeNode) key)) {
+                    return codec.getDelegate();
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * This map is used as only facade for {@link BindingCodec} in different
+     * classloaders to retrieve codec dynamicly based on provided key.
+     * 
+     * @param <T>
+     *            Key type
+     */
+    @SuppressWarnings("rawtypes")
+    private static abstract class MapFacadeBase<T> implements Map<T, BindingCodec> {
+
+        @Override
+        public boolean containsKey(Object key) {
+            return get(key) != null;
+        }
+
+        @Override
+        public void clear() {
+            throw notModifiable();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return super.equals(obj);
+        }
+
+        @Override
+        public BindingCodec remove(Object key) {
+            return null;
+        }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public Collection<BindingCodec> values() {
+            return null;
+        }
+
+        private UnsupportedOperationException notModifiable() {
+            return new UnsupportedOperationException("Not externally modifiable.");
+        }
+
+        @Override
+        public BindingCodec<Map<QName, Object>, Object> put(T key, BindingCodec value) {
+            throw notModifiable();
+        }
+
+        @Override
+        public void putAll(Map<? extends T, ? extends BindingCodec> m) {
+            throw notModifiable();
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+
+        @Override
+        public Set<T> keySet() {
+            return null;
+        }
+
+        @Override
+        public Set<java.util.Map.Entry<T, BindingCodec>> entrySet() {
+            return null;
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return false;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private class AugmentableCompositeCodec implements BindingCodec {
+
+        private final Class augmentableType;
+
+        Map<Class, BindingCodec> rawAugmentationCodecs = new WeakHashMap<>();
+
+        public AugmentableCompositeCodec(Class type) {
+            checkArgument(Augmentable.class.isAssignableFrom(type));
+            augmentableType = type;
+        }
+
+        @Override
+        public Object serialize(Object input) {
+            if (input instanceof Augmentable<?>) {
+
+                Map<Class, Augmentation> augmentations = getAugmentations(input);
+                return serializeImpl(augmentations);
+            }
+            return null;
+        }
+
+        private Map<Class, Augmentation> getAugmentations(Object input) {
+            Field augmentationField;
+            try {
+                augmentationField = input.getClass().getDeclaredField("augmentation");
+                augmentationField.setAccessible(true);
+                Map<Class, Augmentation> augMap = (Map<Class, Augmentation>) augmentationField.get(input);
+                return augMap;
+            } catch (NoSuchFieldException e) {
+
+            } catch (SecurityException e) {
+
+            } catch (IllegalArgumentException e) {
+
+            } catch (IllegalAccessException e) {
+
+            }
+            return Collections.emptyMap();
+        }
+
+        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);
+            }
+            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) {
+
+            } catch (IllegalAccessException e) {
+
+            }
+            return null;
+        }
+
+        @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);
+                    }
+                }
+            }
+            return ret;
+        }
+
+        public Map<Class, BindingCodec> getRawAugmentationCodecs() {
+            return rawAugmentationCodecs;
+        }
+
+        public void setRawAugmentationCodecs(Map<Class, BindingCodec> rawAugmentationCodecs) {
+            this.rawAugmentationCodecs = rawAugmentationCodecs;
+        }
+
+        public Class getAugmentableType() {
+            return augmentableType;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static class LateMixinCodec implements BindingCodec, Delegator<BindingCodec> {
+
+        private BindingCodec delegate;
+
+        @Override
+        public BindingCodec getDelegate() {
+            if (delegate == null) {
+                throw new IllegalStateException("Codec not initialized yet.");
+            }
+            return delegate;
+        }
+
+        @Override
+        public Object deserialize(Object input) {
+            return getDelegate().deserialize(input);
+        }
+
+        @Override
+        public Object serialize(Object input) {
+            return getDelegate().serialize(input);
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend
new file mode 100644 (file)
index 0000000..4614c60
--- /dev/null
@@ -0,0 +1,218 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl
+
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator
+import javassist.ClassPool
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
+import java.util.Map
+import org.opendaylight.yangtools.sal.binding.model.api.Type
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
+import java.util.concurrent.ConcurrentHashMap
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import java.util.Map.Entry
+import java.util.AbstractMap.SimpleEntry
+import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.binding.DataContainer
+import static com.google.common.base.Preconditions.*;
+import java.util.List
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.concepts.Delegator
+import java.util.concurrent.ConcurrentMap
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
+import org.opendaylight.yangtools.yang.binding.BindingCodec
+import com.google.common.collect.HashMultimap
+import com.google.common.util.concurrent.SettableFuture
+import java.util.concurrent.Future
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.LazyGeneratedCodecRegistry
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService
+import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName
+import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec
+import org.opendaylight.yangtools.binding.generator.util.Types
+
+class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener {
+
+    @Property
+    ClassPool pool;
+
+    private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl);
+
+    @Property
+    extension TransformerGenerator binding;
+
+    @Property
+    extension LazyGeneratedCodecRegistry registry;
+
+    @Property
+    val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
+
+    @Property
+    val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
+
+    @Property
+    val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+
+    val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
+
+    val promisedSchemas = HashMultimap.<Type, SettableFuture<SchemaNode>>create;
+
+    override onGlobalContextUpdated(SchemaContext arg0) {
+        recreateBindingContext(arg0);
+        registry.onGlobalContextUpdated(arg0);
+    }
+
+    def recreateBindingContext(SchemaContext schemaContext) {
+        val newBinding = new BindingGeneratorImpl();
+        newBinding.generateTypes(schemaContext);
+
+        for (entry : newBinding.moduleContexts.entrySet) {
+
+            registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
+
+            //val module = entry.key;
+            val context = entry.value;
+            updateBindingFor(context.childNodes, schemaContext);
+            updateBindingFor(context.cases, schemaContext);
+            
+
+            val typedefs = context.typedefs;
+            for (typedef : typedefs.values) {
+                binding.typeDefinitions.put(typedef, typedef as GeneratedType);
+            }
+            val augmentations = context.augmentations;
+            for (augmentation : augmentations) {
+                binding.typeToDefinition.put(augmentation, augmentation);
+            }
+            
+            binding.typeToAugmentation.putAll(context.typeToAugmentation);
+        }
+    }
+
+    override CompositeNode toDataDom(DataObject data) {
+        toCompositeNodeImpl(data);
+    }
+
+    override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
+        Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+        val key = toDataDom(entry.key)
+        val data = toCompositeNodeImpl(entry.value);
+        return new SimpleEntry(key, data);
+    }
+
+    private def CompositeNode toCompositeNodeImpl(DataObject object) {
+        val cls = object.implementedInterface;
+        waitForSchema(cls);
+        val codec = registry.getCodecForDataObject(cls) as DataContainerCodec<DataObject>;
+        val ret = codec.serialize(new ValueWithQName(null, object));
+        return ret as CompositeNode;
+    }
+
+    private def waitForSchema(Class<? extends DataContainer> class1) {
+        val ref = Types.typeForClass(class1);
+        getSchemaWithRetry(ref);
+    }
+
+    override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
+        InstanceIdentifier<? extends DataObject> path) {
+        for (arg : path.path) {
+            waitForSchema(arg.type);
+        }
+        return registry.instanceIdentifierCodec.serialize(path);
+    }
+
+    override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
+        if (node == null) {
+            return null;
+        }
+        val targetType = path.targetType
+        val transformer = registry.getCodecForDataObject(targetType);
+        val ret = transformer.deserialize(node)?.value as DataObject;
+        return ret;
+    }
+
+    private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
+        for (entry : map.entrySet) {
+            val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
+            //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
+            if (schemaNode != null) {
+                typeToSchemaNode.put(entry.value, schemaNode);
+                typeToDefinition.put(entry.value, entry.value);
+                updatePromisedSchemas(entry.value, schemaNode);
+            }
+        }
+    }
+
+    public def void start() {
+        binding = new TransformerGenerator(pool);
+        registry = new LazyGeneratedCodecRegistry()
+        registry.generator = binding
+
+        //binding.staticFieldsInitializer = registry
+        binding.listener = registry
+        binding.typeToDefinition = typeToDefinition
+        binding.typeToSchemaNode = typeToSchemaNode
+        binding.typeDefinitions = typeDefinitions
+
+    }
+
+    private def getTypeDefinition(Type type) {
+        val typeDef = typeToDefinition.get(type);
+        if (typeDef !== null) {
+            return typeDef;
+        }
+        return type.getTypeDefInFuture.get();
+    }
+
+    private def Future<GeneratedTypeBuilder> getTypeDefInFuture(Type type) {
+        val future = SettableFuture.<GeneratedTypeBuilder>create()
+        promisedTypeDefinitions.put(type, future);
+        return future;
+    }
+
+    private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) {
+        val futures = promisedTypeDefinitions.get(builder);
+        if (futures === null || futures.empty) {
+            return;
+        }
+        for (future : futures) {
+            future.set(builder);
+        }
+        promisedTypeDefinitions.removeAll(builder);
+    }
+
+    private def getSchemaWithRetry(Type type) {
+        val typeDef = typeToSchemaNode.get(type);
+        if (typeDef !== null) {
+            return typeDef;
+        }
+        return type.getSchemaInFuture.get();
+    }
+
+    private def Future<SchemaNode> getSchemaInFuture(Type type) {
+        val future = SettableFuture.<SchemaNode>create()
+        promisedSchemas.put(type, future);
+        return future;
+    }
+
+    private def void updatePromisedSchemas(Type builder, SchemaNode schema) {
+        val ref = new ReferencedTypeImpl(builder.packageName, builder.name);
+        val futures = promisedSchemas.get(ref);
+        if (futures === null || futures.empty) {
+            return;
+        }
+        for (future : futures) {
+            future.set(schema);
+        }
+        promisedSchemas.removeAll(builder);
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java
new file mode 100644 (file)
index 0000000..e5b36e1
--- /dev/null
@@ -0,0 +1,6 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+public interface StaticFieldInitializer {
+
+    void initializeStaticFields(Class<?> cls);
+}
index 2136572..8e059aa 100644 (file)
@@ -9,9 +9,9 @@ import java.util.Map
 import org.opendaylight.yangtools.yang.common.QName
 import javassist.CtField
 import static javassist.Modifier.*
+import static org.opendaylight.controller.sal.binding.dom.serializer.impl.CodecMapping.*
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
 import org.opendaylight.yangtools.sal.binding.model.api.Type
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
@@ -22,7 +22,6 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import java.util.WeakHashMap
 import java.util.List
 import java.util.TreeSet
 import com.google.common.base.Joiner
@@ -31,13 +30,21 @@ import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
 import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*;
 import org.opendaylight.yangtools.yang.binding.BindingDeserializer
-import org.opendaylight.yangtools.yang.binding.BindingSerializer
 import org.opendaylight.yangtools.yang.binding.BindingCodec
 import org.slf4j.LoggerFactory
 import org.opendaylight.controller.sal.binding.codegen.CodeGenerationException
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
 import java.security.ProtectionDomain
 import java.io.File
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
+import java.util.Map.Entry
+import java.util.AbstractMap.SimpleEntry
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import java.util.Iterator
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
+import java.util.concurrent.ConcurrentHashMap
 
 class TransformerGenerator {
 
@@ -46,6 +53,7 @@ class TransformerGenerator {
     public static val STRING = Types.typeForClass(String);
     public static val BOOLEAN = Types.typeForClass(Boolean);
     public static val INTEGER = Types.typeForClass(Integer);
+    public static val INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier)
 
     //public static val DECIMAL = Types.typeForClass(Decimal);
     public static val LONG = Types.typeForClass(Long);
@@ -53,36 +61,39 @@ class TransformerGenerator {
     val ClassPool classPool
     val extension JavassistUtils utils;
 
-    CtClass ctTransformator
+    CtClass BINDING_CODEC
 
     CtClass ctQName
 
     @Property
     var File classFileCapturePath;
 
+    @Property
+    var Map<Type, Type> typeDefinitions = new ConcurrentHashMap();
 
     @Property
-    var Map<Type, Type> typeDefinitions;
+    var Map<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
 
     @Property
-    var Map<Type, GeneratedTypeBuilder> typeToDefinition
+    var Map<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
 
     @Property
-    var Map<Type, SchemaNode> typeToSchemaNode
+    var Map<Type, AugmentationSchema> typeToAugmentation = new ConcurrentHashMap();
 
-    val Map<Class<?>, Class<?>> generatedClasses = new WeakHashMap();
+    @Property
+    var GeneratorListener listener;
 
     public new(ClassPool pool) {
         classPool = pool;
         utils = new JavassistUtils(pool)
 
-        ctTransformator = BindingCodec.asCtClass;
+        BINDING_CODEC = BindingCodec.asCtClass;
         ctQName = QName.asCtClass
     }
 
     def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType) {
-        return withClassLoader(inputType.classLoader) [ |
-            val ret = generatedClasses.get(inputType);
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
             if (ret !== null) {
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
@@ -90,60 +101,148 @@ class TransformerGenerator {
             val node = typeToSchemaNode.get(ref)
             val typeSpecBuilder = typeToDefinition.get(ref)
             val typeSpec = typeSpecBuilder.toInstance();
-            val newret = generateTransformerFor(inputType, typeSpec, node)
-            generatedClasses.put(inputType, newret);
+            val newret = generateTransformerFor(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(Class<?> inputType) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            val node = typeToAugmentation.get(ref)
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateAugmentationTransformerFor(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Object, Object>> caseCodecFor(Class<?> inputType, ChoiceCaseNode node) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Object, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateCaseCodec(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Object, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(Class<?> parentType) {
+        return withClassLoaderAndLock(parentType.classLoader, lock) [ |
+            val inputName = parentType.name + "Key";
+            val inputType = loadClassWithTCCL(inputName);
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(parentType)
+            val node = typeToSchemaNode.get(ref) as ListSchemaNode
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.identifierDefinition;
+            val newret = generateKeyTransformerFor(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def getIdentifierDefinition(GeneratedTypeBuilder builder) {
+        val inst = builder.toInstance
+        val keyMethod = inst.methodDefinitions.findFirst[name == "getKey"]
+        return keyMethod.returnType as GeneratedTransferObject
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(Class<?> inputType) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            val node = typeToSchemaNode.get(ref) as ListSchemaNode
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateKeyTransformerFor(inputType, typeSpec, node);
             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         ]
     }
 
     private def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
-        return withClassLoader(inputType.classLoader) [ |
-            val transformer = generatedClasses.get(inputType);
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val transformer = getGeneratedClass(inputType)
             if (transformer != null) {
                 return transformer;
             }
             val newret = generateKeyTransformerFor(inputType, type, schema);
-            generatedClasses.put(inputType, newret);
             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         ]
     }
 
-    def Class<?> keyTransformer(GeneratedType type, ListSchemaNode node) {
+    private def Class getGeneratedClass(Class<? extends Object> cls) {
+
+        try {
+            return loadClassWithTCCL(cls.codecClassName)
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    private def Class<?> keyTransformer(GeneratedType type, ListSchemaNode node) {
         val cls = loadClassWithTCCL(type.resolvedName + "Key");
         keyTransformerFor(cls, type, node);
     }
 
     private def serializer(Type type) {
         val cls = loadClassWithTCCL(type.resolvedName);
+
         transformerFor(cls);
 
     }
 
     private def Class<?> getValueSerializer(GeneratedTransferObject type) {
         val cls = loadClassWithTCCL(type.resolvedName);
-        val transformer = generatedClasses.get(cls);
+        val transformer = cls.generatedClass;
         if (transformer !== null) {
             return transformer;
         }
         val valueTransformer = generateValueTransformer(cls, type);
-        generatedClasses.put(cls, valueTransformer);
         return valueTransformer;
     }
 
     private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val properties = typeSpec.allProperties;
-            val ctCls = createClass(inputType.transformatorFqn) [
+            val ctCls = createClass(inputType.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 staticQNameField(node.QName);
-                implementsType(ctTransformator)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
                         {
-                        
-                            return null;
+                            «QName.name» _resultName;
+                            if($1 != null) {
+                                _resultName = «QName.name».create($1,QNAME.getLocalName());
+                            } else {
+                                _resultName = QNAME;
+                            }
+                            java.util.List _childNodes = new java.util.ArrayList();
+                            «inputType.name» value = («inputType.name») $2;
+                            «FOR key : node.keyDefinition»
+                                «val propertyName = key.getterName»
+                                «val keyDef = node.getDataChildByName(key)»
+                                «val property = properties.get(propertyName)»
+                                «serializeProperty(keyDef, property, propertyName)»;
+                            «ENDFOR»
+                            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
                         }
                     '''
                 ]
@@ -160,7 +259,7 @@ class TransformerGenerator {
                                 «val propertyName = key.getterName»
                                 «val keyDef = node.getDataChildByName(key)»
                                 «val property = properties.get(propertyName)»
-                                «deserializeProperty(keyDef, property.returnType, property)»;
+                                «deserializeProperty(keyDef, property, propertyName)»;
                             «ENDFOR»
                             «inputType.name» _value = new «inputType.name»(«node.keyDefinition.keyConstructorList»);
                             return _value;
@@ -169,7 +268,12 @@ class TransformerGenerator {
                 ]
                 method(Object, "serialize", Object) [
                     body = '''
-                        return toDomStatic(QNAME,$1);
+                        {
+                            java.util.Map.Entry _input =  (java.util.Map.Entry) $1;
+                            «QName.name» _localQName = («QName.name») _input.getKey();
+                            «inputType.name» _keyValue = («inputType.name») _input.getValue();
+                            return toDomStatic(_localQName,_keyValue);
+                        }
                     '''
                 ]
                 method(Object, "deserialize", Object) [
@@ -179,29 +283,95 @@ class TransformerGenerator {
                 ]
             ]
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            log.info("DOM Codec for {} was generated {}",inputType,ret)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
         } catch (Exception e) {
-            processException(inputType,e);
+            processException(inputType, e);
             return null;
         }
     }
 
-    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(Class inputType,
-        GeneratedType typeSpec, SchemaNode node) {
+    private def Class<? extends BindingCodec<Object, Object>> generateCaseCodec(Class inputType, GeneratedType type,
+        ChoiceCaseNode node) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(type.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                implementsType(BINDING_CODEC)
                 staticQNameField(inputType);
-                implementsType(ctTransformator)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                method(Object, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        {
+                            «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+                            java.util.List _childNodes = new java.util.ArrayList();
+                            «type.resolvedName» value = («type.resolvedName») $2;
+                            «transformDataContainerBody(type.allProperties, node)»
+                            return ($r) _childNodes;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    body = '''
+                        {
+                            java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                            «QName.name» _localName = QNAME;
+                            if(_input.getKey() != null) {
+                                _localName = («QName.name») _input.getKey();
+                            }
+                            return toDomStatic(_localName,_input.getValue());
+                        }
+                    '''
+                ]
+                method(Object, "fromDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = deserializeBody(type, node)
+                ]
+                method(Object, "deserialize", Object) [
+                    body = '''
+                        {
+                            
+                            return fromDomStatic(QNAME,$1);
+                        }
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
+            return ret as Class<? extends BindingCodec<Object, Object>>;
+        } catch (Exception e) {
+            processException(inputType, e);
+            return null;
+        }
+    }
+
+    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
+        Class inputType, GeneratedType typeSpec, SchemaNode node) {
+        try {
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(typeSpec.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                staticQNameField(inputType);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = serializeBodyFacade(typeSpec, node)
                 ]
                 method(Object, "serialize", Object) [
                     body = '''
-                        return toDomStatic(QNAME,$1);
+                        {
+                            java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                            «QName.name» _localName = QNAME;
+                            if(_input.getKey() != null) {
+                                _localName = («QName.name») _input.getKey();
+                            }
+                            return toDomStatic(_localName,_input.getValue());
+                        }
                     '''
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
@@ -215,55 +385,159 @@ class TransformerGenerator {
                 ]
             ]
 
-            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
+            listener?.onDataContainerCodecCreated(inputType, ret);
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
+            return ret;
         } catch (Exception e) {
-            processException(inputType,e);
+            processException(inputType, e);
             return null;
         }
     }
-    
-    
-    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(Class inputType,
-        GeneratedType typeSpec, ChoiceNode node) {
+
+    private def Class<? extends BindingCodec<Map<QName, Object>, Object>> generateAugmentationTransformerFor(
+        Class inputType, GeneratedType type, AugmentationSchema node) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val properties = type.allProperties
+            val ctCls = createClass(type.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                //staticQNameField(inputType);
-                implementsType(ctTransformator)
+                staticQNameField(inputType);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
-                        return null;
+                        {
+                            //System.out.println("Qname " + $1);
+                            //System.out.println("Value " + $2);
+                            «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+                            java.util.List _childNodes = new java.util.ArrayList();
+                            «type.resolvedName» value = («type.resolvedName») $2;
+                            «FOR child : node.childNodes»
+                                «var signature = properties.getFor(child)»
+                                //System.out.println("«signature.key»" + value.«signature.key»());
+                                «serializeProperty(child, signature.value, signature.key)»
+                            «ENDFOR»
+                            return ($r) _childNodes;
+                        }
                     '''
                 ]
                 method(Object, "serialize", Object) [
                     body = '''
-                        return null;
+                        {
+                        java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                        «QName.name» _localName = QNAME;
+                        if(_input.getKey() != null) {
+                            _localName = («QName.name») _input.getKey();
+                        }
+                        return toDomStatic(_localName,_input.getValue());
+                        }
                     '''
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
-                        return null;
+                        {
+                            «QName.name» _localQName = QNAME;
+                            
+                            if($2 == null) {
+                            return null;
+                            }
+                            java.util.Map _compositeNode = (java.util.Map) $2;
+                            ////System.out.println(_localQName + " " + _compositeNode);
+                            «type.builderName» _builder = new «type.builderName»();
+                            «FOR child : node.childNodes»
+                                «val signature = properties.getFor(child)»
+                                «deserializeProperty(child, signature.value, signature.key)»
+                                
+                                _builder.«signature.key.toSetter»(«signature.key»);
+                            «ENDFOR»
+                            return _builder.build();
+                        }
                     '''
                 ]
                 method(Object, "deserialize", Object) [
                     body = '''
-                        return null;
+                        return fromDomStatic(QNAME,$1);
                     '''
                 ]
             ]
 
-            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
+            listener?.onDataContainerCodecCreated(inputType, ret);
+            return ret;
         } catch (Exception e) {
-            processException(inputType,e);
+            processException(inputType, e);
+            return null;
+        }
+    }
+
+    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
+        Class inputType, GeneratedType typeSpec, ChoiceNode node) {
+        try {
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(typeSpec.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                //staticQNameField(inputType);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, CLASS_TO_CASE_MAP, Map)
+                staticField(it, COMPOSITE_TO_CASE, Map)
+                //staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
+                implementsType(BINDING_CODEC)
+                method(List, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        {
+                            if($2 == null) {
+                                return null;
+                            }
+                            «DataObject.name» _baValue = («DataObject.name») $2;
+                            Class _baClass = _baValue.getImplementedInterface();
+                            «BINDING_CODEC.name» _codec =  «CLASS_TO_CASE_MAP».get(_baClass);
+                            if(_codec == null) {
+                                return null;
+                            }
+                            java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue);
+                            return (java.util.List) _codec.serialize(_input);
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    body = '''
+                        throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
+                    '''
+                ]
+                method(Object, "fromDomStatic", QName, Map) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        {
+                            «BINDING_CODEC.name» _codec = («BINDING_CODEC.name») «COMPOSITE_TO_CASE».get($2);
+                            if(_codec != null) {
+                                return _codec.deserialize(new «SimpleEntry.name»($1,$2));
+                            }
+                            return null;
+                        }
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    body = '''
+                        throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
+                    '''
+                ]
+            ]
+
+            val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            val ret = rawRet as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            listener?.onChoiceCodecCreated(inputType, ret);
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
+            return ret;
+        } catch (Exception e) {
+            processException(inputType, e);
             return null;
         }
     }
-    
 
     private def keyConstructorList(List<QName> qnames) {
         val names = new TreeSet<String>()
@@ -302,7 +576,6 @@ class TransformerGenerator {
             }
             java.util.Map _compositeNode = (java.util.Map) $2;
             «type.builderName» _builder = new «type.builderName»();
-            
             return _builder.build();
         }
     '''
@@ -317,6 +590,7 @@ class TransformerGenerator {
             «type.builderName» _builder = new «type.builderName»();
             «deserializeKey(type, node)»
             «deserializeDataNodeContainerBody(type, node)»
+            «deserializeAugmentations»
             return _builder.build();
         }
     '''
@@ -330,6 +604,7 @@ class TransformerGenerator {
             java.util.Map _compositeNode = (java.util.Map) $2;
             «type.builderName» _builder = new «type.builderName»();
             «deserializeDataNodeContainerBody(type, node)»
+            «deserializeAugmentations»
             return _builder.build();
         }
     '''
@@ -337,12 +612,15 @@ class TransformerGenerator {
     private def dispatch String deserializeBodyImpl(GeneratedType type, ChoiceCaseNode node) '''
         {
             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
+            
             if($2 == null) {
                 return null;
             }
             java.util.Map _compositeNode = (java.util.Map) $2;
+            ////System.out.println(_localQName + " " + _compositeNode);
             «type.builderName» _builder = new «type.builderName»();
             «deserializeDataNodeContainerBody(type, node)»
+            «deserializeAugmentations»
             return _builder.build();
         }
     '''
@@ -351,87 +629,106 @@ class TransformerGenerator {
         deserializeNodeContainerBodyImpl(type, type.allProperties, node);
     }
 
-    private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, MethodSignature> properties,
+    private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, Type> properties,
         DataNodeContainer node) {
         val ret = '''
             «FOR child : node.childNodes.filter[!augmenting]»
                 «val signature = properties.getFor(child)»
-                «deserializeProperty(child, signature.returnType, signature)»
-                _builder.«signature.name.toSetter»(«signature.name»);
+                «deserializeProperty(child, signature.value, signature.key)»
+                
+                _builder.«signature.key.toSetter»(«signature.key»);
             «ENDFOR»
         '''
         return ret;
     }
 
+    def deserializeAugmentations() '''
+        java.util.Map _augmentation = (java.util.Map) «AUGMENTATION_CODEC».deserialize(_compositeNode);
+        if(_augmentation != null) {
+            «Iterator.name» _entries = _augmentation.entrySet().iterator();
+            while(_entries.hasNext()) {
+                java.util.Map.Entry _entry = (java.util.Map.Entry) _entries.next();
+                //System.out.println("Aug. key:" + _entry.getKey());
+                Class _type = (Class) _entry.getKey();
+                «Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue();
+                _builder.addAugmentation(_type,_value);
+            }
+        }
+    '''
+
     private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type,
-        MethodSignature property) '''
-        java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
+        String propertyName) '''
+        java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
             localName»"));
-        //System.out.println("«property.name»#deCode"+_dom_«property.name»);
-        java.util.List «property.name» = new java.util.ArrayList();
-        if(_dom_«property.name» != null) {
+        ////System.out.println("«propertyName»#deCode"+_dom_«propertyName»);
+        java.util.List «propertyName» = new java.util.ArrayList();
+        if(_dom_«propertyName» != null) {
             java.util.List _serialized = new java.util.ArrayList();
-            java.util.Iterator _iterator = _dom_«property.name».iterator();
+            java.util.Iterator _iterator = _dom_«propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
-                //System.out.println("  item" + _listItem);
-                Object _value = «type.actualTypeArguments.get(0).serializer.name».fromDomStatic(_localQName,_listItem);
-                //System.out.println("  value" + _value);
-                «property.name».add(_value);
+                ////System.out.println("  item" + _listItem);
+                Object _value = «type.actualTypeArguments.get(0).serializer.resolvedName».fromDomStatic(_localQName,_listItem);
+                ////System.out.println("  value" + _value);
+                «propertyName».add(_value);
                 _hasNext = _iterator.hasNext();
             }
         }
         
-        //System.out.println(" list" + «property.name»);
+        ////System.out.println(" list" + «propertyName»);
     '''
 
     private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type,
-        MethodSignature property) '''
-        java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
+        String propertyName) '''
+        java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
             localName»"));
-        java.util.List «property.name» = new java.util.ArrayList();
-        if(_dom_«property.name» != null) {
+        java.util.List «propertyName» = new java.util.ArrayList();
+        if(_dom_«propertyName» != null) {
             java.util.List _serialized = new java.util.ArrayList();
-            java.util.Iterator _iterator = _dom_«property.name».iterator();
+            java.util.Iterator _iterator = _dom_«propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
                 if(_listItem instanceof java.util.Map.Entry) {
                     Object _innerValue = ((java.util.Map.Entry) _listItem).getValue();
                     Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue")»;
-                    «property.name».add(_value);
+                    «propertyName».add(_value);
                 }
                 _hasNext = _iterator.hasNext();
             }
         }
     '''
 
-    private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) '''
-        java.util.List _dom_«property.name»_list = 
+    private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
+        java.util.List _dom_«propertyName»_list = 
             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
-        «type.resolvedName» «property.name» = null;
-        if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) {
-            java.util.Map.Entry _dom_«property.name» = (java.util.Map.Entry) _dom_«property.name»_list.get(0);
-            Object _inner_value = _dom_«property.name».getValue();
-            «property.name» = «deserializeValue(type, "_inner_value")»;
+        «type.resolvedName» «propertyName» = null;
+        if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
+            java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0);
+            Object _inner_value = _dom_«propertyName».getValue();
+            «propertyName» = «deserializeValue(type, "_inner_value")»;
         }
     '''
 
     private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type,
-        MethodSignature property) '''
-        java.util.List _dom_«property.name»_list = 
+        String propertyName) '''
+        java.util.List _dom_«propertyName»_list = 
             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
-        «type.resolvedName» «property.name» = null;
-        if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) {
+        «type.resolvedName» «propertyName» = null;
+        if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
             
-            java.util.Map _dom_«property.name» = (java.util.Map) _dom_«property.name»_list.get(0);
-            «type.resolvedName» «property.name» =  «type.serializer.name».fromDomStatic(_localQName,_dom_«property.name»);
+            java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0);
+            «propertyName» =  «type.serializer.resolvedName».fromDomStatic(_localQName,_dom_«propertyName»);
         }
     '''
 
+    private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) '''
+        «type.resolvedName» «propertyName» = «type.serializer.resolvedName».fromDomStatic(_localQName,_compositeNode);
+    '''
+
     private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) '''
-        («type.resolvedName») «type.valueSerializer.name».fromDomValue(«domParameter»);
+        («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»);
     '''
 
     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
@@ -445,9 +742,10 @@ class TransformerGenerator {
                 val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                implementsType(ctTransformator)
+                implementsType(BINDING_CODEC)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 implementsType(BindingDeserializer.asCtClass)
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
@@ -459,10 +757,11 @@ class TransformerGenerator {
                                 return null;
                             }
                             «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
-                            //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
+                            ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
                             «returnType.resolvedName» _value =  _encapsulatedValue.getValue();
-                            //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
-                            return _value;
+                            ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
+                            Object _domValue = «serializeValue(returnType, "_value")»;
+                            return _domValue;
                         }
                     '''
                 ]
@@ -477,7 +776,7 @@ class TransformerGenerator {
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
                         {
-                            //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+                            ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
                             
                             if($1 == null) {
                                 return null;
@@ -497,10 +796,10 @@ class TransformerGenerator {
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            log.info("DOM Codec for {} was generated {}",inputType,ret)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}",inputType,e);
+            log.error("Cannot compile DOM Codec for {}", inputType, e);
             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
             exception.addSuppressed(e);
             throw exception;
@@ -509,10 +808,10 @@ class TransformerGenerator {
     }
 
     private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
-        log.info("Generating Dummy DOM Codec for {} with {}",object,object.classLoader)
-        return createClass(typeSpec.transformatorFqn) [
+        log.info("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
+        return createClass(typeSpec.codecClassName) [
             //staticField(Map,"AUGMENTATION_SERIALIZERS");
-            implementsType(ctTransformator)
+            implementsType(BINDING_CODEC)
             implementsType(BindingDeserializer.asCtClass)
             method(Object, "toDomValue", Object) [
                 modifiers = PUBLIC + FINAL + STATIC
@@ -553,10 +852,10 @@ class TransformerGenerator {
     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
         Class<?> inputType, Enumeration typeSpec) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                implementsType(ctTransformator)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
@@ -591,49 +890,57 @@ class TransformerGenerator {
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            log.info("DOM Codec for {} was generated {}",inputType,ret)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (CodeGenerationException e) {
-            throw new CodeGenerationException("Cannot compile Transformator for " + inputType,e);
+            throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}",inputType,e);
+            log.error("Cannot compile DOM Codec for {}", inputType, e);
             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
             exception.addSuppressed(e);
             throw exception;
         }
 
     }
-    
+
     def Class<?> toClassImpl(CtClass newClass, ClassLoader loader, ProtectionDomain domain) {
-        val cls = newClass.toClass(loader,domain);
-        if(classFileCapturePath !== null) {
+        val cls = newClass.toClass(loader, domain);
+        if (classFileCapturePath !== null) {
             newClass.writeFile(classFileCapturePath.absolutePath);
         }
+        listener?.onCodecCreated(cls);
         return cls;
     }
-    
+
     def debugWriteClass(CtClass class1) {
-        val path = class1.name.replace(".","/")+".class"
-        
-        val captureFile = new File(classFileCapturePath,path);
+        val path = class1.name.replace(".", "/") + ".class"
+
+        val captureFile = new File(classFileCapturePath, path);
         captureFile.createNewFile
-        
-        
+
     }
 
-    private def dispatch String deserializeValue(Type type, String domParameter) '''(«type.resolvedName») «domParameter»'''
+    private def dispatch String deserializeValue(Type type, String domParameter) {
+        if (INSTANCE_IDENTIFIER.equals(type)) {
+
+            return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
+        }
+
+        return '''(«type.resolvedName») «domParameter»'''
+
+    }
 
     /** 
      * Default catch all
      * 
      **/
-    private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, MethodSignature property) '''
-        «type.resolvedName» «property.name» = null;
+    private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, String propertyName) '''
+        «type.resolvedName» «propertyName» = null;
     '''
 
     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
-        MethodSignature property) {
-        _deserializeProperty(container, type.toInstance, property)
+        String propertyName) {
+        _deserializeProperty(container, type.toInstance, propertyName)
     }
 
     public static def toSetter(String it) {
@@ -647,84 +954,96 @@ class TransformerGenerator {
     }
 
     /* 
-    private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, MethodSignature property) '''
-        «property.returnType.resolvedName» «property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            Object domValue = «type.serializer».toDomStatic(QNAME,«property.name»);
-            childNodes.add(domValue);
+    private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, String propertyName) '''
+        «type.resolvedName» «propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Object domValue = «type.serializer».toDomStatic(QNAME,«propertyName»);
+            _childNodes.add(domValue);
         }
     '''
     */
     private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder'''
 
-    private def staticQNameField(CtClass it, Class node) {
+    private def staticQNameField(CtClass it, Class<?> node) {
         val field = new CtField(ctQName, "QNAME", it);
         field.modifiers = PUBLIC + FINAL + STATIC;
         addField(field, '''«node.name».QNAME''')
     }
-    
+
     private def staticQNameField(CtClass it, QName node) {
         val field = new CtField(ctQName, "QNAME", it);
         field.modifiers = PUBLIC + FINAL + STATIC;
-        addField(field, '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
+        addField(field,
+            '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
     }
 
     private def dispatch String serializeBody(GeneratedType type, ListSchemaNode node) '''
         {
-            «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+            «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             «type.resolvedName» value = («type.resolvedName») $2;
             «transformDataContainerBody(type.allProperties, node)»
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            «serializeAugmentations»
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
     private def dispatch String serializeBody(GeneratedType type, ContainerSchemaNode node) '''
         {
-            «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+            «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             «type.resolvedName» value = («type.resolvedName») $2;
             «transformDataContainerBody(type.allProperties, node)»
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            «serializeAugmentations»
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
     private def dispatch String serializeBody(GeneratedType type, ChoiceCaseNode node) '''
         {
-        «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+        «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             «type.resolvedName» value = («type.resolvedName») $2;
             «transformDataContainerBody(type.allProperties, node)»
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            «serializeAugmentations»
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
     private def dispatch String serializeBody(GeneratedType type, SchemaNode node) '''
         {
-        «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+        «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             «type.resolvedName» value = («type.resolvedName») $2;
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
-
-    private def transformDataContainerBody(Map<String, MethodSignature> properties, DataNodeContainer node) {
+    private def transformDataContainerBody(Map<String, Type> properties, DataNodeContainer node) {
         val ret = '''
             «FOR child : node.childNodes.filter[!augmenting]»
                 «var signature = properties.getFor(child)»
-                «serializeProperty(child, signature.returnType, signature)»
+                //System.out.println("«signature.key»" + value.«signature.key»());
+                «serializeProperty(child, signature.value, signature.key)»
             «ENDFOR»
         '''
         return ret;
     }
-    
-    def MethodSignature getFor(Map<String,MethodSignature> map, DataSchemaNode node) {
+
+    def serializeAugmentations() '''
+        java.util.List _augmentations = (java.util.List) «AUGMENTATION_CODEC».serialize(value);
+        if(_augmentations != null) {
+            _childNodes.addAll(_augmentations);
+        }
+    '''
+
+    def Entry<String, Type> getFor(Map<String, Type> map, DataSchemaNode node) {
         val sig = map.get(node.getterName);
-        if(sig == null) {
-            return map.get(node.booleanGetterName);
+        if (sig == null) {
+
+            return new SimpleEntry(node.booleanGetterName, map.get(node.booleanGetterName));
         }
-        return sig;
+        return new SimpleEntry(node.getterName, sig);
     }
 
     private static def String getBooleanGetterName(DataSchemaNode node) {
@@ -740,106 +1059,126 @@ class TransformerGenerator {
     }
 
     private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type,
-        MethodSignature property) '''
-        «property.returnType.resolvedName» «property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            java.util.Iterator _iterator = «property.name».iterator();
+        String propertyName) '''
+        «type.resolvedName» «propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            java.util.Iterator _iterator = «propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
-                Object _domValue = «type.actualTypeArguments.get(0).serializer.name».toDomStatic(QNAME,_listItem);
-                childNodes.add(_domValue);
+                Object _domValue = «type.actualTypeArguments.get(0).serializer.resolvedName».toDomStatic(_resultName,_listItem);
+                _childNodes.add(_domValue);
                 _hasNext = _iterator.hasNext();
             }
         }
     '''
 
-    private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) '''
-        «property.returnType.resolvedName» «property.name» = value.«property.name»();
+    private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
+        «type.resolvedName» «propertyName» = value.«propertyName»();
         
-        if(«property.name» != null) {
-            «QName.name» _qname = «QName.name».create(resultName,"«schema.QName.localName»");
-            Object _propValue = «serializeValue(type, property.name)»;
+        if(«propertyName» != null) {
+            «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»");
+            Object _propValue = «serializeValue(type, propertyName)»;
             if(_propValue != null) {
                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
-                childNodes.add(_domValue);
+                _childNodes.add(_domValue);
             }
         }
     '''
 
-    private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.name».toDomValue(«parameter»)'''
+    private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.
+        resolvedName».toDomValue(«parameter»)'''
 
-    private def dispatch serializeValue(Type signature, String property) '''«property»'''
+    private def dispatch serializeValue(Type signature, String property) {
+        if (INSTANCE_IDENTIFIER == signature) {
+            return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
+        }
+        return '''«property»''';
+    }
 
-    private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, Type type, MethodSignature property) '''
-        «property.returnType.resolvedName» «property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            «QName.name» _qname = «QName.name».create(resultName,"«schema.QName.localName»");
-            java.util.Iterator _iterator = «property.name».iterator();
+    private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, ParameterizedType type,
+        String propertyName) '''
+        «type.resolvedName» «propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»");
+            java.util.Iterator _iterator = «propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
-                Object _propValue = «property.name»;
+                Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem")»;
                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
-                childNodes.add(_domValue);
+                _childNodes.add(_domValue);
                 _hasNext = _iterator.hasNext();
             }
         }
     '''
 
+    private def dispatch CharSequence serializeProperty(ChoiceNode container, GeneratedType type,
+        String propertyName) '''
+        «type.resolvedName» «propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            java.util.List domValue = «type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
+            _childNodes.addAll(domValue);
+        }
+    '''
+
     /** 
      * Default catch all
      * 
      **/
-    private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, MethodSignature property) '''
-        «property.returnType.resolvedName» «property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            Object domValue = «property.name»;
-            childNodes.add(domValue);
+    private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, String propertyName) '''
+        «type.resolvedName» «propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Object domValue = «propertyName»;
+            _childNodes.add(domValue);
         }
     '''
 
     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
-        MethodSignature property) {
-        serializeProperty(container, type.toInstance, property)
+        String propertyName) {
+        serializeProperty(container, type.toInstance, propertyName)
     }
 
     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type,
-        MethodSignature property) '''
-        «property.returnType.resolvedName» «property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            Object domValue = «type.serializer.name».toDomStatic(QNAME,«property.name»);
-            childNodes.add(domValue);
+        String propertyName) '''
+        «type.resolvedName» «propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Object domValue = «type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
+            _childNodes.add(domValue);
         }
     '''
 
-
-
-    private def transformatorFqn(GeneratedType typeSpec) {
+    private def codecClassName(GeneratedType typeSpec) {
         return '''«typeSpec.resolvedName»$Broker$Codec$DOM'''
     }
 
-    private def transformatorFqn(Class typeSpec) {
+    private def codecClassName(Class typeSpec) {
         return '''«typeSpec.name»$Broker$Codec$DOM'''
     }
 
-    private def HashMap<String, MethodSignature> getAllProperties(GeneratedType type) {
-        val ret = new HashMap<String, MethodSignature>();
+    private def dispatch HashMap<String, Type> getAllProperties(GeneratedType type) {
+        val ret = new HashMap<String, Type>();
         type.collectAllProperties(ret);
         return ret;
     }
 
-    private def dispatch void collectAllProperties(GeneratedType type, Map<String, MethodSignature> set) {
+    private def dispatch void collectAllProperties(GeneratedType type, Map<String, Type> set) {
         for (definition : type.methodDefinitions) {
-            set.put(definition.name, definition);
+            set.put(definition.name, definition.returnType);
+        }
+        for (property : type.properties) {
+            set.put(property.getterName, property.returnType);
         }
-
         for (parent : type.implements) {
             parent.collectAllProperties(set);
         }
     }
 
-    private def dispatch void collectAllProperties(Type type, Map<String, MethodSignature> set) {
+    def String getGetterName(GeneratedProperty property) {
+        return "get" + property.name.toFirstUpper
+    }
+
+    private def dispatch void collectAllProperties(Type type, Map<String, Type> set) {
         // NOOP for generic type.
     }
 
@@ -847,22 +1186,24 @@ class TransformerGenerator {
         return type.asCtClass.name;
     }
 
+    def String getResolvedName(Class type) {
+        return type.asCtClass.name;
+    }
+
     def CtClass asCtClass(Type type) {
         val name = type.fullyQualifiedName
         val cls = loadClassWithTCCL(type.fullyQualifiedName)
         return cls.asCtClass;
     }
-    
-    
-    
-    private def dispatch processException(Class<?> inputType,CodeGenerationException e){
-        log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.",inputType);
+
+    private def dispatch processException(Class<?> inputType, CodeGenerationException e) {
+        log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.", inputType);
         throw e;
     }
-    
-    private def dispatch processException(Class<?> inputType,Exception e){
-        log.error("Cannot compile DOM Codec for {}",inputType,e);
-        val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType,e);
+
+    private def dispatch processException(Class<?> inputType, Exception e) {
+        log.error("Cannot compile DOM Codec for {}", inputType, e);
+        val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
         throw exception;
     }
 
@@ -876,7 +1217,7 @@ class PropertyPair {
     Type type;
 
     @Property
-    MethodSignature signature;
+    Type returnType;
     @Property
     SchemaNode schemaNode;
 }
index 6e49305..887ef82 100644 (file)
@@ -179,7 +179,7 @@ class NotifyTask implements Callable<Object> {
         try {
             listener.onNotification(notification);
         } catch (Exception e) {
-            log.error("Unhandled exception {} thrown by listener: {} Notification: {}", e, listener, notification);
+            log.error("Unhandled exception thrown by listener: {}", listener, e);
         }
         return null;
     }
index d8fbc70..8e61c9b 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom;
 
 import java.util.Map.Entry;
 
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -16,4 +17,6 @@ public interface BindingIndependentMappingService {
     org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier<? extends DataObject> path);
 
     DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result);
+    
+    
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend
deleted file mode 100644 (file)
index a0e1c98..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-package org.opendaylight.controller.sal.binding.impl.connect.dom
-
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext
-import java.util.List
-import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
-import org.opendaylight.yangtools.sal.binding.model.api.Type
-import org.opendaylight.yangtools.yang.model.api.SchemaNode
-import java.util.Map
-import org.opendaylight.yangtools.yang.model.api.SchemaPath
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
-import org.opendaylight.yangtools.binding.generator.util.Types
-import java.util.HashMap
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.binding.DataContainer
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
-import java.util.Collections
-import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
-import org.opendaylight.yangtools.yang.model.util.ExtendedType
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
-import com.google.common.collect.FluentIterable
-import org.opendaylight.yangtools.yang.data.api.SimpleNode
-import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
-import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
-import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
-import com.google.common.collect.HashMultimap
-import com.google.common.collect.ArrayListMultimap
-import com.google.common.collect.Multimap
-import java.util.Collection
-import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
-
-class BindingMapping {
-
-    @Property
-    val Map<Type, GeneratedTypeBuilder> typeToDefinition = new HashMap();
-    
-    @Property
-    val Map<Type, SchemaNode> typeToSchemaNode = new HashMap();
-
-    def QName getSchemaNode(Class<?> cls) {
-        val ref = Types.typeForClass(cls);
-        return typeToSchemaNode.get(ref)?.QName;
-    }
-
-    def void updateBinding(SchemaContext schemaContext, ModuleContext moduleBindingContext) {
-        updateBindingFor(moduleBindingContext.childNodes, schemaContext);
-
-    }
-
-    def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
-        InstanceIdentifier<? extends DataObject> obj) {
-        val pathArguments = obj.path;
-        var Class<? extends DataObject> parent;
-        val dataDomArgs = new ArrayList<PathArgument>();
-        for (pathArgument : pathArguments) {
-            dataDomArgs.add(pathArgument.toDataDomPathArgument(parent));
-            parent = pathArgument.type;
-        }
-
-        return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
-    }
-
-    
-
-    def DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
-        if (node == null) {
-            return null;
-        }
-        val targetClass = identifier.targetType;
-        val classLoader = targetClass.classLoader;
-        val ref = Types.typeForClass(targetClass);
-        val targetType = typeToDefinition.get(ref);
-        val targetSchema = typeToSchemaNode.get(ref);
-        return node.toDataObject(classLoader, targetType.toInstance, targetSchema);
-
-    }
-
-    private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument, Class<? extends DataObject> parent) {
-        val Class rawType = argument.type;
-        val ref = Types.typeForClass(rawType);
-        val schemaType = typeToSchemaNode.get(ref);
-        val qname = schemaType.QName
-
-        val Object key = argument.key;
-        val predicates = key.toPredicates(schemaType as ListSchemaNode);
-
-        return new NodeIdentifierWithPredicates(qname, predicates);
-    }
-    
-    private def dispatch PathArgument toDataDomPathArgument(Item<?> argument, Class<? extends DataObject> parent) {
-        val ref = Types.typeForClass(argument.type);
-        val qname = typeToSchemaNode.get(ref).QName
-        return new NodeIdentifier(qname);
-    }
-
-    private def Map<QName, Object> toPredicates(Object identifier, ListSchemaNode node) {
-        val keyDefinitions = node.keyDefinition;
-        val map = new HashMap<QName, Object>();
-        for (keydef : keyDefinitions) {
-            val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode;
-            val value = identifier.getSimpleValue(keydef, keyNode.type);
-            map.put(keydef, value.value);
-        }
-        return map;
-    }
-
-    def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
-        for (entry : map.entrySet) {
-            val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
-            typeToDefinition.put(entry.value, entry.value);
-            typeToSchemaNode.put(entry.value, schemaNode)
-        }
-    }
-
-    def CompositeNode toCompositeNode(DataContainer data) {
-        val type = data.implementedInterface;
-        val typeRef = Types.typeForClass(type);
-        val schemaNode = typeToSchemaNode.get(typeRef);
-        val generatedType = typeToDefinition.get(typeRef);
-
-        return data.toDataDom(schemaNode, generatedType);
-    }
-
-    private def dispatch CompositeNode toDataDom(DataContainer data, ContainerSchemaNode node,
-        GeneratedTypeBuilder builder) {
-        val subnodes = data.toDataDomComponents(node);
-        return new CompositeNodeTOImpl(node.QName, null, subnodes);
-    }
-
-    private def dispatch CompositeNode toDataDom(DataContainer data, NotificationDefinition node,
-        GeneratedTypeBuilder builder) {
-        val subnodes = data.toDataDomComponents(node);
-        return new CompositeNodeTOImpl(node.QName, null, subnodes);
-    }
-
-    private def dispatch CompositeNode toDataDom(DataContainer data, ListSchemaNode node,
-        GeneratedTypeBuilder builder) {
-        val subnodes = data.toDataDomComponents(node);
-        return new CompositeNodeTOImpl(node.QName, null, subnodes);
-    }
-
-    private def List<Node<?>> toDataDomComponents(DataContainer data, DataNodeContainer node) {
-        val subnodes = new ArrayList<Node<?>>();
-        for (childNode : node.childNodes) {
-            val value = childNode.dataDomFromParent(data);
-            if (value !== null) {
-                subnodes.addAll(value);
-            }
-        }
-        return subnodes;
-    }
-
-    private def List<Node<?>> dataDomFromParent(DataSchemaNode node, DataContainer container) {
-        if (node.augmenting) {
-            return Collections.emptyList();
-        }
-        return dataDomFromParentImpl(node, container);
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(LeafSchemaNode node, DataContainer container) {
-        val value = container.getSimpleValue(node.QName, node.type);
-        if (value !== null) {
-            return Collections.<Node<?>>singletonList(value);
-        }
-        return Collections.emptyList();
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(LeafListSchemaNode node, DataContainer container) {
-        val values = container.getSimpleValues(node);
-        if (values !== null) {
-            //val it = new ArrayList<Node<?>>();
-            //for (value : values) {
-            //}
-
-        }
-        return Collections.emptyList();
-    }
-
-    private def getSimpleValues(DataContainer container, LeafListSchemaNode node) {
-        return Collections.emptyList();
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(ListSchemaNode node, DataContainer container) {
-        val qname = node.QName;
-        val values = container.<List>getValue(qname, List) as List<? extends DataContainer>;
-        if (values === null) {
-            return Collections.emptyList;
-        }
-        val it = new ArrayList<Node<?>>();
-        for (value : values) {
-            add(value.toCompositeNode());
-        }
-
-        return it;
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(ChoiceNode node, DataContainer container) {
-    }
-
-    private def dispatch List<Node<?>> serializeValueImpl(List<?> list, GeneratedTypeBuilder builder,
-        ListSchemaNode node) {
-        val it = new ArrayList<Node<?>>();
-        for (value : list) {
-
-            val serVal = value.serializeValueImpl(builder, node);
-            if (serVal !== null) {
-                addAll(serVal);
-            }
-        }
-        return it;
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, ExtendedType type) {
-        getSimpleValue(container, name, type.baseType);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, StringTypeDefinition type) {
-        val value = container.getValue(name, String);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, TypeDefinition<?> type) {
-        val value = container.getValue(name, Object);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, BooleanTypeDefinition type) {
-        val value = container.getValue(name, Boolean);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, BinaryTypeDefinition type) {
-        val Object value = container.getValue(name, Object); //Constants.BYTES_CLASS);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def <T> T getValue(Object object, QName node, Class<T> type) {
-        val methodName = BindingGeneratorImpl.getterMethodName(node.localName, Types.typeForClass(type));
-        var clz = object.class;
-        if (object instanceof DataContainer) {
-            clz = (object as DataContainer).implementedInterface;
-        }
-        val method = clz.getMethod(methodName);
-        if (method === null) {
-            return null;
-        }
-        val value = method.invoke(object);
-        if (value === null) {
-            return null;
-        }
-        if (type.isAssignableFrom(value.class)) {
-            return value  as T;
-        }
-        return value.getEncapsulatedValue(type);
-    }
-
-    public static def <T> T getEncapsulatedValue(Object value, Class<T> type) {
-        val method = value.class.getMethod("getValue");
-        if (method !== null && type.isAssignableFrom(method.returnType)) {
-            return method.invoke(value) as T;
-        }
-        return null;
-    }
-
-    private def dispatch List<Node<?>> serializeValueImpl(DataContainer data, GeneratedTypeBuilder builder,
-        SchemaNode node) {
-        return Collections.<Node<?>>singletonList(data.toDataDom(node, builder));
-    }
-
-    private def dispatch List<Node<?>> serializeValueImpl(Object object, GeneratedTypeBuilder builder,
-        SchemaNode node) {
-    }
-
-    def DataObject toDataObject(CompositeNode node, ClassLoader loader, GeneratedType type, SchemaNode schema) {
-
-        // Nasty reflection hack (for now)
-        val builderClass = loader.loadClass(type.builderFQN);
-        val builder = builderClass.newInstance;
-        val buildMethod = builderClass.getMethod("build");
-
-        node.fillDataObject(builder, loader, type, schema);
-
-        return buildMethod.invoke(builder) as DataObject;
-    }
-
-    private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
-        ListSchemaNode schema) {
-
-        if (schema.keyDefinition !== null && !schema.keyDefinition.empty) {
-
-            val value = node.keyToBindingKey(loader, type, schema);
-            builder.setProperty("key", value);
-        }
-        node.fillBuilderFromContainer(builder,loader,type,schema);
-    }
-    
-    
-
-    private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
-        ContainerSchemaNode schema) {
-        node.fillBuilderFromContainer(builder,loader,type,schema);
-    }
-
-    
-    private def void fillBuilderFromContainer(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, DataNodeContainer schema) {
-        val Multimap<QName,Node<?>> dataMap = ArrayListMultimap.create();
-        for(child :node.children) {
-            dataMap.put(child.nodeType,node);
-        }
-        for(entry : dataMap.asMap.entrySet) {
-            val entrySchema = schema.getDataChildByName(entry.key);
-            val entryType = type.methodDefinitions.byQName(entry.key);
-            entry.value.addValueToBuilder(builder,loader,entryType,entrySchema);
-        }
-    }
-    
-    private def Type byQName(List<MethodSignature> signatures, QName name) {
-      
-    }
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafSchemaNode container) {
-        
-    }
-    
-    
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ContainerSchemaNode container) {
-        
-    }
-    
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ListSchemaNode container) {
-        
-    }
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafListSchemaNode container) {
-        
-    }
-    
-    
-    
-    
-    private def Object keyToBindingKey(CompositeNode node, ClassLoader loader, GeneratedType type, ListSchemaNode schema) {
-        val keyClass = loader.loadClass(type.keyFQN);
-        val constructor = keyClass.constructors.get(0);
-        val keyType = type.keyTypeProperties;
-        val args = new ArrayList();
-        for (key : schema.keyDefinition) {
-            var keyProperty = keyType.get(BindingGeneratorUtil.parseToClassName(key.localName));
-            if (keyProperty == null) {
-                keyProperty = keyType.get(BindingGeneratorUtil.parseToValidParamName(key.localName));
-            }
-            val domKeyValue = node.getFirstSimpleByName(key);
-            val keyValue = domKeyValue.deserializeSimpleValue(loader, keyProperty.returnType,
-                schema.getDataChildByName(key));
-            args.add(keyValue);
-        }
-        return ClassLoaderUtils.construct(constructor, args);
-    }
-
-    private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        LeafSchemaNode node2) {
-        deserializeSimpleValueImpl(node, loader, type, node2.type);
-    }
-
-    private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        LeafListSchemaNode node2) {
-        deserializeSimpleValueImpl(node, loader, type, node2.type);
-    }
-
-    private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        ExtendedType definition) {
-        deserializeSimpleValueImpl(node, loader, type, definition.baseType);
-    }
-
-    private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        StringTypeDefinition definition) {
-        if (type instanceof GeneratedTransferObject) {
-            val cls = loader.getClassForType(type);
-            val const = cls.getConstructor(String);
-            val str = String.valueOf(node.value);
-            return const.newInstance(str);
-        }
-        return node.value;
-    }
-
-    private def Class<?> getClassForType(ClassLoader loader, Type type) {
-        loader.loadClass(type.fullyQualifiedName);
-    }
-
-    private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        TypeDefinition definition) {
-        throw new UnsupportedOperationException("TODO: auto-generated method stub")
-    }
-
-    private def Map<String, GeneratedProperty> getKeyTypeProperties(GeneratedType type) {
-        val method = FluentIterable.from(type.methodDefinitions).findFirst[name == "getKey"]
-        val key = method.returnType as GeneratedTransferObject;
-        val ret = new HashMap<String, GeneratedProperty>();
-        for (prop : key.properties) {
-            ret.put(prop.name, prop);
-        }
-        return ret;
-    }
-
-    private def void setProperty(Object object, String property, Object value) {
-        val cls = object.class;
-        val valMethod = cls.getMethod("set" + property.toFirstUpper, value.class);
-        if (valMethod != null)
-            valMethod.invoke(object, value);
-    }
-
-    private def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder'''
-
-    private def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key'''
-
-}
-
-@Data
-class PropertyCapture {
-
-    @Property
-    val Type returnType;
-    @Property
-    val String name;
-
-}
index af18e9c..f69e664 100644 (file)
@@ -6,6 +6,7 @@ import java.util.Collections;
 import javassist.ClassPool;
 
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
 import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.Provider;
@@ -42,6 +43,7 @@ public class ConnectorActivator implements Provider, ServiceTrackerCustomizer<Br
     public void onSessionInitiated(ProviderSession session) {
 
         RuntimeGeneratedMappingServiceImpl mappingImpl = new RuntimeGeneratedMappingServiceImpl();
+        mappingImpl.setPool(new ClassPool());
         SchemaService schemaService = (session.getService(SchemaService.class));
         ClassPool pool = new ClassPool();
         mappingImpl.setBinding(new TransformerGenerator(pool));
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/MappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/MappingServiceImpl.xtend
deleted file mode 100644 (file)
index 84a0065..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.opendaylight.controller.sal.binding.impl.connect.dom
-
-import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.sal.binding.model.api.CodeGenerator
-import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
-import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import java.util.Collections
-import java.util.Map.Entry
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import java.util.AbstractMap.SimpleEntry
-import org.opendaylight.controller.sal.core.api.model.SchemaService
-
-class MappingServiceImpl implements SchemaServiceListener, BindingIndependentMappingService {
-
-    var extension BindingMapping mapping = new BindingMapping;
-
-    @Property
-    BindingGeneratorImpl binding;
-
-    @Property
-    SchemaService schemaService;
-
-    override onGlobalContextUpdated(SchemaContext arg0) {
-        recreateBindingContext(arg0);
-    }
-
-    def recreateBindingContext(SchemaContext schemaContext) {
-        val newBinding = new BindingGeneratorImpl();
-        newBinding.generateTypes(schemaContext);
-        val newMapping = new BindingMapping();
-        for (entry : newBinding.moduleContexts.entrySet) {
-            val module = entry.key;
-            val context = entry.value;
-            
-            newMapping.updateBinding(schemaContext, context);
-        }
-        mapping = newMapping
-    }
-
-    override CompositeNode toDataDom(DataObject data) {
-        mapping.toCompositeNode(data);
-    }
-
-    override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
-        Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
-        val key = mapping.toDataDom(entry.key);
-        val data = mapping.toCompositeNode(entry.value);
-        return new SimpleEntry(key, data);
-    }
-
-    override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
-        InstanceIdentifier<? extends DataObject> path) {
-        return mapping.toDataDom(path);
-    }
-    
-    override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) {
-        return mapping.dataObjectFromDataDom(path,result);
-    }
-    
-    public def void start() {
-        schemaService.registerSchemaServiceListener(this);
-        recreateBindingContext(schemaService.globalContext);
-    }
-}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend
deleted file mode 100644 (file)
index c1efd11..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-package org.opendaylight.controller.sal.binding.impl.connect.dom
-
-import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator
-import javassist.ClassPool
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
-import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
-import java.util.Map
-import org.opendaylight.yangtools.sal.binding.model.api.Type
-import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
-import org.opendaylight.yangtools.yang.model.api.SchemaNode
-import java.util.HashMap
-import java.util.concurrent.ConcurrentHashMap
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import java.util.Map.Entry
-import java.util.AbstractMap.SimpleEntry
-import org.opendaylight.yangtools.yang.model.api.SchemaPath
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
-import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.binding.generator.util.Types
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
-import org.opendaylight.yangtools.yang.binding.DataContainer
-import static com.google.common.base.Preconditions.*;
-import java.util.List
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
-import org.opendaylight.yangtools.concepts.Delegator
-import java.util.concurrent.ConcurrentMap
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
-import org.opendaylight.yangtools.yang.binding.BindingCodec
-
-class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener {
-
-    ClassPool pool;
-
-    @Property
-    extension TransformerGenerator binding;
-    
-    val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
-
-    val ConcurrentMap<Class<? extends DataContainer>, TransformerWrapper> domSerializers = new ConcurrentHashMap();
-
-    @Property
-    val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
-
-    @Property
-    val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
-
-    override onGlobalContextUpdated(SchemaContext arg0) {
-        recreateBindingContext(arg0);
-    }
-
-    def recreateBindingContext(SchemaContext schemaContext) {
-        val newBinding = new BindingGeneratorImpl();
-        newBinding.generateTypes(schemaContext);
-
-        for (entry : newBinding.moduleContexts.entrySet) {
-
-            //val module = entry.key;
-            val context = entry.value;
-            updateBindingFor(context.childNodes, schemaContext);
-            
-            val typedefs = context.typedefs;
-            for(typedef : typedefs.values) {
-                binding.typeDefinitions.put(typedef,typedef as GeneratedType);
-            }
-        }
-    }
-
-    override CompositeNode toDataDom(DataObject data) {
-        toCompositeNodeImpl(data);
-    }
-
-    override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
-        Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
-        val key = toDataDomImpl(entry.key);
-        val data = toCompositeNodeImpl(entry.value);
-        return new SimpleEntry(key, data);
-    }
-
-    private def CompositeNode toCompositeNodeImpl(DataObject object) {
-        val cls = object.implementedInterface;
-        val transformator = resolveTransformator(cls);
-        val ret = transformator.transform(object);
-        return ret;
-    }
-
-    private def resolveTransformator(Class<? extends DataContainer> cls) {
-        val serializer = domSerializers.get(cls);
-        if (serializer !== null) {
-            return serializer;
-        }
-        val transformerClass = binding.transformerFor(cls).newInstance;
-        val wrapper = new TransformerWrapper(transformerClass);
-        domSerializers.putIfAbsent(cls, wrapper);
-        return wrapper;
-    }
-
-    private def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDomImpl(
-        InstanceIdentifier<? extends DataObject> object) {
-        val pathArguments = object.path;
-        var Class<? extends DataObject> parent;
-        val dataDomArgs = new ArrayList<PathArgument>();
-        for (pathArgument : pathArguments) {
-            dataDomArgs.add(pathArgument.toDataDomPathArgument(parent));
-            parent = pathArgument.type;
-        }
-
-        return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
-    }
-
-    override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
-        InstanceIdentifier<? extends DataObject> path) {
-        return toDataDomImpl(path);
-    }
-
-    override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) {
-        return dataObjectFromDataDomImpl(path, result);
-    }
-
-    def DataObject dataObjectFromDataDomImpl(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
-        val targetType = identifier.targetType
-        val transformer = resolveTransformator(targetType);
-        val ret = transformer.deserialize(node) as DataObject;
-        return ret;
-    }
-
-    def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
-        for (entry : map.entrySet) {
-            val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
-            typeToDefinition.put(entry.value, entry.value);
-            typeToSchemaNode.put(entry.value, schemaNode)
-        }
-    }
-
-    private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument,
-        Class<? extends DataObject> parent) {
-        val Class<?> rawType = argument.type;
-        val ref = Types.typeForClass(rawType);
-        val schemaType = typeToSchemaNode.get(ref);
-        val qname = schemaType.QName
-
-        val Object key = argument.key;
-        val predicates = key.toPredicates(schemaType as ListSchemaNode);
-
-        return new NodeIdentifierWithPredicates(qname, predicates);
-    }
-
-    private def Map<QName, Object> toPredicates(Object identifier, ListSchemaNode node) {
-        val keyDefinitions = node.keyDefinition;
-        val map = new HashMap<QName, Object>();
-        for (keydef : keyDefinitions) {
-            val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode;
-            val value = BindingMapping.getSimpleValue(identifier, keydef, keyNode.type);
-            map.put(keydef, value.value);
-        }
-        return map;
-    }
-
-    private def dispatch PathArgument toDataDomPathArgument(Item<?> argument, Class<? extends DataObject> parent) {
-        val ref = Types.typeForClass(argument.type);
-        val qname = typeToSchemaNode.get(ref).QName
-        return new NodeIdentifier(qname);
-    }
-
-    public def void start() {
-        pool = new ClassPool()
-        binding = new TransformerGenerator(pool);
-
-        binding.typeToDefinition = typeToDefinition
-        binding.typeToSchemaNode = typeToSchemaNode
-        binding.typeDefinitions = typeDefinitions
-
-    }
-}
-
-class TransformerWrapper implements // //
-Delegator<BindingCodec<Map<QName, Object>, Object>> {
-
-    @Property
-    val BindingCodec<Map<QName, Object>, Object> delegate;
-
-    new(BindingCodec<Map<QName, Object>, Object> delegate) {
-        _delegate = delegate;
-    }
-
-    def CompositeNode transform(DataObject input) {
-        val ret = delegate.serialize(input);
-        val node = toNode(ret)
-        return node as CompositeNode;
-    }
-
-    def deserialize(CompositeNode node) {
-        if (node === null) {
-            return null;
-        }
-        val Map mapCapture = node
-        return delegate.deserialize(mapCapture as Map<QName,Object>);
-    }
-
-    static def Node<?> toNode(Map map) {
-        val nodeMap = map as Map<QName,Object>;
-        checkArgument(map.size == 1);
-        val elem = nodeMap.entrySet.iterator.next;
-        val qname = elem.key;
-        val value = elem.value;
-        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));
-        }
-        return new CompositeNodeTOImpl(name, null, values);
-    }
-
-    static def dispatch Node<?> toNodeImpl(QName name, Map<QName, Object> object) {
-        throw new UnsupportedOperationException("Unsupported node hierarchy.");
-    }
-
-    static def dispatch Node<?> toNodeImpl(QName name, Object object) {
-        return new SimpleNodeTOImpl(name, null, object);
-    }
-}
index 87f31ac..6478a03 100644 (file)
@@ -3,6 +3,7 @@ package org.opendaylight.controller.sal.binding.impl.util;
 
 
 import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Lock;
 
 import static com.google.common.base.Preconditions.*;
 
@@ -10,20 +11,35 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 
+import com.google.common.base.Optional;
+
 public class ClassLoaderUtils {
     
     public static <V> V withClassLoader(ClassLoader cls,Callable<V> function) throws Exception {
-        checkNotNull(cls);
-        checkNotNull(function);
+        return withClassLoaderAndLock(cls, Optional.<Lock>absent(), function);
+    }
+    
+    public static <V> V withClassLoaderAndLock(ClassLoader cls,Lock lock,Callable<V> function) throws Exception {
+        checkNotNull(lock,"Lock should not be null");
+        return withClassLoaderAndLock(cls, Optional.of(lock), function);
+    }
+    
+    public static <V> V withClassLoaderAndLock(ClassLoader cls,Optional<Lock> lock,Callable<V> function) throws Exception {
+        checkNotNull(cls, "Classloader should not be null");
+        checkNotNull(function,"Function should not be null");
+        if(lock.isPresent()) {
+            lock.get().lock();
+        }
         ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
         try {
             Thread.currentThread().setContextClassLoader(cls);
             V result = function.call();
-            Thread.currentThread().setContextClassLoader(oldCls);
             return result;
-        } catch (Exception e) {
+        }  finally {
             Thread.currentThread().setContextClassLoader(oldCls);
-            throw new Exception(e);
+            if(lock.isPresent()) {
+                lock.get().unlock();
+            }
         }
     }
 
index 27d985b..7d8a8f1 100644 (file)
@@ -6,13 +6,14 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
+import javassist.ClassPool;
+
 import org.junit.Before;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.RuntimeGeneratedMappingServiceImpl;
-import org.opendaylight.controller.sal.binding.test.connect.dom.MappingServiceTest;
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
 import org.opendaylight.yangtools.yang.model.api.Module;
@@ -29,6 +30,12 @@ public  abstract class AbstractDataServiceTest {
     protected DataBrokerService biDataService;
     protected DataProviderService baDataService;
     
+    /**
+     * Workaround for JUNIT sharing classloaders
+     * 
+     */
+    protected static final ClassPool POOL = new ClassPool();
+    
     protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
     protected BindingIndependentMappingService mappingService;
     protected DataBrokerImpl baDataImpl;
@@ -56,6 +63,7 @@ public  abstract class AbstractDataServiceTest {
         biDataImpl.registerCommitHandler(treeRoot, dataStore);
         
         mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
+        mappingServiceImpl.setPool(POOL);
         mappingService = mappingServiceImpl;
         File pathname = new File("target/gen-classes-debug");
         //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath());
@@ -69,15 +77,17 @@ public  abstract class AbstractDataServiceTest {
         connectorServiceImpl.start();
         
         String[] yangFiles= getModelFilenames();
-        mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles));
+        if(yangFiles != null && yangFiles.length > 0) {
+            mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles));
+        }
     }
 
 
     protected  String[] getModelFilenames() {
-        return getModelFilenamesImpl();
+        return getAllModelFilenames();
     }
     
-    public static String[] getModelFilenamesImpl() {
+    public static String[] getAllModelFilenames() {
         Predicate<String> predicate = new Predicate<String>() {
             @Override
             public boolean apply(String input) {
index 08eb409..4e7628f 100644 (file)
@@ -1,22 +1,41 @@
 package org.opendaylight.controller.sal.binding.test.bugfix;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
@@ -27,78 +46,130 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 
 import static org.junit.Assert.*;
 
-/**
- * 
- * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id=144
- * 
- * Cannot compile CoDec for org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow
- * 
- * @author ttkacik
- *
- */
 public class DOMCodecBug01Test extends AbstractDataServiceTest {
 
     private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
     private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id");
     private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node");
-    
     private static final long FLOW_ID = 1234;
     private static final String NODE_ID = "node:1";
 
     private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder().node(Nodes.class)
-            .node(Node.class, NODE_KEY).toInstance();
-    
-    
+
     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() //
+            .node(Nodes.class) //
+            .toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .toInstance();
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .child(Node.class, NODE_KEY).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();
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .toInstance();
     private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
-    
+
     private static final FlowKey FLOW_KEY = new FlowKey(FLOW_ID, NODE_REF);
 
     private static final Map<QName, Object> FLOW_KEY_BI = //
-            ImmutableMap.<QName,Object>of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_REF);
-
-
-    
+    ImmutableMap.<QName, Object> of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_INSTANCE_ID_BI);
 
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier FLOW_INSTANCE_ID_BI = //
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
-                    .node(Flows.QNAME) //
-                    .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) //
-                    .toInstance();
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Flows.QNAME) //
+            .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) //
+            .toInstance();
     private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
-            InstanceIdentifier.builder() //
-                .node(Flows.class) //
-                .node(Flow.class, FLOW_KEY) //
-                .toInstance();
+    InstanceIdentifier.builder() //
+            .node(Flows.class) //
+            .node(Flow.class, FLOW_KEY) //
+            .toInstance();
+
+
+
     /**
-     * 
+     *
+     * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id=
+     *
+     * Cannot compile CoDec for
+     * org.opendaylight.yang.gen.v1.urn.opendaylight.flow
+     * .config.rev130819.flows.Flow
+     *
      * When invoking following code in the consumer, user got an
      * IllegalStateException during creation of mapping between Java DTOs and
      * data-dom.
-     * 
+     *
      * Exception was compilation error which was caused by incorect generation
      * of code.
-     * 
-     * 
+     *
+     * Reported by Depthi V V
+     *
      */
     @Test
     public void testIndirectGeneration() throws Exception {
 
+        ExecutorService basePool = Executors.newFixedThreadPool(2);
+        ListeningExecutorService listenablePool = MoreExecutors.listeningDecorator(basePool);
+
+        createFlow();
+
+        Object lock = new Object();
+        CreateFlowTask task1 = new CreateFlowTask(lock);
+        CreateFlowTask task2 = new CreateFlowTask(lock);
+        CreateFlowTask task3 = new CreateFlowTask(lock);
+
+        ListenableFuture<Void> task1Future = listenablePool.submit(task1);
+        ListenableFuture<Void> task2Future = listenablePool.submit(task2);
+        ListenableFuture<Void> task3Future = listenablePool.submit(task3);
+
+
+        ListenableFuture<List<Void>> compositeFuture = Futures.allAsList(task1Future,task2Future,task3Future);
+
+        Thread.sleep(500);
+        //lock.notifyAll();
+        compositeFuture.get();
+
+        verifyDataAreStoredProperly();
+
+        DataModificationTransaction modification2 = baDataService.beginTransaction();
+        modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA);
+
+        DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA);
+        assertNotNull(originalData);
+        RpcResult<TransactionStatus> ret2 = modification2.commit().get();
+
+        assertNotNull(ret2);
+        assertEquals(TransactionStatus.COMMITED, ret2.getResult());
+
+        // Data are not in the store.
+        assertNull(baDataService.readOperationalData(FLOW_INSTANCE_ID_BA));
+
+    }
+
+    private void createFlow() throws Exception {
+
         DataModificationTransaction modification = baDataService.beginTransaction();
 
-       FlowBuilder flow = new FlowBuilder();
+        FlowBuilder flow = new FlowBuilder();
         MatchBuilder match = new MatchBuilder();
         VlanMatchBuilder vlanBuilder = new VlanMatchBuilder();
         VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
@@ -110,35 +181,58 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest {
         flow.setMatch(match.build());
         flow.setNode(NODE_REF);
 
+
+        InstructionsBuilder instructions = new InstructionsBuilder();
+        InstructionBuilder instruction = new InstructionBuilder();
+        ApplyActionsBuilder applyActions = new ApplyActionsBuilder();
+        List<Action> actionList = new ArrayList<>();
+        PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder();
+        popMplsAction.setEthernetType(34);
+        actionList.add(new ActionBuilder().setAction(popMplsAction.build()).build());
+
+        applyActions.setAction(actionList );
+
+
+        instruction.setInstruction(applyActions.build());
+
+
+        List<Instruction> instructionList = Collections.<Instruction>singletonList(instruction.build());
+        instructions.setInstruction(instructionList );
+
+        flow.setInstructions(instructions.build());
         modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build());
         RpcResult<TransactionStatus> ret = modification.commit().get();
         assertNotNull(ret);
         assertEquals(TransactionStatus.COMMITED, ret.getResult());
-        
-        verifyDataAreStoredProperly();
-        
-        
-        DataModificationTransaction modification2 = baDataService.beginTransaction();
-        modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA);
-        
-        DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA);
-        assertNotNull(originalData);
-        RpcResult<TransactionStatus> ret2 = modification2.commit().get();
-        
-        assertNotNull(ret2);
-        assertEquals(TransactionStatus.COMMITED, ret2.getResult());
-        
-        
-        // Data are not in the store.
-        assertNull(baDataService.readOperationalData(FLOW_INSTANCE_ID_BA));
-        
-        
+    }
+
+    private class CreateFlowTask implements Callable<Void> {
+
+        final Object startSyncObject;
+
+        public CreateFlowTask(Object startSync) {
+            startSyncObject = startSync;
+        }
+
+        @Override
+        public Void call() {
+            try {
+                //startSyncObject.wait();
+                //Thread.sleep(500);
+                createFlow();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            return null;
+        }
     }
 
     private void verifyDataAreStoredProperly() {
         CompositeNode biFlow = biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI);
         assertNotNull(biFlow);
-        CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME,Match.QNAME.getLocalName()));
+        CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME, Match.QNAME.getLocalName()));
         assertNotNull(biMatch);
     }
+
+
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java
new file mode 100644 (file)
index 0000000..773bab8
--- /dev/null
@@ -0,0 +1,121 @@
+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 java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import static org.junit.Assert.*;
+
+public class DOMCodecBug02Test extends AbstractDataServiceTest {
+
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id");
+    private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node");
+
+    private static final String FLOW_ID = "foo";
+    private static final String NODE_ID = "node: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() //
+            .node(Nodes.class) //
+            .toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .toInstance();
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .child(Node.class, NODE_KEY).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 NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
+
+    @Override
+    protected String[] getModelFilenames() {
+        return null;
+    }
+
+    /**
+     * 
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testSchemaContextNotAvailable() throws Exception {
+
+        ExecutorService testExecutor = Executors.newFixedThreadPool(1);
+        
+        Future<Future<RpcResult<TransactionStatus>>> future = testExecutor.submit(new Callable<Future<RpcResult<TransactionStatus>>>() {
+            @Override
+            public Future<RpcResult<TransactionStatus>> call() throws Exception {
+                NodesBuilder nodesBuilder = new NodesBuilder();
+                nodesBuilder.setNode(Collections.<Node> emptyList());
+                DataModificationTransaction transaction = baDataService.beginTransaction();
+                transaction.putOperationalData(NODES_INSTANCE_ID_BA, nodesBuilder.build());
+                return transaction.commit();
+            }
+        });
+        mappingServiceImpl.onGlobalContextUpdated(getContext(getAllModelFilenames()));
+        
+        RpcResult<TransactionStatus> result = future.get().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        
+        Nodes nodes = checkForNodes();
+        assertNotNull(nodes);
+
+    }
+
+    private Nodes checkForNodes() {
+        return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java
new file mode 100644 (file)
index 0000000..ae54591
--- /dev/null
@@ -0,0 +1,156 @@
+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 java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+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.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+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.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+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.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import static org.junit.Assert.*;
+
+public class DOMCodecBug03Test 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() //
+            .node(Nodes.class) //
+            .toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .toInstance();
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .child(Node.class, NODE_KEY).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 NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
+    private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
+
+    
+    
+    /**
+     * Test for Bug 148
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testAugmentSerialization() throws Exception {
+
+        
+        baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
+        
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setId(new NodeId(NODE_ID));
+        nodeBuilder.setKey(NODE_KEY);
+        DataModificationTransaction transaction = baDataService.beginTransaction();
+        
+        
+        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();
+        nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
+        Node original = nodeBuilder.build();
+        transaction.putOperationalData(NODE_INSTANCE_ID_BA, original);
+        
+        RpcResult<TransactionStatus> result = transaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        assertNotNull(receivedChangeEvent);
+        
+        verifyNodes((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(),original);
+        assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+        Nodes nodes = checkForNodes();
+        verifyNodes(nodes,original);
+        
+        
+    }
+
+    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;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java
deleted file mode 100644 (file)
index e26273e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.opendaylight.controller.sal.binding.test.connect.dom;
-
-import static org.junit.Assert.*;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-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.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.MappingServiceImpl;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
-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.NodesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
-import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-
-public class MappingServiceTest {
-
-    private static final QName NODES = QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes");
-    private static final QName NODE = QName.create(NODES,"node");
-    private static final QName ID = QName.create(NODES,"id");
-    
-    BindingIndependentMappingService service;
-    private MappingServiceImpl impl;
-
-    @Before
-    public void setUp() {
-        impl = new MappingServiceImpl();
-        service = impl;
-    }
-
-    @Test
-    public void baDataToBiData() throws Exception {
-
-        String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl();
-
-        SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles);
-
-        impl.onGlobalContextUpdated(ctx);
-
-        NodesBuilder nodes = new NodesBuilder();
-
-        List<Node> nodeList = new ArrayList<>();
-        nodeList.add(createChildNode("foo"));
-        nodeList.add(createChildNode("bar"));
-
-        nodes.setNode(nodeList);
-        Nodes nodesTO = nodes.build();
-        CompositeNode xmlNodes = service.toDataDom(nodesTO);
-        assertNotNull(xmlNodes);
-        List<CompositeNode> invNodes = xmlNodes.getCompositesByName(NODE);
-        assertNotNull(invNodes);
-        assertEquals(2, invNodes.size());
-    }
-
-    @Test
-    public void instanceIdentifierTest() throws Exception {
-
-        String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl();
-        SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles);
-        impl.onGlobalContextUpdated(ctx);
-
-        NodeKey nodeKey = new NodeKey(new NodeId("foo"));
-        InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).child(Node.class, nodeKey).toInstance();
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier result = service.toDataDom(path);
-        assertNotNull(result);
-        assertEquals(2, result.getPath().size());
-    }
-
-    private Node createChildNode(String id) {
-        NodeBuilder node = new NodeBuilder();
-        NodeId nodeId = new NodeId(id);
-
-        node.setId(nodeId);
-        node.setKey(new NodeKey(nodeId));
-
-        FlowCapableNodeBuilder aug = new FlowCapableNodeBuilder();
-        aug.setManufacturer(id);
-        node.addAugmentation(FlowCapableNode.class, aug.build());
-
-        return node.build();
-    }
-
-}
index b878071..74c4e0a 100644 (file)
@@ -27,25 +27,37 @@ import java.util.concurrent.Future
 import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter
 import org.opendaylight.yangtools.concepts.Path
 import org.slf4j.LoggerFactory
-
-abstract class AbstractDataBroker<P extends Path<P>,D,DCL extends DataChangeListener<P,D>> implements 
-DataModificationTransactionFactory<P, D>, //
+import java.util.HashSet
+import java.util.Map.Entry
+import java.util.Iterator
+import java.util.Collection
+import com.google.common.collect.FluentIterable;
+import java.util.Set
+import com.google.common.collect.ImmutableList
+
+abstract class AbstractDataBroker<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements DataModificationTransactionFactory<P, D>, //
 DataReader<P, D>, //
 DataChangePublisher<P, D, DCL>, //
-DataProvisionService<P,D> {
+DataProvisionService<P, D> {
 
     @Property
     var ExecutorService executor;
 
     @Property
-    var AbstractDataReadRouter<P,D> dataReadRouter;
-
-    Multimap<P, DataChangeListenerRegistration<P,D,DCL>> listeners = HashMultimap.create();
-    Multimap<P, DataCommitHandlerRegistration<P,D>> commitHandlers = HashMultimap.create();
+    var AbstractDataReadRouter<P, D> dataReadRouter;
 
+    Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = HashMultimap.create();
+    Multimap<P, DataCommitHandlerRegistration<P, D>> commitHandlers = HashMultimap.create();
 
     public new() {
-        
+    }
+
+    protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedCommitHandlers(
+        HashSet<P> paths) {
+        return FluentIterable.from(commitHandlers.asMap.entrySet)
+            .filter[key.isAffectedBy(paths)] //
+            .transformAndConcat [value] //
+            .transform[instance].toList()
     }
 
     override final readConfigurationData(P path) {
@@ -56,11 +68,10 @@ DataProvisionService<P,D> {
         return dataReadRouter.readOperationalData(path);
     }
 
-    override final registerCommitHandler(P path,
-        DataCommitHandler<P, D> commitHandler) {
-            val registration = new DataCommitHandlerRegistration(path,commitHandler,this);
-            commitHandlers.put(path,registration)
-            return registration;
+    override final registerCommitHandler(P path, DataCommitHandler<P, D> commitHandler) {
+        val registration = new DataCommitHandlerRegistration(path, commitHandler, this);
+        commitHandlers.put(path, registration)
+        return registration;
     }
 
     override final def registerDataChangeListener(P path, DCL listener) {
@@ -69,27 +80,49 @@ DataProvisionService<P,D> {
         return reg;
     }
 
-     final def registerDataReader(P path,DataReader<P,D> reader) {
-        
-        val confReg = dataReadRouter.registerConfigurationReader(path,reader);
-        val dataReg = dataReadRouter.registerOperationalReader(path,reader);
-        
-        return new CompositeObjectRegistration(reader,Arrays.asList(confReg,dataReg));
+    final def registerDataReader(P path, DataReader<P, D> reader) {
+
+        val confReg = dataReadRouter.registerConfigurationReader(path, reader);
+        val dataReg = dataReadRouter.registerOperationalReader(path, reader);
+
+        return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg));
     }
 
-    protected  final def removeListener(DataChangeListenerRegistration<P,D,DCL> registration) {
+    protected final def removeListener(DataChangeListenerRegistration<P, D, DCL> registration) {
         listeners.remove(registration.path, registration);
     }
 
-    protected  final def removeCommitHandler(DataCommitHandlerRegistration<P,D> registration) {
+    protected final def removeCommitHandler(DataCommitHandlerRegistration<P, D> registration) {
         commitHandlers.remove(registration.path, registration);
     }
-    
-    protected  final def getActiveCommitHandlers() {
-        return commitHandlers.entries.map[ value.instance].toSet
+
+    protected final def getActiveCommitHandlers() {
+        return commitHandlers.entries;
     }
 
-    package final def Future<RpcResult<TransactionStatus>>  commit(AbstractDataTransaction<P,D> transaction) {
+    protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedListenersWithInitialState(
+        HashSet<P> paths) {
+        return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [
+            val operationalState = readOperationalData(key)
+            val configurationState = readConfigurationData(key)
+            return new ListenerStateCapture(key, value, operationalState, configurationState)
+        ].toList()
+    }
+
+    protected def boolean isAffectedBy(P key, Set<P> paths) {
+        if (paths.contains(key)) {
+            return true;
+        }
+        for (path : paths) {
+            if (key.contains(path)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    package final def Future<RpcResult<TransactionStatus>> commit(AbstractDataTransaction<P, D> transaction) {
         checkNotNull(transaction);
         transaction.changeStatus(TransactionStatus.SUBMITED);
         val task = new TwoPhaseCommit(transaction, this);
@@ -98,14 +131,30 @@ DataProvisionService<P,D> {
 
 }
 
-package class DataChangeListenerRegistration<P extends Path<P>,D,DCL extends DataChangeListener<P,D>> extends AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {
+@Data
+package class ListenerStateCapture<P extends Path<P>, D,DCL extends DataChangeListener<P, D>> {
 
-    AbstractDataBroker<P,D,DCL> dataBroker;
+    @Property
+    P path;
+
+    @Property
+    Collection<DataChangeListenerRegistration<P, D, DCL>> listeners;
+
+    @Property
+    D initialOperationalState;
+
+    @Property
+    D initialConfigurationState;
+}
+
+package class DataChangeListenerRegistration<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> extends AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {
+
+    AbstractDataBroker<P, D, DCL> dataBroker;
 
     @Property
     val P path;
 
-    new(P path, DCL instance, AbstractDataBroker<P,D,DCL> broker) {
+    new(P path, DCL instance, AbstractDataBroker<P, D, DCL> broker) {
         super(instance)
         dataBroker = broker;
         _path = path;
@@ -118,16 +167,14 @@ package class DataChangeListenerRegistration<P extends Path<P>,D,DCL extends Dat
 
 }
 
-package class DataCommitHandlerRegistration<P extends Path<P>,D>
-extends AbstractObjectRegistration<DataCommitHandler<P, D>> {
+package class DataCommitHandlerRegistration<P extends Path<P>, D> extends AbstractObjectRegistration<DataCommitHandler<P, D>> {
 
-    AbstractDataBroker<P,D,?> dataBroker;
+    AbstractDataBroker<P, D, ?> dataBroker;
 
     @Property
     val P path;
 
-    new(P path, DataCommitHandler<P, D> instance,
-        AbstractDataBroker<P,D,?> broker) {
+    new(P path, DataCommitHandler<P, D> instance, AbstractDataBroker<P, D, ?> broker) {
         super(instance)
         dataBroker = broker;
         _path = path;
@@ -140,74 +187,105 @@ extends AbstractObjectRegistration<DataCommitHandler<P, D>> {
 
 }
 
-package class TwoPhaseCommit<P extends Path<P>,D> implements Callable<RpcResult<TransactionStatus>> {
-    
+package class TwoPhaseCommit<P extends Path<P>, D,DCL extends DataChangeListener<P, D>> implements Callable<RpcResult<TransactionStatus>> {
+
     private static val log = LoggerFactory.getLogger(TwoPhaseCommit);
 
-    val AbstractDataTransaction<P,D> transaction;
-    val AbstractDataBroker<P,D,?> dataBroker;
+    val AbstractDataTransaction<P, D> transaction;
+    val AbstractDataBroker<P, D, DCL> dataBroker;
 
-    new(AbstractDataTransaction<P,D> transaction, AbstractDataBroker<P,D,?> broker) {
+    new(AbstractDataTransaction<P, D> transaction, AbstractDataBroker<P, D, DCL> broker) {
         this.transaction = transaction;
         this.dataBroker = broker;
     }
 
     override call() throws Exception {
 
-        val Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.activeCommitHandlers;
+        // get affected paths
+        val affectedPaths = new HashSet<P>();
+
+        affectedPaths.addAll(transaction.createdConfigurationData.keySet);
+        affectedPaths.addAll(transaction.updatedConfigurationData.keySet);
+        affectedPaths.addAll(transaction.removedConfigurationData);
+
+        affectedPaths.addAll(transaction.createdOperationalData.keySet);
+        affectedPaths.addAll(transaction.updatedOperationalData.keySet);
+        affectedPaths.addAll(transaction.removedOperationalData);
+
+        val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths);
 
         // requesting commits
+        val Iterable<DataCommitHandler<P, D>> commitHandlers =   dataBroker.affectedCommitHandlers(affectedPaths);
         val List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList();
         try {
             for (handler : commitHandlers) {
                 handlerTransactions.add(handler.requestCommit(transaction));
             }
         } catch (Exception e) {
-            log.error("Request Commit failded",e);
-            return rollback(handlerTransactions,e);
+            log.error("Request Commit failded", e);
+            return rollback(handlerTransactions, e);
         }
         val List<RpcResult<Void>> results = new ArrayList();
         try {
             for (subtransaction : handlerTransactions) {
                 results.add(subtransaction.finish());
             }
+            listeners.publishDataChangeEvent();
         } catch (Exception e) {
-            log.error("Finish Commit failed",e);
-            return rollback(handlerTransactions,e);
+            log.error("Finish Commit failed", e);
+            return rollback(handlerTransactions, e);
         }
 
+        
         return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet());
+
+    }
+    
+    def void publishDataChangeEvent(ImmutableList<ListenerStateCapture<P, D,DCL>> listeners) {
+        for(listenerSet : listeners) {
+            val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path);
+            val updatedOperational = dataBroker.readOperationalData(listenerSet.path);
+            
+            val changeEvent = new DataChangeEventImpl(transaction,listenerSet.initialConfigurationState,listenerSet.initialOperationalState,updatedOperational,updatedConfiguration);
+            for(listener : listenerSet.listeners) {
+                try {
+                    listener.instance.onDataChanged(changeEvent);
+                    
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
     }
 
-    def rollback(List<DataCommitTransaction<P, D>> transactions,Exception e) {
+    def rollback(List<DataCommitTransaction<P, D>> transactions, Exception e) {
         for (transaction : transactions) {
             transaction.rollback()
         }
+
         // FIXME return encountered error.
         return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet());
     }
 }
-
 public abstract class AbstractDataTransaction<P extends Path<P>, D> extends AbstractDataModification<P, D> {
 
     @Property
     private val Object identifier;
 
-    
     var TransactionStatus status;
-    
-    
+
     var AbstractDataBroker<P, D, ?> broker;
 
-    protected new (AbstractDataBroker<P,D,?> dataBroker) {
+    protected new(AbstractDataBroker<P, D, ?> dataBroker) {
         super(dataBroker);
         _identifier = new Object();
         broker = dataBroker;
         status = TransactionStatus.NEW;
-        //listeners = new ListenerRegistry<>();
+
+    //listeners = new ListenerRegistry<>();
     }
 
-    override  commit() {
+    override commit() {
         return broker.commit(this);
     }
 
@@ -230,7 +308,7 @@ public abstract class AbstractDataTransaction<P extends Path<P>, D> extends Abst
             return false;
         if (getClass() != obj.getClass())
             return false;
-        val other = (obj as AbstractDataTransaction<P,D>) ;
+        val other = (obj as AbstractDataTransaction<P,D>);
         if (broker == null) {
             if (other.broker != null)
                 return false;
@@ -248,12 +326,11 @@ public abstract class AbstractDataTransaction<P extends Path<P>, D> extends Abst
         return status;
     }
 
-    
     protected abstract def void onStatusChange(TransactionStatus status);
-    
+
     public def changeStatus(TransactionStatus status) {
         this.status = status;
         onStatusChange(status);
     }
-    
+
 }
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java
new file mode 100644 (file)
index 0000000..4eb9586
--- /dev/null
@@ -0,0 +1,73 @@
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChange;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+
+public class DataChangeEventImpl<P, D> implements DataChangeEvent<P, D> {
+
+    private final DataChange<P, D> dataChange;
+
+    private final D originalConfigurationSubtree;
+    private final D originalOperationalSubtree;
+    private final D updatedOperationalSubtree;
+    private final D updatedConfigurationSubtree;
+
+    
+    
+    
+    public DataChangeEventImpl(DataChange<P, D> dataChange, D originalConfigurationSubtree,
+            D originalOperationalSubtree, D updatedOperationalSubtree, D updatedConfigurationSubtree) {
+        super();
+        this.dataChange = dataChange;
+        this.originalConfigurationSubtree = originalConfigurationSubtree;
+        this.originalOperationalSubtree = originalOperationalSubtree;
+        this.updatedOperationalSubtree = updatedOperationalSubtree;
+        this.updatedConfigurationSubtree = updatedConfigurationSubtree;
+    }
+
+    @Override
+    public D getUpdatedOperationalSubtree() {
+        return updatedOperationalSubtree;
+    }
+
+    @Override
+    public D getUpdatedConfigurationSubtree() {
+        return updatedConfigurationSubtree;
+    }
+
+    public Map<P, D> getCreatedOperationalData() {
+        return dataChange.getCreatedOperationalData();
+    }
+
+    public Map<P, D> getCreatedConfigurationData() {
+        return dataChange.getCreatedConfigurationData();
+    }
+
+    public Map<P, D> getUpdatedOperationalData() {
+        return dataChange.getUpdatedOperationalData();
+    }
+
+    public Map<P, D> getUpdatedConfigurationData() {
+        return dataChange.getUpdatedConfigurationData();
+    }
+
+    public Set<P> getRemovedConfigurationData() {
+        return dataChange.getRemovedConfigurationData();
+    }
+
+    public Set<P> getRemovedOperationalData() {
+        return dataChange.getRemovedOperationalData();
+    }
+
+    public Map<P, D> getOriginalConfigurationData() {
+        return dataChange.getOriginalConfigurationData();
+    }
+
+    public Map<P, D> getOriginalOperationalData() {
+        return dataChange.getOriginalOperationalData();
+    }
+
+}