Bug 2404: RPC and Notification support for Binding Data Codec
authorTony Tkacik <ttkacik@cisco.com>
Fri, 19 Dec 2014 15:48:14 +0000 (16:48 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Mon, 19 Jan 2015 14:47:50 +0000 (15:47 +0100)
Added support for serialization and deserialization of RPC
and Notification data from Binding representation to Normalized
Representation.

Change-Id: I2e071ac1fac9d5f2ac34421f1718dbaa6051975c
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
15 files changed:
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeSerializer.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/api/BindingNormalizedNodeWriterFactory.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractStreamWriterGenerator.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/StreamWriterGenerator.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingCodecContext.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ChoiceNodeCodecContext.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataContainerCodecPrototype.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/LazyDataObject.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NotificationCodecContext.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/SchemaRootCodecContext.java
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NotificationProcessingTest.java [new file with mode: 0644]
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/RpcDataSerializationTest.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/BindingRuntimeContext.java
code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-binding-test.yang

index 3e10492e10c75a4d573c5b06fe52797fee54f454..5e3fd0be5f34a257904b0694b6b28114b7571885 100644 (file)
  */
 package org.opendaylight.yangtools.binding.data.codec.api;
 
-import java.util.Map;
 import java.util.Map.Entry;
-
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-
+import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
 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.SchemaPath;
 
 /**
- * Serialization service, which provides two-way serialization between
- * Java Binding Data representation and NormalizedNode representation.
+ * 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(@Nonnull InstanceIdentifier<?> binding);
+    /**
+     * Translates supplied Binding Instance Identifier into NormalizedNode
+     * instance identifier.
+     *
+     * @param binding
+     *            Binding Instance Identifier
+     * @return DOM Instance Identifier
+     */
+    YangInstanceIdentifier toYangInstanceIdentifier(@Nonnull InstanceIdentifier<?> binding);
+
+    /**
+     * Translates supplied YANG Instance Identifier into Binding instance
+     * identifier.
+     *
+     * @param dom
+     *            YANG Instance Identifier
+     * @return Binding Instance Identifier, or null if the instance identifier
+     *         is not representable.
+     */
+    @Nullable
+    InstanceIdentifier<?> fromYangInstanceIdentifier(@Nonnull YangInstanceIdentifier dom);
+
+    /**
+     * Translates supplied Binding Instance Identifier and data into
+     * NormalizedNode representation.
+     *
+     * @param path
+     *            Binding Instance Identifier pointing to data
+     * @param data
+     *            Data object representing data
+     * @return NormalizedNode representation
+     */
+    <T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
+            InstanceIdentifier<T> path, T data);
 
-     /**
-      * Translates supplied YANG Instance Identifier into Binding instance identifier.
-      *
-      * @param dom YANG Instance Identifier
-      * @return Binding Instance Identifier, or null if the instance identifier is not
-      *         representable.
-      */
-     @Nullable InstanceIdentifier<?> fromYangInstanceIdentifier(@Nonnull YangInstanceIdentifier dom);
+    /**
+     * Translates supplied YANG Instance Identifier and NormalizedNode into
+     * Binding data.
+     *
+     * @param path Binding Instance Identifier
+     * @param data NormalizedNode representing data
+     * @return DOM Instance Identifier
+     */
+    @Nullable
+    Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(@Nonnull YangInstanceIdentifier path,
+            NormalizedNode<?, ?> data);
 
