Propagate notification status to generated listener methods 57/93257/14
authorVladyslav Marchenko <vladyslav.marchenko@pantheon.tech>
Thu, 22 Oct 2020 12:51:40 +0000 (15:51 +0300)
committerRobert Varga <nite@hq.sk>
Mon, 26 Oct 2020 10:30:49 +0000 (10:30 +0000)
When we are generating listener interface for notifications:
- deprecated notification methods are marked as @deprecated;
- obsolete notification methods are marked as @deprecated and
  additionally are "default no-op" (so that users are not forced
  to implement them);

JIRA: MDSAL-554
Change-Id: I298b4dff44bd74715d9e1ebac277ac4d7918ffe6
Signed-off-by: Vladyslav Marchenko <vladyslav.marchenko@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal554Test.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/test/resources/mdsal554.yang [new file with mode: 0644]
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BaseTemplate.xtend
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceTemplate.xtend
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/JavaFileTemplate.java
binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceGeneratorTest.java

index afed7fe272826f746896653b310dbeb2dfd7aec4..96c880171dbd37d6450fab0710703665f82f328e 100644 (file)
@@ -124,6 +124,7 @@ import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
@@ -630,9 +631,16 @@ abstract class AbstractTypeGenerator {
                 resolveDataSchemaNodes(context, notificationInterface, notificationInterface,
                     notification.getChildNodes(), false);
 
-                addComment(listenerInterface.addMethod("on" + notificationInterface.getName())
+                final MethodSignatureBuilder notificationMethod =
+                    listenerInterface.addMethod("on" + notificationInterface.getName())
                     .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
-                    .setReturnType(primitiveVoidType()), notification);
+                    .setReturnType(primitiveVoidType());
+
+                annotateDeprecatedIfNecessary(notification, notificationMethod);
+                if (notification.getStatus().equals(Status.OBSOLETE)) {
+                    notificationMethod.setDefault(true);
+                }
+                addComment(notificationMethod, notification);
             }
         }
 
diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal554Test.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal554Test.java
new file mode 100644 (file)
index 0000000..632c155
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 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.mdsal.binding.generator.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class Mdsal554Test {
+    @Test
+    public void builderTemplateGenerateListenerMethodsTest() {
+        final EffectiveModelContext context = YangParserTestUtils.parseYangResource("/mdsal554.yang");
+
+        final Set<Module> toGenModules = new HashSet<>();
+        for (final Module module : context.getModules()) {
+            toGenModules.add(module);
+        }
+
+        final List<Type> genTypes = DefaultBindingGenerator.generateFor(context, toGenModules);
+
+        final GeneratedType type = (GeneratedType) genTypes.get(3);
+
+        final List<MethodSignature> methods = type.getMethodDefinitions();
+
+        assertEquals(3, methods.size());
+        assertEquals(methods.get(0).getName(), "onDeprecatedNotification");
+        assertEquals(methods.get(0).isDefault(), false);
+        assertEquals(methods.get(0).getAnnotations().size(), 1);
+        assertEquals(methods.get(0).getAnnotations().get(0).getIdentifier(), JavaTypeName.create(Deprecated.class));
+        assertEquals(methods.get(0).getAnnotations().get(0).getParameters().size(), 0);
+
+        assertEquals(methods.get(1).getName(), "onObsoleteNotification");
+        assertEquals(methods.get(1).isDefault(), true);
+        assertEquals(methods.get(1).getAnnotations().size(), 1);
+        assertEquals(methods.get(1).getAnnotations().get(0).getIdentifier(), JavaTypeName.create(Deprecated.class));
+        assertEquals(methods.get(1).getAnnotations().get(0).getParameters().size(), 1);
+        assertEquals(methods.get(1).getAnnotations().get(0).getParameters().get(0).getName(), "forRemoval");
+        assertEquals(methods.get(1).getAnnotations().get(0).getParameters().get(0).getValue(), "true");
+
+        assertEquals(methods.get(2).getName(), "onTestNotification");
+        assertEquals(methods.get(2).isDefault(), false);
+        assertEquals(methods.get(2).getAnnotations().size(), 0);
+    }
+}
diff --git a/binding/mdsal-binding-generator-impl/src/test/resources/mdsal554.yang b/binding/mdsal-binding-generator-impl/src/test/resources/mdsal554.yang
new file mode 100644 (file)
index 0000000..427e1cd
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 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
+ */
+module test-listener {
+    yang-version 1;
+    namespace "urn:opendaylight:test-listener";
+    prefix "t";
+
+    revision "2020-10-22" {
+    }
+
+    notification deprecated-notification {
+        description "Just a testing deprecated notification.";
+        status deprecated;
+    }
+
+    notification obsolete-notification {
+        description "Just a testing obsolete notification.";
+        status obsolete;
+    }
+
+    notification test-notification {
+        description "Just a testing notification.";
+    }
+}
index ed6bcea2c14bac35a071b2499c7bb3a61e6b6ecc..24ea00a0191f132dac0c1568ba06e06802bc5be0 100644 (file)
@@ -32,7 +32,6 @@ import org.opendaylight.mdsal.binding.model.api.JavaTypeName
 import org.opendaylight.mdsal.binding.model.api.MethodSignature
 import org.opendaylight.mdsal.binding.model.api.Restrictions
 import org.opendaylight.mdsal.binding.model.api.Type
