Bug 1411 #5 BindingGeneratorImpl decomposition - Notifications 23/53723/12
authorMartin Ciglan <mciglan@cisco.com>
Thu, 23 Mar 2017 10:47:47 +0000 (11:47 +0100)
committerMartin Ciglan <mciglan@cisco.com>
Tue, 28 Mar 2017 07:13:38 +0000 (07:13 +0000)
- resolve YANG notifications & notification tied to
data schema nodes from schema context
- further util methods added
- further decomposition in order to
decrease initial BindingGeneratorImpl complexity

TODO: JUnit tests, models

Change-Id: Ie9e16d0ee23a7e1c1f2aab7871967261a013bb6f
Signed-off-by: Martin Ciglan <mciglan@cisco.com>
binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/impl/AuxiliaryGenUtils.java
binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/impl/GenHelperUtil.java
binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/impl/ModuleToGenType.java

index e30ef8623aedb30325511a39f7ef95a49799cd9d..d5d11c078cb26d4c56c02e2b006f65524834481c 100644 (file)
@@ -18,12 +18,14 @@ import com.google.common.base.Strings;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 import org.opendaylight.mdsal.binding.javav2.generator.impl.txt.yangTemplateForModule;
 import org.opendaylight.mdsal.binding.javav2.generator.impl.txt.yangTemplateForNode;
+import org.opendaylight.mdsal.binding.javav2.generator.impl.txt.yangTemplateForNodes;
 import org.opendaylight.mdsal.binding.javav2.generator.impl.util.YangTextTemplate;
 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
@@ -246,6 +248,36 @@ final class AuxiliaryGenUtils {
         return replaceAllIllegalChars(sb);
     }
 
+    static String createDescription(final Set<? extends SchemaNode> schemaNodes, final String moduleName, final
+            boolean verboseClassComments) {
+        final StringBuilder sb = new StringBuilder();
+
+        if (!isNullOrEmpty(schemaNodes)) {
+            final SchemaNode node = schemaNodes.iterator().next();
+
+            if (node instanceof RpcDefinition) {
+                sb.append("Interface for implementing the following YANG RPCs defined in module <b>" + moduleName + "</b>");
+            } else if (node instanceof NotificationDefinition) {
+                sb.append("Interface for receiving the following YANG notifications defined in module <b>" + moduleName + "</b>");
+            }
+        }
+        sb.append(NEW_LINE);
+
+        if (verboseClassComments) {
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(encodeAngleBrackets(yangTemplateForNodes.render(schemaNodes).body()));
+            sb.append("</pre>");
+            sb.append(NEW_LINE);
+        }
+
+        return replaceAllIllegalChars(sb);
+    }
+
+    private static boolean isNullOrEmpty(final Collection<?> list) {
+        return list == null || list.isEmpty();
+    }
+
     /**
      * Returns first unique name for the augment generated type builder. The
      * generated type builder name for augment consists from name of augmented
index 6ba8f594adf11c13b92aafacbf4094b9d0881994..b69161216c14dc410ae54f909bc985a194d3171a 100644 (file)
@@ -21,7 +21,9 @@ import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenU
 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveInnerEnumFromTypeDefinition;
 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTOBuilder;
 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.computeDefaultSUID;
+import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
+import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
 
 import com.google.common.annotations.Beta;
@@ -32,10 +34,13 @@ import java.util.Map;
 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
+import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
+import org.opendaylight.mdsal.binding.javav2.generator.util.NonJavaCharsConverter;
 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
+import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
@@ -57,6 +62,7 @@ import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -118,7 +124,7 @@ final class GenHelperUtil {
      * @throws IllegalArgumentException
      *             if <code>module</code> is null
      */