-     /**
-      * Translates supplied Binding Instance Identifier and data into NormalizedNode representation.
-      *
-      * @param path Binding Instance Identifier pointing to data
-      * @param data Data object representing data
-      * @return NormalizedNode representation
-      */
-     <T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode<?,?>> toNormalizedNode(InstanceIdentifier<T> path, T data);
+    /**
+     * Translates supplied NormalizedNode Notification into Binding data.
+     *
+     * @param path Schema Path of Notification, schema path is absolute, and consists of Notification QName.
+     * @param data NormalizedNode representing data
+     * @return Binding representation of Notification
+     */
+    @Nullable Notification fromNormalizedNodeNotification(@Nonnull SchemaPath path,@Nonnull ContainerNode 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
-      */
-     @Nullable Entry<InstanceIdentifier<?>,DataObject> fromNormalizedNode(@Nonnull YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+    /**
+     * Translates supplied NormalizedNode RPC input or output into Binding data.
+     *
+     * @param path Schema path of RPC data, Schema path consists of rpc QName and input / output QName.
+     * @param data NormalizedNode representing data
+     * @return Binding representation of RPC data
+     */
+    @Nullable DataObject fromNormalizedNodeRpcData(@Nonnull SchemaPath path,@Nonnull ContainerNode 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);
+    /**
+     * Translates supplied Binding Notification or output into NormalizedNode notification.
+     *
+     * @param data NormalizedNode representing notification data
+     * @return NormalizedNode representation of notification
+     */
+    @Nonnull ContainerNode toNormalizedNodeNotification(@Nonnull Notification data);
 
+    /**
+     * Translates supplied Binding RPC input or output into NormalizedNode data.
+     *
+     * @param data NormalizedNode representing rpc data
+     * @return NormalizedNode representation of rpc data
+     */
+    @Nonnull ContainerNode toNormalizedNodeRpcData(@Nonnull DataContainer data);
 }
index 7494440126ff3c5620ec2b57ff01bf3b98ac3f9d..cd87da1f795e7a102c582efdcea3fa29b83d73e3 100644 (file)
@@ -8,9 +8,11 @@
 package org.opendaylight.yangtools.binding.data.codec.api;
 
 import java.util.Map.Entry;
-
+import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 
@@ -45,8 +47,8 @@ public interface BindingNormalizedNodeWriterFactory {
      * @return Instance Identifier and {@link BindingStreamEventWriter}
      *         which will write to supplied {@link NormalizedNodeStreamWriter}.
      */
-    Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(InstanceIdentifier<?> path,
-            NormalizedNodeStreamWriter domWriter);
+    @Nonnull Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(@Nonnull InstanceIdentifier<?> path,
+            @Nonnull NormalizedNodeStreamWriter domWriter);
 
     /**
      *
@@ -65,5 +67,41 @@ public interface BindingNormalizedNodeWriterFactory {
      * @return {@link BindingStreamEventWriter}
      *         which will write to supplied {@link NormalizedNodeStreamWriter}.
      */
-    BindingStreamEventWriter newWriter(InstanceIdentifier<?> path, NormalizedNodeStreamWriter domWriter);
+    @Nonnull
+    BindingStreamEventWriter newWriter(@Nonnull InstanceIdentifier<?> path,
+            @Nonnull NormalizedNodeStreamWriter domWriter);
+
+    /**
+     *
+     * Creates a {@link BindingStreamEventWriter} for rpc data which will
+     * translate to NormalizedNode model and invoke proper events on supplied
+     * {@link NormalizedNodeStreamWriter}.
+     *
+     * @param rpcInputOrOutput Binding class representing RPC input or output,
+     *            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}.
+     */
+    @Nonnull
+    BindingStreamEventWriter newRpcWriter(@Nonnull Class<? extends DataContainer> rpcInputOrOutput,
+            @Nonnull NormalizedNodeStreamWriter domWriter);
+
+    /**
+     *
+     * Creates a {@link BindingStreamEventWriter} for notification which will
+     * translate to NormalizedNode model and invoke proper events on supplied
+     * {@link NormalizedNodeStreamWriter}.
+     *
+     * @param notification Binding class representing notification,
+     *            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}.
+     */
+    @Nonnull
+    BindingStreamEventWriter newNotificationWriter(@Nonnull Class<? extends Notification> notification,
+            @Nonnull NormalizedNodeStreamWriter domWriter);
 }
index 43333f6b9d2a1bcdd09220047f975e6eb2003b64..8efdc87ba5d3a5d304a78982b3b3a3d3bca14bc8 100644 (file)
@@ -12,18 +12,15 @@ import com.google.common.base.Supplier;
 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.lang.reflect.InvocationTargetException;
 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.StaticConstantDefinition;
 import org.opendaylight.yangtools.binding.data.codec.util.AugmentableDispatchSerializer;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -42,6 +39,7 @@ 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.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -122,7 +120,7 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
             try {
                 cls = (Class<? extends DataObjectSerializerImplementation>) ClassLoaderUtils
                         .loadClass(type.getClassLoader(), serializerName);
-            } catch (ClassNotFoundException e) {
+            } catch (final ClassNotFoundException e) {
                 cls = generateSerializer(type, serializerName);
             }
 
@@ -145,7 +143,7 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
              * classes. This should be almost as good as that, as we are resetting the
              * fields to final before ever leaking the class.
              */
-            for (StaticConstantDefinition constant : source.getStaticConstants()) {
+            for (final StaticConstantDefinition constant : source.getStaticConstants()) {
                 final Field field = cls.getDeclaredField(constant.getName());
                 field.setAccessible(true);
                 field.set(null, constant.getValue());
@@ -162,15 +160,15 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
     private DataObjectSerializerSource generateEmitterSource(final Class<?> type, final String serializerName) {
         Types.typeForClass(type);
         javassist.appendClassLoaderIfMissing(type.getClassLoader());
-        Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(type);
-        GeneratedType generatedType = typeWithSchema.getKey();
-        Object schema = typeWithSchema.getValue();
+        final Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(type);
+        final GeneratedType generatedType = typeWithSchema.getKey();
+        final 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;
+            final ListSchemaNode casted = (ListSchemaNode) schema;
             if (casted.getKeyDefinition().isEmpty()) {
                 source = generateUnkeyedListEntrySerializer(generatedType, casted);
             } else {
@@ -180,6 +178,8 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
             source = generateSerializer(generatedType,(AugmentationSchema) schema);
         } else if(schema instanceof ChoiceCaseNode) {
             source = generateCaseSerializer(generatedType,(ChoiceCaseNode) schema);
+        } else if(schema instanceof NotificationDefinition) {
+            source = generateNotificationSerializer(generatedType,(NotificationDefinition) schema);
         } else {
             throw new UnsupportedOperationException("Schema type " + schema.getClass() + " is not supported");
         }
@@ -205,8 +205,8 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
                     );
 
                     // Generate any static fields
-                    for (StaticConstantDefinition def : source.getStaticConstants()) {
-                        CtField field = new CtField(javassist.asCtClass(def.getType()), def.getName(), cls);
+                    for (final StaticConstantDefinition def : source.getStaticConstants()) {
+                        final CtField field = new CtField(javassist.asCtClass(def.getType()), def.getName(), cls);
                         field.setModifiers(Modifier.PRIVATE + Modifier.STATIC);
                         cls.addField(field);
                     }
@@ -219,7 +219,7 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
                     cls.setModifiers(Modifier.setPublic(cls.getModifiers()));
                 }
             });
-        } catch (NotFoundException e) {
+        } catch (final NotFoundException e) {
             LOG.error("Failed to instatiate serializer {}", source, e);
             throw new LinkageError("Unexpected instantation problem: serializer prototype not found", e);
         }
@@ -296,4 +296,18 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
      */
     protected abstract DataObjectSerializerSource generateSerializer(GeneratedType type, AugmentationSchema schema);
 
+    /**
+     * Generates serializer source for notification 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 notification
+     * @param node Schema of notification
+     * @return Source for notification node writer
+     */
+    protected abstract DataObjectSerializerSource generateNotificationSerializer(GeneratedType type, NotificationDefinition node);
+
 }
