Add codegen support for nested notifications 24/86324/1
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 9 Dec 2019 15:44:30 +0000 (16:44 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 10 Dec 2019 11:45:11 +0000 (12:45 +0100)
We do not have a concept of instance notification, which is similar
in many respects to an action. Add the baseline interface marker
and teach mdsal-binding-generator-impl to emit interface definitions
for them.

JIRA: MDSAL-493
Change-Id: I6af84b50f3083a8e1046ee0521b126aae1ffafe5
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit 480afab4e0a0eb8d64367c0bd12fa3ec892a3383)

binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/BindingTypes.java
binding/mdsal-binding-test-model/src/main/yang/opendaylight-test-notification.yang
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BaseNotification.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceNotification.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyedListNotification.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/Notification.java

index 84f925537e5645cb9e60c204a49e01891de630fe..133d5c16d6dcf4695dca8ae597d156cc0c0a5d55 100644 (file)
@@ -29,7 +29,9 @@ import static org.opendaylight.mdsal.binding.model.util.BindingTypes.childOf;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.choiceIn;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.identifiable;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.identifier;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.instanceNotification;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.keyedListAction;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.keyedListNotification;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.opaqueObject;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.rpcResult;
 import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN;
@@ -109,6 +111,7 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
@@ -302,6 +305,7 @@ abstract class AbstractTypeGenerator {
             constructGetter(parent, genType, node);
             resolveDataSchemaNodes(context, genType, genType, node.getChildNodes(), inGrouping);
             actionsToGenType(context, genType, node, null, inGrouping);
+            notificationsToGenType(context, genType, node, null, inGrouping);
         }
     }
 
