From 07490d7f8c00e1000d57efaf2b00913e18002517 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 9 Dec 2019 16:44:30 +0100 Subject: [PATCH] Add codegen support for nested notifications 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 (cherry picked from commit 480afab4e0a0eb8d64367c0bd12fa3ec892a3383) --- .../generator/impl/AbstractTypeGenerator.java | 42 +++++++++++++++++++ .../binding/model/util/BindingTypes.java | 42 +++++++++++++++++++ .../yang/opendaylight-test-notification.yang | 36 +++++++++++++++- .../yang/binding/BaseNotification.java | 17 ++++++++ .../yang/binding/InstanceNotification.java | 27 ++++++++++++ .../yang/binding/KeyedListNotification.java | 26 ++++++++++++ .../yangtools/yang/binding/Notification.java | 10 +++-- 7 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BaseNotification.java create mode 100644 binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceNotification.java create mode 100644 binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyedListNotification.java diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java index 84f925537e..133d5c16d6 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java @@ -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 void notificationsToGenType( + final ModuleContext context, final Type parent, final T parentSchema, final Type keyType, + final boolean inGrouping) { + final Set 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 identities of the module to the list of * Type 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()) { diff --git a/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/BindingTypes.java b/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/BindingTypes.java index 4cfc2e9e4b..3bb4e824d1 100644 --- a/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/BindingTypes.java +++ b/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/BindingTypes.java @@ -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} + * @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} + * @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} + * @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. * diff --git a/binding/mdsal-binding-test-model/src/main/yang/opendaylight-test-notification.yang b/binding/mdsal-binding-test-model/src/main/yang/opendaylight-test-notification.yang index 31ec7aed61..ed3cf36922 100644 --- a/binding/mdsal-binding-test-model/src/main/yang/opendaylight-test-notification.yang +++ b/binding/mdsal-binding-test-model/src/main/yang/opendaylight-test-notification.yang @@ -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 index 0000000000..a445e418b2 --- /dev/null +++ b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BaseNotification.java @@ -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 index 0000000000..83fd1c8806 --- /dev/null +++ b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceNotification.java @@ -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 Concrete notification type + * @param Parent data tree instance type + */ +@Beta +public interface InstanceNotification, T extends DataObject> + extends BaseNotification { + + @Override + @NonNull Class 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 index 0000000000..40dd832e98 --- /dev/null +++ b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyedListNotification.java @@ -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 Concrete notification type + * @param Parent data tree instance type + * @param Parent data tree key type + */ +@Beta +public interface KeyedListNotification, T extends DataObject & Identifiable, + K extends Identifier> extends InstanceNotification { + +} diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/Notification.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/Notification.java index 0d7c6ae387..2bb40f371e 100644 --- a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/Notification.java +++ b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/Notification.java @@ -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 { } -- 2.36.6