index 1804d9a50aea2816f8c77cb785945fd34ddde106..b9bbbace0e354683e586803c5c39a67b0c4683cb 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 
 /**
  * Concrete implementation of {@link AbstractStreamWriterGenerator}
@@ -71,6 +72,17 @@ public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
         };
     }
 
+    @Override
+    protected DataObjectSerializerSource generateNotificationSerializer(final GeneratedType type, final NotificationDefinition node) {
+
+        return new AugmentableDataNodeContainerEmmiterSource(this, type, node) {
+            @Override
+            public CharSequence emitStartEvent() {
+                return startContainerNode(classReference(type), getChildSizeFromSchema(node));
+            }
+        };
+    }
+
     @Override
     protected DataObjectSerializerSource generateCaseSerializer(final GeneratedType type, final ChoiceCaseNode node) {
         return new AugmentableDataNodeContainerEmmiterSource(this, type, node) {
index 414c553578960f0973175869f01813091748fe3a..06870b42213b27581b5841bd3ff6f6f4fa4a658a 100644 (file)
@@ -36,10 +36,12 @@ 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.DataContainer;
 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.Notification;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -50,6 +52,7 @@ 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.SchemaPath;
 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.EmptyTypeDefinition;
@@ -102,6 +105,18 @@ final class BindingCodecContext implements CodecContextFactory, Immutable {
         return new BindingToNormalizedStreamWriter(getCodecContextNode(path, null), domWriter);
     }
 
+    BindingStreamEventWriter newRpcWriter(final Class<? extends DataContainer> rpcInputOrOutput,
+            final NormalizedNodeStreamWriter domWriter) {
+        final NodeCodecContext schema = root.getRpc(rpcInputOrOutput);
+        return new BindingToNormalizedStreamWriter(schema, domWriter);
+    }
+
+    BindingStreamEventWriter newNotificationWriter(final Class<? extends Notification> notification,
+            final NormalizedNodeStreamWriter domWriter) {
+        final NodeCodecContext schema = root.getNotification(notification);
+        return new BindingToNormalizedStreamWriter(schema, domWriter);
+    }
+
     public DataContainerCodecContext<?> getCodecContextNode(final InstanceIdentifier<?> binding,
             final List<YangInstanceIdentifier.PathArgument> builder) {
         DataContainerCodecContext<?> currentNode = root;
@@ -183,6 +198,14 @@ final class BindingCodecContext implements CodecContextFactory, Immutable {
         return currentNode;
     }
 
+    NotificationCodecContext getNotificationContext(final SchemaPath notification) {
+        return root.getNotification(notification);
+    }
+
+    ContainerNodeCodecContext getRpcDataContext(final SchemaPath path) {
+        return root.getRpc(path);
+    }
+
     @Override
     public ImmutableMap<String, LeafNodeCodecContext> getLeafNodes(final Class<?> parentClass,
             final DataNodeContainer childSchema) {
@@ -461,4 +484,8 @@ final class BindingCodecContext implements CodecContextFactory, Immutable {
         return new IdentifiableItemCodec(schema, identifier, listClz, valueCtx);
     }
 
+
+
+
+
 }
index bfdad3efeb4cb555a22946a035ae460a8592698a..37145b3bed206a9e6dbc1a367360c2790285d44f 100644 (file)
@@ -13,28 +13,28 @@ 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.io.IOException;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 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.DataObjectSerializerGenerator;
 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.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.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
@@ -44,6 +44,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 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;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -86,23 +87,61 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
 
     @Override
     public <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> path, final T data) {
-        NormalizedNodeResult result = new NormalizedNodeResult();
+        final NormalizedNodeResult result = new NormalizedNodeResult();
         // We create DOM stream writer which produces normalized nodes
-        NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
 
         // We create Binding Stream Writer which translates from Binding to Normalized Nodes
-        Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path, domWriter);
+        final 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
         try {
             getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
-        } catch (IOException e) {
+        } catch (final IOException e) {
             LOG.error("Unexpected failure while serializing path {} data {}", path, data, e);
             throw new IllegalStateException("Failed to create normalized node", e);
         }
         return new SimpleEntry<YangInstanceIdentifier,NormalizedNode<?,?>>(writeCtx.getKey(),result.getResult());
     }
 
+    @Override
+    public ContainerNode toNormalizedNodeNotification(final Notification data) {
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        // We create DOM stream writer which produces normalized nodes
+        final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final Class<? extends DataObject> type = (Class) data.getImplementedInterface();
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final BindingStreamEventWriter writer = newNotificationWriter((Class) type, domWriter);
+        try {
+            // FIXME: Should be cast to DataObject necessary?
+            getSerializer(type).serialize((DataObject) data, writer);
+        } catch (final IOException e) {
+            LOG.error("Unexpected failure while serializing data {}", data, e);
+            throw new IllegalStateException("Failed to create normalized node", e);
+        }
+        return (ContainerNode) result.getResult();
+
+    }
+
+    @Override
+    public ContainerNode toNormalizedNodeRpcData(final DataContainer data) {
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        // We create DOM stream writer which produces normalized nodes
+        final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final Class<? extends DataObject> type = (Class) data.getImplementedInterface();
+        final BindingStreamEventWriter writer = newRpcWriter(type, domWriter);
+        try {
+            // FIXME: Should be cast to DataObject necessary?
+            getSerializer(type).serialize((DataObject) data, writer);
+        } catch (final IOException e) {
+            LOG.error("Unexpected failure while serializing data {}", data, e);
+            throw new IllegalStateException("Failed to create normalized node", e);
+        }
+        return (ContainerNode) result.getResult();
+    }
+
     private static boolean isBindingRepresentable(final NormalizedNode<?, ?> data) {
         if (data instanceof ChoiceNode) {
             return false;
@@ -147,11 +186,18 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
     }
 
     @Override
-    public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
-        throw new UnsupportedOperationException("Not implemented yet");
+    public Notification fromNormalizedNodeNotification(final SchemaPath path, final ContainerNode data) {
+        final NotificationCodecContext codec = codecContext.getNotificationContext(path);
+        return (Notification) codec.dataFromNormalizedNode(data);
     }
 
     @Override
+    public DataObject fromNormalizedNodeRpcData(final SchemaPath path, final ContainerNode data) {
+        final ContainerNodeCodecContext codec = codecContext.getRpcDataContext(path);
+        return (DataObject) codec.dataFromNormalizedNode(data);
+    }
+
+   @Override
     public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(final InstanceIdentifier<?> path, final NormalizedNodeStreamWriter domWriter) {
         return codecContext.newWriter(path, domWriter);
     }
@@ -161,9 +207,22 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         return codecContext.newWriterWithoutIdentifier(path, domWriter);
     }
 
+    @Override
+    public BindingStreamEventWriter newNotificationWriter(final Class<? extends Notification> notification,
+            final NormalizedNodeStreamWriter streamWriter) {
+        return codecContext.newNotificationWriter(notification, streamWriter);
+    }
+
+
+    @Override
+    public BindingStreamEventWriter newRpcWriter(final Class<? extends DataContainer> rpcInputOrOutput,
+            final NormalizedNodeStreamWriter streamWriter) {
+        return codecContext.newRpcWriter(rpcInputOrOutput,streamWriter);
+    }
+
 
     public <T extends DataObject> Function<Optional<NormalizedNode<?, ?>>, Optional<T>>  deserializeFunction(final InstanceIdentifier<T> path) {
-        DataObjectCodecContext<?> ctx = (DataObjectCodecContext<?>) codecContext.getCodecContextNode(path, null);
+        final DataObjectCodecContext<?> ctx = (DataObjectCodecContext<?>) codecContext.getCodecContextNode(path, null);
         return new DeserializeFunction<T>(ctx);
     }
 
@@ -186,11 +245,11 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         }
     }
 
-    private class GeneratorLoader extends CacheLoader<Class<? extends DataObject>, DataObjectSerializer> {
+    private class GeneratorLoader extends CacheLoader<Class<? extends DataContainer>, DataObjectSerializer> {
 
         @Override
-        public DataObjectSerializer load(final Class<? extends DataObject> key) throws Exception {
-            DataObjectSerializerImplementation prototype = generator.getSerializer(key);
+        public DataObjectSerializer load(final Class<? extends DataContainer> key) throws Exception {
+            final DataObjectSerializerImplementation prototype = generator.getSerializer(key);
             return new DataObjectSerializerProxy(prototype);
         }
     }
index ca79b879bba5135509fa9bd44085fddb637b7ea5..8bc5b0872117edd80e099d9977b92603546f6cb7 100644 (file)
@@ -43,7 +43,7 @@ final class ChoiceNodeCodecContext extends DataContainerCodecContext<ChoiceNode>
         Map<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClassBuilder = new HashMap<>();
         Set<Class<?>> potentialSubstitutions = new HashSet<>();
         // Walks all cases for supplied choice in current runtime context
-        for (Class caze : factory().getRuntimeContext().getCases(bindingClass())) {
+        for (Class<?> caze : factory().getRuntimeContext().getCases(bindingClass())) {
             // We try to load case using exact match thus name
             // and original schema must equals
             DataContainerCodecPrototype<ChoiceCaseNode> cazeDef = loadCase(caze);
index 353fedaa54c6155a5c81404c2e313e89ecf880c9..0d437b06ef7f8b299228ae46d55773bef959eccb 100644 (file)
@@ -17,12 +17,14 @@ 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.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 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.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 class DataContainerCodecPrototype<T> implements NodeContextSupplier {
@@ -66,23 +68,29 @@ class DataContainerCodecPrototype<T> implements NodeContextSupplier {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
             final CodecContextFactory factory) {
-        NodeIdentifier arg = new NodeIdentifier(schema.getQName());
+        final NodeIdentifier arg = new NodeIdentifier(schema.getQName());
         return new DataContainerCodecPrototype(cls, arg, schema, factory);
     }
 
     static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
-        SchemaContext schema = factory.getRuntimeContext().getSchemaContext();
-        NodeIdentifier arg = new NodeIdentifier(schema.getQName());
+        final SchemaContext schema = factory.getRuntimeContext().getSchemaContext();
+        final NodeIdentifier arg = new NodeIdentifier(schema.getQName());
         return new DataContainerCodecPrototype<SchemaContext>(DataRoot.class, arg, schema, factory);
     }
 
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    public static DataContainerCodecPrototype<?> from(final Class<?> augClass, final AugmentationIdentifier arg,
+    static DataContainerCodecPrototype<?> from(final Class<?> augClass, final AugmentationIdentifier arg,
             final AugmentationSchema schema, final CodecContextFactory factory) {
         return new DataContainerCodecPrototype(augClass, arg, schema, factory);
     }
 
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass, final NotificationDefinition schema, final CodecContextFactory factory) {
+        final PathArgument arg = new NodeIdentifier(schema.getQName());
+        return new DataContainerCodecPrototype<NotificationDefinition>(augClass,arg, schema, factory);
+    }
+
     protected final T getSchema() {
         return schema;
     }
index f1227ed997afaa35bd992812c300f67aa8d8a260..9a3f24feb27f0909b77b93c5b9cc6886285bcb97 100644 (file)
@@ -53,7 +53,7 @@ class LazyDataObject implements InvocationHandler, AugmentationReader {
     @Override
     public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
         if (method.getParameterTypes().length == 0) {
-            String name = method.getName();
+            final String name = method.getName();
             if (GET_IMPLEMENTED_INTERFACE.equals(name)) {
                 return context.bindingClass();
             } else if (TO_STRING.equals(name)) {
@@ -78,9 +78,9 @@ class LazyDataObject implements InvocationHandler, AugmentationReader {
             return false;
         }
         try {
-            for (Method m : context.getHashCodeAndEqualsMethods()) {
-                Object thisValue = getBindingData(m);
-                Object otherValue = m.invoke(other);
+            for (final Method m : context.getHashCodeAndEqualsMethods()) {
+                final Object thisValue = getBindingData(m);
+                final Object otherValue = m.invoke(other);
                 if(!Objects.equals(thisValue, otherValue)) {
                     return false;
                 }
@@ -93,15 +93,15 @@ class LazyDataObject implements InvocationHandler, AugmentationReader {
     }
 
     private Integer bindingHashCode() {
-        Integer ret = cachedHashcode;
+        final Integer ret = cachedHashcode;
         if (ret != null) {
             return ret;
         }
 
         final int prime = 31;
         int result = 1;
-        for (Method m : context.getHashCodeAndEqualsMethods()) {
-            Object value = getBindingData(m);
+        for (final Method m : context.getHashCodeAndEqualsMethods()) {
+            final Object value = getBindingData(m);
             result += prime * result + ((value == null) ? 0 : value.hashCode());
         }
         if (Augmentation.class.isAssignableFrom(context.bindingClass())) {
@@ -114,7 +114,7 @@ class LazyDataObject implements InvocationHandler, AugmentationReader {
     private Object getBindingData(final Method method) {
         Object cached = cachedData.get(method);
         if (cached == null) {
-            Object readedValue = context.getBindingChildValue(method, data);
+            final Object readedValue = context.getBindingChildValue(method, data);
             if (readedValue == null) {
                 cached = NULL_VALUE;
             } else {
@@ -166,9 +166,9 @@ class LazyDataObject implements InvocationHandler, AugmentationReader {
     }
 
     public String bindingToString() {
-        ToStringHelper helper = com.google.common.base.Objects.toStringHelper(context.bindingClass()).omitNullValues();
+        final ToStringHelper helper = com.google.common.base.Objects.toStringHelper(context.bindingClass()).omitNullValues();
 
-        for (Method m :context.getHashCodeAndEqualsMethods()) {
+        for (final Method m :context.getHashCodeAndEqualsMethods()) {
             helper.add(m.getName(), getBindingData(m));
         }
         if (Augmentable.class.isAssignableFrom(context.bindingClass())) {
@@ -197,7 +197,7 @@ class LazyDataObject implements InvocationHandler, AugmentationReader {
         if (getClass() != obj.getClass()) {
             return false;
         }
-        LazyDataObject other = (LazyDataObject) obj;
+        final LazyDataObject other = (LazyDataObject) obj;
         if (context == null) {
             if (other.context != null) {
                 return false;
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NotificationCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NotificationCodecContext.java
new file mode 100644 (file)
index 0000000..6d292bd
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 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.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+
+final class NotificationCodecContext extends DataObjectCodecContext<NotificationDefinition> {
+
+    public NotificationCodecContext(final Class<?> key, final NotificationDefinition schema, final CodecContextFactory factory) {
+        super(DataContainerCodecPrototype.from(key, schema, factory));
+    }
+
+    @Override
+    protected Object dataFromNormalizedNode(final NormalizedNode<?, ?> data) {
+        Preconditions.checkState(data instanceof ContainerNode);
+        return createBindingProxy((NormalizedNodeContainer<?, ?, ?>) data);
+    }
+
+}
\ No newline at end of file
index 1fafb40ac4a1408a3d0c2656c934b8bde16a1b92..874a778817d944a5cfbb4b78dfc839031d85f9f3 100644 (file)
@@ -13,46 +13,94 @@ import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 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.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
 
-class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
+final class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
 
-    private final LoadingCache<Class<?>, DataContainerCodecContext<?>> childrenByClass = CacheBuilder.newBuilder().build(
-            new CacheLoader<Class<?>, DataContainerCodecContext<?>>() {
+    private final LoadingCache<Class<?>, DataContainerCodecContext<?>> childrenByClass = CacheBuilder.newBuilder()
+            .build(new CacheLoader<Class<?>, DataContainerCodecContext<?>>() {
                 @Override
                 public DataContainerCodecContext<?> load(final Class<?> key) {
-                    Class<Object> parent = ClassLoaderUtils.findFirstGenericArgument(key, ChildOf.class);
-                    Preconditions.checkArgument(DataRoot.class.isAssignableFrom(parent));
-                    QName qname = BindingReflections.findQName(key);
-                    DataSchemaNode childSchema = schema().getDataChildByName(qname);
-                    return DataContainerCodecPrototype.from(key, childSchema, factory()).get();
+                    return createDataTreeChildContext(key);
+                }
+
+            });
+
+    private final LoadingCache<Class<?>, ContainerNodeCodecContext> rpcDataByClass = CacheBuilder.newBuilder().build(
+            new CacheLoader<Class<?>, ContainerNodeCodecContext>() {
+                @Override
+                public ContainerNodeCodecContext load(final Class<?> key) {
+                    return createRpcDataContext(key);
+                }
+            });
+
+    private final LoadingCache<Class<?>, NotificationCodecContext> notificationsByClass = CacheBuilder.newBuilder()
+            .build(new CacheLoader<Class<?>, NotificationCodecContext>() {
+                @Override
+                public NotificationCodecContext load(final Class<?> key) {
+                    return createNotificationDataContext(key);
                 }
             });
 
     private final LoadingCache<QName, DataContainerCodecContext<?>> childrenByQName = CacheBuilder.newBuilder().build(
-        new CacheLoader<QName, DataContainerCodecContext<?>>() {
-            @Override
-            public DataContainerCodecContext<?> load(final QName qname) {
-                final DataSchemaNode childSchema = schema().getDataChildByName(qname);
-                Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", qname, schema());
-
-                if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
-                    final Class<?> childCls = factory().getRuntimeContext().getClassForSchema(childSchema);
-                    return getStreamChild(childCls);
-                } else {
-                    throw new UnsupportedOperationException("Unsupported child type " + childSchema.getClass());
+            new CacheLoader<QName, DataContainerCodecContext<?>>() {
+                @Override
+                public DataContainerCodecContext<?> load(final QName qname) {
+                    final DataSchemaNode childSchema = schema().getDataChildByName(qname);
+                    Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", qname,
+                            schema());
+
+                    if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
+                        final Class<?> childCls = factory().getRuntimeContext().getClassForSchema(childSchema);
+                        return getStreamChild(childCls);
+                    } else {
+                        throw new UnsupportedOperationException("Unsupported child type " + childSchema.getClass());
+                    }
                 }
-            }
-        });
+            });
+
+    private final LoadingCache<SchemaPath, ContainerNodeCodecContext> rpcDataByPath = CacheBuilder.newBuilder().build(
+            new CacheLoader<SchemaPath, ContainerNodeCodecContext>() {
+
+                @SuppressWarnings({ "rawtypes", "unchecked" })
+                @Override
+                public ContainerNodeCodecContext load(final SchemaPath key) {
+                    final ContainerSchemaNode schema = SchemaContextUtil.getRpcDataSchema(schema(), key);
+                    final Class cls = factory().getRuntimeContext().getClassForSchema(schema);
+                    return getRpc(cls);
+                }
+            });
+
+    private final LoadingCache<SchemaPath, NotificationCodecContext> notificationsByPath = CacheBuilder.newBuilder()
+            .build(new CacheLoader<SchemaPath, NotificationCodecContext>() {
+
+                @SuppressWarnings({ "rawtypes", "unchecked" })
+                @Override
+                public NotificationCodecContext load(final SchemaPath key) throws Exception {
+                    final NotificationDefinition schema = SchemaContextUtil.getNotificationSchema(schema(), key);
+                    final Class clz = factory().getRuntimeContext().getClassForSchema(schema);
+                    return getNotification(clz);
+                }
+            });
 
     private SchemaRootCodecContext(final DataContainerCodecPrototype<SchemaContext> dataPrototype) {
         super(dataPrototype);
@@ -66,7 +114,7 @@ class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
      * @return
      */
     static SchemaRootCodecContext create(final CodecContextFactory factory) {
-        DataContainerCodecPrototype<SchemaContext> prototype = DataContainerCodecPrototype.rootPrototype(factory);
+        final DataContainerCodecPrototype<SchemaContext> prototype = DataContainerCodecPrototype.rootPrototype(factory);
         return new SchemaRootCodecContext(prototype);
     }
 