@@ -326,6 +330,7 @@ abstract class AbstractTypeGenerator {
             constructNonnull(parent, listType, node);
 
             actionsToGenType(context, genType, node, keyTypeBuilder, inGrouping);
+            notificationsToGenType(context, genType, node, keyTypeBuilder, inGrouping);
 
             for (final DataSchemaNode schemaNode : node.getChildNodes()) {
                 if (!schemaNode.isAugmenting()) {
@@ -601,6 +606,40 @@ abstract class AbstractTypeGenerator {
         context.addTopLevelNodeType(listenerInterface);
     }
 
+    private <T extends DataNodeContainer & NotificationNodeContainer> void notificationsToGenType(
+            final ModuleContext context, final Type parent, final T parentSchema, final Type keyType,
+            final boolean inGrouping) {
+        final Set<NotificationDefinition> notifications = parentSchema.getNotifications();
+        if (notifications.isEmpty()) {
+            return;
+        }
+
+        for (NotificationDefinition notif : notifications) {
+            if (notif.isAugmenting()) {
+                continue;
+            }
+            if (parentSchema instanceof GroupingDefinition) {
+                // Notifications cannot be really established, as they lack instantiation context, which would be
+                // completely described by an InstanceIdentifier -- hence we cannot create a binding class
+                continue;
+            }
+
+            processUsesAugments(notif, context, false);
+
+            final GeneratedTypeBuilder notifInterface = addDefaultInterfaceDefinition(
+                packageNameForGeneratedType(context.modulePackageName(), notif.getPath()), notif, DATA_OBJECT, context);
+            defaultImplementedInterace(notifInterface);
+            annotateDeprecatedIfNecessary(notif, notifInterface);
+
+            notifInterface.addImplementsType(keyType != null ? keyedListNotification(notifInterface, parent, keyType)
+                    : instanceNotification(notifInterface, parent));
+            context.addChildNodeType(notif, notifInterface);
+
+            // Notification object
+            resolveDataSchemaNodes(context, notifInterface, notifInterface, notif.getChildNodes(), false);
+        }
+    }
+
     /**
      * Converts all <b>identities</b> of the module to the list of
      * <code>Type</code> objects.
@@ -709,6 +748,7 @@ abstract class AbstractTypeGenerator {
             groupingsToGenTypes(context, grouping.getGroupings());
             processUsesAugments(grouping, context, true);
             actionsToGenType(context, genType, grouping, null, true);
+            notificationsToGenType(context, genType, grouping, null, true);
         }
     }
 
@@ -939,6 +979,8 @@ abstract class AbstractTypeGenerator {
 
         augSchemaNodeToMethods(context, augTypeBuilder, augSchema.getChildNodes(), inGrouping);
         actionsToGenType(context, augTypeBuilder, augSchema, null, inGrouping);
+        notificationsToGenType(context, augTypeBuilder, augSchema, null, inGrouping);
+
         augmentBuilders.put(augTypeName, augTypeBuilder);
 
         if (!augSchema.getChildNodes().isEmpty()) {
index 4cfc2e9e4bbca4f33c83eed2012b81d5f78e11b0..3bb4e824d14a0981ec7abdf405b0188e332faa2d 100644 (file)
@@ -27,7 +27,10 @@ import org.opendaylight.yangtools.yang.binding.DataRoot;
 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.InstanceNotification;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedListAction;
+import org.opendaylight.yangtools.yang.binding.KeyedListNotification;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.binding.NotificationListener;
 import org.opendaylight.yangtools.yang.binding.OpaqueObject;
@@ -68,7 +71,10 @@ public final class BindingTypes {
     private static final ConcreteType ACTION = typeForClass(Action.class);
     private static final ConcreteType CHILD_OF = typeForClass(ChildOf.class);
     private static final ConcreteType CHOICE_IN = typeForClass(ChoiceIn.class);
+    private static final ConcreteType INSTANCE_NOTIFICATION = typeForClass(InstanceNotification.class);
+    private static final ConcreteType KEYED_INSTANCE_IDENTIFIER = typeForClass(KeyedInstanceIdentifier.class);
     private static final ConcreteType KEYED_LIST_ACTION = typeForClass(KeyedListAction.class);
+    private static final ConcreteType KEYED_LIST_NOTIFICATION = typeForClass(KeyedListNotification.class);
     private static final ConcreteType OPAQUE_OBJECT = typeForClass(OpaqueObject.class);
     private static final ConcreteType RPC_RESULT = typeForClass(RpcResult.class);
 
@@ -104,6 +110,30 @@ public final class BindingTypes {
         return parameterizedTypeFor(KEYED_LIST_ACTION, keyType, parent, input, output);
     }
 
+    /**
+     * Type specializing {@link InstanceNotification} for a particular type.
+     *
+     * @param parent Type of parent defining the notification
+     * @return A parameterized type corresponding to {@code InstanceNotification<Parent>}
+     * @throws NullPointerException if {@code parent} is is null
+     */
+    public static ParameterizedType instanceNotification(final Type concreteType, final Type parent) {
+        return parameterizedTypeFor(INSTANCE_NOTIFICATION, concreteType, parent);
+    }
+
+    /**
+     * Type specializing {@link InstanceNotification} for a particular type.
+     *
+     * @param parent Type of parent defining the notification
+     * @param keyType Type of parent's key
+     * @return A parameterized type corresponding to {@code KeyedInstanceNotification<ParentKey, Parent>}
+     * @throws NullPointerException if any argument is is null
+     */
+    public static ParameterizedType keyedListNotification(final Type concreteType, final Type parent,
+            final Type keyType) {
+        return parameterizedTypeFor(KEYED_LIST_NOTIFICATION, concreteType, parent, keyType);
+    }
+
     /**
      * Specialize {@link Augmentable} for a particular type.
      *
@@ -170,6 +200,18 @@ public final class BindingTypes {
         return parameterizedTypeFor(INSTANCE_IDENTIFIER, type);
     }
 
+    /**
+     * Type specializing {@link KeyedInstanceIdentifier} for a particular type.
+     *
+     * @param type Type for which to specialize
+     * @param keyType Type of key
+     * @return A parameterized type corresponding to {@code KeyedInstanceIdentifier<Type, KeyType>}
+     * @throws NullPointerException if any argument is is null
+     */
+    public static ParameterizedType keyedInstanceIdentifier(final Type type, final Type keyType) {
+        return parameterizedTypeFor(KEYED_INSTANCE_IDENTIFIER, type, keyType);
+    }
+
     /**
      * Type specializing {@link OpaqueObject} for a particular type.
      *
index 31ec7aed619c84984c69e0d8b23b835b00b839ed..ed3cf36922e4c658b35fd8d1c31b5afa4677156b 100644 (file)
@@ -1,5 +1,5 @@
 module opendaylight-test-notification {
-    yang-version 1;
+    yang-version 1.1;
     namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:bi:ba:notification";
     prefix "ntf";
 
@@ -22,4 +22,36 @@ module opendaylight-test-notification {
             type uint16;
         }
     }
-}
\ No newline at end of file
+
+    container wood {
+        typedef tree-id {
+            type uint64;
+        }
+
+        grouping tree-fell-properties {
+            // There might have been a mime around, do you care?
+            leaf hit-mime {
+                type boolean;
+            }
+        }
+
+        notification a-tree-fell {
+            leaf tree-id {
+                type tree-id;
+            }
+            uses tree-fell-properties;
+        }
+
+        list tree {
+            leaf id {
+                type tree-id;
+            }
+            key id;
+
+            notification i-fell {
+                uses tree-fell-properties;
+            }
+        }
+    }
+}
+
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BaseNotification.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BaseNotification.java
new file mode 100644 (file)
index 0000000..a445e41
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.yang.binding;
+
+/**
+ * Marker interface for YANG-defined all notifications. This interface should never be implemented directly. It exists
+ * only to tie together semantics of global notifications (as represented by {@link Notification}) and instance
+ * notifications (as represented by {@link InstanceNotification}.
+ */
+public interface BaseNotification extends DataContainer {
+
+}
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceNotification.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceNotification.java
new file mode 100644 (file)
index 0000000..83fd1c8
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.yang.binding;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Marker interface for YANG-defined instance {@code notification}s. A concrete InstanceNotification and its
+ * implementations may choose to also extend/implement the {@link EventInstantAware} interface. In case they do,
+ * {@link EventInstantAware#eventInstant()} returns the time when this notification was generated.
+ *
+ * @param <N> Concrete notification type
+ * @param <T> Parent data tree instance type
+ */
+@Beta
+public interface InstanceNotification<N extends InstanceNotification<N, T>, T extends DataObject>
+        extends BaseNotification {
+
+    @Override
+    @NonNull Class<N> implementedInterface();
+}
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyedListNotification.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyedListNotification.java
new file mode 100644 (file)
index 0000000..40dd832
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.yang.binding;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * An {@code notification} which is defined within the schema tree and is thus tied to a data tree instance and
+ * additionally its parent is a {code list} with a {@code key} statement. A concrete KeyedListNotification and its
+ * implementations may choose to also extend/implement the {@link EventInstantAware} interface. In case they do,
+ * {@link EventInstantAware#eventInstant()} returns the time when this notification was generated.
+ *
+ * @param <N> Concrete notification type
+ * @param <T> Parent data tree instance type
+ * @param <K> Parent data tree key type
+ */
+@Beta
+public interface KeyedListNotification<N extends KeyedListNotification<N, T, K>, T extends DataObject & Identifiable<K>,
+    K extends Identifier<T>> extends InstanceNotification<N, T> {
+
+}
index 0d7c6ae38771d204b0e18973fd056487025a55cd..2bb40f371eb53a9adf186f85653fad2f71008030 100644 (file)
@@ -8,10 +8,12 @@
 package org.opendaylight.yangtools.yang.binding;
 
 /**
- * Marker interface for YANG-defined notifications. This interface should never be implemented directly. A concrete
- * Notification and its implementations may choose to also extend/implement the {@link EventInstantAware} interface.
- * In case they do, {@link EventInstantAware#eventInstant()} returns the time when this notification was generated.
+ * Marker interface for YANG-defined global notifications. This interface should never be implemented directly. A
+ * concrete Notification and its implementations may choose to also extend/implement the {@link EventInstantAware}
+ * interface. In case they do, {@link EventInstantAware#eventInstant()} returns the time when this notification was
+ * generated.
  */
-public interface Notification extends DataContainer {
+// FIXME: 6.0.0: narrow implementedInterface()
+public interface Notification extends BaseNotification {
 
 }