-import org.opendaylight.mdsal.binding.model.api.TypeMember
 import org.opendaylight.mdsal.binding.model.api.TypeMemberComment
 import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition.Single
 import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition.Multiple
index ac67e9655575e70d676f5535b5d69da6026a0169..903b99fdd251f1c6de74a5b67fc320a3422894d2 100644 (file)
@@ -31,7 +31,6 @@ import org.opendaylight.mdsal.binding.model.api.MethodSignature
 import org.opendaylight.mdsal.binding.model.api.Type
 import org.opendaylight.mdsal.binding.model.util.Types
 import org.opendaylight.mdsal.binding.model.util.TypeConstants
-import org.opendaylight.mdsal.binding.model.api.TypeMember
 
 /**
  * Template for generating JAVA interfaces.
@@ -190,6 +189,10 @@ class InterfaceTemplate extends BaseTemplate {
         } else {
             switch method.name {
                 case DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME : generateDefaultImplementedInterface
+                default :
+                    if (VOID == method.returnType.identifier) {
+                        generateNoopVoidInterfaceMethod(method)
+                    }
             }
         }
     }
@@ -208,6 +211,14 @@ class InterfaceTemplate extends BaseTemplate {
         «method.returnType.importedName» «method.name»(«method.parameters.generateParameters»);
     '''
 
+    def private generateNoopVoidInterfaceMethod(MethodSignature method) '''
+        «method.comment.asJavadoc»
+        «method.annotations.generateAnnotations»
+        default «VOID.importedName» «method.name»(«method.parameters.generateParameters») {
+            // No-op
+        }
+    '''
+
     def private static accessorJavadoc(MethodSignature method, String orString) {
         val reference = method.comment?.referenceDescription
         val propReturn = method.propertyNameFromGetter + ", or " + orString + " if it is not present."
index ec891f26250447d2dce4056f7a72587fcbb2a5b6..d86bbfe66e561ebafa90b5e9604e0c682f9cf762 100644 (file)
@@ -67,9 +67,13 @@ class JavaFileTemplate {
      */
     static final @NonNull JavaTypeName OVERRIDE = JavaTypeName.create(Override.class);
     /**
-     * {@code java.lang.SuppressWarnings} as a JavaTypeName.
+     * {@code java.lang.void} as a JavaTypeName.
      */
     static final @NonNull JavaTypeName SUPPRESS_WARNINGS = JavaTypeName.create(SuppressWarnings.class);
