Move RuntimeGeneratedMappingService from md-sal to yang-data-impl(codecs + apis)... 31/4631/2
authorMaros Marsalek <mmarsale@cisco.com>
Thu, 23 Jan 2014 09:01:05 +0000 (10:01 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Thu, 23 Jan 2014 13:28:22 +0000 (14:28 +0100)
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Change-Id: I44b19aa5221baf8e954553789e96f0cb662703d9

35 files changed:
code-generator/binding-generator-impl/pom.xml
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingClassListener.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecMapping.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecTypeUtils.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.xtend [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/IntermediateMapping.xtend [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/StaticFieldInitializer.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassGenerator.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/CodeGenerationException.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/FieldGenerator.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.xtend [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/MethodGenerator.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/XtendHelper.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/YangSchemaUtils.java [new file with mode: 0644]
code-generator/pom.xml
pom.xml
yang/yang-data-impl/pom.xml
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/AugmentationCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCaseCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/CodecRegistry.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DataContainerCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DeserializationException.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DomCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentifierCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentitityCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ValueWithQName.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaServiceListener.java [new file with mode: 0644]

index 29410091ff8c70ac55f763edcdfb45048a1bccdb..f46d14e22c5a7ff54bafc88b47b0b03b19457f51 100644 (file)
     <artifactId>binding-generator-impl</artifactId>
 
     <dependencies>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>binding-generator-util</artifactId>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-parser-impl</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-impl</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>binding-generator-api</artifactId>
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingClassListener.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingClassListener.java
new file mode 100644 (file)
index 0000000..fd7589d
--- /dev/null
@@ -0,0 +1,8 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl;
+
+public interface BindingClassListener {
+
+    void onBindingClassCaptured(Class<?> cls);
+
+    void onBindingClassProcessed(Class<?> cls);
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecMapping.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecMapping.java
new file mode 100644 (file)
index 0000000..caf0216
--- /dev/null
@@ -0,0 +1,105 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.data.impl.codec.IdentitityCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CodecMapping {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CodecMapping.class);
+
+    public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC";
+    public static final String IDENTITYREF_CODEC = "IDENTITYREF_CODEC";
+
+    public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE";
+    public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE";
+    public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC";
+
+    public static void setIdentifierCodec(Class<?> obj,InstanceIdentifierCodec codec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = obj.getField(INSTANCE_IDENTIFIER_CODEC);
+            if(obj != null) {
+                instanceIdField.set(null, codec);
+            }
+        } catch (NoSuchFieldException e) {
+           LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
+        } catch (SecurityException | IllegalAccessException e) {
+            LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
+        }
+    }
+
+
+    public static void setIdentityRefCodec(Class<?> obj,IdentitityCodec<?> codec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = obj.getField(IDENTITYREF_CODEC);
+            if(obj != null) {
+                instanceIdField.set(null, codec);
+            }
+        } catch (NoSuchFieldException e) {
+           LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
+        } catch (SecurityException | IllegalAccessException e) {
+            LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
+        }
+    }
+
+    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) {
+            LOG.debug("BUG: Class to case mappping is not needed for {}",codec.getName(),e);
+        } catch (SecurityException | IllegalAccessException e) {
+            LOG.error("Class to case mappping could not be set for {}",codec.getName(),e);
+        }
+    }
+
+    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) {
+            LOG.debug("BUG: Class to case mappping is not needed for {}",codec.getName(),e);
+        } catch (SecurityException | IllegalAccessException e) {
+            LOG.error("Composite node to case mappping could not be set for {}",codec.getName(),e);
+        }
+    }
+
+    public static void setAugmentationCodec(Class<? extends BindingCodec<?,?>> dataCodec,
+            BindingCodec<?,?> augmentableCodec) {
+            Field instanceIdField;
+            try {
+                instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+                instanceIdField.set(null, augmentableCodec);
+            } catch (NoSuchFieldException e) {
+                LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e);
+            } catch (SecurityException | IllegalAccessException e) {
+                LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
+            }
+    }
+
+
+    public static BindingCodec<?,?> getAugmentationCodec(Class<? extends BindingCodec<?,?>> dataCodec) {
+            Field instanceIdField;
+            try {
+                instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+                return (BindingCodec<?,?>) instanceIdField.get(null);
+            } catch (NoSuchFieldException e) {
+                LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e);
+            } catch (SecurityException | IllegalAccessException e) {
+                LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
+            }
+            return null;
+    }
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecTypeUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecTypeUtils.java
new file mode 100644 (file)
index 0000000..1cba8de
--- /dev/null
@@ -0,0 +1,15 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl;
+
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+
+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/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java
new file mode 100644 (file)
index 0000000..91fca36
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+
+public interface GeneratorListener {
+
+
+
+    void onClassProcessed(Class<?> cl);
+
+    void onCodecCreated(Class<?> codec);
+    void onValueCodecCreated(Class<?> valueClass, Class<?> valueCodec);
+    void onCaseCodecCreated(Class<?> choiceClass, Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec);
+    void onDataContainerCodecCreated(Class<?> dataClass, Class<? extends BindingCodec<?, ?>> dataCodec);
+
+    void onChoiceCodecCreated(Class<?> choiceClass,
+                              Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec, ChoiceNode schema);
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.xtend
new file mode 100644 (file)
index 0000000..42fb8d9
--- /dev/null
@@ -0,0 +1,151 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.yang.data.impl.codec.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.yangtools.yang.data.impl.codec.InstanceIdentifierCodec
+import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName
+import java.util.HashMap
+import org.slf4j.LoggerFactory
+import java.util.List
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.data.impl.codec.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
+import org.opendaylight.yangtools.yang.binding.Augmentable
+import com.google.common.collect.ImmutableList
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import java.util.concurrent.ConcurrentHashMap
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections
+
+class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
+
+    private static val LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl);
+    val CodecRegistry codecRegistry;
+
+    val Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = 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)
+            baType = baArg?.type
+            val injectAugment = classToPreviousAugment.get(baType);
+            if(injectAugment != null) {
+                val augment = injectAugment.get(scannedPath) as Class<? extends DataObject>;
+                if(augment != null) {
+                    baArgs.add(new Item(augment));
+                }
+            }
+            baArgs.add(baArg)
+        }
+        val ret = new InstanceIdentifier(baArgs,baType as Class<? extends DataObject>);
+        LOG.debug("DOM Instance Identifier {} deserialized to {}",input,ret);
+        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) {
+        var Class<?> previousAugmentation = null
+        val pathArgs = input.path as List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>
+        var QName previousQName = null;
+        val components = new ArrayList<PathArgument>(pathArgs.size);
+        val qnamePath = new ArrayList<QName>(pathArgs.size);
+        for(baArg : pathArgs) {
+
+            if(!Augmentation.isAssignableFrom(baArg.type)) {
+
+                val biArg = serializePathArgument(baArg,previousQName);
+                previousQName = biArg.nodeType;
+                components.add(biArg);
+                qnamePath.add(biArg.nodeType);
+                val immutableList = ImmutableList.copyOf(qnamePath);
+                codecRegistry.putPathToClass(immutableList,baArg.type);
+                if(previousAugmentation !== null) {
+                    updateAugmentationInjection(baArg.type,immutableList,previousAugmentation)
+                }
+
+                previousAugmentation = null;
+            } else {
+                previousQName = codecRegistry.getQNameForAugmentation(baArg.type as Class);
+                previousAugmentation = baArg.type;
+            }
+        }
+        val ret = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(components);
+        LOG.debug("Binding Instance Identifier {} serialized to DOM InstanceIdentifier {}",input,ret);
+        return ret;
+    }
+
+    def updateAugmentationInjection(Class<? extends DataObject> class1, ImmutableList<QName> list, Class<?> augmentation) {
+        if(classToPreviousAugment.get(class1) == null) {
+            classToPreviousAugment.put(class1,new ConcurrentHashMap());
+        }
+        classToPreviousAugment.get(class1).put(list,augmentation);
+    }
+
+    private def dispatch PathArgument serializePathArgument(Item argument, QName previousQname) {
+        val type = argument.type;
+        val qname = BindingReflections.findQName(type);
+        if(previousQname == null) {
+            return new NodeIdentifier(qname);
+        }
+        return new NodeIdentifier(QName.create(previousQname,qname.localName));
+    }
+
+    @SuppressWarnings("rawtypes")
+    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 = BindingReflections.findQName(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);
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/IntermediateMapping.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/IntermediateMapping.xtend
new file mode 100644 (file)
index 0000000..63fc325
--- /dev/null
@@ -0,0 +1,48 @@
+package org.opendaylight.yangtools.sal.binding.generator.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) {
+        if(map instanceof Node<?>) {
+            return map as Node<?>;
+        }
+        val nodeMap = map as Map<QName,Object>;
+        Preconditions.checkArgument(map.size == 1);
+        val elem = nodeMap.entrySet.iterator.next;
+        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) {
+            if(obj instanceof Node<?>) {
+                values.add(obj as Node<?>);
+            } else if(obj instanceof Map<?,?>) {
+                values.add(toNode(obj as Map<?,?>));
+            }
+        }
+        return new CompositeNodeTOImpl(name, null, values);
+    }
+
+    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/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java
new file mode 100644 (file)
index 0000000..fa25e95
--- /dev/null
@@ -0,0 +1,976 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.data.impl.codec.*;
+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.sal.binding.model.api.ConcreteType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.binding.*;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.model.api.*;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+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 final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
+
+    private TransformerGenerator generator;
+
+    // Concrete class to codecs
+    private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, AugmentationCodec<?>> augmentationCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, QName> identityQNames = new WeakHashMap<>();
+    private static final Map<QName, Type> qnamesToIdentityMap = new ConcurrentHashMap<>();
+    /** Binding type to encountered classes mapping **/
+    @SuppressWarnings("rawtypes")
+    private static final Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
+
+    @SuppressWarnings("rawtypes")
+    private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
+
+    private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
+
+    private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+    private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+    private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
+
+    private SchemaContext currentSchema;
+
+    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) {
+        AugmentationCodec<T> codec = null;
+        @SuppressWarnings("rawtypes")
+        AugmentationCodec potentialCodec = augmentationCodecs.get(object);
+        if (potentialCodec != null) {
+            codec = potentialCodec;
+        } else
+            try {
+                Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
+                        .augmentationTransformerFor(object);
+                BindingCodec<Map<QName, Object>, Object> rawCodec = augmentRawCodec.newInstance();
+                codec = new AugmentationCodecWrapper<T>(rawCodec);
+                augmentationCodecs.put(augmentRawCodec, codec);
+            } catch (InstantiationException e) {
+                LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e);
+            } catch (IllegalAccessException e) {
+                LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e);
+            }
+        Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
+        if (objectSupertype != null) {
+            getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec);
+        } else {
+            LOG.warn("Could not find augmentation target for augmentation {}", object);
+        }
+        return codec;
+    }
+
+    @Override
+    public QName getQNameForAugmentation(Class<?> cls) {
+        Preconditions.checkArgument(Augmentation.class.isAssignableFrom(cls));
+        return getCodecForAugmentation((Class<? extends Augmentation>)cls).getAugmentationQName();
+    }
+
+    private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
+            final Class<? extends Augmentation<?>> augmentation) {
+        try {
+            Class<? extends Augmentable<?>> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(),
+                    new Callable<Class<? extends Augmentable<?>>>() {
+                        @Override
+                        @SuppressWarnings("unchecked")
+                        public Class<? extends Augmentable<?>> call() throws Exception {
+                            for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) {
+                                if (supertype instanceof ParameterizedType
+                                        && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) {
+                                    ParameterizedType augmentationGeneric = (ParameterizedType) supertype;
+                                    return (Class<? extends Augmentable<?>>) augmentationGeneric
+                                            .getActualTypeArguments()[0];
+                                }
+                            }
+                            return null;
+                        }
+                    });
+            return ret;
+        } catch (Exception e) {
+            LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
+            return null;
+        }
+    }
+
+    @Override
+    public Class<?> getClassForPath(List<QName> names) {
+        DataSchemaNode node = getSchemaNode(names);
+        SchemaPath path = node.getPath();
+        Type type = pathToType.get(path);
+        if (type != null) {
+            type = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+        } else {
+            type = pathToInstantiatedType.get(names);
+        }
+        @SuppressWarnings("rawtypes")
+        WeakReference<Class> weakRef = typeToClass.get(type);
+        if (weakRef == null) {
+            LOG.error("Could not find loaded class for path: {} and type: {}", path, type.getFullyQualifiedName());
+        }
+        return weakRef.get();
+    }
+
+    @Override
+    public void putPathToClass(List<QName> names, Class<?> cls) {
+        Type reference = Types.typeForClass(cls);
+        pathToInstantiatedType.put(names, reference);
+        bindingClassEncountered(cls);
+    }
+
+    @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;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public void bindingClassEncountered(Class cls) {
+
+        ConcreteType typeRef = Types.typeForClass(cls);
+        if (typeToClass.containsKey(typeRef)) {
+            return;
+        }
+        LOG.trace("Binding Class {} encountered.", cls);
+        WeakReference<Class> weakRef = new WeakReference<>(cls);
+        typeToClass.put(typeRef, weakRef);
+        if (Augmentation.class.isAssignableFrom(cls)) {
+
+        } else if (DataObject.class.isAssignableFrom(cls)) {
+            @SuppressWarnings({ "unchecked", "unused" })
+            Object cdc = getCodecForDataObject((Class<? extends DataObject>) cls);
+        }
+    }
+
+    @Override
+    public void onClassProcessed(Class<?> cls) {
+        ConcreteType typeRef = Types.typeForClass(cls);
+        if (typeToClass.containsKey(typeRef)) {
+            return;
+        }
+        LOG.trace("Binding Class {} encountered.", cls);
+        WeakReference<Class> weakRef = new WeakReference<>((Class) 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) {
+                Preconditions.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 IdentitityCodec<?> getIdentityCodec() {
+        return identityRefCodec;
+    }
+
+    @Override
+    public <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec) {
+        bindingClassEncountered(codec);
+        return identityRefCodec;
+    }
+
+    @Override
+    public void onCodecCreated(Class<?> cls) {
+        CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
+        CodecMapping.setIdentityRefCodec(cls, identityRefCodec);
+    }
+
+    @Override
+    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 = typeToCaseCodecs.get(typeref);
+
+        Preconditions.checkState(caseCodec != null, "Case Codec was not created proactivelly for %s", caseClass.getName());
+        Preconditions.checkState(caseCodec.getSchema() != null, "Case schema is not available for %s", caseClass.getName());
+        @SuppressWarnings("unchecked")
+        Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema());
+        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());
+        qnamesToIdentityMap.putAll(context.getIdentities());
+        for (Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
+            typeToQname.put(
+                    new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),
+                    identity.getKey());
+        }
+        captureCases(context.getCases(), schemaContext);
+    }
+
+    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());
+
+            pathToType.put(caseNode.getKey(), caseNode.getValue());
+
+            ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
+
+            if (node == null) {
+                LOG.error("YANGTools Bug: SchemaNode for {}, with path {} was not found in context.",
+                        typeref.getFullyQualifiedName(), caseNode.getKey());
+                @SuppressWarnings("rawtypes")
+                ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl();
+                typeToCaseCodecs.putIfAbsent(typeref, value);
+                continue;
+            }
+            @SuppressWarnings("rawtypes")
+            ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node);
+            typeToCaseCodecs.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, ChoiceNode schema) {
+        ChoiceCodec<?> oldCodec = choiceCodecs.get(choiceClass);
+        Preconditions.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());
+
+        tryToCreateCasesCodecs(schema);
+
+    }
+
+    private void tryToCreateCasesCodecs(ChoiceNode schema) {
+        for (ChoiceCaseNode caseNode : schema.getCases()) {
+            SchemaPath path = caseNode.getPath();
+            GeneratedTypeBuilder type;
+            if (path != null && (type = pathToType.get(path)) != null) {
+                ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+                ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
+                if (partialCodec.getSchema() == null) {
+                    partialCodec.setSchema(caseNode);
+                }
+
+                Class<?> caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName());
+                if (caseClass != null) {
+                    getCaseCodecFor(caseClass);
+                }
+            }
+        }
+
+    }
+
+    @Override
+    public void onValueCodecCreated(Class<?> valueClass, Class<?> valueCodec) {
+    }
+
+    @Override
+    public void onCaseCodecCreated(Class<?> choiceClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
+    }
+
+    @Override
+    public void onDataContainerCodecCreated(Class<?> dataClass, Class<? extends BindingCodec<?, ?>> dataCodec) {
+        if (Augmentable.class.isAssignableFrom(dataClass)) {
+            AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass);
+            CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec);
+        }
+
+    }
+
+    public 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 IntermediateMapping.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 boolean augmenting;
+        private BindingCodec delegate;
+
+        private Set<String> validNames;
+        private Set<QName> validQNames;
+        private ChoiceCaseNode schema;
+
+        public void setSchema(ChoiceCaseNode caseNode) {
+            this.schema = schema;
+            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();
+        }
+
+        public ChoiceCaseCodecImpl() {
+            this.delegate = NOT_READY_CODEC;
+        }
+
+        public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) {
+            this.delegate = NOT_READY_CODEC;
+            setSchema(caseNode);
+        }
+
+        @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 (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 (!Objects.equals(parent.getNamespace(), child.getNamespace())
+                        || !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<Entry<Class, BindingCodec<Object, Object>>> entrySet() {
+            return Collections.emptySet();
+        }
+
+        @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 BindingCodec get(Object key) {
+            if (!(key instanceof CompositeNode)) {
+                return null;
+            }
+            for (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 org.opendaylight.yangtools.yang.binding.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 Collections.emptySet();
+        }
+
+        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 true;
+        }
+
+        @Override
+        public Set<T> keySet() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public Set<Entry<T, BindingCodec<?, ?>>> entrySet() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return false;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private class AugmentableCompositeCodec implements BindingCodec {
+
+        private final Class augmentableType;
+
+        Map<Class, AugmentationCodec<?>> localAugmentationCodecs = new WeakHashMap<>();
+
+        public AugmentableCompositeCodec(Class type) {
+            Preconditions.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 (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+                LOG.debug("Could not read augmentations for {}", input, e);
+            }
+            return Collections.emptyMap();
+        }
+
+        private List serializeImpl(Map<Class, Augmentation> input) {
+            List ret = new ArrayList<>();
+            for (Entry<Class, Augmentation> entry : input.entrySet()) {
+                AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
+                CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
+                ret.addAll(node.getChildren());
+            }
+            return ret;
+        }
+
+        public synchronized <T extends Augmentation<?>> void addAugmentationCodec(Class<T> augmentationClass,
+                AugmentationCodec<T> value) {
+            localAugmentationCodecs.put(augmentationClass, value);
+        }
+
+        @Override
+        public Map<Class, Augmentation> deserialize(Object input) {
+            Map<Class, Augmentation> ret = new HashMap<>();
+            if (input instanceof CompositeNode) {
+                List<Entry<Class, AugmentationCodec<?>>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet());
+                for (Entry<Class, AugmentationCodec<?>> codec : codecs) {
+                    ValueWithQName<?> value = codec.getValue().deserialize((CompositeNode) input);
+                    if (value != null && value.getValue() != null) {
+                        ret.put(codec.getKey(), (Augmentation) value.getValue());
+                    }
+                }
+            }
+            return ret;
+        }
+
+        public 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);
+        }
+    }
+
+    private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
+            Delegator<BindingCodec> {
+
+        private BindingCodec delegate;
+        private QName augmentationQName;
+
+        public AugmentationCodecWrapper(BindingCodec<Map<QName, Object>, Object> rawCodec) {
+            this.delegate = rawCodec;
+            this.augmentationQName = BindingReflections.findQName(rawCodec.getClass());
+        }
+
+        @Override
+        public BindingCodec getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            @SuppressWarnings("unchecked")
+            List<Map<QName, Object>> rawValues = (List<Map<QName, Object>>) getDelegate().serialize(input);
+            List<Node<?>> serialized = new ArrayList<>(rawValues.size());
+            for (Map<QName, Object> val : rawValues) {
+                serialized.add(IntermediateMapping.toNode(val));
+            }
+            return new CompositeNodeTOImpl(input.getQname(), null, serialized);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            Object rawCodecValue = getDelegate().deserialize((Map<QName, Object>) input);
+            return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
+        }
+
+        @Override
+        public QName getAugmentationQName() {
+            return augmentationQName;
+        }
+    }
+
+    private class IdentityCompositeCodec implements IdentitityCodec {
+
+        @Override
+        public Object deserialize(Object input) {
+            Preconditions.checkArgument(input instanceof QName);
+            return deserialize((QName) input);
+        }
+
+        @Override
+        public Class<?> deserialize(QName input) {
+            Type type = qnamesToIdentityMap.get(input);
+            if (type == null) {
+                return null;
+            }
+            ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+            WeakReference<Class> softref = typeToClass.get(typeref);
+            if (softref == null) {
+                return null;
+            }
+            return softref.get();
+        }
+
+        @Override
+        public QName serialize(Class input) {
+            Preconditions.checkArgument(BaseIdentity.class.isAssignableFrom(input));
+            bindingClassEncountered(input);
+            QName qname = identityQNames.get(input);
+            if (qname != null) {
+                return qname;
+            }
+            ConcreteType typeref = Types.typeForClass(input);
+            qname = typeToQname.get(typeref);
+            if (qname != null) {
+                identityQNames.put(input, qname);
+            }
+            return qname;
+        }
+
+        @Override
+        public Object serialize(Object input) {
+            Preconditions.checkArgument(input instanceof Class);
+            return serialize((Class) input);
+        }
+    }
+
+    public boolean isCodecAvailable(Class<? extends DataContainer> cls) {
+        if (containerCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (identifierCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (choiceCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (caseCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (augmentableCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (augmentationCodecs.containsKey(cls)) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend
new file mode 100644 (file)
index 0000000..0a06967
--- /dev/null
@@ -0,0 +1,302 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl
+
+import javassist.ClassPool
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.yang.model.api.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 org.opendaylight.yangtools.yang.binding.DataContainer
+import java.util.concurrent.ConcurrentMap
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
+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.yangtools.yang.data.impl.codec.BindingIndependentMappingService
+import org.slf4j.LoggerFactory
+import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName
+import org.opendaylight.yangtools.yang.data.impl.codec.DataContainerCodec
+import org.opendaylight.yangtools.binding.generator.util.Types
+//import org.osgi.framework.BundleContext
+import java.util.Hashtable
+//import org.osgi.framework.ServiceRegistration
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException
+import java.util.concurrent.Callable
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils
+import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.binding.RpcService
+import java.util.Set
+import org.opendaylight.yangtools.yang.common.QName
+import com.google.common.collect.FluentIterable
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
+
+class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
+
+    @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();
+
+    @Property
+    val ConcurrentMap<Type,Set<QName>> serviceTypeToRpc = new ConcurrentHashMap();
+
+    val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
+
+    val promisedSchemas = HashMultimap.<Type, SettableFuture<SchemaNode>>create;
+
+    //ServiceRegistration<SchemaServiceListener> listenerRegistration
+
+    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);
+            binding.pathToType.putAll(entry.value.childNodes)
+            val module = entry.key;
+            val context = entry.value;
+            updateBindingFor(context.childNodes, schemaContext);
+            updateBindingFor(context.cases, schemaContext);
+            val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+
+            if(!module.rpcs.empty) {
+            val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
+            val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service");
+                serviceTypeToRpc.put(serviceClass,rpcs);
+            }
+
+            val typedefs = context.typedefs;
+            for (typedef : typedefs.entrySet) {
+                val typeRef = new ReferencedTypeImpl(typedef.value.packageName,typedef.value.name)
+                binding.typeDefinitions.put(typeRef, typedef.value as GeneratedType);
+                val schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext,typedef.key);
+                if(schemaNode != null) {
+
+                    binding.typeToSchemaNode.put(typeRef,schemaNode);
+                } else {
+                    LOG.error("Type definition for {} is not available",typedef.value);
+                }
+
+            }
+            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) {
+
+        try {
+        val key = toDataDom(entry.key)
+        var CompositeNode data;
+        if(Augmentation.isAssignableFrom(entry.key.targetType)) {
+            data = toCompositeNodeImpl(key,entry.value);
+        } else {
+          data = toCompositeNodeImpl(entry.value);
+        }
+        return new SimpleEntry(key, data);
+
+        } catch (Exception e) {
+            LOG.error("Error during serialization for {}.", entry.key,e);
+            throw e;
+        }
+    }
+
+    private def CompositeNode toCompositeNodeImpl(DataObject object) {
+        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 CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
+
+        //val cls = object.implementedInterface;
+        //waitForSchema(cls);
+        val last = identifier.path.last;
+        val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
+        val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
+        if(last instanceof NodeIdentifierWithPredicates) {
+            val predicates = last as NodeIdentifierWithPredicates;
+            val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
+            for(predicate : predicates.keyValues.entrySet) {
+                newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
+            }
+            newNodes.addAll(ret.children);
+            return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
+        }
+        return ret as CompositeNode;
+    }
+
+    private def void waitForSchema(Class<? extends DataContainer> class1) {
+        if(Augmentation.isAssignableFrom(class1)) {
+            /*  FIXME: We should wait also for augmentations. Currently YANGTools does not provide correct
+             *  mapping between java Augmentation classes and augmentations.
+             */
+            return;
+        }
+        if(registry.isCodecAvailable(class1)) {
+            return;
+        }
+        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) {
+         dataObjectFromDataDom(path.targetType,node) as DataObject;
+    }
+
+    override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
+        return tryDeserialization[ |
+            registry.instanceIdentifierCodec.deserialize(entry);
+        ]
+    }
+
+    override getCodecRegistry() {
+        return getRegistry();
+    }
+
+    private static def <T> T tryDeserialization(Callable<T> deserializationBlock) throws DeserializationException {
+        try {
+            deserializationBlock.call()
+        } catch (Exception e) {
+
+            // FIXME: Make this block providing more information.
+            throw new DeserializationException(e);
+        }
+    }
+
+    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)
+            val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
+            typeToDefinition.put(typeRef, entry.value);
+            if (schemaNode != null) {
+                typeToSchemaNode.put(typeRef, schemaNode);
+                updatePromisedSchemas(typeRef, schemaNode);
+            }
+
+        }
+    }
+
+    public def void init() {
+        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
+//        if (ctx !== null) {
+//            listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
+//        }
+    }
+
+    override getRpcQNamesFor(Class<? extends RpcService> service) {
+        return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName));
+    }
+
+    private def getSchemaWithRetry(Type type) {
+        val typeDef = typeToSchemaNode.get(type);
+        if (typeDef !== null) {
+            return typeDef;
+        }
+        LOG.trace("Thread blocked waiting for schema for: {}",type.fullyQualifiedName)
+        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);
+    }
+
+    override close() throws Exception {
+        //listenerRegistration?.unregister();
+    }
+
+    override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
+        return tryDeserialization[ |
+            if (domData == null) {
+                return null;
+            }
+            val transformer = registry.getCodecForDataObject(container);
+            val ret = transformer.deserialize(domData)?.value as DataObject;
+            return ret;
+        ]
+    }
+
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/StaticFieldInitializer.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/StaticFieldInitializer.java
new file mode 100644 (file)
index 0000000..65ed3f7
--- /dev/null
@@ -0,0 +1,6 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl;
+
+public interface StaticFieldInitializer {
+
+    void initializeStaticFields(Class<?> cls);
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend
new file mode 100644 (file)
index 0000000..9753650
--- /dev/null
@@ -0,0 +1,1566 @@
+package org.opendaylight.yangtools.sal.binding.generator.impl
+
+import javassist.ClassPool
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils
+import javassist.CtClass
+import java.util.Map
+import org.opendaylight.yangtools.yang.common.QName
+import javassist.CtField
+import static javassist.Modifier.*
+import static org.opendaylight.yangtools.sal.binding.generator.impl.CodecMapping.*
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+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
+import org.opendaylight.yangtools.binding.generator.util.Types
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
+import java.util.HashMap
+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.List
+import java.util.TreeSet
+import com.google.common.base.Joiner
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
+import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
+import static org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils.*;
+import org.opendaylight.yangtools.yang.binding.BindingDeserializer
+import org.opendaylight.yangtools.yang.binding.BindingCodec
+import org.slf4j.LoggerFactory
+import org.opendaylight.yangtools.sal.binding.generator.util.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
+import static extension org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils.*;
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
+import org.opendaylight.yangtools.yang.model.util.ExtendedType
+import org.opendaylight.yangtools.yang.model.util.EnumerationType
+import static com.google.common.base.Preconditions.*
+import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import javassist.CtMethod
+import javassist.CannotCompileException
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.Callable
+import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
+import java.util.HashSet
+import java.util.Collections
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit
+import java.util.Set
+import org.opendaylight.yangtools.sal.binding.generator.util.XtendHelper
+
+class TransformerGenerator {
+
+    private static val log = LoggerFactory.getLogger(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);
+
+    val ClassPool classPool
+    val extension JavassistUtils utils;
+
+    CtClass BINDING_CODEC
+
+    CtClass ctQName
+
+    @Property
+    var File classFileCapturePath;
+
+    @Property
+    var Map<Type, Type> typeDefinitions = new ConcurrentHashMap();
+
+    @Property
+    var Map<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
+
+    @Property
+    var Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap();
+
+    @Property
+    var Map<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+
+    @Property
+    var Map<Type, AugmentationSchema> typeToAugmentation = new ConcurrentHashMap();
+
+    @Property
+    var GeneratorListener listener;
+
+    public static val CLASS_TYPE = Types.typeForClass(Class);
+
+    public new(ClassPool pool) {
+        classPool = pool;
+        utils = new JavassistUtils(pool)
+
+        BINDING_CODEC = BindingCodec.asCtClass;
+        ctQName = QName.asCtClass
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                listener.onClassProcessed(inputType);
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            val node = typeToSchemaNode.get(ref)
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            checkState(typeSpecBuilder !== null, "Could not find typedefinition for %s", inputType.name);
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateTransformerFor(inputType, typeSpec, node);
+            listener.onClassProcessed(inputType);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType, DataSchemaNode node) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                listener.onClassProcessed(inputType);
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            var typeSpecBuilder = typeToDefinition.get(ref)
+            if (typeSpecBuilder == null) {
+                typeSpecBuilder = pathToType.get(node.path);
+            }
+            var schemaNode = typeToSchemaNode.get(ref);
+            if(schemaNode === null) {
+                schemaNode = node;
+            }
+            checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node);
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateTransformerFor(inputType, typeSpec, schemaNode);
+            listener.onClassProcessed(inputType);
+            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);
+            listener.onClassProcessed(inputType);
+            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 withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val transformer = getGeneratedClass(inputType)
+            if (transformer != null) {
+                return transformer;
+            }
+            val newret = generateKeyTransformerFor(inputType, type, schema);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    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, DataSchemaNode node) {
+        val cls = loadClassWithTCCL(type.resolvedName);
+        transformerFor(cls, node);
+    }
+
+    private def Class<?> valueSerializer(GeneratedTransferObject type, TypeDefinition<?> typeDefinition) {
+        val cls = loadClassWithTCCL(type.resolvedName);
+        val transformer = cls.generatedClass;
+        if (transformer !== null) {
+            return transformer;
+        }
+        var baseType = typeDefinition;
+        while (baseType.baseType != null) {
+            baseType = baseType.baseType;
+        }
+        val finalType = baseType;
+        return withClassLoaderAndLock(cls.classLoader, lock) [ |
+            val valueTransformer = generateValueTransformer(cls, type, finalType);
+            return valueTransformer;
+        ]
+    }
+
+    private def Class<?> valueSerializer(Enumeration type, TypeDefinition<?> typeDefinition) {
+        val cls = loadClassWithTCCL(type.resolvedName);
+        val transformer = cls.generatedClass;
+        if (transformer !== null) {
+            return transformer;
+        }
+
+        return withClassLoaderAndLock(cls.classLoader, lock) [ |
+            val valueTransformer = generateValueTransformer(cls, type);
+            return valueTransformer;
+        ]
+    }
+
+    private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
+        try {
+
+            //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val properties = typeSpec.allProperties;
+            val ctCls = createClass(inputType.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                staticQNameField(node.QName);
+                implementsType(BINDING_CODEC)
+                method(Object, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            Â«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.resolvedName» 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);
+                        }
+                    '''
+                ]
+                method(Object, "fromDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            if($2 == null){
+                                return  null;
+                            }
+                            Â«QName.name» _localQName = $1;
+                            java.util.Map _compositeNode = (java.util.Map) $2;
+                            boolean _is_empty = true;
+                            Â«FOR key : node.keyDefinition»
+                                Â«val propertyName = key.getterName»
+                                Â«val keyDef = node.getDataChildByName(key)»
+                                Â«val property = properties.get(propertyName)»
+                                Â«deserializeProperty(keyDef, property, propertyName)»;
+                            Â«ENDFOR»
+                            Â«inputType.resolvedName» _value = new Â«inputType.name»(«node.keyDefinition.
+                            keyConstructorList»);
+                            return _value;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        {
+                            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) [
+                    bodyChecked = '''
+                        return fromDomStatic(QNAME,$1);
+                    '''
+                ]
+            ]
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            log.debug("DOM Codec for {} was generated {}", inputType, ret)
+            return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
+        } catch (Exception e) {
+            processException(inputType, e);
+            return null;
+        }
+    }
+
+    private def Class<? extends BindingCodec<Object, Object>> generateCaseCodec(Class<?> inputType, GeneratedType type,
+        ChoiceCaseNode node) {
+        try {
+
+            //log.info("Generating DOM Codec for {} with {}, TCCL is: {}", inputType, inputType.classLoader,Thread.currentThread.contextClassLoader)
+            val ctCls = createClass(type.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                implementsType(BINDING_CODEC)
+                staticQNameField(node.QName);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                method(Object, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            Â«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, type.allProperties, node)»
+                            return ($r) _childNodes;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        {
+                            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
+                    bodyChecked = deserializeBody(type, node)
+                ]
+                method(Object, "deserialize", Object) [
+                    bodyChecked = '''
+                        {
+                            //System.out.println("«type.name»#deserialize: " +$1);
+                            java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                            return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue());
+                        }
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)  as Class<? extends BindingCodec<Object, Object>>
+            listener?.onDataContainerCodecCreated(inputType, ret);
+            log.debug("DOM Codec for {} was generated {}", inputType, ret)
+            return ret;
+        } 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(node.QName);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                implementsType(BINDING_CODEC)
+                method(Object, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = serializeBodyFacade(typeSpec, node)
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        {
+                            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
+                    bodyChecked = deserializeBody(typeSpec, node)
+                ]
+                method(Object, "deserialize", Object) [
+                    bodyChecked = '''
+                        return fromDomStatic(QNAME,$1);
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
+            listener?.onDataContainerCodecCreated(inputType, ret);
+            log.debug("DOM Codec for {} was generated {}", inputType, ret)
+            return ret;
+        } catch (Exception e) {
+            processException(inputType, e);
+            return null;
+        }
+    }
+
+    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 properties = type.allProperties
+            val ctCls = createClass(type.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                staticQNameField(node.augmentationQName);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                implementsType(BINDING_CODEC)
+                method(Object, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            ////System.out.println("Qname " + $1);
+                            ////System.out.println("Value " + $2);
+                            Â«QName.name» _resultName = Â«QName.name».create(QNAME,QNAME.getLocalName());
+                            java.util.List _childNodes = new java.util.ArrayList();
+                            Â«type.resolvedName» value = («type.resolvedName») $2;
+                            Â«FOR child : node.childNodes»
+                                Â«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) [
+                    bodyChecked = '''
+                        {
+                        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
+                    bodyChecked = '''
+                        {
+                            Â«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»();
+                            boolean _is_empty = true;
+                            Â«FOR child : node.childNodes»
+                                Â«val signature = properties.getFor(child)»
+                                Â«deserializeProperty(child, signature.value, signature.key)»
+                                _builder.«signature.key.toSetter»(«signature.key»);
+                            Â«ENDFOR»
+                            if(_is_empty) {
+                                return null;
+                            }
+                            return _builder.build();
+                        }
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    bodyChecked = '''
+                        return fromDomStatic(QNAME,$1);
+                    '''
+                ]
+            ]
+
+            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);
+            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, IDENTITYREF_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
+                    bodyChecked = '''
+                        {
+                            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);
+                            Object _ret =  _codec.serialize(_input);
+                            ////System.out.println("«typeSpec.name»#toDomStatic: " + _ret);
+                            return («List.name») _ret;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
+                    '''
+                ]
+                method(Object, "fromDomStatic", QName, Map) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            Â«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) [
+                    bodyChecked = '''
+                        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, node);
+            log.debug("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>()
+        for (name : qnames) {
+            val fieldName = name.getterName;
+            names.add(fieldName);
+        }
+        return Joiner.on(",").join(names);
+    }
+
+    private def serializeBodyFacade(GeneratedType type, SchemaNode node) {
+        val ret = serializeBody(type, node);
+        return ret;
+    }
+
+    private def String deserializeBody(GeneratedType type, SchemaNode node) {
+        val ret = deserializeBodyImpl(type, node);
+        return ret;
+    }
+
+    private def deserializeKey(GeneratedType type, ListSchemaNode node) {
+        if (node.keyDefinition != null && !node.keyDefinition.empty) {
+            return '''
+                Â«type.resolvedName»Key getKey = («type.resolvedName»Key) Â«keyTransformer(type, node).canonicalName».fromDomStatic(_localQName,_compositeNode);
+                _builder.setKey(getKey);
+            ''';
+        }
+    }
+
+    private def dispatch String deserializeBodyImpl(GeneratedType type, SchemaNode node) '''
+        {
+            Â«QName.name» _localQName = Â«QName.name».create($1,QNAME.getLocalName());
+
+            if($2 == null) {
+                return null;
+            }
+            java.util.Map _compositeNode = (java.util.Map) $2;
+            Â«type.builderName» _builder = new Â«type.builderName»();
+            return _builder.build();
+        }
+    '''
+
+    private def dispatch String deserializeBodyImpl(GeneratedType type, ListSchemaNode 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»();
+            Â«deserializeKey(type, node)»
+            Â«deserializeDataNodeContainerBody(type, node)»
+            Â«deserializeAugmentations»
+            return _builder.build();
+        }
+    '''
+
+    private def dispatch String deserializeBodyImpl(GeneratedType type, ContainerSchemaNode 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();
+        }
+    '''
+
+    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();
+        }
+    '''
+
+    private def deserializeDataNodeContainerBody(GeneratedType type, DataNodeContainer node) {
+        deserializeNodeContainerBodyImpl(type, type.allProperties, node);
+    }
+
+    private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, Type> properties,
+        DataNodeContainer node) {
+        val ret = '''
+            boolean _is_empty = true;
+            Â«FOR child : node.childNodes»
+                Â«val signature = properties.getFor(child)»
+                Â«IF signature !== null»
+                    Â«deserializeProperty(child, signature.value, signature.key)»
+                    _builder.«signature.key.toSetter»(«signature.key»);
+                Â«ENDIF»
+            Â«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();
+                if(_value != null) {
+                    _builder.addAugmentation(_type,_value);
+                }
+            }
+        }
+    '''
+
+    private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type,
+        String propertyName) '''
+        java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
+            localName»"));
+        ////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_«propertyName».iterator();
+            boolean _hasNext = _iterator.hasNext();
+            while(_hasNext) {
+                Object _listItem = _iterator.next();
+                _is_empty = false;
+                ////System.out.println("  item" + _listItem);
+                Object _value = Â«type.actualTypeArguments.get(0).serializer(schema).resolvedName».fromDomStatic(_localQName,_listItem);
+                ////System.out.println("  value" + _value);
+                Â«propertyName».add(_value);
+                _hasNext = _iterator.hasNext();
+            }
+        }
+
+        ////System.out.println(" list" + Â«propertyName»);
+    '''
+
+    private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type,
+        String propertyName) '''
+        java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
+            localName»"));
+        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_«propertyName».iterator();
+            boolean _hasNext = _iterator.hasNext();
+            while(_hasNext) {
+                _is_empty = false;
+                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", schema.type)»;
+                    Â«propertyName».add(_value);
+                }
+                _hasNext = _iterator.hasNext();
+            }
+        }
+    '''
+
+    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» Â«propertyName» = null;
+        if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
+            _is_empty = false;
+            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", schema.type)»;
+        }
+    '''
+
+    private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type,
+        String propertyName) '''
+        java.util.List _dom_«propertyName»_list =
+            _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
+        Â«type.resolvedName» Â«propertyName» = null;
+        if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
+            _is_empty = false;
+            java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0);
+            Â«propertyName» =  Â«type.serializer(schema).resolvedName».fromDomStatic(_localQName,_dom_«propertyName»);
+        }
+    '''
+
+    private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = Â«type.serializer(schema).resolvedName».fromDomStatic(_localQName,_compositeNode);
+        if(«propertyName» != null) {
+            _is_empty = false;
+        }
+    '''
+
+    private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter,
+        TypeDefinition<?> typeDefinition) '''
+        («type.resolvedName») Â«type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter»)
+    '''
+
+    private def dispatch String deserializeValue(Enumeration type, String domParameter, TypeDefinition<?> typeDefinition) '''
+        («type.resolvedName») Â«type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter»)
+    '''
+
+    private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
+        Class<?> inputType, GeneratedTransferObject typeSpec, TypeDefinition<?> typeDef) {
+        try {
+
+            val returnType = typeSpec.valueReturnType;
+            if (returnType == null) {
+                val ctCls = createDummyImplementation(inputType, typeSpec);
+                val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+
+            val ctCls = createClass(typeSpec.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                if (inputType.isYangBindingAvailable) {
+                    implementsType(BINDING_CODEC)
+                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                    implementsType(BindingDeserializer.asCtClass)
+                }
+                method(Object, "toDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    val ctSpec = typeSpec.asCtClass;
+                    bodyChecked = '''
+                        {
+                            ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
+
+                            if($1 == null) {
+                                return null;
+                            }
+                            Â«typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
+                            ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
+                            Â«returnType.resolvedName» _value =  _encapsulatedValue.getValue();
+                            ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
+                            Object _domValue = Â«serializeValue(returnType, "_value", null)»;
+                            return _domValue;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        {
+                            return toDomValue($1);
+                        }
+                    '''
+                ]
+                method(Object, "fromDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+
+                            if($1 == null) {
+                                return null;
+                            }
+                            Â«returnType.resolvedName» _simpleValue = Â«deserializeValue(returnType, "$1", null)»;
+                            Â«typeSpec.resolvedName» _value = new Â«typeSpec.resolvedName»(_simpleValue);
+                            return _value;
+                        }
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    bodyChecked = '''{
+                            return fromDomValue($1);
+                    }
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            log.debug("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);
+            val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
+            exception.addSuppressed(e);
+            throw exception;
+        }
+    }
+
+    private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
+        Class<?> inputType, GeneratedTransferObject typeSpec, UnionTypeDefinition typeDef) {
+        try {
+            val ctCls = createClass(typeSpec.codecClassName) [
+                val properties = typeSpec.allProperties;
+                val getterToTypeDefinition = XtendHelper.getTypes(typeDef).toMap[type | type.QName.getterName];
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                if (inputType.isYangBindingAvailable) {
+                    implementsType(BINDING_CODEC)
+                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                    implementsType(BindingDeserializer.asCtClass)
+                }
+                method(Object, "toDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    val ctSpec = inputType.asCtClass;
+
+                    bodyChecked = '''
+                        {
+                            ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
+
+                            if($1 == null) {
+                                return null;
+                            }
+                            Â«typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
+                            Â«FOR property : properties.entrySet»
+                                Â«IF property.key != "getValue"»
+                                    Â«property.value.resolvedName» Â«property.key» = («property.value.resolvedName») _value.«property.
+                            key»();
+                                    if(«property.key» != null) {
+                                        return Â«serializeValue(property.value, property.key, getterToTypeDefinition.get(property.key))»;
+                                    }
+                                Â«ENDIF»
+                            Â«ENDFOR»
+
+                            return null;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        {
+                            return toDomValue($1);
+                        }
+                    '''
+                ]
+                method(Object, "fromDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+
+                            if($1 == null) {
+                                return null;
+                            }
+                            if($1 instanceof String) {
+                                String _simpleValue = (String) $1;
+                                return new Â«typeSpec.resolvedName»(_simpleValue.toCharArray());
+                            }
+                            return null;
+                        }
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    bodyChecked = '''{
+                            return fromDomValue($1);
+                    }
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            log.debug("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);
+            val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
+            exception.addSuppressed(e);
+            throw exception;
+        }
+    }
+
+
+    private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
+        Class<?> inputType, GeneratedTransferObject typeSpec, BitsTypeDefinition typeDef) {
+        try {
+            val ctCls = createClass(typeSpec.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                if (inputType.isYangBindingAvailable) {
+                    implementsType(BINDING_CODEC)
+                    staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                    implementsType(BindingDeserializer.asCtClass)
+                }
+                method(Object, "toDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    val ctSpec = typeSpec.asCtClass;
+                    bodyChecked = '''
+                        {
+                            ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
+
+                            if($1 == null) {
+                                return null;
+                            }
+                            Â«typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
+                            Â«HashSet.resolvedName» _value = new Â«HashSet.resolvedName»();
+                            //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
+
+                            Â«FOR bit : typeDef.bits»
+                                Â«val getter = bit.getterName()»
+                                if(Boolean.TRUE.equals(_encapsulatedValue.«getter»())) {
+                                    _value.add("«bit.name»");
+                                }
+                            Â«ENDFOR»
+                            Â«Set.resolvedName» _domValue =  Â«Collections.resolvedName».unmodifiableSet(_value);
+                            //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_domValue);
+
+                            return _domValue;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        {
+                            return toDomValue($1);
+                        }
+                    '''
+                ]
+                method(Object, "fromDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    val sortedBits = typeDef.bits.sort[o1, o2|o1.propertyName.compareTo(o2.propertyName)]
+                    bodyChecked = '''
+                        {
+                            //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+
+                            if($1 == null) {
+                                return null;
+                            }
+                            Â«Set.resolvedName» _domValue = («Set.resolvedName») $1;
+                            Â«FOR bit : sortedBits»
+                                Boolean Â«bit.propertyName» = Boolean.valueOf(_domValue.contains("«bit.name»"));
+                            Â«ENDFOR»
+
+                            return new Â«inputType.resolvedName»(«FOR bit : sortedBits SEPARATOR ","»«bit.propertyName»«ENDFOR»);
+                        }
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    bodyChecked = '''{
+                            return fromDomValue($1);
+                    }
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            log.debug("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);
+            val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
+            exception.addSuppressed(e);
+            throw exception;
+        }
+    }
+
+    def String getPropertyName(Bit bit) {
+        '''_«BindingGeneratorUtil.parseToValidParamName(bit.name)»'''
+    }
+
+    def String getterName(Bit bit) {
+
+        val paramName = BindingGeneratorUtil.parseToValidParamName(bit.name);
+        return '''is«paramName.toFirstUpper»''';
+    }
+
+    def boolean isYangBindingAvailable(Class<?> class1) {
+        try {
+            val bindingCodecClass = class1.classLoader.loadClass(BINDING_CODEC.name);
+            return bindingCodecClass !== null;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
+    private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
+        log.trace("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
+        return createClass(typeSpec.codecClassName) [
+            if (object.isYangBindingAvailable) {
+                implementsType(BINDING_CODEC)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                implementsType(BindingDeserializer.asCtClass)
+            }
+            //implementsType(BindingDeserializer.asCtClass)
+            method(Object, "toDomValue", Object) [
+                modifiers = PUBLIC + FINAL + STATIC
+                bodyChecked = '''{
+                    if($1 == null) {
+                        return null;
+                    }
+                    return $1.toString();
+
+                    }'''
+            ]
+            method(Object, "serialize", Object) [
+                bodyChecked = '''
+                    {
+                        return toDomValue($1);
+                    }
+                '''
+            ]
+            method(Object, "fromDomValue", Object) [
+                modifiers = PUBLIC + FINAL + STATIC
+                bodyChecked = '''return null;'''
+            ]
+            method(Object, "deserialize", Object) [
+                bodyChecked = '''{
+                        return fromDomValue($1);
+                    }
+                    '''
+            ]
+        ]
+    }
+
+    private def Type getValueReturnType(GeneratedTransferObject object) {
+        for (prop : object.properties) {
+            if (prop.name == "value") {
+                return prop.returnType;
+            }
+        }
+        if (object.superType != null) {
+            return getValueReturnType(object.superType);
+        }
+        return null;
+    }
+
+    private def Class<?> generateValueTransformer(Class<?> inputType, Enumeration typeSpec) {
+        try {
+            val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name);
+            val schema = typeToSchemaNode.get(typeRef) as ExtendedType;
+            val enumSchema = schema.baseType as EnumerationType;
+
+            //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(typeSpec.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                //implementsType(BINDING_CODEC)
+                method(Object, "toDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''{
+                            if($1 == null) {
+                                return null;
+                            }
+                            Â«typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
+                            Â«FOR en : enumSchema.values»
+                            if(«typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)».equals(_value)) {
+                                return "«en.name»";
+                            }
+                            Â«ENDFOR»
+                            return null;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    bodyChecked = '''
+                        return toDomValue($1);
+                    '''
+                ]
+                method(Object, "fromDomValue", Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    bodyChecked = '''
+                        {
+                            if($1 == null) {
+                                return null;
+                            }
+                            String _value = (String) $1;
+                            Â«FOR en : enumSchema.values»
+                                if("«en.name»".equals(_value)) {
+                                    return Â«typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)»;
+                                }
+                            Â«ENDFOR»
+                            return null;
+                        }
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    bodyChecked = '''
+                        return fromDomValue($1);
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            log.debug("DOM Codec for {} was generated {}", inputType, ret)
+            return ret;
+        } catch (CodeGenerationException e) {
+            throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
+        } catch (Exception 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) {
+            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);
+        captureFile.createNewFile
+
+    }
+
+    private def dispatch String deserializeValue(Type type, String domParameter, TypeDefinition<?> typeDef) {
+        if (INSTANCE_IDENTIFIER.equals(type)) {
+            return '''(«InstanceIdentifier.name») Â«INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
+        } else if (CLASS_TYPE.equals(type)) {
+            return '''(«Class.name») Â«IDENTITYREF_CODEC».deserialize(«domParameter»)'''
+        }
+        return '''(«type.resolvedName») Â«domParameter»'''
+
+    }
+
+    /**
+     * Default catch all
+     *
+     **/
+    private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = null;
+    '''
+
+    private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
+        String propertyName) {
+        _deserializeProperty(container, type.toInstance, propertyName)
+    }
+
+    public static def toSetter(String it) {
+
+        if (startsWith("is")) {
+            return "set" + substring(2);
+        } else if (startsWith("get")) {
+            return "set" + substring(3);
+        }
+        return "set" + it;
+    }
+
+    /*
+    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, 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»")''')
+    }
+
+    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();
+            Â«type.resolvedName» value = («type.resolvedName») $2;
+            Â«transformDataContainerBody(type, type.allProperties, node)»
+            Â«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();
+            Â«type.resolvedName» value = («type.resolvedName») $2;
+            Â«transformDataContainerBody(type, type.allProperties, node)»
+            Â«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();
+            Â«type.resolvedName» value = («type.resolvedName») $2;
+            Â«transformDataContainerBody(type, type.allProperties, node)»
+            Â«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();
+            Â«type.resolvedName» value = («type.resolvedName») $2;
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
+        }
+    '''
+
+    private def transformDataContainerBody(Type type, Map<String, Type> properties, DataNodeContainer node) {
+        val ret = '''
+            Â«FOR child : node.childNodes»
+                Â«val signature = properties.getFor(child)»
+                Â«IF signature !== null»
+                    ////System.out.println("«type.name»#«signature.key»" + value.«signature.key»());
+                    Â«serializeProperty(child, signature.value, signature.key)»
+                Â«ENDIF»
+            Â«ENDFOR»
+        '''
+        return ret;
+    }
+
+    private 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) {
+        var sig = map.get(node.getterName);
+        if (sig != null) {
+            return new SimpleEntry(node.getterName, sig);
+        }
+        sig = map.get(node.booleanGetterName);
+        if (sig != null) {
+            return new SimpleEntry(node.booleanGetterName, map.get(node.booleanGetterName));
+        }
+        return null;
+    }
+
+    private static def String getBooleanGetterName(DataSchemaNode node) {
+        return "is" + BindingGeneratorUtil.parseToClassName(node.QName.localName);
+    }
+
+    private static def String getGetterName(DataSchemaNode node) {
+        return "get" + BindingGeneratorUtil.parseToClassName(node.QName.localName);
+    }
+
+    private static def String getGetterName(QName node) {
+        return "get" + BindingGeneratorUtil.parseToClassName(node.localName);
+    }
+
+    private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type,
+        String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        ////System.out.println("«propertyName»:" + Â«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(schema).resolvedName».toDomStatic(_resultName,_listItem);
+                _childNodes.add(_domValue);
+                _hasNext = _iterator.hasNext();
+            }
+        }
+    '''
+
+    private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+
+        if(«propertyName» != null) {
+            Â«QName.name» _qname = Â«QName.name».create(_resultName,"«schema.QName.localName»");
+            Object _propValue = Â«serializeValue(type, propertyName, schema.type)»;
+            if(_propValue != null) {
+                Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
+                _childNodes.add(_domValue);
+            }
+        }
+    '''
+
+    private def dispatch serializeValue(GeneratedTransferObject type, String parameter, TypeDefinition<?> typeDefinition) {
+        '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)'''
+    }
+
+    private def dispatch serializeValue(Enumeration type, String parameter, TypeDefinition<?> typeDefinition) {
+        '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)'''
+    }
+
+    private def dispatch serializeValue(Type signature, String property, TypeDefinition<?> typeDefinition) {
+        if (INSTANCE_IDENTIFIER == signature) {
+            return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
+        } else if (CLASS_TYPE.equals(signature)) {
+            return '''(«QName.resolvedName») Â«IDENTITYREF_CODEC».serialize(«property»)'''
+        }
+        if ("char[]" == signature.name) {
+            return '''new String(«property»)''';
+        }
+        return '''«property»''';
+    }
+
+    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 = Â«serializeValue(type.actualTypeArguments.get(0), "_listItem", schema.type)»;
+                Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
+                _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(container).resolvedName».toDomStatic(_resultName,«propertyName»);
+            _childNodes.addAll(domValue);
+        }
+    '''
+
+    /**
+     * Default catch all
+     *
+     **/
+    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,
+        String propertyName) {
+        serializeProperty(container, type.toInstance, propertyName)
+    }
+
+    private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type,
+        String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Object domValue = Â«type.serializer(container).resolvedName».toDomStatic(_resultName,«propertyName»);
+            _childNodes.add(domValue);
+        }
+    '''
+
+    private def codecClassName(GeneratedType typeSpec) {
+        return '''«typeSpec.resolvedName»$Broker$Codec$DOM'''
+    }
+
+    private def codecClassName(Class<?> typeSpec) {
+        return '''«typeSpec.name»$Broker$Codec$DOM'''
+    }
+
+    private def 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, Type> set) {
+        for (definition : type.methodDefinitions) {
+            set.put(definition.name, definition.returnType);
+        }
+        for (property : type.properties) {
+            set.put(property.getterName, property.returnType);
+        }
+        for (parent : type.implements) {
+            parent.collectAllProperties(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.
+    }
+
+    def String getResolvedName(Type type) {
+        return type.asCtClass.name;
+    }
+
+    def String getResolvedName(Class<?> type) {
+        return type.asCtClass.name;
+    }
+
+    def CtClass asCtClass(Type type) {
+        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);
+        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);
+        throw exception;
+    }
+
+    private def setBodyChecked(CtMethod method, String body) {
+        try {
+            method.setBody(body);
+        } catch (CannotCompileException e) {
+            log.error("Cannot compile method: {}#{} {}, Reason: {} Body: {}", method.declaringClass, method.name,
+                method.signature, e.message, body)
+            throw e;
+        }
+    }
+
+    private def <V> V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable<V> function) throws Exception {
+        appendClassLoaderIfMissing(cls);
+        ClassLoaderUtils.withClassLoaderAndLock(cls, lock, function);
+    }
+
+}
+
+@Data
+class PropertyPair {
+
+    String getterName;
+
+    Type type;
+
+    @Property
+    Type returnType;
+    @Property
+    SchemaNode schemaNode;
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassGenerator.java
new file mode 100644 (file)
index 0000000..03adb87
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.yangtools.sal.binding.generator.util;
+
+import javassist.CtClass;
+
+public interface ClassGenerator {
+    void process(CtClass cls);
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java
new file mode 100644 (file)
index 0000000..faf0eeb
--- /dev/null
@@ -0,0 +1,85 @@
+package org.opendaylight.yangtools.sal.binding.generator.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Lock;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+
+public final class ClassLoaderUtils {
+
+    private ClassLoaderUtils() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+
+    public static <V> V withClassLoader(ClassLoader cls, Callable<V> function) throws Exception {
+        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);
+            return function.call();
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldCls);
+            if (lock.isPresent()) {
+                lock.get().unlock();
+            }
+        }
+    }
+
+    public static Object construct(Constructor<? extends Object> constructor, List<Object> objects)
+            throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        Object[] initargs = objects.toArray(new Object[] {});
+        return constructor.newInstance(initargs);
+    }
+
+    public static Class<?> loadClassWithTCCL(String name) throws ClassNotFoundException {
+        if ("byte[]".equals(name)) {
+            return byte[].class;
+        } else if("char[]".equals(name)) {
+            return char[].class;
+        }
+        try {
+            return Thread.currentThread().getContextClassLoader().loadClass(name);
+        } catch (ClassNotFoundException e) {
+            String[] components = name.split("\\.");
+            String potentialOuter;
+            int length = components.length;
+            if (length > 2 && (potentialOuter = components[length - 2]) != null && Character.isUpperCase(potentialOuter.charAt(0))) {
+
+                    String outerName = Joiner.on(".").join(Arrays.asList(components).subList(0, length - 1));
+                    String innerName = outerName + "$" + components[length-1];
+                    return Thread.currentThread().getContextClassLoader().loadClass(innerName);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    public static Class<?> tryToLoadClassWithTCCL(String fullyQualifiedName) {
+        try {
+            return loadClassWithTCCL(fullyQualifiedName);
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/CodeGenerationException.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/CodeGenerationException.java
new file mode 100644 (file)
index 0000000..561d88c
--- /dev/null
@@ -0,0 +1,25 @@
+package org.opendaylight.yangtools.sal.binding.generator.util;
+
+public class CodeGenerationException extends RuntimeException{
+
+    public CodeGenerationException() {
+        super();
+    }
+
+    public CodeGenerationException(String message, Throwable cause, boolean enableSuppression,
+            boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+    public CodeGenerationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public CodeGenerationException(String message) {
+        super(message);
+    }
+
+    public CodeGenerationException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/FieldGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/FieldGenerator.java
new file mode 100644 (file)
index 0000000..f359e64
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.yangtools.sal.binding.generator.util;
+
+import javassist.CtField;
+
+public interface FieldGenerator {
+    void process(CtField field);
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.xtend
new file mode 100644 (file)
index 0000000..c45e055
--- /dev/null
@@ -0,0 +1,128 @@
+package org.opendaylight.yangtools.sal.binding.generator.util
+
+import javassist.CtClass
+import javassist.CtMethod
+import javassist.ClassPool
+import java.util.Arrays
+import static com.google.common.base.Preconditions.*;
+import javassist.CtField
+import javassist.Modifier
+import javassist.NotFoundException
+import javassist.LoaderClassPath
+import javassist.ClassClassPath
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
+import org.slf4j.LoggerFactory
+import java.util.HashMap
+import java.util.WeakHashMap
+
+class JavassistUtils {
+
+    private static val LOG = LoggerFactory.getLogger(JavassistUtils);
+
+    private val loaderClassPaths = new WeakHashMap<ClassLoader,LoaderClassPath>();
+
+    ClassPool classPool
+
+    @Property
+    val Lock lock = new ReentrantLock();
+
+    new(ClassPool pool) {
+        classPool = pool;
+    }
+
+    def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
+        val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
+        function1.process(method);
+        it.addMethod(method);
+    }
+
+        def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter1, Class<?> parameter2,  MethodGenerator function1) {
+        val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter1.asCtClass,parameter2.asCtClass), it);
+        function1.process(method);
+        it.addMethod(method);
+    }
+
+
+    def void staticMethod(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
+        val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
+        function1.process(method);
+        it.addMethod(method);
+    }
+
+    def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
+        for (method : source.methods) {
+            if (method.declaringClass == source) {
+                val redeclaredMethod = new CtMethod(method, target, null);
+                function1.process(redeclaredMethod);
+                target.addMethod(redeclaredMethod);
+            }
+        }
+    }
+
+    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);
+        return target;
+    }
+
+    def void implementsType(CtClass it, CtClass supertype) {
+        checkArgument(supertype.interface, "Supertype must be interface");
+        addInterface(supertype);
+    }
+
+    def asCtClass(Class<?> class1) {
+        classPool.get(class1);
+    }
+
+    def CtField field(CtClass it, String name, Class<?> returnValue) {
+        val field = new CtField(returnValue.asCtClass, name, it);
+        field.modifiers = Modifier.PUBLIC
+        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 {
+            return pool.get(cls.name)
+        } catch (NotFoundException e) {
+            appendClassLoaderIfMissing(cls.classLoader)
+            try {
+                return pool.get(cls.name)
+            } catch (NotFoundException ef) {
+                LOG.warn("Appending ClassClassPath for {}",cls);
+                pool.appendClassPath(new ClassClassPath(cls));
+
+                return pool.get(cls.name)
+            }
+        }
+    }
+
+    def void appendClassLoaderIfMissing(ClassLoader loader) {
+        if(loaderClassPaths.containsKey(loader)) {
+            return;
+        }
+        val ctLoader = new LoaderClassPath(loader);
+        classPool.appendClassPath(ctLoader);
+    }
+
+    def void ensureClassLoader(Class<?> child) {
+        appendClassLoaderIfMissing(child.classLoader);
+    }
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/MethodGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/MethodGenerator.java
new file mode 100644 (file)
index 0000000..046cb8b
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.yangtools.sal.binding.generator.util;
+
+import javassist.CtMethod;
+
+public interface MethodGenerator {
+    void process(CtMethod method);
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/XtendHelper.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/XtendHelper.java
new file mode 100644 (file)
index 0000000..fc5b27c
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.yangtools.sal.binding.generator.util;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+
+public class XtendHelper {
+
+    @SuppressWarnings({"rawtypes","unchecked"})
+    public static Iterable<TypeDefinition> getTypes(UnionTypeDefinition definition) {
+        return (Iterable<TypeDefinition>) (List) definition.getTypes();
+    }
+}
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/YangSchemaUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/YangSchemaUtils.java
new file mode 100644 (file)
index 0000000..30acf1e
--- /dev/null
@@ -0,0 +1,63 @@
+package org.opendaylight.yangtools.sal.binding.generator.util;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.*;
+
+import com.google.common.base.Preconditions;
+
+public class YangSchemaUtils {
+
+    public static final String AUGMENT_IDENTIFIER = "augment-identifier";
+
+
+    public YangSchemaUtils() {
+        throw new UnsupportedOperationException("Helper class. Instantiation is prohibited");
+    }
+
+
+    public static QName getAugmentationQName(AugmentationSchema augmentation) {
+        Preconditions.checkNotNull(augmentation, "Augmentation must not be null.");
+        QName identifier = getAugmentationIdentifier(augmentation);
+        if(identifier != null) {
+            return identifier;
+        }
+        for(DataSchemaNode child : augmentation.getChildNodes()) {
+            // FIXME: Return true name
+            return QName.create(child.getQName(), "foo_augment");
+        }
+        // FIXME: Allways return a qname with module namespace.
+        return null;
+    }
+
+    public static QName getAugmentationIdentifier(AugmentationSchema augmentation) {
+        for(UnknownSchemaNode extension : augmentation.getUnknownSchemaNodes()) {
+            if(AUGMENT_IDENTIFIER.equals(extension.getNodeType().getLocalName())) {
+                return extension.getQName();
+            }
+        }
+        return null;
+    }
+
+
+    public static TypeDefinition<?> findTypeDefinition(SchemaContext context, SchemaPath path) {
+        List<QName> arguments = path.getPath();
+        QName first = arguments.get(0);
+        QName typeQName = arguments.get(arguments.size() -1);
+        DataNodeContainer previous = context.findModuleByNamespaceAndRevision(first.getNamespace(), first.getRevision());
+        if(previous == null) {
+            return null;
+        }
+        Preconditions.checkArgument(arguments.size() == 1);
+        for (QName qName : arguments) {
+            //previous.getDataChildByName(qName);
+        }
+        for(TypeDefinition<?> typedef : previous.getTypeDefinitions()) {
+            if(typedef.getQName().equals(typeQName)) {
+                return typedef;
+            }
+        }
+        return null;
+    }
+}
index 064739c5068cc51bfe980cc5316c46f0606a47b9..e1b4c2e9a821d23716ad72a35c7446da9f33692e 100644 (file)
 
     <dependencyManagement>
         <dependencies>
-            <!-- Local Dependencies --> 
+            <dependency>
+                <groupId>org.javassist</groupId>
+                <artifactId>javassist</artifactId>
+                <version>${javassist.version}</version>
+            </dependency>
+
+            <!-- Local Dependencies -->
             <dependency>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>binding-model-api</artifactId>
                 <artifactId>yang-data-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-data-impl</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-data-util</artifactId>
 
     <build>
         <pluginManagement>
-            <plugins> 
+            <plugins>
                 <plugin>
                     <groupId>org.apache.felix</groupId>
                     <artifactId>maven-bundle-plugin</artifactId>
diff --git a/pom.xml b/pom.xml
index 2725b2d198388c688d3cbb70a77b1e3c1e1d003d..b0a4b7601fa7596d57730387773bc5620e34010e 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -34,6 +34,7 @@
         <xtend.version>2.4.3</xtend.version>
         <groovy.version>2.1.6</groovy.version>
         <mockito.version>1.9.5</mockito.version>
+        <javassist.version>3.17.1-GA</javassist.version>
     </properties>
 
     <scm>
                     <version>${maven.jar.version}</version>
                     <configuration>
                         <archive>
-                            <!-- Bundle OSGi Manifest created by maven-bundle-plugin 
+                            <!-- Bundle OSGi Manifest created by maven-bundle-plugin
                                 into jar file -->
                             <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
                         </archive>
index a6958ba9be108369b37ab7fdb7d8fe4490735527..31dee339d75ca81ba00992c9449ae2fda21a9665 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-data-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-parser-impl</artifactId>
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/AugmentationCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/AugmentationCodec.java
new file mode 100644 (file)
index 0000000..a5127d7
--- /dev/null
@@ -0,0 +1,18 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.common.QName;
+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);
+
+    public QName getAugmentationQName();
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java
new file mode 100644 (file)
index 0000000..7c22be7
--- /dev/null
@@ -0,0 +1,32 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public interface BindingIndependentMappingService {
+
+    CodecRegistry getCodecRegistry();
+
+    CompositeNode toDataDom(DataObject data);
+
+    Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
+            Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry);
+
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier<? extends DataObject> path);
+
+    DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) throws DeserializationException;
+
+    InstanceIdentifier<?> fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry)  throws DeserializationException;
+
+    Set<QName> getRpcQNamesFor(Class<? extends RpcService> service);
+
+    DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput);
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCaseCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCaseCodec.java
new file mode 100644 (file)
index 0000000..839ae30
--- /dev/null
@@ -0,0 +1,16 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCodec.java
new file mode 100644 (file)
index 0000000..c255290
--- /dev/null
@@ -0,0 +1,12 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/CodecRegistry.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/CodecRegistry.java
new file mode 100644 (file)
index 0000000..938dcd6
--- /dev/null
@@ -0,0 +1,39 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.common.QName;
+
+
+public interface CodecRegistry {
+
+    InstanceIdentifierCodec getInstanceIdentifierCodec();
+
+    IdentitityCodec<?> getIdentityCodec();
+
+    <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);
+
+    <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec);
+
+    Class<?> getClassForPath(List<QName> names);
+
+    IdentifierCodec<?> getKeyCodecForPath(List<QName> names);
+
+
+    void bindingClassEncountered(Class<?> cls);
+
+    void putPathToClass(List<QName> names, Class<?> cls);
+
+    public abstract QName getQNameForAugmentation(Class<?> cls);
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DataContainerCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DataContainerCodec.java
new file mode 100644 (file)
index 0000000..6e6e968
--- /dev/null
@@ -0,0 +1,15 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+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 DataContainerCodec<T extends DataContainer> extends  DomCodec<T> {
+
+
+    @Override
+    public ValueWithQName<T> deserialize(Node<?> input);
+
+    @Override
+    public CompositeNode serialize(ValueWithQName<T> input);
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DeserializationException.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DeserializationException.java
new file mode 100644 (file)
index 0000000..cf1d3fd
--- /dev/null
@@ -0,0 +1,24 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+public class DeserializationException extends Exception {
+
+    public DeserializationException() {
+    }
+
+    public DeserializationException(String message) {
+        super(message);
+    }
+
+    public DeserializationException(Throwable cause) {
+        super(cause);
+    }
+
+    public DeserializationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public DeserializationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DomCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DomCodec.java
new file mode 100644 (file)
index 0000000..c681b2c
--- /dev/null
@@ -0,0 +1,16 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentifierCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentifierCodec.java
new file mode 100644 (file)
index 0000000..b8bab87
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentitityCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentitityCodec.java
new file mode 100644 (file)
index 0000000..649804c
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface IdentitityCodec<T extends BaseIdentity> extends BindingCodec<QName, Class<T>>{
+
+    @Override
+    public QName serialize(Class<T> input);
+
+    @Override
+    public Class<T> deserialize(QName input);
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..1d58e8c
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ValueWithQName.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ValueWithQName.java
new file mode 100644 (file)
index 0000000..b2097da
--- /dev/null
@@ -0,0 +1,72 @@
+package org.opendaylight.yangtools.yang.data.impl.codec;
+
+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/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaServiceListener.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaServiceListener.java
new file mode 100644 (file)
index 0000000..a4cf027
--- /dev/null
@@ -0,0 +1,12 @@
+package org.opendaylight.yangtools.yang.model.api;
+
+import java.util.EventListener;
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+// TODO rename to schemaContextListener
+public interface SchemaServiceListener extends EventListener {
+
+    void onGlobalContextUpdated(SchemaContext context);
+
+}