-    private static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
+    static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
             verboseClassComments) {
         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
         final String packageName = BindingMapping.getRootPackageName(module);
@@ -374,7 +380,7 @@ final class GenHelperUtil {
      * @param schemaContext schema context
      * @return generated type builder <code>schemaNode</code>
      */
-    private static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
+    static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
             schemaNode, final Type parent, final Module module, final Map<Module, ModuleContext> genCtx,
             final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
 
@@ -398,6 +404,39 @@ final class GenHelperUtil {
         return it;
     }
 
+    static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, String
+            parentName, final String basePackageName, final NotificationDefinition notification, final Module module,
+            final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>>
+            genTypeBuilders, TypeProvider typeProvider, Map<Module, ModuleContext> genCtx) {
+
+        processUsesAugments(schemaContext, notification, module, genCtx, genTypeBuilders,
+                verboseClassComments, typeProvider);
+
+        final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition
+                (basePackageName, notification, null, module, genCtx, schemaContext,
+                        verboseClassComments, genTypeBuilders);
+        annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
+        notificationInterface.addImplementsType(NOTIFICATION);
+        genCtx.get(module).addChildNodeType(notification, notificationInterface);
+
+        // Notification object
+        resolveDataSchemaNodes(module, basePackageName, notificationInterface,
+                notificationInterface, notification.getChildNodes(), genCtx, schemaContext,
+                verboseClassComments, genTypeBuilders, typeProvider);
+
+        //in case of tied notification, incorporate parent's localName
+        final StringBuilder sb = new StringBuilder("on_");
+        if (parentName != null) {
+            sb.append(parentName).append('_');
+        }
+        sb.append(notificationInterface.getName());
+
+        listenerInterface.addMethod(NonJavaCharsConverter.convertIdentifier(sb.toString(), JavaIdentifier.METHOD))
+                .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
+                .setComment(encodeAngleBrackets(notification.getDescription())).setReturnType(Types.VOID);
+        return listenerInterface;
+    }
+
     /**
      * Returns reference to generated type builder for specified
      * <code>schemaNode</code> with <code>packageName</code>.
@@ -743,5 +782,4 @@ final class GenHelperUtil {
         }
         return genType;
     }
-
 }
index f98f64a82b6565f5f8b530d4041bd1002fecc18a..8c5e13ba4bb35a9bcaa0122c2d6bb72c81e6af74 100644 (file)
@@ -8,16 +8,27 @@
 
 package org.opendaylight.mdsal.binding.javav2.generator.impl;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createDescription;
+import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.moduleTypeBuilder;
+import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.resolveNotification;
+import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION_LISTENER;
+
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
@@ -35,8 +46,9 @@ final class ModuleToGenType {
 
         genCtx.put(module, new ModuleContext());
         genCtx = allTypeDefinitionsToGenTypes(module, genCtx, typeProvider);
+        genCtx = notificationsToGenType(module, genCtx, schemaContext, genTypeBuilders, verboseClassComments, typeProvider);
 
-        //TODO: call generate for other entities (groupings, rpcs, identities, notifications)
+        //TODO: call generate for other entities (groupings, rpcs, actions, identities)
 
         if (!module.getChildNodes().isEmpty()) {
             final GeneratedTypeBuilder moduleType = GenHelperUtil.moduleToDataType(module, genCtx, verboseClassComments);
@@ -64,7 +76,7 @@ final class ModuleToGenType {
      *             if set of type definitions from module is null
      */
     private static Map<Module, ModuleContext> allTypeDefinitionsToGenTypes(final Module module, Map<Module, ModuleContext> genCtx,
-                                                     TypeProvider typeProvider) {
+            TypeProvider typeProvider) {
         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
         Preconditions.checkArgument(module.getName() != null, "Module name cannot be NULL.");
         final DataNodeIterator it = new DataNodeIterator(module);
@@ -82,4 +94,66 @@ final class ModuleToGenType {
         });
         return genCtx;
     }
+
+    /**
+     * Converts all <b>notifications</b> of the module to the list of
+     * <code>Type</code> objects. In addition are to this list added containers
+     * and lists which are part of this notification.
+     *
+     * @param module
+     *            module from which is obtained set of all notification objects
+     *            to iterate over them
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if the module equals null</li>
+     *             <li>if the name of module equals null</li>
+     *             </ul>
+     * @throws IllegalStateException
+     *             if set of notifications from module is null
+     */
+    private static Map<Module, ModuleContext> notificationsToGenType(final Module module, Map<Module, ModuleContext> genCtx,
+            final SchemaContext schemaContext, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
+            final boolean verboseClassComments, TypeProvider typeProvider) {
+        checkArgument(module != null, "Module reference cannot be NULL.");
+        checkArgument(module.getName() != null, "Module name cannot be NULL.");
+        final Set<NotificationDefinition> notifications = module.getNotifications();
+        if (notifications.isEmpty()) {
+            return genCtx;
+        }
+
+        final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(module, "Listener", verboseClassComments);
+        listenerInterface.addImplementsType(NOTIFICATION_LISTENER);
+        final String basePackageName = BindingMapping.getRootPackageName(module);
+
+        for (final NotificationDefinition notification : notifications) {
+            if (notification != null) {
+                resolveNotification(listenerInterface, null, basePackageName, notification, module, schemaContext,
+                        verboseClassComments, genTypeBuilders, typeProvider, genCtx);
+            }
+        }
+
+        //YANG 1.1 allows notifications be tied to containers and lists
+        final Collection<DataSchemaNode> potentials = module.getChildNodes();
+
+        for (final DataSchemaNode potential : potentials) {
+            if (potential instanceof NotificationNodeContainer) {
+                final Set<NotificationDefinition> tiedNotifications = ((NotificationNodeContainer) potential)
+                        .getNotifications();
+                for (final NotificationDefinition tiedNotification: tiedNotifications) {
+                    if (tiedNotification != null) {
+                        resolveNotification(listenerInterface, potential.getQName().getLocalName(), basePackageName,
+                                tiedNotification, module, schemaContext, verboseClassComments, genTypeBuilders,
+                                typeProvider, genCtx);
+                        notifications.add(tiedNotification);
+                    }
+                }
+            }
+        }
+
+        listenerInterface.setDescription(createDescription(notifications, module.getName(), verboseClassComments));
+
+        genCtx.get(module).addTopLevelNodeType(listenerInterface);
+
+        return genCtx;
+    }
 }