Bug 1439, Bug 1443 Binding Codec NormalizedNodeWriter support 97/9497/11
authorTony Tkacik <ttkacik@cisco.com>
Fri, 1 Aug 2014 17:28:13 +0000 (19:28 +0200)
committerRobert Varga <rovarga@cisco.com>
Mon, 4 Aug 2014 20:08:00 +0000 (22:08 +0200)
Added initial implementation of Code generator for Binding Stream Writers
which uses NormalizedNodeStreamWriter on the backend
to write data.

Change-Id: Icae22fd1b9ed4256022650d3ad16b38c577f3d3a
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
Signed-off-by: Robert Varga <rovarga@cisco.com>
35 files changed:
code-generator/binding-data-codec/pom.xml [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeWriterFactory.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractStreamWriterGenerator.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/StreamWriterGenerator.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/spi/AbstractSource.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/spi/StaticConstantDefinition.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/AugmentationNode.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingToNormalizedStreamWriter.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BitsCodec.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CaseNodeCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CompositeValueCodec.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ContainerNodeCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataContainerCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/EncapsulatedValueCodec.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/EnumerationCodec.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/LeafNodeCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ListNodeCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NodeCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ReflectionBasedCodec.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ValueTypeCodec.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/AugmentableDispatchSerializer.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/ChoiceDispatchSerializer.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/BindingRuntimeContext.java
code-generator/pom.xml
restconf/restconf-util/pom.xml
restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/BindingStreamWriterTest.java [new file with mode: 0644]
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BindingStreamEventWriter.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNormalizedNodeStreamWriter.java

diff --git a/code-generator/binding-data-codec/pom.xml b/code-generator/binding-data-codec/pom.xml
new file mode 100644 (file)
index 0000000..a30a7ad
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>binding-generator</artifactId>
+        <version>0.6.2-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>binding-data-codec</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>binding-generator-impl</artifactId>
+        </dependency>
+        <dependency>
+            <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>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>binding-generator-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>binding-type-provider</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.xtend</groupId>
+            <artifactId>org.eclipse.xtend.lib</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                        <Export-Package>
+                            org.opendaylight.yangtools.sal.binding.generator.impl.*,
+                            org.opendaylight.yangtools.sal.binding.generator.util.*
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.eclipse.xtend</groupId>
+                <artifactId>xtend-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java
new file mode 100644 (file)
index 0000000..9ab9bb3
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.api;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Serialization service, which provides two-way serialization between
+ * Java Binding Data representation and NormalizedNode representation.
+ *
+ */
+public interface BindingNormalizedNodeSerializer {
+
+     /**
+      * Translates supplied Binding Instance Identifier into NormalizedNode instance identifier.
+      *
+      * @param binding Binding Instance Identifier
+      * @return DOM Instance Identifier
+      */
+     YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding);
+
+     /**
+      * Translates supplied YANG Instance Identifier into Binding instance identifier.
+      *
+      * @param dom YANG Instance Identifier
+      * @return Binding Instance Identifier
+      */
+     InstanceIdentifier<?> fromYangInstanceIdentifier(final YangInstanceIdentifier dom);
+
+     /**
+      * Translates supplied Binding Instance Identifier and data into NormalizedNode representatoin.
+      *
+      * @param path Binding Instance Identifier pointing to data
+      * @param data Data object representing data
+      * @return NormalizedNode representation
+      */
+     <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> path, final T data);
+
+     /**
+      * Translates supplied YANG Instance Identifier and NormalizedNode into Binding data.
+      *
+      * @param path Binding Instance Identifier
+      * @param data NormalizedNode representing data
+      * @return DOM Instance Identifier
+      */
+     Entry<InstanceIdentifier<?>,DataObject> fromNormalizedNode(final YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+     /**
+      * Returns map view which contains translated set of entries to normalized nodes.
+      * Returned set will not contain representation of leaf nodes.
+      *
+      * @param dom Map of YANG Instance Identifier to Data
+      * @return Map of Binding Instance Identifier to data.
+      */
+     Map<InstanceIdentifier<?>,DataObject> fromNormalizedNodes(Map<YangInstanceIdentifier,NormalizedNode<?,?>> dom);
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeWriterFactory.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeWriterFactory.java
new file mode 100644 (file)
index 0000000..cd79e6a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.api;
+
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+
+/**
+ *
+ * Factory for {@link BindingStreamEventWriter}, which provides stream writers
+ * which translates data and delegates calls to
+ * {@link NormalizedNodeStreamWriter}.
+ *
+ */
+public interface BindingNormalizedNodeWriterFactory {
+
+    /**
+     *
+     * Creates a {@link BindingStreamEventWriter} for data tree path which will
+     * translate to NormalizedNode model and invoke proper events on supplied
+     * {@link NormalizedNodeStreamWriter}.
+     * <p>
+     * Also provides translation of supplied Instance Identifier to
+     * {@link YangInstanceIdentifier} so client code, does not need to translate
+     * that separately.
+     * <p>
+     * If {@link YangInstanceIdentifier} is not needed, please use
+     * {@link #newWriter(InstanceIdentifier, NormalizedNodeStreamWriter)}
+     * method to conserve resources.
+     *
+     * @param path
+     *            Binding Path in conceptual data tree, for which writer should
+     *            be instantiated
+     * @param domWriter
+     *            Stream writer on which events will be invoked.
+     * @return Instance Identifier and {@link BindingStreamEventWriter}
+     *         which will write to supplied {@link NormalizedNodeStreamWriter}.
+     */
+    public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(final InstanceIdentifier<?> path,
+            final NormalizedNodeStreamWriter domWriter);
+
+    /**
+     *
+     * Creates a {@link BindingStreamEventWriter} for data tree path which will
+     * translate to NormalizedNode model and invoke proper events on supplied
+     * {@link NormalizedNodeStreamWriter}.
+     * <p>
+     *
+     * This variation does not provide YANG instance identifier and is useful
+     * for use-cases, where {@link InstanceIdentifier} translation is done
+     * in other way, or YANG instance identifier is unnecessary (e.g. notifications, RPCs).
+     *
+     * @param path Binding Path in conceptual data tree, for which writer should
+     *            be instantiated
+     * @param domWriter Stream writer on which events will be invoked.
+     * @return {@link BindingStreamEventWriter}
+     *         which will write to supplied {@link NormalizedNodeStreamWriter}.
+     */
+    public BindingStreamEventWriter newWriter(final InstanceIdentifier<?> path,
+            final NormalizedNodeStreamWriter domWriter);
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractStreamWriterGenerator.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractStreamWriterGenerator.java
new file mode 100644 (file)
index 0000000..be35585
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import java.lang.reflect.Field;
+import java.util.Map.Entry;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.Modifier;
+import javassist.NotFoundException;
+
+import org.opendaylight.yangtools.binding.data.codec.gen.spi.AbstractSource;
+import org.opendaylight.yangtools.binding.data.codec.gen.spi.StaticConstantDefinition;
+import org.opendaylight.yangtools.binding.data.codec.util.AugmentableDispatchSerializer;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.ClassGenerator;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractStreamWriterGenerator {
+
+    protected static final String SERIALIZER_SUFFIX = "$StreamWriter";
+    protected static final String STATIC_SERIALIZE_METHOD_NAME = "staticSerialize";
+    protected static final String SERIALIZE_METHOD_NAME = "serialize";
+
+    protected static final AugmentableDispatchSerializer AUGMENTABLE = new AugmentableDispatchSerializer();
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractStreamWriterGenerator.class);
+
+    private final JavassistUtils javassist;
+    private final CtClass serializerCt;
+    private final CtClass dataObjectCt;
+    private final CtClass writerCt;
+    private final CtClass voidCt;
+    private final CtClass registryCt;
+
+    private final CtClass[] serializeArguments;
+    private final CtMethod serializeToMethod;
+
+    private final LoadingCache<Class<?>, Class<? extends DataObjectSerializerImplementation>> implementations;
+    private final ClassLoadingStrategy strategy;
+
+    private BindingRuntimeContext context;
+
+    protected AbstractStreamWriterGenerator(final JavassistUtils utils) {
+        super();
+        this.javassist = Preconditions.checkNotNull(utils,"JavassistUtils instance is required.");
+        this.serializerCt = javassist.asCtClass(DataObjectSerializerImplementation.class);
+        this.registryCt = javassist.asCtClass(DataObjectSerializerRegistry.class);
+        this.writerCt = javassist.asCtClass(BindingStreamEventWriter.class);
+        this.dataObjectCt = javassist.asCtClass(DataObject.class);
+        this.voidCt = javassist.asCtClass(Void.class);
+        this.serializeArguments =  new CtClass[] { registryCt,dataObjectCt, writerCt };
+
+        try {
+            this.serializeToMethod = serializerCt.getDeclaredMethod(SERIALIZE_METHOD_NAME, serializeArguments);
+        } catch (NotFoundException e) {
+            throw new IllegalStateException("Required method " + SERIALIZE_METHOD_NAME + "was not found in class " + BindingStreamEventWriter.class ,e);
+        }
+        this.implementations = CacheBuilder.newBuilder().weakKeys().build(new SerializerImplementationLoader());
+        strategy = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+    }
+
+    private final class SerializerImplementationLoader extends
+            CacheLoader<Class<?>, Class<? extends DataObjectSerializerImplementation>> {
+
+        @Override
+        public Class<? extends DataObjectSerializerImplementation> load(final Class<?> type) throws Exception {
+            Preconditions.checkArgument(BindingReflections.isBindingClass(type));
+            Preconditions.checkArgument(DataContainer.class.isAssignableFrom(type));
+
+            String serializerName = getSerializerName(type);
+            try {
+                @SuppressWarnings("unchecked")
+                final Class<? extends DataObjectSerializerImplementation> preexisting = (Class<? extends DataObjectSerializerImplementation>) ClassLoaderUtils
+                        .loadClass(type.getClassLoader(), serializerName);
+                return preexisting;
+            } catch (ClassNotFoundException e) {
+                return loadFromClassPoolOrGenerate(type, serializerName);
+            }
+        }
+
+        private Class<? extends DataObjectSerializerImplementation> loadFromClassPoolOrGenerate(final Class<?> type,
+                final String serializerName) throws CannotCompileException {
+            CtClass poolClass;
+            DataObjectSerializerSource source = generateEmitterSource(type, serializerName);
+            poolClass = generateEmitter0(source, serializerName);
+            @SuppressWarnings("unchecked")
+            Class<? extends DataObjectSerializerImplementation> cls = poolClass.toClass(type.getClassLoader(), type.getProtectionDomain());
+            initStaticConstants(cls,source);
+            return cls;
+        }
+
+        private void initStaticConstants(final Class<? extends DataObjectSerializerImplementation> cls, final DataObjectSerializerSource source) {
+            for(StaticConstantDefinition constant : source.getStaticConstants()) {
+                try {
+                    Field field = cls.getDeclaredField(constant.getName());
+                    field.set(null, constant.getValue());
+                } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+                    throw new IllegalStateException("Could not initialize expected constant",e);
+                }
+            }
+        }
+    }
+
+
+
+    protected DataObjectSerializerSource generateEmitterSource(final Class<?> type, final String serializerName) {
+        Types.typeForClass(type);
+        Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(type);
+        GeneratedType generatedType = typeWithSchema.getKey();
+        Object schema = typeWithSchema.getValue();
+
+        final DataObjectSerializerSource source;
+        if (schema instanceof ContainerSchemaNode) {
+            source = generateContainerSerializer(generatedType, (ContainerSchemaNode) schema);
+        } else if (schema instanceof ListSchemaNode){
+            ListSchemaNode casted = (ListSchemaNode) schema;
+            if (casted.getKeyDefinition().isEmpty()) {
+                source = generateUnkeyedListEntrySerializer(generatedType, casted);
+            } else {
+                source = generateMapEntrySerializer(generatedType, casted);
+            }
+        } else if(schema instanceof AugmentationSchema) {
+            source = generateSerializer(generatedType,(AugmentationSchema) schema);
+        } else if(schema instanceof ChoiceCaseNode) {
+            source = generateCaseSerializer(generatedType,(ChoiceCaseNode) schema);
+        } else {
+            throw new UnsupportedOperationException("Schema type " + schema.getClass() + " is not supported");
+        }
+        return source;
+    }
+
+    private CtClass generateEmitter0(final DataObjectSerializerSource source, final String serializerName) {
+        CtClass product = javassist.createClass(serializerName, serializerCt, new ClassGenerator() {
+
+            @Override
+            public void process(final CtClass cls) {
+                final String staticBody = source.getStaticSerializeBody().toString();
+                try {
+
+                    for(StaticConstantDefinition def : source.getStaticConstants()) {
+                        CtField field = new CtField(javassist.asCtClass(def.getType()), def.getName(), cls);
+                        field.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
+                        cls.addField(field);
+                    }
+
+                    CtMethod staticSerializeTo = new CtMethod(voidCt, STATIC_SERIALIZE_METHOD_NAME, serializeArguments, cls);
+                    staticSerializeTo.setModifiers(Modifier.PUBLIC + Modifier.FINAL + Modifier.STATIC);
+                    staticSerializeTo.setBody(staticBody);
+                    cls.addMethod(staticSerializeTo);
+
+
+                    CtMethod serializeTo = new CtMethod(serializeToMethod,cls,null);
+                    serializeTo.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
+                    serializeTo.setBody(
+                            new StringBuilder().append('{')
+                            .append(STATIC_SERIALIZE_METHOD_NAME).append("($$);\n")
+                            .append("return null;")
+                            .append('}')
+                            .toString()
+                            );
+                    cls.addMethod(serializeTo);
+                } catch (CannotCompileException e) {
+                    LOG.error("Can not compile body of codec for {}.",serializerName,e);
+                    throw new IllegalStateException(e);
+                }
+
+            }
+        });
+        return product;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Class<? extends DataContainer> loadClass(final Type childType) {
+        try {
+            return (Class<? extends DataContainer>) strategy.loadClass(childType);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Could not load referenced class ",e);
+        }
+    }
+
+    public DataObjectSerializerImplementation getSerializer(final Class<?> type) {
+        try {
+            return implementations.getUnchecked(type).newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Generates serializer source code for supplied container node,
+     * which will read supplied binding type and invoke proper methods
+     * on supplied {@link BindingStreamEventWriter}.
+     * <p>
+     * Implementation is required to recursively invoke events
+     * for all reachable binding objects.
+     *
+     * @param type Binding type of container
+     * @param node Schema of container
+     * @return Source for container node writer
+     */
+    abstract DataObjectSerializerSource generateContainerSerializer(GeneratedType type, ContainerSchemaNode node);
+
+    /**
+     * Generates serializer source for supplied case node,
+     * which will read supplied binding type and invoke proper methods
+     * on supplied {@link BindingStreamEventWriter}.
+     * <p>
+     * Implementation is required to recursively invoke events
+     * for all reachable binding objects.
+     *
+     * @param type Binding type of case
+     * @param node Schema of case
+     * @return Source for case node writer
+     */
+    abstract DataObjectSerializerSource generateCaseSerializer(GeneratedType type, ChoiceCaseNode node);
+
+    /**
+     * Generates serializer source for supplied list node,
+     * which will read supplied binding type and invoke proper methods
+     * on supplied {@link BindingStreamEventWriter}.
+     * <p>
+     * Implementation is required to recursively invoke events
+     * for all reachable binding objects.
+     *
+     * @param type Binding type of list
+     * @param node Schema of list
+     * @return Source for list node writer
+     */
+    abstract DataObjectSerializerSource generateMapEntrySerializer(GeneratedType type, ListSchemaNode node);
+
+    /**
+     * Generates serializer source for supplied list node,
+     * which will read supplied binding type and invoke proper methods
+     * on supplied {@link BindingStreamEventWriter}.
+     * <p>
+     * Implementation is required to recursively invoke events
+     * for all reachable binding objects.
+     *
+     * @param type Binding type of list
+     * @param node Schema of list
+     * @return Source for list node writer
+     */
+    abstract DataObjectSerializerSource generateUnkeyedListEntrySerializer(GeneratedType type, ListSchemaNode node);
+
+    /**
+     * Generates serializer source for supplied augmentation node,
+     * which will read supplied binding type and invoke proper methods
+     * on supplied {@link BindingStreamEventWriter}.
+     * <p>
+     * Implementation is required to recursively invoke events
+     * for all reachable binding objects.
+     *
+     * @param type Binding type of augmentation
+     * @param node Schema of augmentation
+     * @return Source for augmentation node writer
+     */
+    abstract DataObjectSerializerSource generateSerializer(GeneratedType type, AugmentationSchema schema);
+
+    protected static String getSerializerName(final Class<?> type) {
+        return type.getName() + SERIALIZER_SUFFIX;
+    }
+
+    protected abstract class DataObjectSerializerSource extends AbstractSource {
+
+        protected static final String STREAM = "_stream";
+        protected static final String ITERATOR = "_iterator";
+        protected static final String CURRENT = "_current";
+        protected static final String REGISTRY = "_registry";
+
+        /**
+         * Returns body of static serialize method.
+         *
+         * <ul>
+         * <li> {@link DataObjectSerializerRegistry} - registry of serializers
+         * <li> {@link DataObject} - object to be serialized
+         * <li> {@link BindingStreamEventWriter} - writer to which events should be serialized.
+         * </ul>
+         *
+         * @return Valid javassist code describing static serialization body.
+         */
+        protected abstract CharSequence getStaticSerializeBody();
+
+        protected final CharSequence leafNode(final String localName, final CharSequence value) {
+            return invoke(STREAM, "leafNode", escape(localName), value);
+        }
+
+        protected final CharSequence startLeafSet(final String localName,final CharSequence expected) {
+            return invoke(STREAM, "startLeafSet", escape(localName),expected);
+        }
+
+        protected final CharSequence leafSetEntryNode(final CharSequence value) {
+            return invoke(STREAM, "leafSetEntryNode", value);
+
+        }
+
+        protected final CharSequence startContainerNode(final CharSequence type, final CharSequence expected) {
+            return invoke(STREAM, "startContainerNode", (type),expected);
+        }
+
+        protected final  CharSequence escape(final String localName) {
+            return '"'+localName+'"';
+        }
+
+        protected final CharSequence startUnkeyedList(final CharSequence type, final CharSequence expected) {
+            return invoke(STREAM, "startUnkeyedList", (type),expected);
+        }
+
+        protected final CharSequence startUnkeyedListItem(final CharSequence expected) {
+            return invoke(STREAM, "startUnkeyedListItem",expected);
+        }
+
+        protected final CharSequence startMapNode(final CharSequence type,final CharSequence expected) {
+            return invoke(STREAM, "startMapNode", (type),expected);
+        }
+
+        protected final CharSequence startOrderedMapNode(final CharSequence type,final CharSequence expected) {
+            return invoke(STREAM, "startOrderedMapNode", (type),expected);
+        }
+
+        protected final CharSequence startMapEntryNode(final CharSequence key, final CharSequence expected) {
+            return invoke(STREAM,"startMapEntryNode",key,expected);
+
+        }
+
+        protected final CharSequence startAugmentationNode(final CharSequence key) {
+            return invoke(STREAM,"startAugmentationNode",key);
+
+        }
+
+        protected final CharSequence startChoiceNode(final CharSequence localName,final CharSequence expected) {
+            return invoke(STREAM, "startChoiceNode", (localName),expected);
+        }
+
+        protected final CharSequence startCaseNode(final CharSequence localName,final CharSequence expected) {
+            return invoke(STREAM, "startCase", (localName),expected);
+        }
+
+
+        protected final CharSequence anyxmlNode(final String name, final String value) throws IllegalArgumentException {
+            return invoke(STREAM,"anyxmlNode",escape(name),name);
+        }
+
+        protected final CharSequence endNode() {
+            return invoke(STREAM, "endNode");
+        }
+
+        protected final CharSequence forEach(final String iterable,final Type valueType,final CharSequence body) {
+            return forEach(iterable,ITERATOR,valueType.getFullyQualifiedName(),CURRENT,body);
+        }
+
+        protected final CharSequence classReference(final Type type) {
+            return new StringBuilder().append(type.getFullyQualifiedName()).append(".class");
+        }
+
+        protected final CharSequence staticInvokeEmitter(final Type childType, final String name) {
+            Class<?> cls;
+            try {
+                cls = strategy.loadClass(childType);
+                String className = implementations.getUnchecked(cls).getName();
+                return invoke(className, STATIC_SERIALIZE_METHOD_NAME,REGISTRY, name,STREAM);
+            } catch (ClassNotFoundException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+    public void onBindingRuntimeContextUpdated(final BindingRuntimeContext runtime) {
+        this.context = runtime;
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/StreamWriterGenerator.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/StreamWriterGenerator.java
new file mode 100644 (file)
index 0000000..f3fddd4
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.yangtools.binding.data.codec.util.AugmentableDispatchSerializer;
+import org.opendaylight.yangtools.binding.data.codec.util.ChoiceDispatchSerializer;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature;
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+
+/**
+ *
+ * Concrete implementation of {@link AbstractStreamWriterGenerator}
+ * which in runtime generates classes implementing {@link DataObjectSerializerImplementation}
+ * interface and are used to serialize Binding {@link DataObject}.
+ *
+ * Actual implementation of codecs is done via static methods, which allows
+ * for static wiring of codecs. Choice codec and Augmentable codecs
+ * are static properties of parent codec and stateless implementations
+ * are used ( {@link ChoiceDispatchSerializer}, {@link AugmentableDispatchSerializer},
+ * which uses registry to dispatch to concrete item codec.
+ *
+ */
+public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
+
+    public StreamWriterGenerator(final JavassistUtils utils) {
+        super(utils);
+    }
+
+    private abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSource {
+
+        protected static final String INPUT = "_input";
+        protected static final String CHOICE_SERIALIZER = "CHOICE_SERIALIZER";
+        protected static final String AUGMENTABLE_SERIALIZER = "AUGMENTABLE_SERIALIZER";
+
+        GeneratedType dtoType;
+        DataNodeContainer schemaNode;
+
+        public DataNodeContainerSerializerSource(final GeneratedType type, final DataNodeContainer node) {
+            this.dtoType = type;
+            this.schemaNode = node;
+            customize();
+        }
+
+        protected void customize() {
+            // Intentionally NOOP
+        }
+
+        public abstract CharSequence emitStartEvent();
+
+        @Override
+        protected CharSequence getStaticSerializeBody() {
+            StringBuilder b = new StringBuilder();
+            b.append("{\n");
+            b.append(statement(assign(DataObjectSerializerRegistry.class.getName(), REGISTRY, "$1")));
+            b.append(statement(assign(dtoType.getFullyQualifiedName(), INPUT,
+                    cast(dtoType.getFullyQualifiedName(), "$2"))));
+            b.append(statement(assign(BindingStreamEventWriter.class.getName(), STREAM, cast(BindingStreamEventWriter.class.getName(), "$3"))));
+            b.append(statement(emitStartEvent()));
+
+            emitBody(b);
+            emitAfterBody(b);
+            b.append(statement(endNode()));
+            b.append(statement("return null"));
+            b.append("}");
+            return b;
+        }
+
+        /**
+         * Allows for customization of emitting code, which is processed after
+         * normal DataNodeContainer body. Ideal for augmentations or others.
+         */
+        protected void emitAfterBody(final StringBuilder b) {
+            //
+        }
+
+        private void emitBody(final StringBuilder b) {
+            Map<String, Type> getterToType = collectAllProperties(dtoType, new HashMap<String, Type>());
+            for (DataSchemaNode schemaChild : schemaNode.getChildNodes()) {
+                if (!schemaChild.isAugmenting()) {
+                    String getter = getGetterName(schemaChild);
+                    Type childType = getterToType.get(getter);
+                    emitChild(b, getter, childType, schemaChild);
+                }
+            }
+        }
+
+        private void emitChild(final StringBuilder b, final String getterName, final Type childType,
+                final DataSchemaNode schemaChild) {
+            b.append(statement(assign(childType, getterName, cast(childType, invoke(INPUT, getterName)))));
+
+            b.append("if (").append(getterName).append(" != null) {\n");
+            emitChildInner(b, getterName, childType, schemaChild);
+            b.append("}\n");
+        }
+
+        private void emitChildInner(final StringBuilder b, final String getterName, final Type childType,
+                final DataSchemaNode child) {
+            if (child instanceof LeafSchemaNode) {
+                b.append(statement(leafNode(child.getQName().getLocalName(), getterName)));
+            } else if (child instanceof AnyXmlSchemaNode) {
+                b.append(statement(anyxmlNode(child.getQName().getLocalName(), getterName)));
+            } else if (child instanceof LeafListSchemaNode) {
+                b.append(statement(startLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"))));
+                Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+                b.append(forEach(getterName, valueType, statement(leafSetEntryNode(CURRENT))));
+                b.append(statement(endNode()));
+            } else if (child instanceof ListSchemaNode) {
+                Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+                ListSchemaNode casted = (ListSchemaNode) child;
+                emitList(b, getterName, valueType, casted);
+            } else if (child instanceof ContainerSchemaNode) {
+                b.append(statement(staticInvokeEmitter(childType, getterName)));
+            } else if (child instanceof ChoiceNode) {
+                String propertyName = "CHOICE_" + childType.getName();
+                staticConstant(propertyName, DataObjectSerializerImplementation.class, ChoiceDispatchSerializer.from(loadClass(childType)));
+                b.append(statement(invoke(propertyName, SERIALIZE_METHOD_NAME, REGISTRY, cast(DataObject.class.getName(),getterName), STREAM)));
+            }
+        }
+
+        private void emitList(final StringBuilder b, final String getterName, final Type valueType,
+                final ListSchemaNode child) {
+            final CharSequence startEvent;
+
+            b.append(statement(assign("int", "_count", invoke(getterName, "size"))));
+            if (child.getKeyDefinition().isEmpty()) {
+                startEvent = startUnkeyedList(classReference(valueType), "_count");
+            } else if (child.isUserOrdered()) {
+                startEvent = startOrderedMapNode(classReference(valueType), "_count");
+            } else {
+                startEvent = startMapNode(classReference(valueType), "_count");
+            }
+            b.append(statement(startEvent));
+            b.append(forEach(getterName, valueType, statement(staticInvokeEmitter(valueType, CURRENT))));
+            b.append(statement(endNode()));
+        }
+    }
+
+    protected abstract class AugmentableDataNodeContainerEmmiterSource extends DataNodeContainerSerializerSource {
+
+        public AugmentableDataNodeContainerEmmiterSource(final GeneratedType type, final DataNodeContainer node) {
+            super(type, node);
+            staticConstant(AUGMENTABLE_SERIALIZER, DataObjectSerializerImplementation.class,AUGMENTABLE);
+        }
+
+        @Override
+        protected void emitAfterBody(final StringBuilder b) {
+            b.append(statement(invoke(AUGMENTABLE_SERIALIZER, "serialize",REGISTRY, INPUT, STREAM)));
+        }
+    }
+
+    private static Map<String, Type> collectAllProperties(final GeneratedType type, final Map<String, Type> hashMap) {
+        for (MethodSignature definition : type.getMethodDefinitions()) {
+            hashMap.put(definition.getName(), definition.getReturnType());
+        }
+        for (Type parent : type.getImplements()) {
+            if (parent instanceof GeneratedType) {
+                collectAllProperties((GeneratedType) parent, hashMap);
+            }
+        }
+        return hashMap;
+    }
+
+
+
+    private CharSequence getChildSizeFromSchema(final DataNodeContainer node) {
+        return Integer.toString(node.getChildNodes().size());
+    }
+
+    @Override
+    DataObjectSerializerSource generateContainerSerializer(final GeneratedType type, final ContainerSchemaNode node) {
+
+        return new DataNodeContainerSerializerSource(type, node) {
+            @Override
+            public CharSequence emitStartEvent() {
+                return startContainerNode(classReference(type), getChildSizeFromSchema(node));
+            }
+        };
+    }
+
+    protected static final String getGetterName(final DataSchemaNode node) {
+        final TypeDefinition<?> type ;
+        if (node instanceof LeafSchemaNode) {
+            type = ((LeafSchemaNode) node).getType();
+        } else if(node instanceof LeafListSchemaNode) {
+            type = ((LeafListSchemaNode) node).getType();
+        } else {
+            type = null;
+        }
+        String prefix = "get";
+        if(type != null) {
+            TypeDefinition<?> rootType = type;
+            while (rootType.getBaseType() != null) {
+                rootType = rootType.getBaseType();
+            }
+            if(rootType instanceof BooleanTypeDefinition) {
+                prefix = "is";
+            }
+        }
+
+        return prefix + BindingMapping.getClassName(node.getQName().getLocalName());
+    }
+
+    @Override
+    DataObjectSerializerSource generateCaseSerializer(final GeneratedType type, final ChoiceCaseNode node) {
+        return new AugmentableDataNodeContainerEmmiterSource(type, node) {
+            @Override
+            public CharSequence emitStartEvent() {
+                return startCaseNode(classReference(type),getChildSizeFromSchema(node));
+            }
+        };
+    }
+
+    @Override
+    DataObjectSerializerSource generateUnkeyedListEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
+        return new AugmentableDataNodeContainerEmmiterSource(type, node) {
+
+            @Override
+            public CharSequence emitStartEvent() {
+                return startUnkeyedListItem(getChildSizeFromSchema(schemaNode));
+            }
+        };
+    }
+
+    @Override
+    DataObjectSerializerSource generateSerializer(final GeneratedType type, final AugmentationSchema schema) {
+        return new DataNodeContainerSerializerSource(type,schema) {
+
+            @Override
+            public CharSequence emitStartEvent() {
+                return startAugmentationNode(classReference(type));
+            }
+        };
+    }
+
+    @Override
+    DataObjectSerializerSource generateMapEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
+        return new AugmentableDataNodeContainerEmmiterSource(type, node) {
+
+            @Override
+            public CharSequence emitStartEvent() {
+                return startMapEntryNode(invoke(INPUT, "getKey"), getChildSizeFromSchema(node));
+            }
+        };
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/spi/AbstractSource.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/spi/AbstractSource.java
new file mode 100644 (file)
index 0000000..5f792d1
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.spi;
+
+import com.google.common.collect.Iterators;
+import com.google.common.collect.UnmodifiableIterator;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+
+public abstract class AbstractSource {
+
+    private final Set<StaticConstantDefinition> staticConstants = new HashSet<>();
+
+    public final <T> void staticConstant(final String name, final Class<T> type, final T value) {
+        staticConstants.add(new StaticConstantDefinition(name, type, value));
+    }
+
+    public final Set<StaticConstantDefinition> getStaticConstants() {
+        return Collections.unmodifiableSet(staticConstants);
+    }
+
+    protected final CharSequence invoke(final CharSequence object, final String methodName, final Object... args) {
+        StringBuilder builder = new StringBuilder();
+        if (object != null) {
+            builder.append(object);
+            builder.append(".");
+        }
+        builder.append(methodName);
+        builder.append('(');
+
+        UnmodifiableIterator<Object> iterator = Iterators.forArray(args);
+        while (iterator.hasNext()) {
+            builder.append(iterator.next());
+            if (iterator.hasNext()) {
+                builder.append(',');
+            }
+        }
+        builder.append(')');
+        return builder;
+    }
+
+    protected final CharSequence assign(final String var, final CharSequence value) {
+        return assign((String) null, var, value);
+    }
+
+    protected final CharSequence assign(final String type, final String var, final CharSequence value) {
+        StringBuilder builder = new StringBuilder();
+        if(type != null) {
+            builder.append(type);
+            builder.append(' ');
+        }
+        builder.append(var);
+        builder.append(" = ");
+        builder.append(value);
+        return builder;
+    }
+
+    protected final CharSequence assign(final Type type, final String var, final CharSequence value) {
+        return assign(type.getFullyQualifiedName(), var, value);
+    }
+
+    protected final CharSequence cast(final Type type, final CharSequence value) {
+        return cast(type.getFullyQualifiedName(), value);
+    }
+
+    protected final CharSequence forEach(final String iterable,final String iteratorName, final String valueType,final String valueName, final CharSequence body) {
+        StringBuilder b = new StringBuilder();
+        b.append(statement(assign(java.util.Iterator.class.getName(), iteratorName,invoke(iterable, "iterator"))));
+        b.append("while (").append(invoke(iteratorName, "hasNext")).append(") {\n");
+        b.append(statement(assign(valueType, valueName,cast(valueType, invoke(iteratorName, "next")))));
+        b.append(body);
+        b.append("\n}\n");
+        return b;
+    }
+
+    protected final CharSequence statement(final CharSequence statement) {
+        return new StringBuilder().append(statement).append(";\n");
+    }
+
+    protected final CharSequence cast(final String type, final CharSequence value) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("((");
+        builder.append(type);
+        builder.append(')');
+        builder.append(' ');
+        builder.append(value);
+        builder.append(')');
+        return builder;
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/spi/StaticConstantDefinition.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/spi/StaticConstantDefinition.java
new file mode 100644 (file)
index 0000000..1688afd
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.spi;
+
+import com.google.common.base.Preconditions;
+
+/**
+ *
+ * Definition of static property for generated class
+ * <p>
+ * This definition consists of
+ * <ul>
+ * <li>name - property name</li>
+ * <li>type - Java type for property</li>
+ * <li>value - value to which property should be initialized</li>
+ *
+ */
+public class StaticConstantDefinition {
+
+    private final String name;
+    private final Class<?> type;
+    private final Object value;
+
+    public StaticConstantDefinition(final String name, final Class<?> type, final Object value) {
+        super();
+        this.name = Preconditions.checkNotNull(name);
+        this.type = Preconditions.checkNotNull(type);
+        this.value = Preconditions.checkNotNull(value);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Class<?> getType() {
+        return type;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + name.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        StaticConstantDefinition other = (StaticConstantDefinition) obj;
+        if (!name.equals(other.name)) {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/AugmentationNode.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/AugmentationNode.java
new file mode 100644 (file)
index 0000000..816a414
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+
+public class AugmentationNode extends DataObjectCodecContext<AugmentationSchema> {
+
+    private final YangInstanceIdentifier.PathArgument yangIdentifier;
+
+    public AugmentationNode(final Class<?> cls, final QNameModule namespace,
+            final AugmentationIdentifier identifier, final AugmentationSchema nodeSchema,
+            final CodecContextFactory loader) {
+        super(cls, namespace, nodeSchema, loader);
+        this.yangIdentifier = identifier;
+    }
+
+    @Override
+    public YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        return yangIdentifier;
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java
new file mode 100644 (file)
index 0000000..cd223ce
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.binding.data.codec.impl.NodeCodecContext.CodecContextFactory;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+
+class BindingCodecContext implements CodecContextFactory, Immutable {
+
+    private static final String GETTER_PREFIX = "get";
+    private final SchemaRootCodecContext root;
+    private final BindingRuntimeContext context;
+    private final Codec<YangInstanceIdentifier,InstanceIdentifier<?>> instanceIdentifierCodec;
+    private final Codec<QName,Class<?>> identityCodec;
+
+    public BindingCodecContext(final BindingRuntimeContext context) {
+        this.context =  Preconditions.checkNotNull(context, "Bidning Runtime Context is required.");
+        this.root = SchemaRootCodecContext.create(this);
+        this.instanceIdentifierCodec = new InstanceIdentifierCodec();
+        this.identityCodec = new IdentityCodec();
+    }
+
+    @Override
+    public BindingRuntimeContext getRuntimeContext() {
+        return context;
+    }
+
+    public Codec<YangInstanceIdentifier,InstanceIdentifier<?>> getInstanceIdentifierCodec() {
+        return instanceIdentifierCodec;
+    }
+
+    public Codec<QName, Class<?>> getIdentityCodec() {
+        return identityCodec;
+    }
+
+    public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriter(final InstanceIdentifier<?> path,
+            final NormalizedNodeStreamWriter domWriter) {
+        LinkedList<YangInstanceIdentifier.PathArgument> yangArgs = new LinkedList<>();
+        DataContainerCodecContext<?> codecContext = getCodecContextNode(path, yangArgs);
+        BindingStreamEventWriter writer = new BindingToNormalizedStreamWriter(codecContext, domWriter);
+        return new SimpleEntry<>(YangInstanceIdentifier.create(yangArgs), writer);
+    }
+
+    public BindingStreamEventWriter newWriterWithoutIdentifier(final InstanceIdentifier<?> path,
+            final NormalizedNodeStreamWriter domWriter) {
+        return new BindingToNormalizedStreamWriter(getCodecContextNode(path, null), domWriter);
+    }
+
+    public DataContainerCodecContext<?> getCodecContextNode(final InstanceIdentifier<?> binding,
+            final List<YangInstanceIdentifier.PathArgument> builder) {
+        DataContainerCodecContext<?> currentNode = root;
+        for (InstanceIdentifier.PathArgument bindingArg : binding.getPathArguments()) {
+            currentNode = currentNode.getIdentifierChild(bindingArg, builder);
+        }
+        return currentNode;
+    }
+
+    public NodeCodecContext getCodecContextNode(final YangInstanceIdentifier dom,
+            final List<InstanceIdentifier.PathArgument> builder) {
+        NodeCodecContext currentNode = root;
+        ListNodeCodecContext currentList = null;
+        for (YangInstanceIdentifier.PathArgument domArg : dom.getPathArguments()) {
+            Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext<?>);
+            DataContainerCodecContext<?> previous = (DataContainerCodecContext<?>) currentNode;
+            NodeCodecContext nextNode = previous.getYangIdentifierChild(domArg);
+            /*
+             * List representation in YANG Instance Identifier consists of two
+             * arguments: first is list as a whole, second is list as an item so
+             * if it is /list it means list as whole, if it is /list/list - it
+             * is wildcarded and if it is /list/list[key] it is concrete item,
+             * all this variations are expressed in Binding Aware Instance
+             * Identifier as Item or IdentifiableItem
+             */
+            if (currentList != null) {
+
+                if (currentList == nextNode) {
+
+                    // We entered list, so now we have all information to emit
+                    // list
+                    // path using second list argument.
+                    builder.add(currentList.getBindingPathArgument(domArg));
+                    currentList = null;
+                    currentNode = nextNode;
+                } else {
+                    throw new IllegalArgumentException(
+                            "List should be referenced two times in YANG Instance Identifier");
+                }
+            } else if (nextNode instanceof ListNodeCodecContext) {
+                // We enter list, we do not update current Node yet,
+                // since we need to verify
+                currentList = (ListNodeCodecContext) nextNode;
+            } else if (nextNode instanceof ChoiceNodeCodecContext) {
+                // We do not add path argument for choice, since
+                // it is not supported by binding instance identifier.
+                currentNode = nextNode;
+            }else if (nextNode instanceof DataContainerCodecContext<?>) {
+                builder.add(((DataContainerCodecContext<?>) nextNode).getBindingPathArgument(domArg));
+                currentNode = nextNode;
+            } else if (nextNode instanceof LeafNodeCodecContext) {
+                Preconditions.checkArgument(builder == null,"Instance Identifier for leaf is not representable.");
+            }
+        }
+        // Algorithm ended in list as whole representation
+        // we sill need to emit identifier for list
+        if (currentList != null) {
+            builder.add(currentList.getBindingPathArgument(null));
+            return currentList;
+        }
+        return currentNode;
+    }
+
+    @Override
+    public ImmutableMap<String, LeafNodeCodecContext> getLeafNodes(final Class<?> parentClass, final DataNodeContainer childSchema) {
+        HashMap<String, DataSchemaNode> getterToLeafSchema = new HashMap<>();
+        for (DataSchemaNode leaf : childSchema.getChildNodes()) {
+            final TypeDefinition<?> typeDef;
+            if (leaf instanceof LeafSchemaNode) {
+                typeDef = ((LeafSchemaNode) leaf).getType();
+            } else if (leaf instanceof LeafListSchemaNode) {
+                typeDef = ((LeafListSchemaNode) leaf).getType();
+            } else {
+                continue;
+            }
+
+            String getterName =  getGetterName(leaf.getQName(),typeDef);
+            getterToLeafSchema.put(getterName, leaf);
+        }
+        return getLeafNodesUsingReflection(parentClass, getterToLeafSchema);
+    }
+
+    private String getGetterName(final QName qName, TypeDefinition<?> typeDef) {
+        String suffix = BindingMapping.getClassName(qName);
+
+        while(typeDef.getBaseType() != null) {
+            typeDef = typeDef.getBaseType();
+        }
+        if(typeDef instanceof BooleanTypeDefinition) {
+            return "is" + suffix;
+        }
+        return GETTER_PREFIX + suffix;
+    }
+
+    private ImmutableMap<String, LeafNodeCodecContext> getLeafNodesUsingReflection(final Class<?> parentClass,
+            final Map<String, DataSchemaNode> getterToLeafSchema) {
+        Map<String, LeafNodeCodecContext> leaves = new HashMap<>();
+        for (Method method : parentClass.getMethods()) {
+            if (method.getParameterTypes().length == 0) {
+                DataSchemaNode schema = getterToLeafSchema.get(method.getName());
+                final LeafNodeCodecContext leafNode;
+                if (schema instanceof LeafSchemaNode) {
+                    leafNode = leafNodeFrom(method.getReturnType(), schema);
+
+                } else {
+                    // FIXME: extract inner list value
+                    leafNode = null;
+                }
+                if (leafNode != null) {
+                    leaves.put(schema.getQName().getLocalName(), leafNode);
+                }
+            }
+        }
+        return ImmutableMap.copyOf(leaves);
+    }
+
+
+    private LeafNodeCodecContext leafNodeFrom(final Class<?> returnType, final DataSchemaNode schema) {
+        return new LeafNodeCodecContext(schema, getCodec(returnType,schema));
+    }
+
+    private Codec<Object, Object> getCodec(final Class<?> returnType, final DataSchemaNode schema) {
+        if(Class.class.equals(returnType)) {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            final Codec<Object,Object>casted = (Codec) identityCodec;
+            return casted;
+        } else if(InstanceIdentifier.class.equals(returnType)) {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            final Codec<Object,Object>casted = (Codec) instanceIdentifierCodec;
+            return casted;
+        } else if(BindingReflections.isBindingClass(returnType)) {
+            final TypeDefinition<?> instantiatedType;
+            if(schema instanceof LeafSchemaNode) {
+                instantiatedType = ((LeafSchemaNode) schema).getType();
+            } else if(schema instanceof LeafListSchemaNode) {
+                instantiatedType = ((LeafListSchemaNode) schema).getType();
+            } else {
+                instantiatedType = null;
+            }
+            if(instantiatedType != null) {
+                return getCodec(returnType,instantiatedType);
+            }
+        }
+        return ValueTypeCodec.NOOP_CODEC;
+    }
+
+    private Codec<Object, Object> getCodec(final Class<?> returnType, final TypeDefinition<?> instantiatedType) {
+        @SuppressWarnings("rawtypes")
+        TypeDefinition rootType = instantiatedType;
+        while(rootType.getBaseType() != null) {
+            rootType = rootType.getBaseType();
+        }
+         if (rootType instanceof IdentityrefTypeDefinition) {
+            return ValueTypeCodec.encapsulatedValueCodecFor(returnType,identityCodec);
+        } else if (rootType instanceof InstanceIdentifierTypeDefinition) {
+            return ValueTypeCodec.encapsulatedValueCodecFor(returnType,instanceIdentifierCodec);
+        } else if(rootType instanceof UnionTypeDefinition) {
+            // FIXME: Return union codec
+            return ValueTypeCodec.NOOP_CODEC;
+        }
+        return ValueTypeCodec.getCodecFor(returnType, instantiatedType);
+    }
+
+    private class InstanceIdentifierCodec implements Codec<YangInstanceIdentifier,InstanceIdentifier<?>> {
+
+        @Override
+        public YangInstanceIdentifier serialize(final InstanceIdentifier<?> input) {
+            List<YangInstanceIdentifier.PathArgument> domArgs = new LinkedList<>();
+            getCodecContextNode(input, domArgs);
+            return YangInstanceIdentifier.create(domArgs);
+        }
+
+        @Override
+        public InstanceIdentifier<?> deserialize(final YangInstanceIdentifier input) {
+            List<InstanceIdentifier.PathArgument> builder = new LinkedList<>();
+            getCodecContextNode(input, builder);
+            return InstanceIdentifier.create(builder);
+        }
+    }
+
+    private class IdentityCodec implements Codec<QName,Class<?>> {
+
+
+        @Override
+        public Class<?> deserialize(final QName input) {
+            Preconditions.checkArgument(input != null, "Input must not be null.");
+            return context.getIdentityClass(input);
+        }
+
+        @Override
+        public QName serialize(final Class<?> input) {
+            Preconditions.checkArgument(BaseIdentity.class.isAssignableFrom(input));
+            return BindingReflections.findQName(input);
+        }
+    }
+
+    private static class ValueContext {
+
+        Method getter;
+        Codec<Object,Object> codec;
+
+        public ValueContext(final Class<?> identifier, final LeafNodeCodecContext leaf) {
+            final String getterName = GETTER_PREFIX + BindingMapping.getClassName(leaf.getDomPathArgument().getNodeType());
+            try {
+                getter =identifier.getMethod(getterName);
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new IllegalStateException(e);
+            }
+            codec = leaf.getValueCodec();
+        }
+
+        public Object getAndSerialize(final Object obj) {
+            try {
+                Object value = getter.invoke(obj);
+                return codec.serialize(value);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+
+        public Object deserialize(final Object obj) {
+            return codec.deserialize(obj);
+        }
+
+    }
+
+    private class IdentifiableItemCodec implements Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> {
+
+        private final Class<? extends Identifier<?>> keyClass;
+        private final ImmutableMap<QName, ValueContext> keyValueContexts;
+        private final QName name;
+        private final Constructor<? extends Identifier<?>> constructor;
+        private final Class<?> identifiable;
+
+        public IdentifiableItemCodec(final QName name,final Class<? extends Identifier<?>> keyClass,final Class<?> identifiable,final Map<QName, ValueContext> keyValueContexts) {
+            this.name = name;
+            this.identifiable = identifiable;
+            this.keyClass = keyClass;
+            this.keyValueContexts = ImmutableMap.copyOf(keyValueContexts);
+            this.constructor = getConstructor(keyClass);
+        }
+
+        @Override
+        public IdentifiableItem<?,?> deserialize(final NodeIdentifierWithPredicates input) {
+            ArrayList<Object> bindingValues = new ArrayList<>();
+            for(Entry<QName, Object> yangEntry : input.getKeyValues().entrySet()) {
+                QName yangName = yangEntry.getKey();
+                Object yangValue = yangEntry.getValue();
+                bindingValues.add(keyValueContexts.get(yangName).deserialize(yangValue));
+            }
+            try {
+                Identifier<?> identifier = constructor.newInstance(bindingValues.toArray());
+                return new IdentifiableItem(identifiable, identifier);
+            } catch (InstantiationException | IllegalAccessException
+                    | InvocationTargetException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        @Override
+        public NodeIdentifierWithPredicates serialize(final IdentifiableItem<?, ?> input) {
+            Object value = input.getKey();
+
+            Map<QName,Object> values = new HashMap<>();
+            for(Entry<QName, ValueContext> valueCtx : keyValueContexts.entrySet()) {
+                values.put(valueCtx.getKey(), valueCtx.getValue().getAndSerialize(value));
+            }
+            return new NodeIdentifierWithPredicates(name, values);
+        }
+
+    }
+
+    private static Constructor<? extends Identifier<?>> getConstructor(final Class<? extends Identifier<?>> clazz) {
+        for(Constructor constr : clazz.getConstructors()) {
+            Class<?>[] parameters = constr.getParameterTypes();
+            if (!clazz.equals(parameters[0])) {
+                // It is not copy constructor;
+                return constr;
+            }
+        }
+        throw new IllegalArgumentException("Supplied class " + clazz +"does not have required constructor.");
+    }
+
+
+    @Override
+    public Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> getPathArgumentCodec(final Class<?> listClz,
+            final ListSchemaNode schema) {
+        Class<? extends Identifier<?>> identifier =ClassLoaderUtils.findFirstGenericArgument(listClz, Identifiable.class);
+        Map<QName, ValueContext> valueCtx = new HashMap<>();
+        for(LeafNodeCodecContext leaf : getLeafNodes(identifier, schema).values()) {
+            QName name = leaf.getDomPathArgument().getNodeType();
+            valueCtx.put(name, new ValueContext(identifier,leaf));
+        }
+        return new IdentifiableItemCodec(schema.getQName(), identifier, listClz, valueCtx);
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java
new file mode 100644 (file)
index 0000000..780e148
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeWriterFactory;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.AbstractStreamWriterGenerator;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+
+public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry, BindingNormalizedNodeWriterFactory, BindingNormalizedNodeSerializer {
+
+    private final AbstractStreamWriterGenerator generator;
+    private final LoadingCache<Class<? extends DataObject>, DataObjectSerializer> serializers;
+    private BindingCodecContext codecContext;
+
+    public BindingNormalizedNodeCodecRegistry(final AbstractStreamWriterGenerator generator) {
+        this.generator = Preconditions.checkNotNull(generator);
+        this.serializers = CacheBuilder.newBuilder().weakKeys().build(new GeneratorLoader());
+    }
+
+    @Override
+    public DataObjectSerializer getSerializer(final Class<? extends DataObject> type) {
+        return serializers.getUnchecked(type);
+    }
+
+    public BindingCodecContext getCodecContext() {
+        return codecContext;
+    }
+
+    public void onBindingRuntimeContextUpdated(final BindingRuntimeContext context) {
+        codecContext = new BindingCodecContext(context);
+        generator.onBindingRuntimeContextUpdated(context);
+    }
+
+
+    @Override
+    public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
+        List<YangInstanceIdentifier.PathArgument> builder = new LinkedList<>();
+        codecContext.getCodecContextNode(binding, builder);
+        return codecContext.getInstanceIdentifierCodec().serialize(binding);
+    }
+
+    @Override
+    public InstanceIdentifier<?> fromYangInstanceIdentifier(final YangInstanceIdentifier dom) {
+        return codecContext.getInstanceIdentifierCodec().deserialize(dom);
+   }
+
+    @Override
+    public <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> path, final T data) {
+        NormalizedNodeResult result = new NormalizedNodeResult();
+        // We create dom stream writer which produces normalized nodes
+        NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+        // We create Binding Stream Writer wchich translates from Binding to Normalized Nodes
+        Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path, domWriter);
+
+        // We get serializer which reads binding data and uses Binding To NOrmalized Node writer to write result
+        getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
+        return new SimpleEntry<YangInstanceIdentifier,NormalizedNode<?,?>>(writeCtx.getKey(),result.getResult());
+    }
+
+    @Override
+    public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
+            final NormalizedNode<?, ?> data) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(
+            final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(final InstanceIdentifier<?> path, final NormalizedNodeStreamWriter domWriter) {
+        return codecContext.newWriter(path, domWriter);
+    }
+
+    @Override
+    public BindingStreamEventWriter newWriter(final InstanceIdentifier<?> path, final NormalizedNodeStreamWriter domWriter) {
+        return codecContext.newWriterWithoutIdentifier(path, domWriter);
+    }
+
+    private class GeneratorLoader extends CacheLoader<Class<? extends DataObject>, DataObjectSerializer> {
+
+        @Override
+        public DataObjectSerializer load(final Class<? extends DataObject> key) throws Exception {
+            DataObjectSerializerImplementation prototype = generator.getSerializer(key);
+            return new DataObjectSerializerProxy(prototype);
+        }
+    }
+
+    private class DataObjectSerializerProxy implements DataObjectSerializer,
+            Delegator<DataObjectSerializerImplementation> {
+
+        private final DataObjectSerializerImplementation delegate;
+
+        DataObjectSerializerProxy(final DataObjectSerializerImplementation delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public DataObjectSerializerImplementation getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public void serialize(final DataObject obj, final BindingStreamEventWriter stream) {
+            delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);
+        }
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingToNormalizedStreamWriter.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingToNormalizedStreamWriter.java
new file mode 100644 (file)
index 0000000..3aa60c9
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+
+import java.util.AbstractMap;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+
+class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Delegator<NormalizedNodeStreamWriter> {
+
+    private final NormalizedNodeStreamWriter delegate;
+    private final Deque<NodeCodecContext> schema = new ArrayDeque<>();
+    private final NodeCodecContext rootNodeSchema;
+
+    public BindingToNormalizedStreamWriter(final NodeCodecContext schema, final NormalizedNodeStreamWriter delegate) {
+        this.delegate = Preconditions.checkNotNull(delegate, "Delegate must not be null");
+        this.rootNodeSchema = Preconditions.checkNotNull(schema);
+
+    }
+
+    private NodeCodecContext current() {
+        return schema.peek();
+    }
+
+    private NodeIdentifier duplicateSchemaEnter() {
+        final NodeCodecContext next;
+        if (current() == null) {
+            // Entry of first node
+            next = rootNodeSchema;
+        } else {
+            next = current();
+        }
+        this.schema.push(next);
+        return (NodeIdentifier) current().getDomPathArgument();
+    }
+
+    private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
+        final NodeCodecContext next;
+        if (current() == null) {
+            // Entry of first node
+            next = rootNodeSchema;
+        } else {
+            Preconditions.checkArgument((current() instanceof DataContainerCodecContext), "Could not start node %s",
+                    name);
+            next = ((DataContainerCodecContext<?>) current()).getStreamChild(name);
+        }
+        this.schema.push(next);
+        @SuppressWarnings("unchecked")
+        T arg = (T) next.getDomPathArgument();
+        return arg;
+    }
+
+    private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
+        NodeCodecContext current = current();
+        NodeCodecContext next = ((DataObjectCodecContext<?>) current).getLeafChild(localName);
+        this.schema.push(next);
+        @SuppressWarnings("unchecked")
+        T arg = (T) next.getDomPathArgument();
+        return arg;
+    }
+
+    @Override
+    public void endNode() {
+        NodeCodecContext left = schema.pop();
+        // NormalizedNode writer does not have entry into case, but into choice
+        // so for leaving case, we do not emit endNode.
+        if (!(left instanceof CaseNodeCodecContext)) {
+            getDelegate().endNode();
+        }
+    }
+
+    @Override
+    public NormalizedNodeStreamWriter getDelegate() {
+        return delegate;
+    }
+
+    private Map.Entry<NodeIdentifier, Object> serializeLeaf(final String localName, final Object value) {
+        Preconditions.checkArgument(current() instanceof DataObjectCodecContext<?>);
+
+        DataObjectCodecContext<?> currentCasted = (DataObjectCodecContext<?>) current();
+        LeafNodeCodecContext leafContext = currentCasted.getLeafChild(localName);
+
+        NodeIdentifier domArg = (NodeIdentifier) leafContext.getDomPathArgument();
+        Object domValue = leafContext.getValueCodec().serialize(value);
+        return new AbstractMap.SimpleEntry<>(domArg, domValue);
+    }
+
+    @Override
+    public void leafNode(final String localName, final Object value) throws IllegalArgumentException {
+        Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
+        getDelegate().leafNode(dom.getKey(), dom.getValue());
+    };
+
+    @Override
+    public void anyxmlNode(final String name, final Object value) throws IllegalArgumentException {
+        Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
+        getDelegate().anyxmlNode(dom.getKey(), dom.getValue());
+    }
+
+    @Override
+    public void leafSetEntryNode(final Object value) throws IllegalArgumentException {
+        LeafNodeCodecContext ctx = (LeafNodeCodecContext) current();
+        getDelegate().leafSetEntryNode(ctx.getValueCodec().serialize(value));
+    }
+
+    @Override
+    public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType)
+            throws IllegalArgumentException {
+        getDelegate().startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
+    }
+
+    @Override
+    public void startCase(final Class<? extends DataObject> caze, final int childSizeHint)
+            throws IllegalArgumentException {
+        enter(caze, NodeIdentifier.class);
+    };
+
+    @Override
+    public void startChoiceNode(final Class<? extends DataContainer> type, final int childSizeHint)
+            throws IllegalArgumentException {
+        getDelegate().startChoiceNode(enter(type, NodeIdentifier.class), childSizeHint);
+    }
+
+    @Override
+    public void startContainerNode(final Class<? extends DataObject> object, final int childSizeHint)
+            throws IllegalArgumentException {
+        getDelegate().startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
+    }
+
+    @Override
+    public void startLeafSet(final String localName, final int childSizeHint) throws IllegalArgumentException {
+        getDelegate().startLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
+    };
+
+    @Override
+    public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IllegalArgumentException {
+        duplicateSchemaEnter();
+        NodeIdentifierWithPredicates identifier = ((ListNodeCodecContext) current()).serialize(key);
+        getDelegate().startMapEntryNode(identifier, childSizeHint);
+    };
+
+    @Override
+    public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
+            final int childSizeHint) throws IllegalArgumentException {
+        getDelegate().startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
+    };
+
+    @Override
+    public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
+            final int childSizeHint) throws IllegalArgumentException {
+        getDelegate().startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
+    };
+
+    @Override
+    public void startUnkeyedList(final Class<? extends DataObject> obj, final int childSizeHint)
+            throws IllegalArgumentException {
+        getDelegate().startUnkeyedList(enter(obj, NodeIdentifier.class), childSizeHint);
+    };
+
+    @Override
+    public void startUnkeyedListItem(final int childSizeHint) throws IllegalStateException {
+        getDelegate().startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BitsCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BitsCodec.java
new file mode 100644 (file)
index 0000000..93ad636
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSortedMap;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.concurrent.Callable;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
+
+class BitsCodec extends ReflectionBasedCodec {
+
+    private final ImmutableSortedMap<String, Method> valueGetters;
+    private final Constructor<?> constructor;
+
+    private BitsCodec(final Class<?> typeClass, final SortedMap<String, Method> valueGetters,
+            final Constructor<?> constructor) {
+        super(typeClass);
+        this.valueGetters = ImmutableSortedMap.copyOf(valueGetters);
+        this.constructor = constructor;
+    }
+
+    static Callable<ReflectionBasedCodec> loader(final Class<?> returnType,
+            final BitsTypeDefinition rootType) {
+        return new Callable<ReflectionBasedCodec>() {
+
+            @Override
+            public ReflectionBasedCodec call() throws Exception {
+                try {
+                    SortedMap<String, Method> valueGetters = new TreeMap<>();
+                    for (Bit bit : rootType.getBits()) {
+                        String bindingName = BindingMapping.getClassName(bit.getName());
+                        Method valueGetter = returnType.getMethod("is" + bindingName);
+                        valueGetters.put(bit.getName(), valueGetter);
+
+                    }
+                    Constructor<?> constructor = null;
+                    for (Constructor<?> cst : returnType.getConstructors()) {
+                        if (cst.getParameterTypes()[0].equals(returnType)) {
+                            continue;
+                        }
+                        constructor = cst;
+                    }
+
+                    return new BitsCodec(returnType, valueGetters, constructor);
+                } catch (IllegalArgumentException | NoSuchMethodException | SecurityException e) {
+                    throw new IllegalStateException(e);
+                }
+            }
+        };
+    }
+
+    @Override
+    public Object deserialize(final Object input) {
+        Preconditions.checkArgument(input instanceof Set);
+        @SuppressWarnings("unchecked")
+        Set<String> casted = (Set<String>) input;
+
+        Object args[] = new Object[valueGetters.size()];
+        int currentArg = 0;
+        for (String value : valueGetters.keySet()) {
+            if (casted.contains(value)) {
+                args[currentArg] = Boolean.TRUE;
+            } else {
+                args[currentArg] = Boolean.FALSE;
+            }
+            currentArg++;
+        }
+
+        try {
+            return constructor.newInstance(args);
+        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public Object serialize(final Object input) {
+        Set<String> result = new HashSet<>();
+        for (Entry<String, Method> valueGet : valueGetters.entrySet()) {
+            try {
+                Boolean value = (Boolean) valueGet.getValue().invoke(input);
+                if (value) {
+                    result.add(valueGet.getKey());
+                }
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CaseNodeCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CaseNodeCodecContext.java
new file mode 100644 (file)
index 0000000..0f64001
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+
+class CaseNodeCodecContext extends DataObjectCodecContext<ChoiceCaseNode> {
+
+    private final YangInstanceIdentifier.PathArgument yangIdentifier;
+
+    CaseNodeCodecContext(final Class<?> cls, final ChoiceCaseNode nodeSchema,
+            final CodecContextFactory runtimeContext) {
+        super(cls, nodeSchema.getQName().getModule(), nodeSchema, runtimeContext);
+        this.yangIdentifier = (new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName()));
+    }
+
+    @Override
+    protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        return yangIdentifier;
+    }
+
+    @Override
+    protected void addYangPathArgument(final PathArgument arg,
+            final List<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> builder) {
+        // NOOP
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java
new file mode 100644 (file)
index 0000000..39efa34
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class ChoiceNodeCodecContext extends DataContainerCodecContext<ChoiceNode> {
+
+    private final YangInstanceIdentifier.PathArgument yangArgument;
+    private final ImmutableMap<QName, ChoiceCaseNode> caseChildToCase;
+
+    ChoiceNodeCodecContext(final Class<?> cls, final ChoiceNode nodeSchema, final CodecContextFactory context) {
+        super(cls, nodeSchema.getQName().getModule(), nodeSchema, context);
+        Map<QName, ChoiceCaseNode> childToCase = new HashMap<>();
+        yangArgument = new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName());
+        for (ChoiceCaseNode caseNode : nodeSchema.getCases()) {
+            for (DataSchemaNode caseChild : caseNode.getChildNodes()) {
+                childToCase.put(caseChild.getQName(), caseNode);
+            }
+        }
+        caseChildToCase = ImmutableMap.copyOf(childToCase);
+    }
+
+    @Override
+    protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        return yangArgument;
+    }
+
+    @Override
+    protected DataContainerCodecContext<?> loadChild(final Class<?> childClass) {
+
+        ChoiceCaseNode childSchema = factory.getRuntimeContext().getCaseSchemaDefinition(schema, childClass);
+        return new CaseNodeCodecContext(childClass, childSchema, factory);
+    }
+
+    @Override
+    protected NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg) {
+
+        QName childQName = arg.getNodeType();
+        ChoiceCaseNode caze = caseChildToCase.get(childQName);
+        Preconditions.checkArgument(caze != null, "Argument %s is not valid child of %s", arg, schema);
+        ;
+        Class<?> cazeClass = factory.getRuntimeContext().getClassForSchema(caze);
+        return getStreamChild(cazeClass).getYangIdentifierChild(arg);
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CompositeValueCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CompositeValueCodec.java
new file mode 100644 (file)
index 0000000..b339410
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.concepts.Codec;
+
+class CompositeValueCodec extends ValueTypeCodec {
+
+    private final ValueTypeCodec bindingToSimpleType;
+    @SuppressWarnings("rawtypes")
+    private final Codec bindingToDom;
+
+    CompositeValueCodec(final ValueTypeCodec extractor,
+            @SuppressWarnings("rawtypes") final Codec delegate) {
+        this.bindingToSimpleType = extractor;
+        this.bindingToDom = delegate;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object deserialize(final Object input) {
+        return bindingToSimpleType.deserialize(bindingToDom.deserialize(input));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object serialize(final Object input) {
+        return bindingToDom.serialize(bindingToSimpleType.serialize(input));
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ContainerNodeCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ContainerNodeCodecContext.java
new file mode 100644 (file)
index 0000000..2ad90d5
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+class ContainerNodeCodecContext extends DataObjectCodecContext<ContainerSchemaNode> {
+
+    private final YangInstanceIdentifier.PathArgument yangIdentifier;
+
+    protected ContainerNodeCodecContext(final Class<?> cls, final ContainerSchemaNode nodeSchema,
+            final CodecContextFactory loader) {
+        super(cls, nodeSchema.getQName().getModule(), nodeSchema, loader);
+        this.yangIdentifier = (new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName()));
+    }
+
+    @Override
+    protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        return yangIdentifier;
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataContainerCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataContainerCodecContext.java
new file mode 100644 (file)
index 0000000..88a5b74
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.util.List;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+abstract class DataContainerCodecContext<T> extends NodeCodecContext {
+
+    protected final T schema;
+    protected final QNameModule namespace;
+    protected final CodecContextFactory factory;
+    protected final Class<?> bindingClass;
+    protected final InstanceIdentifier.Item<?> bindingArg;
+
+    protected final LoadingCache<Class<?>, DataContainerCodecContext<?>> containerChild;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected DataContainerCodecContext(final Class<?> cls, final QNameModule namespace, final T nodeSchema,
+            final CodecContextFactory factory) {
+        super();
+        this.schema = nodeSchema;
+        this.factory = factory;
+        this.namespace = namespace;
+        this.bindingClass = cls;
+        this.bindingArg = new InstanceIdentifier.Item(bindingClass);
+
+        this.containerChild = CacheBuilder.newBuilder().build(new CacheLoader<Class<?>, DataContainerCodecContext<?>>() {
+            @Override
+            public DataContainerCodecContext<?> load(final Class<?> key) throws Exception {
+                return loadChild(key);
+            }
+        });
+    }
+
+    static DataContainerCodecContext<?> from(final Class<?> cls, final DataSchemaNode schema,
+            final CodecContextFactory loader) {
+        if (schema instanceof ContainerSchemaNode) {
+            return new ContainerNodeCodecContext(cls, (ContainerSchemaNode) schema, loader);
+        } else if (schema instanceof ListSchemaNode) {
+            return new ListNodeCodecContext(cls, (ListSchemaNode) schema, loader);
+        } else if (schema instanceof ChoiceNode) {
+            return new ChoiceNodeCodecContext(cls, (ChoiceNode) schema, loader);
+        }
+        throw new IllegalArgumentException("Not supported type " + cls + " " + schema);
+    }
+
+    protected  T getSchema() {
+        return schema;
+    }
+
+    /**
+     * Returns nested node context using supplied YANG Instance Identifier
+     *
+     * @param arg Yang Instance Identifier Argument
+     * @return Context of child
+     * @throws IllegalArgumentException If supplied argument does not represent valid child.
+     */
+    protected abstract NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg);
+
+    /**
+     * Returns nested node context using supplied Binding Instance Identifier
+     * and adds YANG instance identifiers to supplied list.
+     *
+     * @param arg Binding Instance Identifier Argument
+     * @return Context of child
+     * @throws IllegalArgumentException If supplied argument does not represent valid child.
+     */
+    protected  DataContainerCodecContext<?> getIdentifierChild(final InstanceIdentifier.PathArgument arg,
+            final List<YangInstanceIdentifier.PathArgument> builder) {
+        final DataContainerCodecContext<?> child = getStreamChild(arg.getType());
+        if (builder != null) {
+            child.addYangPathArgument(arg,builder);
+        }
+        return child;
+    }
+
+    /**
+     *
+     * Returns deserialized Binding Path Argument from YANG instance identifier.
+     *
+     * @param domArg
+     * @return
+     */
+    protected  PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
+        return bindingArg;
+    }
+
+    /**
+     *
+     * Returns child context as if it was walked by
+     * {@link BindingStreamEventWriter}. This means that to enter case, one
+     * must issue getChild(ChoiceClass).getChild(CaseClass).
+     *
+     * @param childClass
+     * @return Context of child
+     */
+    protected  DataContainerCodecContext<?> getStreamChild(final Class<?> childClass) {
+        return containerChild.getUnchecked(childClass);
+    }
+
+    /**
+     * Loads children identified by supplied class. If children is not
+     * valid, throws {@link IllegalArgumentException}.
+     *
+     * @param childClass
+     * @return Context of child
+     */
+    protected abstract DataContainerCodecContext<?> loadChild(final Class<?> childClass);
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + " [" + bindingClass + "]";
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java
new file mode 100644 (file)
index 0000000..fa6e45d
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
+import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
+
+abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataContainerCodecContext<T> {
+
+    protected final ImmutableMap<String, LeafNodeCodecContext> leafChild;
+    protected final ImmutableMap<Type, Entry<Type, Type>> choiceCaseChildren;
+    protected final ImmutableMap<AugmentationIdentifier, Type> augIdentifierToType;
+
+    protected DataObjectCodecContext(final Class<?> cls, final QNameModule namespace, final T nodeSchema,
+            final CodecContextFactory loader) {
+        super(cls, namespace, nodeSchema, loader);
+        this.leafChild = loader.getLeafNodes(cls, nodeSchema);
+        this.choiceCaseChildren = factory.getRuntimeContext().getChoiceCaseChildren(schema);
+        this.augIdentifierToType = factory.getRuntimeContext().getAvailableAugmentationTypes(nodeSchema);
+    }
+
+    @Override
+    protected DataContainerCodecContext<?> getIdentifierChild(final InstanceIdentifier.PathArgument arg,
+            final List<YangInstanceIdentifier.PathArgument> builder) {
+        if (choiceCaseChildren.isEmpty()) {
+            return super.getIdentifierChild(arg, builder);
+        }
+        // Lookup in choiceCase
+        Class<? extends DataObject> argument = arg.getType();
+        ReferencedTypeImpl ref = new ReferencedTypeImpl(argument.getPackage().getName(), argument.getSimpleName());
+        Entry<Type, Type> cazeId = choiceCaseChildren.get(ref);
+        if (cazeId == null) {
+            return super.getIdentifierChild(arg, builder);
+        }
+        ClassLoadingStrategy loader = factory.getRuntimeContext().getStrategy();
+        try {
+            Class<?> choice = loader.loadClass(cazeId.getKey());
+            Class<?> caze = loader.loadClass(cazeId.getValue());
+            ChoiceNodeCodecContext choiceNode = (ChoiceNodeCodecContext) getStreamChild(choice);
+            choiceNode.addYangPathArgument(arg, builder);
+            CaseNodeCodecContext cazeNode = (CaseNodeCodecContext) choiceNode.getStreamChild(caze);
+            cazeNode.addYangPathArgument(arg, builder);
+            return cazeNode.getIdentifierChild(arg, builder);
+
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("Required class not found.", e);
+        }
+
+    }
+
+    @Override
+    protected NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg) {
+        if (arg instanceof YangInstanceIdentifier.AugmentationIdentifier) {
+            return getChildByAugmentationIdentifier((YangInstanceIdentifier.AugmentationIdentifier) arg);
+        }
+
+        QName childQName = arg.getNodeType();
+        DataSchemaNode childSchema = schema.getDataChildByName(childQName);
+        Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", arg, schema);
+        if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
+            Class<?> childCls = factory.getRuntimeContext().getClassForSchema(childSchema);
+            DataContainerCodecContext<?> childNode = getStreamChild(childCls);
+            return childNode;
+        } else {
+            return getLeafChild(childQName.getLocalName());
+        }
+    }
+
+    protected NodeCodecContext getChildByAugmentationIdentifier(final YangInstanceIdentifier.AugmentationIdentifier arg) {
+        final Type augType = augIdentifierToType.get(arg);
+        try {
+            Class<?> augClass = factory.getRuntimeContext().getStrategy().loadClass(augType);
+            return getStreamChild(augClass);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Unable to load referenced augmentation.", e);
+        }
+    }
+
+    protected final LeafNodeCodecContext getLeafChild(final String name) {
+        final LeafNodeCodecContext value = leafChild.get(name);
+        Preconditions.checkArgument(value != null, "Leaf %s is not valid for %s", name, bindingClass);
+        return value;
+    }
+
+    @Override
+    protected DataContainerCodecContext<?> loadChild(final Class<?> childClass) {
+        if (Augmentation.class.isAssignableFrom(childClass)) {
+            return loadAugmentation(childClass);
+        }
+
+        DataSchemaNode origDef = factory.getRuntimeContext().getSchemaDefinition(childClass);
+        // Direct instantiation or use in same module in which grouping
+        // was defined.
+        DataSchemaNode sameName = schema.getDataChildByName(origDef.getQName());
+        final DataSchemaNode childSchema;
+        if (sameName != null) {
+            // Exactly same schema node
+            if (origDef.equals(sameName)) {
+                childSchema = sameName;
+                // We check if instantiated node was added via uses
+                // statement and is an instantiation of same grouping
+            } else if (origDef.equals(SchemaNodeUtils.getRootOriginalIfPossible(sameName))) {
+                childSchema = sameName;
+            } else {
+                // Node has same name, but clearly is different
+                childSchema = null;
+            }
+        } else {
+            // We are looking for instantiation via uses in other module
+            QName instantiedName = QName.create(namespace, origDef.getQName().getLocalName());
+            DataSchemaNode potential = schema.getDataChildByName(instantiedName);
+            // We check if it is really instantiated from same
+            // definition
+            // as class was derived
+            if (potential != null && origDef.equals(SchemaNodeUtils.getRootOriginalIfPossible(potential))) {
+                childSchema = potential;
+            } else {
+                childSchema = null;
+            }
+        }
+        Preconditions
+        .checkArgument(childSchema != null, "Node %s does not have child named %s", schema, childClass);
+        return DataContainerCodecContext.from(childClass, childSchema, factory);
+    }
+
+    @SuppressWarnings("rawtypes")
+    private AugmentationNode loadAugmentation(final Class childClass) {
+        Preconditions.checkArgument(schema instanceof AugmentationTarget);
+        @SuppressWarnings("unchecked")
+        Entry<AugmentationIdentifier, AugmentationSchema> augSchema = factory.getRuntimeContext()
+                .getResolvedAugmentationSchema(schema, childClass);
+        QNameModule namespace = Iterables.getFirst(augSchema.getKey().getPossibleChildNames(), null).getModule();
+        return new AugmentationNode(childClass, namespace, augSchema.getKey(), augSchema.getValue(), factory);
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/EncapsulatedValueCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/EncapsulatedValueCodec.java
new file mode 100644 (file)
index 0000000..c2df67b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+
+/**
+ *
+ * Derived YANG types are just immutable value holders for simple value
+ * types, which are same as in NormalizedNode model.
+ *
+ */
+class EncapsulatedValueCodec extends ReflectionBasedCodec {
+
+    private final Method getter;
+    private final Constructor<?> constructor;
+
+    EncapsulatedValueCodec(final Class<?> typeClz) {
+        super(typeClz);
+        try {
+            this.getter = typeClz.getMethod("getValue");
+            this.constructor = typeClz.getConstructor(getter.getReturnType());
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException("Could not resolve required method.", e);
+        }
+    }
+
+    static Callable<ReflectionBasedCodec> loader(final Class<?> typeClz) {
+        return new Callable<ReflectionBasedCodec>() {
+            @Override
+            public ReflectionBasedCodec call() throws Exception {
+                return new EncapsulatedValueCodec(typeClz);
+            }
+        };
+    }
+
+    @Override
+    public Object deserialize(final Object input) {
+        try {
+            return constructor.newInstance(input);
+        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public Object serialize(final Object input) {
+        try {
+            return getter.invoke(input);
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/EnumerationCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/EnumerationCodec.java
new file mode 100644 (file)
index 0000000..70379c0
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableBiMap;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+
+class EnumerationCodec extends ReflectionBasedCodec {
+
+    ImmutableBiMap<String, Enum<?>> yangValueToBinding;
+
+    public EnumerationCodec(final Class<? extends Enum<?>> enumeration, final Map<String, Enum<?>> schema) {
+        super(enumeration);
+        yangValueToBinding = ImmutableBiMap.copyOf(schema);
+    }
+
+    static Callable<ReflectionBasedCodec> loader(final Class<?> returnType,
+            final EnumTypeDefinition enumSchema) {
+        Preconditions.checkArgument(Enum.class.isAssignableFrom(returnType));
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        final Class<? extends Enum<?>> enumType = (Class) returnType;
+        return new Callable<ReflectionBasedCodec>() {
+            @Override
+            public ReflectionBasedCodec call() throws Exception {
+
+                Map<String, Enum<?>> nameToValue = new HashMap<>();
+                for (Enum<?> enumValue : enumType.getEnumConstants()) {
+                    nameToValue.put(enumValue.toString(), enumValue);
+                }
+                Map<String, Enum<?>> yangNameToBinding = new HashMap<>();
+                for (EnumPair yangValue : enumSchema.getValues()) {
+                    final String bindingName = BindingMapping.getClassName(yangValue.getName());
+                    final Enum<?> bindingVal = nameToValue.get(bindingName);
+                    yangNameToBinding.put(yangValue.getName(), bindingVal);
+                }
+                return new EnumerationCodec(enumType, yangNameToBinding);
+            }
+        };
+    }
+
+
+    @Override
+    public Object deserialize(final Object input) {
+        Enum<?> value = yangValueToBinding.get(input);
+        Preconditions.checkArgument(value != null, "Invalid enumeration value %s. Valid values are %s", input,
+                yangValueToBinding.keySet());
+        return value;
+    }
+
+    @Override
+    public Object serialize(final Object input) {
+        Preconditions.checkArgument(typeClass.isInstance(input), "Input must be instance of %s", typeClass);
+        return yangValueToBinding.inverse().get(input);
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/LeafNodeCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/LeafNodeCodecContext.java
new file mode 100644 (file)
index 0000000..424bd26
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class LeafNodeCodecContext extends NodeCodecContext {
+
+    private final YangInstanceIdentifier.PathArgument yangIdentifier;
+    private final Codec<Object, Object> valueCodec;
+
+    LeafNodeCodecContext(final DataSchemaNode node, final Codec<Object, Object> codec) {
+        this.yangIdentifier = new YangInstanceIdentifier.NodeIdentifier(node.getQName());
+        this.valueCodec = codec;
+    }
+
+    @Override
+    protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        return (yangIdentifier);
+    }
+
+    protected Codec<Object, Object> getValueCodec() {
+        return valueCodec;
+    }
+
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ListNodeCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ListNodeCodecContext.java
new file mode 100644 (file)
index 0000000..4636c9f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+class ListNodeCodecContext extends DataObjectCodecContext<ListSchemaNode> {
+
+    private final YangInstanceIdentifier.PathArgument yangIdentifier;
+    private final Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> codec;
+
+    ListNodeCodecContext(final Class<?> cls, final ListSchemaNode nodeSchema, final CodecContextFactory loader) {
+        super(cls, nodeSchema.getQName().getModule(), nodeSchema, loader);
+        this.yangIdentifier = new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName());
+        if (Identifiable.class.isAssignableFrom(cls)) {
+            this.codec = loader.getPathArgumentCodec(cls,nodeSchema);
+        } else {
+            this.codec = null;
+        }
+    }
+
+    @Override
+    public YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        return yangIdentifier;
+    }
+
+    @Override
+    public void addYangPathArgument(final InstanceIdentifier.PathArgument arg, final List<YangInstanceIdentifier.PathArgument> builder) {
+
+        /*
+         * DOM Instance Identifier for list is always represent by two
+         * entries one for map and one for children. This is also true for
+         * wildcarded instance identifiers
+         */
+        if (builder == null) {
+            return;
+        }
+        super.addYangPathArgument(arg, builder);
+        if (arg instanceof IdentifiableItem<?, ?>) {
+            builder.add(codec.serialize((IdentifiableItem<?, ?>) arg));
+        } else {
+            // Adding wildcarded
+            super.addYangPathArgument(arg, builder);
+        }
+    }
+
+    @Override
+    public InstanceIdentifier.PathArgument getBindingPathArgument(
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument domArg) {
+        if(domArg instanceof NodeIdentifierWithPredicates) {
+            return codec.deserialize((NodeIdentifierWithPredicates) domArg);
+        }
+        return super.getBindingPathArgument(domArg);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public NodeIdentifierWithPredicates serialize(final Identifier<?> key) {
+        return codec.serialize(new IdentifiableItem(bindingClass, key));
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NodeCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NodeCodecContext.java
new file mode 100644 (file)
index 0000000..dd38625
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ *
+ * Location specific context for schema nodes, which contains codec specific
+ * information to properly serialize / deserialize from Java YANG Binding data
+ * to NormalizedNode data.
+ *
+ * Two core subtypes of codec context are available:
+ * <ul>
+ * <li>{@link LeafNodeCodecContext} - Context for nodes, which does not contain
+ * any nested YANG modeled substructures.</li>
+ * <li>{@link DataObjectCodecContext} - Context for nodes, which does contain
+ * nested YANG modeled substructures. This context nodes contains context
+ * for children nodes.</li>
+ * </ul>
+ *
+ */
+abstract class NodeCodecContext {
+
+    /**
+     * Returns Yang Instance Identifier Path Argument of current node
+     *
+     * @return DOM Path Argument of node
+     */
+    protected abstract YangInstanceIdentifier.PathArgument getDomPathArgument();
+
+    /**
+     *
+     * Immutable factory, which provides access to runtime context,
+     * create leaf nodes and provides path argument codecs.
+     * <p>
+     * During lifetime of factory all calls for same arguments to method must return
+     * equal result (not necessary same instance of result).
+     *
+     */
+    protected interface CodecContextFactory {
+
+        /**
+         * Returns immutable runtime context associated with this factory.
+         * @return runtime context
+         */
+        BindingRuntimeContext getRuntimeContext();
+
+        /**
+         * Returns leaf nodes for supplied data container and parent class.
+         *
+         * @param type Binding type for which leaves should be loaded.
+         * @param schema  Instantiated schema of binding type.
+         * @return Map of local name to leaf node context.
+         */
+        ImmutableMap<String, LeafNodeCodecContext> getLeafNodes(Class<?> type, DataNodeContainer schema);
+
+        /**
+         * Returns Path argument codec for list item
+         *
+         * @param type Type of list item
+         * @param schema Schema of list item
+         * @return Path argument codec for supplied list item.
+         */
+        Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> getPathArgumentCodec(Class<?> type,
+                ListSchemaNode schema);
+
+    }
+
+    /**
+     *
+     * Serializes supplied Binding Path Argument
+     * and adds all necessary YANG instance identifiers to supplied list.
+     *
+     * @param arg Bidning Path Argument
+     * @param builder DOM Path argument.
+     */
+    protected void addYangPathArgument(final InstanceIdentifier.PathArgument arg,
+            final List<YangInstanceIdentifier.PathArgument> builder) {
+        if (builder != null) {
+            builder.add(getDomPathArgument());
+        }
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ReflectionBasedCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ReflectionBasedCodec.java
new file mode 100644 (file)
index 0000000..fa3aa50
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+abstract class ReflectionBasedCodec extends ValueTypeCodec {
+
+    protected final Class<?> typeClass;
+
+    public ReflectionBasedCodec(final Class<?> typeClass) {
+        super();
+        this.typeClass = typeClass;
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java
new file mode 100644 (file)
index 0000000..b17a8a6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
+
+    private SchemaRootCodecContext(final CodecContextFactory factory) {
+        super(SchemaRootCodecContext.class, null, factory.getRuntimeContext().getSchemaContext(), factory);
+    }
+
+    /**
+     * Creates RootNode from supplied CodecContextFactory.
+     *
+     * @param factory
+     *            CodecContextFactory
+     * @return
+     */
+    static SchemaRootCodecContext create(final CodecContextFactory factory) {
+        return new SchemaRootCodecContext(factory);
+    }
+
+    @Override
+    protected DataContainerCodecContext<?> loadChild(final Class<?> childClass) {
+        Class<Object> parent = ClassLoaderUtils.findFirstGenericArgument(childClass, ChildOf.class);
+        Preconditions.checkArgument(DataRoot.class.isAssignableFrom(parent));
+
+        QName qname = BindingReflections.findQName(childClass);
+        DataSchemaNode childSchema = getSchema().getDataChildByName(qname);
+        return DataContainerCodecContext.from(childClass, childSchema, factory);
+    }
+
+    @Override
+    protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg) {
+
+        QName childQName = arg.getNodeType();
+        DataSchemaNode childSchema = schema.getDataChildByName(childQName);
+        Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", arg, schema);
+        if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
+            Class<?> childCls = factory.getRuntimeContext().getClassForSchema(childSchema);
+            DataContainerCodecContext<?> childNode = getStreamChild(childCls);
+            return childNode;
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ValueTypeCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ValueTypeCodec.java
new file mode 100644 (file)
index 0000000..e18c5e5
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+
+/**
+ * Value codec, which serializes / deserializes values from DOM simple values.
+ *
+ */
+abstract class ValueTypeCodec implements Codec<Object, Object> {
+
+    private static final Cache<Class<?>, ReflectionBasedCodec> REFLECTION_CODECS = CacheBuilder.newBuilder().weakKeys()
+            .build();
+
+    /**
+     *
+     * No-op Codec, Java YANG Binding uses same types as NormalizedNode model
+     * for base YANG types, representing numbers, binary and strings.
+     *
+     *
+     */
+    public static final ValueTypeCodec NOOP_CODEC = new ValueTypeCodec() {
+
+        @Override
+        public Object serialize(final Object input) {
+            return input;
+        }
+
+        @Override
+        public Object deserialize(final Object input) {
+            return input;
+        }
+    };
+
+    public static ValueTypeCodec getCodecFor(final Class<?> typeClz, final TypeDefinition<?> def) {
+        if (BindingReflections.isBindingClass(typeClz)) {
+            return getReflectionCodec(typeClz, getCodecLoader(typeClz, def));
+        }
+        return NOOP_CODEC;
+    }
+
+    private static ValueTypeCodec getReflectionCodec(final Class<?> typeClz, final Callable<ReflectionBasedCodec> loader) {
+        try {
+            return REFLECTION_CODECS.get(typeClz, loader);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    private static Callable<ReflectionBasedCodec> getCodecLoader(final Class<?> typeClz, final TypeDefinition<?> def) {
+
+        TypeDefinition<?> rootType = def;
+        while (rootType.getBaseType() != null) {
+            rootType = rootType.getBaseType();
+        }
+        if (rootType instanceof EnumTypeDefinition) {
+            return EnumerationCodec.loader(typeClz, (EnumTypeDefinition) rootType);
+        } else if (rootType instanceof BitsTypeDefinition) {
+            return BitsCodec.loader(typeClz, (BitsTypeDefinition) rootType);
+        }
+        return EncapsulatedValueCodec.loader(typeClz);
+    }
+
+    @SuppressWarnings("rawtypes")
+    static ValueTypeCodec encapsulatedValueCodecFor(final Class<?> typeClz, final Codec delegate) {
+        ValueTypeCodec extractor = getReflectionCodec(typeClz, EncapsulatedValueCodec.loader(typeClz));
+        return new CompositeValueCodec(extractor, delegate);
+    }
+
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/AugmentableDispatchSerializer.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/AugmentableDispatchSerializer.java
new file mode 100644 (file)
index 0000000..3df5866
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.util;
+
+import com.google.common.base.Preconditions;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AugmentableDispatchSerializer implements DataObjectSerializerImplementation {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AugmentableDispatchSerializer.class);
+
+    @Override
+    public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj,
+            final BindingStreamEventWriter stream) {
+        if (obj instanceof Augmentable<?>) {
+            Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations = BindingReflections
+                    .getAugmentations((Augmentable<?>) obj);
+            for (Entry<Class<? extends Augmentation<?>>, Augmentation<?>> aug : augmentations.entrySet()) {
+                emitAugmentation(aug.getKey(), aug.getValue(), stream, reg);
+            }
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private void emitAugmentation(final Class type, final Augmentation<?> value, final BindingStreamEventWriter stream,
+            final DataObjectSerializerRegistry registry) {
+        Preconditions.checkArgument(value instanceof DataObject);
+        @SuppressWarnings("unchecked")
+        DataObjectSerializer serializer = registry.getSerializer(type);
+        if (serializer != null) {
+            serializer.serialize((DataObject) value, stream);
+        } else {
+            LOG.warn("DataObjectSerializer is not present for {} in registry {}", type, registry);
+        }
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/ChoiceDispatchSerializer.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/ChoiceDispatchSerializer.java
new file mode 100644 (file)
index 0000000..1c13023
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.util;
+
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChoiceDispatchSerializer implements DataObjectSerializerImplementation {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ChoiceDispatchSerializer.class);
+
+    @SuppressWarnings("rawtypes")
+    private final Class choiceClass;
+
+    @SuppressWarnings("rawtypes")
+    private ChoiceDispatchSerializer(final Class choiceClass) {
+        super();
+        this.choiceClass = choiceClass;
+    }
+
+    public static final ChoiceDispatchSerializer from(final Class<? extends DataContainer> choiceClass) {
+        return new ChoiceDispatchSerializer(choiceClass);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj, final BindingStreamEventWriter stream) {
+        @SuppressWarnings("rawtypes")
+        Class cazeClass = obj.getImplementedInterface();
+        stream.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
+        DataObjectSerializer caseSerializer = reg.getSerializer(cazeClass);
+        if (caseSerializer != null) {
+            caseSerializer.serialize(obj, stream);
+        } else {
+            LOG.warn("No serializer for case {} is available in registry {}", cazeClass, reg);
+        }
+        stream.endNode();
+    }
+}
index b711c3985fd5afa081e8a857ebbefc43a46d6c07..da757095d6a5d984bbaa2465f772cf86aa5adf33 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
-
 import java.net.URI;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
@@ -28,11 +27,8 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
-
 import javassist.ClassPool;
-
 import javax.annotation.concurrent.GuardedBy;
-
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -49,10 +45,10 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 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.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec;
index c5fb378b53120de632f31cb6847d60ecda72b612..da57c36fb4c27e97537dd91ff890b8a06b671547 100644 (file)
@@ -8,6 +8,7 @@ import com.google.common.collect.HashBiMap;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Multimap;
+
 import java.util.AbstractMap;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.Collection;
@@ -16,6 +17,7 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
@@ -32,6 +34,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -66,6 +69,7 @@ public class BindingRuntimeContext implements Immutable {
     private final BiMap<Type, Object> typeToDefiningSchema = HashBiMap.create();
     private final Multimap<Type, Type> augmentableToAugmentations = HashMultimap.create();
     private final Multimap<Type, Type> choiceToCases = HashMultimap.create();
+    private final Map<QName, Type> identities = new HashMap<>();
 
     private BindingRuntimeContext(final ClassLoadingStrategy strategy, final SchemaContext schema) {
         this.strategy = strategy;
@@ -75,12 +79,12 @@ public class BindingRuntimeContext implements Immutable {
         generator.generateTypes(schema);
         Map<Module, ModuleContext> modules = generator.getModuleContexts();
 
-        for (Entry<Module, ModuleContext> entry : modules.entrySet()) {
-            ModuleContext ctx = entry.getValue();
+        for (ModuleContext ctx : modules.values()) {
             augmentationToSchema.putAll(ctx.getTypeToAugmentation());
             typeToDefiningSchema.putAll(ctx.getTypeToSchema());
             augmentableToAugmentations.putAll(ctx.getAugmentableToAugmentations());
             choiceToCases.putAll(ctx.getChoiceToCases());
+            identities.putAll(ctx.getIdentities());
         }
     }
 
@@ -134,12 +138,12 @@ public class BindingRuntimeContext implements Immutable {
      *
      * @param augClass Augmentation class
      * @return Schema of augmentation
-     * @throws IllegalArgumentException If supplied class is not an augmentation or current context does not contain schema for augmenation.
+     * @throws IllegalArgumentException If supplied class is not an augmentation or current context does not contain schema for augmentation.
      */
     public AugmentationSchema getAugmentationDefinition(final Class<?> augClass) throws IllegalArgumentException {
-        Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass),"Class {} does not represent augmentation",augClass);
+        Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass), "Class {} does not represent augmentation", augClass);
         final AugmentationSchema ret = augmentationToSchema.get(referencedType(augClass));
-        Preconditions.checkArgument(ret != null, "Supplied augmentation {} is not valid in current context",augClass);
+        Preconditions.checkArgument(ret != null, "Supplied augmentation {} is not valid in current context", augClass);
         return ret;
     }
 
@@ -158,7 +162,7 @@ public class BindingRuntimeContext implements Immutable {
      * @return Schema node, from which class was generated.
      */
     public DataSchemaNode getSchemaDefinition(final Class<?> cls) {
-        Preconditions.checkArgument(Augmentation.class.isAssignableFrom(cls));
+        Preconditions.checkArgument(!Augmentation.class.isAssignableFrom(cls),"Supplied class must not be augmentation");
         return (DataSchemaNode) typeToDefiningSchema.get(referencedType(cls));
     }
 
@@ -229,27 +233,62 @@ public class BindingRuntimeContext implements Immutable {
 
     public ImmutableMap<Type, Entry<Type, Type>> getChoiceCaseChildren(final DataNodeContainer schema) {
         Map<Type,Entry<Type,Type>> childToCase = new HashMap<>();;
-        for(ChoiceNode choice :  FluentIterable.from(schema.getChildNodes()).filter(ChoiceNode.class)) {
+        for (ChoiceNode choice :  FluentIterable.from(schema.getChildNodes()).filter(ChoiceNode.class)) {
             ChoiceNode originalChoice = getOriginalSchema(choice);
             Type choiceType = referencedType(typeToDefiningSchema.inverse().get(originalChoice));
             Collection<Type> cases = choiceToCases.get(choiceType);
 
-            for(Type caze : cases) {
+            for (Type caze : cases) {
                 Entry<Type,Type> caseIdentifier = new SimpleEntry<>(choiceType,caze);
                 HashSet<Type> caseChildren = new HashSet<>();
-                if(caze instanceof GeneratedTypeBuilder) {
+                if (caze instanceof GeneratedTypeBuilder) {
                     caze = ((GeneratedTypeBuilder) caze).toInstance();
                 }
                 collectAllContainerTypes((GeneratedType) caze, caseChildren);
-                for(Type caseChild : caseChildren) {
+                for (Type caseChild : caseChildren) {
                     childToCase.put(caseChild, caseIdentifier);
                 }
             }
         }
         return ImmutableMap.copyOf(childToCase);
+    }
+
+    public Class<?> getClassForSchema(final DataSchemaNode childSchema) {
+        DataSchemaNode origSchema = getOriginalSchema(childSchema);
+        Type clazzType = typeToDefiningSchema.inverse().get(origSchema);
+        try {
+            return strategy.loadClass(clazzType);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    public ImmutableMap<AugmentationIdentifier,Type> getAvailableAugmentationTypes(final DataNodeContainer container) {
+        Map<AugmentationIdentifier,Type> identifierToType = new HashMap<>();
+        if (container instanceof AugmentationTarget) {
+            Set<AugmentationSchema> augments = ((AugmentationTarget) container).getAvailableAugmentations();
+            for (AugmentationSchema augment : augments) {
+                // Augmentation must have child nodes if is to be used with Binding classes
+                if (!augment.getChildNodes().isEmpty()) {
+                    Type augType = typeToDefiningSchema.inverse().get(augment);
+                    if (augType != null) {
+                        identifierToType.put(getAugmentationIdentifier(augment),augType);
+                    }
+                }
+            }
+        }
+        return ImmutableMap.copyOf(identifierToType);
 
     }
 
+    private AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchema augment) {
+        Set<QName> childNames = new HashSet<>();
+        for (DataSchemaNode child : augment.getChildNodes()) {
+            childNames.add(child.getQName());
+        }
+        return new AugmentationIdentifier(childNames);
+    }
+
     private static Type referencedType(final Type type) {
         if(type instanceof ReferencedTypeImpl) {
             return type;
@@ -278,10 +317,20 @@ public class BindingRuntimeContext implements Immutable {
     private static final <T extends SchemaNode> T getOriginalSchema(final T choice) {
         @SuppressWarnings("unchecked")
         T original = (T) SchemaNodeUtils.getRootOriginalIfPossible(choice);
-        if(original != null) {
+        if (original != null) {
             return original;
         }
         return choice;
     }
 
+    public Class<?> getIdentityClass(final QName input) {
+        Type identityType = identities.get(input);
+        Preconditions.checkArgument(identityType != null, "Supplied QName is not valid identity");
+        try {
+            return strategy.loadClass(identityType);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("Required class " + identityType + "was not found.",e);
+        }
+    }
+
 }
index 51b19da27d8bc0a1e85804c2a90d13316aa6885a..4cdf7c23c78e0349ef6e162d16a98cf76dd548a1 100644 (file)
@@ -30,6 +30,7 @@
         <module>binding-java-api-generator</module>
         <module>binding-type-provider</module>
         <module>maven-sal-api-gen-plugin</module>
+        <module>binding-data-codec</module>
     </modules>
 
 
index c5e60906ff81c805512b10db16d83c48577a3546..b65308761db3964e8d10b5ff09f98dbe7dda1918 100644 (file)
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>restconf-client-api</artifactId>
             <artifactId>binding-generator-impl</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>binding-data-codec</artifactId>
+            <version>0.6.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>bug527-test-model</artifactId>
diff --git a/restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/BindingStreamWriterTest.java b/restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/BindingStreamWriterTest.java
new file mode 100644 (file)
index 0000000..cb7a2ff
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.restconf.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import java.util.Map.Entry;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.topology.unix.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.unix.UnixSubTlvs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.topology.unix.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.unix.UnixSubTlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.ReportedLsp1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.ReportedLsp1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.Lsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.LspBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.Tlvs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.TlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.LinuxBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.linux.LinuxSubTlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.vs.tlv.VsTlv;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.vs.tlv.VsTlvBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClient;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClientBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingSchemaContextUtils;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class BindingStreamWriterTest {
+
+    private static final InstanceIdentifier<PathComputationClient> PATH_TO_CLIENT = InstanceIdentifier
+            .builder(NetworkTopology.class).child(Topology.class, new TopologyKey(new TopologyId("foo"))).child(Node.class,new NodeKey(new NodeId("test"))).augmentation(Node1.class)
+            .child(PathComputationClient.class).build();
+
+
+    private static final InstanceIdentifier<Tlvs> PATH_TO_TLVS = PATH_TO_CLIENT.child(ReportedLsp.class, new ReportedLspKey("test")).augmentation(ReportedLsp1.class).child(Lsp.class).child(Tlvs.class);
+    private static final InstanceIdentifier<UnixSubTlvs> PATH_TO_UNIX = PATH_TO_TLVS.child(VsTlv.class).child(UnixSubTlvs.class);
+
+    private static final ReportedLspKey LSP1_KEY = new ReportedLspKey("one");
+    private static final ReportedLspKey LSP2_KEY = new ReportedLspKey("two");
+
+    private RuntimeGeneratedMappingServiceImpl mappingService;
+    private Optional<SchemaContext> schemaContext;
+    private org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator generator;
+    private BindingNormalizedNodeCodecRegistry registry;
+    private DataSchemaNode schema;
+    private BindingRuntimeContext runtimeContext;
+
+    @Before
+    public void setup() {
+        this.mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+
+        final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create();
+        moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos());
+        schemaContext = moduleInfo.tryToCreateSchemaContext();
+        this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
+        JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+        generator = new StreamWriterGenerator(utils);
+        registry = new BindingNormalizedNodeCodecRegistry(generator);
+        runtimeContext = BindingRuntimeContext.create(moduleInfo, schemaContext.get());
+        registry.onBindingRuntimeContextUpdated(runtimeContext);
+
+        schema = (DataSchemaNode) BindingSchemaContextUtils.findDataNodeContainer(schemaContext.get(), PATH_TO_CLIENT)
+                .get();
+    }
+
+
+    @Test
+    public void instanceIdentifierCodec() {
+
+    }
+
+    @Test
+    public void writeWithStreamAPI() {
+        Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> result = registry.toNormalizedNode(PATH_TO_CLIENT, createTestData());
+        NormalizedNode<?, ?> output = result.getValue();
+        assertNotNull(output);
+        assertTrue(output instanceof ContainerNode);
+
+        Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> unixResult = registry.toNormalizedNode(PATH_TO_UNIX, new UnixSubTlvsBuilder().setUnixValue((short) 10).build());
+        assertNotNull(unixResult);
+    }
+
+    @Test
+    public void testInstanceIdentifier() {
+        YangInstanceIdentifier yang = registry.toYangInstanceIdentifier(PATH_TO_UNIX);
+        assertNotNull(yang);
+        InstanceIdentifier<?> binding = registry.fromYangInstanceIdentifier(yang);
+        assertEquals(PATH_TO_UNIX,binding);
+    }
+
+    @Test
+    @Ignore
+    public void testPerformance() {
+        for (int i = 1; i < 5; i++) {
+            int repetitions = (int) Math.pow(10, i);
+            measure("streamAPI: " + repetitions, repetitions, new Runnable() {
+                @Override
+                public void run() {
+                    writeWithStreamAPI();
+                }
+            });
+        }
+    }
+
+    private void measure(final String name, final int repetitions, final Runnable runnable) {
+        runnable.run(); // WARM UP
+        long start = System.nanoTime();
+        // TODO Auto-generated method stub
+        for (int i = 0; i < repetitions; i++) {
+            runnable.run();
+        }
+        long finish = System.nanoTime();
+        // To Miliseconds
+        System.out.println(String.format("Type: %s Time: %f", name, (finish - start) / 1000000.d));
+    }
+
+    PathComputationClient createTestData() {
+        return new PathComputationClientBuilder().setReportedLsp(
+                ImmutableList.<ReportedLsp> builder().add(reportedLsp(LSP1_KEY)).add(reportedLsp(LSP2_KEY)).build())
+                .build();
+    }
+
+    private ReportedLsp reportedLsp(final ReportedLspKey lspKey) {
+        return new ReportedLspBuilder()
+                .setKey(lspKey)
+                .addAugmentation(
+                        ReportedLsp1.class,
+                        new ReportedLsp1Builder().setLsp(
+                                new LspBuilder().setTlvs(
+                                        new TlvsBuilder().setVsTlv(
+                                                new VsTlvBuilder().setVendorPayload(
+                                                        new LinuxBuilder().setLinuxSubTlvs(
+                                                                new LinuxSubTlvsBuilder().setLinuxValue((short) 50)
+                                                                        .build()).build()).build()).build()).build())
+                                .build()).build();
+    }
+
+}
index 921a78c23c8bcf47a9ee77f44069faeeb40a35e5..0428ee2c2e73123cdb247a03a6279bca3deaed6f 100644 (file)
@@ -251,7 +251,7 @@ public interface BindingStreamEventWriter {
 
     /**
      *
-     * Emits start of map node event.
+     * Emits start of unordered map node event.
      *
      * <p>
      * End of map node event is emitted by invoking {@link #endNode()}. Valid
@@ -273,6 +273,31 @@ public interface BindingStreamEventWriter {
     <T extends DataObject & Identifiable<?>> void startMapNode(Class<T> mapEntryType, int childSizeHint)
             throws IllegalArgumentException;
 
+
+    /**
+    *
+    * Emits start of ordered map node event.
+    *
+    * <p>
+    * End of map node event is emitted by invoking {@link #endNode()}. Valid
+    * subevents is only {@link #startMapEntryNode(Identifier, int)}. All other methods will
+    * throw {@link IllegalArgumentException}.
+    *
+    * @param mapEntryType
+    *            Class of list item, which has defined key.
+    * @param childSizeHint
+    *            Non-negative count of expected direct child nodes or
+    *            {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+    *            and should not fail writing of child events, if there are more
+    *            events than count.
+    * @throws IllegalArgumentException
+    * @throws IllegalStateException
+    *             If node was emitted inside <code>map</code>,
+    *             <code>choice</code> <code>unkeyed list</code> node.
+    */
+   <T extends DataObject & Identifiable<?>> void startOrderedMapNode(Class<T> mapEntryType, int childSizeHint)
+           throws IllegalArgumentException;
+
     /**
      *
      * Emits start of map entry.
index 21fda47433d6542f80d95bfe6dd0c3eb07b40ace..a0b54900be9f419d0c69f43c5299be4e7f77a7e4 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNo
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
 
 /**
@@ -175,13 +176,17 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
 
     @Override
     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier,final int childSizeHint) throws IllegalArgumentException {
-        Preconditions.checkArgument(getCurrent() instanceof ImmutableMapNodeBuilder);
+        if(!(getCurrent() instanceof NormalizedNodeResultBuilder)) {
+            Preconditions.checkArgument(getCurrent() instanceof ImmutableMapNodeBuilder);
+        }
         enter(Builders.mapEntryBuilder().withNodeIdentifier(identifier));
     }
 
     @Override
     public void startOrderedMapNode(final NodeIdentifier name,final int childSizeHint) throws IllegalArgumentException {
-        checkDataNodeContainer();
+        if(!(getCurrent() instanceof NormalizedNodeResultBuilder)) {
+            Preconditions.checkArgument(getCurrent() instanceof ImmutableOrderedMapNodeBuilder);
+        }
         enter(Builders.mapBuilder().withNodeIdentifier(name));
     }