@@ -80,11 +128,6 @@ class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
         throw new UnsupportedOperationException("Not supported");
     }
 
-    @Override
-    protected PathArgument getDomPathArgument() {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     protected NodeCodecContext getYangIdentifierChild(final PathArgument arg) {
         return childrenByQName.getUnchecked(arg.getNodeType());
@@ -94,4 +137,74 @@ class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
     protected Object dataFromNormalizedNode(final NormalizedNode<?, ?> normalizedNode) {
         throw new UnsupportedOperationException("Could not create Binding data representation for root");
     }
+
+    ContainerNodeCodecContext getRpc(final Class<? extends DataContainer> rpcInputOrOutput) {
+        return rpcDataByClass.getUnchecked(rpcInputOrOutput);
+    }
+
+    NotificationCodecContext getNotification(final Class<? extends Notification> notification) {
+        return notificationsByClass.getUnchecked(notification);
+    }
+
+    NotificationCodecContext getNotification(final SchemaPath notification) {
+        return notificationsByPath.getUnchecked(notification);
+    }
+
+    ContainerNodeCodecContext getRpc(final SchemaPath notification) {
+        return rpcDataByPath.getUnchecked(notification);
+    }
+
+    private DataContainerCodecContext<?> createDataTreeChildContext(final Class<?> key) {
+        final Class<Object> parent = ClassLoaderUtils.findFirstGenericArgument(key, ChildOf.class);
+        Preconditions.checkArgument(DataRoot.class.isAssignableFrom(parent));
+        final QName qname = BindingReflections.findQName(key);
+        final DataSchemaNode childSchema = schema().getDataChildByName(qname);
+        return DataContainerCodecPrototype.from(key, childSchema, factory()).get();
+    }
+
+    private ContainerNodeCodecContext createRpcDataContext(final Class<?> key) {
+        Preconditions.checkArgument(DataContainer.class.isAssignableFrom(key));
+        final QName qname = BindingReflections.findQName(key);
+        final QNameModule module = qname.getModule();
+        RpcDefinition rpc = null;
+        for (final RpcDefinition potential : schema().getOperations()) {
+            final QName potentialQName = potential.getQName();
+            /*
+             *
+             * Check if rpc and class represents data from same module and then
+             * checks if rpc local name produces same class name as class name
+             * appended with Input/Output based on QName associated with bidning
+             * class.
+             *
+             * FIXME: Rework this to have more precise logic regarding Binding
+             * Specification.
+             */
+            if (module.equals(potentialQName.getModule())
+                    && key.getSimpleName().equals(
+                            BindingMapping.getClassName(potentialQName) + BindingMapping.getClassName(qname))) {
+                rpc = potential;
+                break;
+            }
+        }
+        Preconditions.checkArgument(rpc != null, "Supplied class %s is not valid RPC class.", key);
+        final ContainerSchemaNode schema = SchemaNodeUtils.getRpcDataSchema(rpc, qname);
+        Preconditions.checkArgument(schema != null, "Schema for %s does not define input / output.", rpc.getQName());
+        return (ContainerNodeCodecContext) DataContainerCodecPrototype.from(key, schema, factory()).get();
+    }
+
+    private NotificationCodecContext createNotificationDataContext(final Class<?> notificationType) {
+        Preconditions.checkArgument(Notification.class.isAssignableFrom(notificationType));
+        Preconditions.checkArgument(notificationType.isInterface(), "Supplied class must be interface.");
+        final QName qname = BindingReflections.findQName(notificationType);
+        /**
+         *  FIXME: After Lithium cleanup of yang-model-api, use direct call on schema context
+         *  to retrieve notification via index.
+         */
+        final NotificationDefinition schema = SchemaContextUtil.getNotificationSchema(schema(),
+                SchemaPath.create(true, qname));
+        Preconditions.checkArgument(schema != null, "Supplied %s is not valid notification", notificationType);
+
+        return new NotificationCodecContext(notificationType, schema, factory());
+    }
+
 }
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NotificationProcessingTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/NotificationProcessingTest.java
new file mode 100644 (file)
index 0000000..cb61d01
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ *  and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableList;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.TwoLevelListChanged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.TwoLevelListChangedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class NotificationProcessingTest extends AbstractBindingRuntimeTest {
+
+    private BindingNormalizedNodeCodecRegistry registry;
+
+    @Override
+    @Before
+    public void setup() {
+        super.setup();
+        final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+        registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+        registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+    }
+
+    private TwoLevelListChanged createTestData() {
+        final TwoLevelListChangedBuilder tb = new TwoLevelListChangedBuilder();
+        tb.setTopLevelList(ImmutableList.of(new TopLevelListBuilder().setKey(new TopLevelListKey("test")).build()));
+        return tb.build();
+    }
+
+    @Test
+    public void testNotificationToNormalized() {
+        final TwoLevelListChanged bindingOriginal = createTestData();
+        final ContainerNode dom = registry.toNormalizedNodeNotification(bindingOriginal);
+        assertNotNull("Serialization must not return null obejct.",dom);
+        assertEquals(TwoLevelListChanged.QNAME,dom.getIdentifier().getNodeType());
+
+        final Notification bindingDeserialized = registry.fromNormalizedNodeNotification(SchemaPath.create(true, TwoLevelListChanged.QNAME),dom);
+        assertNotNull(bindingDeserialized);
+        assertTrue(bindingDeserialized instanceof TwoLevelListChanged);
+        assertEquals(bindingOriginal,bindingDeserialized);
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/RpcDataSerializationTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/RpcDataSerializationTest.java
new file mode 100644 (file)
index 0000000..3d3dda8
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ *  and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.common.collect.ImmutableList;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.GetTopOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.GetTopOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.PutTopInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.PutTopInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class RpcDataSerializationTest extends AbstractBindingRuntimeTest {
+
+    private BindingNormalizedNodeCodecRegistry registry;
+    private static final QName PUT_TOP = QName.create(PutTopInput.QNAME, "put-top");
+    private static final QName GET_TOP = QName.create(GetTopOutput.QNAME, "get-top");
+
+    private static final SchemaPath PUT_TOP_INPUT = SchemaPath.create(true, PUT_TOP, PutTopInput.QNAME);
+    private static final SchemaPath GET_TOP_OUTPUT = SchemaPath.create(true, GET_TOP, GetTopOutput.QNAME);
+
+    @Override
+    @Before
+    public void setup() {
+        super.setup();
+        final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+        registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+        registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+    }
+
+    @Test
+    public void testRpcInputToNormalized() {
+        final PutTopInputBuilder tb = new PutTopInputBuilder();
+        tb.setTopLevelList(ImmutableList.of(new TopLevelListBuilder().setKey(new TopLevelListKey("test")).build()));
+        final PutTopInput bindingOriginal = tb.build();
+        final ContainerNode dom = registry.toNormalizedNodeRpcData(bindingOriginal);
+        assertNotNull(dom);
+        assertEquals(PutTopInput.QNAME, dom.getIdentifier().getNodeType());
+
+        final DataObject bindingDeserialized = registry.fromNormalizedNodeRpcData(PUT_TOP_INPUT, dom);
+        assertEquals(bindingOriginal, bindingDeserialized);
+    }
+
+    @Test
+    public void testRpcOutputToNormalized() {
+        final GetTopOutputBuilder tb = new GetTopOutputBuilder();
+        tb.setTopLevelList(ImmutableList.of(new TopLevelListBuilder().setKey(new TopLevelListKey("test")).build()));
+        final GetTopOutput bindingOriginal = tb.build();
+        final ContainerNode dom = registry.toNormalizedNodeRpcData(bindingOriginal);
+        assertNotNull(dom);
+        assertEquals(GetTopOutput.QNAME, dom.getIdentifier().getNodeType());
+
+        final DataObject bindingDeserialized = registry.fromNormalizedNodeRpcData(GET_TOP_OUTPUT, dom);
+        assertEquals(bindingOriginal, bindingDeserialized);
+
+    }
+
+}
index fe2510857f89911223c90a539e326c6e25f5e740..caf22b85984df6407bfdeaabbf90a15715d61afe 100644 (file)
@@ -90,7 +90,7 @@ public class BindingRuntimeContext implements Immutable {
                 Preconditions.checkArgument(identityType != null, "Supplied QName %s is not a valid identity", key);
                 try {
                     return strategy.loadClass(identityType);
-                } catch (ClassNotFoundException e) {
+                } catch (final ClassNotFoundException e) {
                     throw new IllegalArgumentException("Required class " + identityType + "was not found.", e);
                 }
             }
@@ -100,11 +100,11 @@ public class BindingRuntimeContext implements Immutable {
         this.strategy = strategy;
         this.schemaContext = schema;
 
-        BindingGeneratorImpl generator = new BindingGeneratorImpl(false);
+        final BindingGeneratorImpl generator = new BindingGeneratorImpl(false);
         generator.generateTypes(schema);
-        Map<Module, ModuleContext> modules = generator.getModuleContexts();
+        final Map<Module, ModuleContext> modules = generator.getModuleContexts();
 
-        for (ModuleContext ctx : modules.values()) {
+        for (final ModuleContext ctx : modules.values()) {
             augmentationToSchema.putAll(ctx.getTypeToAugmentation());
             typeToDefiningSchema.putAll(ctx.getTypeToSchema());
 
@@ -194,7 +194,7 @@ public class BindingRuntimeContext implements Immutable {
 
     public Entry<AugmentationIdentifier, AugmentationSchema> getResolvedAugmentationSchema(final DataNodeContainer target,
             final Class<? extends Augmentation<?>> aug) {
-        AugmentationSchema origSchema = getAugmentationDefinition(aug);
+        final AugmentationSchema origSchema = getAugmentationDefinition(aug);
         /*
          * FIXME: Validate augmentation schema lookup
          *
@@ -207,15 +207,15 @@ public class BindingRuntimeContext implements Immutable {
          * with data and it is up to underlying user to validate data.
          *
          */
-        Set<QName> childNames = new HashSet<>();
-        Set<DataSchemaNode> realChilds = new HashSet<>();
-        for (DataSchemaNode child : origSchema.getChildNodes()) {
+        final Set<QName> childNames = new HashSet<>();
+        final Set<DataSchemaNode> realChilds = new HashSet<>();
+        for (final DataSchemaNode child : origSchema.getChildNodes()) {
             realChilds.add(target.getDataChildByName(child.getQName()));
             childNames.add(child.getQName());
         }
 
-        AugmentationIdentifier identifier = new AugmentationIdentifier(childNames);
-        AugmentationSchema proxy = new AugmentationSchemaProxy(origSchema, realChilds);
+        final AugmentationIdentifier identifier = new AugmentationIdentifier(childNames);
+        final AugmentationSchema proxy = new AugmentationSchemaProxy(origSchema, realChilds);
         return new AbstractMap.SimpleEntry<>(identifier, proxy);
     }
 
@@ -230,7 +230,7 @@ public class BindingRuntimeContext implements Immutable {
      * @throws IllegalArgumentException If supplied class does not represent case.
      */
     public Optional<ChoiceCaseNode> getCaseSchemaDefinition(final ChoiceNode schema, final Class<?> childClass) throws IllegalArgumentException {
-        DataSchemaNode origSchema = getSchemaDefinition(childClass);
+        final DataSchemaNode origSchema = getSchemaDefinition(childClass);
         Preconditions.checkArgument(origSchema instanceof ChoiceCaseNode, "Supplied schema %s is not case.", origSchema);
 
         /* FIXME: Make sure that if there are multiple augmentations of same
@@ -260,8 +260,8 @@ public class BindingRuntimeContext implements Immutable {
      *     which was used to generate supplied class.
      */
     public Entry<GeneratedType, Object> getTypeWithSchema(final Class<?> type) {
-        Object schema = typeToDefiningSchema.get(referencedType(type));
-        Type definedType = typeToDefiningSchema.inverse().get(schema);
+        final Object schema = typeToDefiningSchema.get(referencedType(type));
+        final Type definedType = typeToDefiningSchema.inverse().get(schema);
         Preconditions.checkNotNull(schema);
         Preconditions.checkNotNull(definedType);
         if(definedType instanceof GeneratedTypeBuilder) {
@@ -273,20 +273,20 @@ 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)) {
-            ChoiceNode originalChoice = getOriginalSchema(choice);
-            Type choiceType = referencedType(typeToDefiningSchema.inverse().get(originalChoice));
-            Collection<Type> cases = choiceToCases.get(choiceType);
+        final Map<Type,Entry<Type,Type>> childToCase = new HashMap<>();;
+        for (final ChoiceNode choice :  FluentIterable.from(schema.getChildNodes()).filter(ChoiceNode.class)) {
+            final ChoiceNode originalChoice = getOriginalSchema(choice);
+            final Type choiceType = referencedType(typeToDefiningSchema.inverse().get(originalChoice));
+            final Collection<Type> cases = choiceToCases.get(choiceType);
 
             for (Type caze : cases) {
-                Entry<Type,Type> caseIdentifier = new SimpleEntry<>(choiceType,caze);
-                HashSet<Type> caseChildren = new HashSet<>();
+                final Entry<Type,Type> caseIdentifier = new SimpleEntry<>(choiceType,caze);
+                final HashSet<Type> caseChildren = new HashSet<>();
                 if (caze instanceof GeneratedTypeBuilder) {
                     caze = ((GeneratedTypeBuilder) caze).toInstance();
                 }
                 collectAllContainerTypes((GeneratedType) caze, caseChildren);
-                for (Type caseChild : caseChildren) {
+                for (final Type caseChild : caseChildren) {
                     childToCase.put(caseChild, caseIdentifier);
                 }
             }
@@ -295,25 +295,25 @@ public class BindingRuntimeContext implements Immutable {
     }
 
     public Set<Class<?>> getCases(final Class<?> choice) {
-        Collection<Type> cazes = choiceToCases.get(referencedType(choice));
-        Set<Class<?>> ret = new HashSet<>(cazes.size());
-        for(Type caze : cazes) {
+        final Collection<Type> cazes = choiceToCases.get(referencedType(choice));
+        final Set<Class<?>> ret = new HashSet<>(cazes.size());
+        for(final Type caze : cazes) {
             try {
                 final Class<?> c = strategy.loadClass(caze);
                 ret.add(c);
-            } catch (ClassNotFoundException e) {
+            } catch (final ClassNotFoundException e) {
                 LOG.warn("Failed to load class for case {}, ignoring it", caze, e);
             }
         }
         return ret;
     }
 
-    public Class<?> getClassForSchema(final DataSchemaNode childSchema) {
-        DataSchemaNode origSchema = getOriginalSchema(childSchema);
-        Type clazzType = typeToDefiningSchema.inverse().get(origSchema);
+    public Class<?> getClassForSchema(final SchemaNode childSchema) {
+        final SchemaNode origSchema = getOriginalSchema(childSchema);
+        final Type clazzType = typeToDefiningSchema.inverse().get(origSchema);
         try {
             return strategy.loadClass(clazzType);
-        } catch (ClassNotFoundException e) {
+        } catch (final ClassNotFoundException e) {
             throw new IllegalStateException(e);
         }
     }
@@ -321,8 +321,8 @@ public class BindingRuntimeContext implements Immutable {
     public ImmutableMap<AugmentationIdentifier,Type> getAvailableAugmentationTypes(final DataNodeContainer container) {
         final Map<AugmentationIdentifier,Type> identifierToType = new HashMap<>();
         if (container instanceof AugmentationTarget) {
-            Set<AugmentationSchema> augments = ((AugmentationTarget) container).getAvailableAugmentations();
-            for (AugmentationSchema augment : augments) {
+            final Set<AugmentationSchema> augments = ((AugmentationTarget) container).getAvailableAugmentations();
+            for (final AugmentationSchema augment : augments) {
                 // Augmentation must have child nodes if is to be used with Binding classes
                 AugmentationSchema augOrig = augment;
                 while (augOrig.getOriginalDefinition().isPresent()) {
@@ -330,7 +330,7 @@ public class BindingRuntimeContext implements Immutable {
                 }
 
                 if (!augment.getChildNodes().isEmpty()) {
-                    Type augType = typeToDefiningSchema.inverse().get(augOrig);
+                    final Type augType = typeToDefiningSchema.inverse().get(augOrig);
                     if (augType != null) {
                         identifierToType.put(getAugmentationIdentifier(augment),augType);
                     }
@@ -342,8 +342,8 @@ public class BindingRuntimeContext implements Immutable {
     }
 
     private AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchema augment) {
-        Set<QName> childNames = new HashSet<>();
-        for (DataSchemaNode child : augment.getChildNodes()) {
+        final Set<QName> childNames = new HashSet<>();
+        for (final DataSchemaNode child : augment.getChildNodes()) {
             childNames.add(child.getQName());
         }
         return new AugmentationIdentifier(childNames);
@@ -357,7 +357,7 @@ public class BindingRuntimeContext implements Immutable {
     }
 
     private static Set<Type> collectAllContainerTypes(final GeneratedType type, final Set<Type> collection) {
-        for (MethodSignature definition : type.getMethodDefinitions()) {
+        for (final MethodSignature definition : type.getMethodDefinitions()) {
             Type childType = definition.getReturnType();
             if(childType instanceof ParameterizedType) {
                 childType = ((ParameterizedType) childType).getActualTypeArguments()[0];
@@ -366,7 +366,7 @@ public class BindingRuntimeContext implements Immutable {
                 collection.add(referencedType(childType));
             }
         }
-        for (Type parent : type.getImplements()) {
+        for (final Type parent : type.getImplements()) {
             if (parent instanceof GeneratedType) {
                 collectAllContainerTypes((GeneratedType) parent, collection);
             }
@@ -376,7 +376,7 @@ public class BindingRuntimeContext implements Immutable {
 
     private static final <T extends SchemaNode> T getOriginalSchema(final T choice) {
         @SuppressWarnings("unchecked")
-        T original = (T) SchemaNodeUtils.getRootOriginalIfPossible(choice);
+        final T original = (T) SchemaNodeUtils.getRootOriginalIfPossible(choice);
         if (original != null) {
             return original;
         }
index 8042e3dd8c345c4a8b839f1832879138c7243dda..5ba1cbcf9a3b2097ec8401954e50030dbaae72f3 100644 (file)
@@ -106,4 +106,14 @@ module opendaylight-yangtools-binding-test {
             uses two-level-list;
         }
     }
+
+    notification two-level-list-changed {
+        uses two-level-list;
+    }
+
+    rpc get-top {
+        output {
+            uses two-level-list;
+        }
+    }
 }