+    /**
+     * {@code java.lang.SuppressWarnings} as a JavaTypeName.
+     */
+    static final @NonNull JavaTypeName VOID = JavaTypeName.create(void.class);
 
     /**
      * {@code java.util.Arrays} as a JavaTypeName.
index 4afa2511857be89572af9867596cc408f27e3450..93ff32956883a2cb45b5bb3814614505e992aa64 100644 (file)
 package org.opendaylight.mdsal.binding.java.api.generator;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
 import org.junit.Test;
+import org.opendaylight.mdsal.binding.model.api.AnnotationType;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature;
 import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.model.util.Types;
 
 public class InterfaceGeneratorTest {
+    private static final String TEST = "test";
+    private static final JavaTypeName TYPE_NAME = JavaTypeName.create(TEST, TEST);
+
     @Test
-    public void basicTest() throws Exception {
+    public void basicTest() {
         assertEquals("", new InterfaceGenerator().generate(mock(Type.class)));
     }
+
+    @Test
+    public void builderTemplateListenerMethodTest() {
+        final MethodSignature methSign = mockMethSign("on" + TEST);
+        final GeneratedType genType = mockGenType(methSign);
+
+        String expected = String.join(System.lineSeparator(),
+            "package test;",
+            "",
+            "public interface test",
+            "{",
+            "",
+            "",
+            "",
+            "",
+            "    void ontest();",
+            "",
+            "}",
+            "",
+            ""
+        );
+        assertEquals(expected, new InterfaceGenerator().generate(genType));
+    }
+
+    @Test
+    public void builderTemplateDeprecatedListenerMethodTest() {
+        final MethodSignature methSign = mockMethSign("on" + TEST);
+        addMethodStatus(methSign, JavaTypeName.create(Deprecated.class));
+        final GeneratedType genType = mockGenType(methSign);
+
+        String expected = String.join(System.lineSeparator(),
+            "package test;",
+            "import java.lang.Deprecated;",
+            "",
+            "public interface test",
+            "{",
+            "",
+            "",
+            "",
+            "",
+            "    @Deprecated",
+            "    void ontest();",
+            "",
+            "}",
+            "",
+            ""
+        );
+        assertEquals(expected, new InterfaceGenerator().generate(genType));
+    }
+
+    @Test
+    public void builderTemplateGenerateObsoleteListenerMethodTest() {
+        final MethodSignature methSign = mockMethSign("on" + TEST);
+        addMethodStatus(methSign, JavaTypeName.create(Deprecated.class));
+        doReturn(true).when(methSign).isDefault();
+        final GeneratedType genType = mockGenType(methSign);
+
+        String expected = String.join(System.lineSeparator(),
+            "package test;",
+            "import java.lang.Deprecated;",
+            "",
+            "public interface test",
+            "{",
+            "",
+            "",
+            "",
+            "",
+            "    @Deprecated",
+            "    default void ontest() {",
+            "        // No-op",
+            "    }",
+            "",
+            "}",
+            "",
+            ""
+        );
+        assertEquals(expected, new InterfaceGenerator().generate(genType));
+    }
+
+    private static GeneratedType mockGenType(final MethodSignature methSign) {
+        final GeneratedType genType = spy(GeneratedType.class);
+        doReturn(TYPE_NAME).when(genType).getIdentifier();
+        doReturn(TEST).when(genType).getName();
+        doReturn(TEST).when(genType).getPackageName();
+        final List<MethodSignature> listMethodSign = new ArrayList<>();
+        listMethodSign.add(methSign);
+        doReturn(listMethodSign).when(genType).getMethodDefinitions();
+
+        final List<Type> impls = new ArrayList<>();
+        doReturn(impls).when(genType).getImplements();
+        return genType;
+    }
+
+    private static MethodSignature mockMethSign(final String methodeName) {
+        final MethodSignature methSign = mock(MethodSignature.class);
+        doReturn(methodeName).when(methSign).getName();
+        final Type methType = Types.typeForClass(void.class);
+        doReturn(methType).when(methSign).getReturnType();
+        doReturn(MethodSignature.ValueMechanics.NORMAL).when(methSign).getMechanics();
+        return methSign;
+    }
+
+    private static void addMethodStatus(MethodSignature methSign, JavaTypeName annotationJavaType) {
+        final AnnotationType annotationType = mock(AnnotationType.class);
+        doReturn(annotationJavaType).when(annotationType).getIdentifier();
+        doReturn(ImmutableList.of(annotationType)).when(methSign).getAnnotations();
+    }
 }
\ No newline at end of file