Allow rpc definition for RuntimeMXBeans to come from groupings 29/13129/4
authorMaros Marsalek <mmarsale@cisco.com>
Tue, 25 Nov 2014 17:02:02 +0000 (18:02 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Mon, 15 Dec 2014 13:19:15 +0000 (13:19 +0000)
Change-Id: I796b43e8a4b01277bcb0c73f5ac86bc710839061
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/config/yang-jmx-generator/pom.xml
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/util/NetconfTestImplModuleUtil.java
opendaylight/config/yang-test/src/main/yang/config-test-impl.yang
opendaylight/config/yang-test/src/main/yang/types/test-groups.yang [new file with mode: 0644]
opendaylight/config/yang-test/src/main/yang/types/test-types.yang
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java

index 979b39688b04aac10514db6e0b796bfd97b139e4..bfeb3f0f7acd74605a2f39782e5ea9a991b22044 100644 (file)
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>binding-type-provider</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-model-util</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
index 80db46df2b5eaa627a84f8e2aaf2fa97a9aed6d5..ed727c9a13590733178d84e66b64cae71f23b058 100644 (file)
@@ -374,7 +374,7 @@ final class ModuleMXBeanEntryBuilder {
             final String javaNamePrefix) {
 
         return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, dataNodeContainer, moduleLocalNameFromXPath,
-                typeProviderWrapper, javaNamePrefix, currentModule).values();
+                typeProviderWrapper, javaNamePrefix, currentModule, schemaContext).values();
 
     }
 
index b6ed8243217f1e70d350342ce746d7e0e79bbdac..74981a95827d7aafd4cf767599d363575e6a4a99 100644 (file)
@@ -11,8 +11,14 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -20,6 +26,7 @@ import java.util.Comparator;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -36,15 +43,16 @@ import org.opendaylight.yangtools.yang.common.QName;
 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.IdentitySchemaNode;
 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.Module;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
 /**
  * Holds information about runtime bean to be generated. There are two kinds of
@@ -56,6 +64,21 @@ import org.opendaylight.yangtools.yang.model.api.UsesNode;
  * lined via children so that a tree with all beans can be created.
  */
 public class RuntimeBeanEntry {
+
+    private static final Function<SchemaNode, QName> QNAME_FROM_NODE = new Function<SchemaNode, QName>() {
+        @Override
+        public QName apply(final SchemaNode input) {
+            return input.getQName();
+        }
+    };
+
+    private static final Function<UnknownSchemaNode, String> UNKNOWN_NODE_TO_STRING = new Function<UnknownSchemaNode, String>() {
+        @Override
+        public String apply(final UnknownSchemaNode input) {
+            return input.getQName().getLocalName() + input.getNodeParameter();
+        }
+    };
+
     private final String packageName;
     private final String yangName, javaNamePrefix;
     private final boolean isRoot;
@@ -112,13 +135,12 @@ public class RuntimeBeanEntry {
     public static Map<String, RuntimeBeanEntry> extractClassNameToRuntimeBeanMap(
             final String packageName, final DataNodeContainer container,
             final String moduleYangName, final TypeProviderWrapper typeProviderWrapper,
-            final String javaNamePrefix, final Module currentModule) {
+            final String javaNamePrefix, final Module currentModule, final SchemaContext schemaContext) {
 
-        Map<QName, Set<RpcDefinition>> identitiesToRpcs = getIdentitiesToRpcs(currentModule);
 
         AttributesRpcsAndRuntimeBeans attributesRpcsAndRuntimeBeans = extractSubtree(
                 packageName, container, typeProviderWrapper, currentModule,
-                identitiesToRpcs);
+                schemaContext);
         Map<String, RuntimeBeanEntry> result = new HashMap<>();
 
         List<AttributeIfc> attributes;
@@ -150,52 +172,41 @@ public class RuntimeBeanEntry {
         return result;
     }
 
-    private static Map<QName/* of identity */, Set<RpcDefinition>> getIdentitiesToRpcs(
-            final Module currentModule) {
-        // currently only looks for local identities (found in currentModule)
-        Map<QName, Set<RpcDefinition>> result = new HashMap<>();
-        for (IdentitySchemaNode identity : currentModule.getIdentities()) {
-            // add all
-            result.put(identity.getQName(), new HashSet<RpcDefinition>());
-        }
+    private static Multimap<QName/* of identity */, RpcDefinition> getIdentitiesToRpcs(
+            final SchemaContext schemaCtx) {
+        Multimap<QName, RpcDefinition> result = HashMultimap.create();
+        for (Module currentModule : schemaCtx.getModules()) {
 
-        for (RpcDefinition rpc : currentModule.getRpcs()) {
-            ContainerSchemaNode input = rpc.getInput();
-            if (input != null) {
-                for (UsesNode uses : input.getUses()) {
+            // Find all identities in current module for later identity->rpc mapping
+            Set<QName> allIdentitiesInModule = Sets.newHashSet(Collections2.transform(currentModule.getIdentities(), QNAME_FROM_NODE));
 
-                    if (uses.getGroupingPath().getPath().size() != 1) {
-                        continue;
-                    }
+            for (RpcDefinition rpc : currentModule.getRpcs()) {
+                ContainerSchemaNode input = rpc.getInput();
+                if (input != null) {
+                    for (UsesNode uses : input.getUses()) {
 
-                    // check grouping path
-                    QName qname = uses.getGroupingPath().getPath().get(0);
-                    if (false == qname
-                            .equals(ConfigConstants.RPC_CONTEXT_REF_GROUPING_QNAME)) {
-                        continue;
-                    }
+                        // Check if the rpc is config rpc by looking for input argument rpc-context-ref
+                        Iterator<QName> pathFromRoot = uses.getGroupingPath().getPathFromRoot().iterator();
+                        if (!pathFromRoot.hasNext() ||
+                                !pathFromRoot.next().equals(ConfigConstants.RPC_CONTEXT_REF_GROUPING_QNAME)) {
+                            continue;
+                        }
 
-                    for (SchemaNode refinedNode : uses.getRefines().values()) {
-
-                        for (UnknownSchemaNode unknownSchemaNode : refinedNode
-                                .getUnknownSchemaNodes()) {
-                            if (ConfigConstants.RPC_CONTEXT_INSTANCE_EXTENSION_QNAME
-                                    .equals(unknownSchemaNode.getNodeType())) {
-                                String localIdentityName = unknownSchemaNode
-                                        .getNodeParameter();
-                                QName identityQName = QName.create(
-                                        currentModule.getNamespace(),
-                                        currentModule.getRevision(),
-                                        localIdentityName);
-                                Set<RpcDefinition> rpcDefinitions = result
-                                        .get(identityQName);
-                                if (rpcDefinitions == null) {
-                                    throw new IllegalArgumentException(
-                                            "Identity referenced by rpc not found. Identity:"
-                                                    + localIdentityName + " , rpc "
-                                                    + rpc);
+                        for (SchemaNode refinedNode : uses.getRefines().values()) {
+                            for (UnknownSchemaNode unknownSchemaNode : refinedNode
+                                    .getUnknownSchemaNodes()) {
+                                if (ConfigConstants.RPC_CONTEXT_INSTANCE_EXTENSION_QNAME
+                                        .equals(unknownSchemaNode.getNodeType())) {
+                                    String localIdentityName = unknownSchemaNode
+                                            .getNodeParameter();
+                                    QName identityQName = QName.create(
+                                            currentModule.getNamespace(),
+                                            currentModule.getRevision(),
+                                            localIdentityName);
+                                    Preconditions.checkArgument(allIdentitiesInModule.contains(identityQName),
+                                            "Identity referenced by rpc not found. Identity: %s, rpc: %s", localIdentityName, rpc);
+                                    result.put(identityQName, rpc);
                                 }
-                                rpcDefinitions.add(rpc);
                             }
                         }
                     }
@@ -212,7 +223,9 @@ public class RuntimeBeanEntry {
     private static AttributesRpcsAndRuntimeBeans extractSubtree(
             final String packageName, final DataNodeContainer subtree,
             final TypeProviderWrapper typeProviderWrapper, final Module currentModule,
-            final Map<QName, Set<RpcDefinition>> identitiesToRpcs) {
+            final SchemaContext ctx) {
+
+        Multimap<QName, RpcDefinition> identitiesToRpcs = getIdentitiesToRpcs(ctx);
 
         List<AttributeIfc> attributes = Lists.newArrayList();
         List<RuntimeBeanEntry> runtimeBeanEntries = new ArrayList<>();
@@ -234,7 +247,7 @@ public class RuntimeBeanEntry {
                     ListSchemaNode listSchemaNode = (ListSchemaNode) child;
                     RuntimeBeanEntry hierarchicalChild = createHierarchical(
                             packageName, listSchemaNode, typeProviderWrapper,
-                            currentModule, identitiesToRpcs);
+                            currentModule, ctx);
                     runtimeBeanEntries.add(hierarchicalChild);
                 } else /* ordinary list attribute */{
                     ListAttribute listAttribute = ListAttribute.create(
@@ -258,18 +271,11 @@ public class RuntimeBeanEntry {
             if (ConfigConstants.RPC_CONTEXT_INSTANCE_EXTENSION_QNAME
                     .equals(unknownSchemaNode.getNodeType())) {
                 String localIdentityName = unknownSchemaNode.getNodeParameter();
-                QName identityQName = QName.create(currentModule.getNamespace(),
-                        currentModule.getRevision(), localIdentityName);
-                Set<RpcDefinition> rpcDefinitions = identitiesToRpcs
-                        .get(identityQName);
-                if (rpcDefinitions == null) {
-                    throw new IllegalArgumentException("Cannot find identity "
-                            + localIdentityName + " to be used as "
-                            + "context reference when resolving "
-                            + unknownSchemaNode);
-                }
+                QName identityQName = unknownSchemaNode.isAddedByUses() ?
+                        findQNameFromGrouping(subtree, ctx, unknownSchemaNode, localIdentityName) :
+                        QName.create(currentModule.getNamespace(), currentModule.getRevision(), localIdentityName);
                 // convert RpcDefinition to Rpc
-                for (RpcDefinition rpcDefinition : rpcDefinitions) {
+                for (RpcDefinition rpcDefinition : identitiesToRpcs.get(identityQName)) {
                     String name = TypeProviderWrapper
                             .findJavaParameter(rpcDefinition);
                     AttributeIfc returnType;
@@ -310,6 +316,22 @@ public class RuntimeBeanEntry {
                 attributes, rpcs);
     }
 
+    /**
+     * Find "proper" qname of unknown node in case it comes from a grouping
+     */
+    private static QName findQNameFromGrouping(final DataNodeContainer subtree, final SchemaContext ctx, final UnknownSchemaNode unknownSchemaNode, final String localIdentityName) {
+        QName identityQName = null;
+        for (UsesNode usesNode : subtree.getUses()) {
+            SchemaNode dataChildByName = SchemaContextUtil.findDataSchemaNode(ctx, usesNode.getGroupingPath());
+            Module m = SchemaContextUtil.findParentModule(ctx, dataChildByName);
+            List<UnknownSchemaNode> unknownSchemaNodes = dataChildByName.getUnknownSchemaNodes();
+            if(Collections2.transform(unknownSchemaNodes, UNKNOWN_NODE_TO_STRING).contains(UNKNOWN_NODE_TO_STRING.apply(unknownSchemaNode))) {
+                identityQName = QName.create(dataChildByName.getQName(), localIdentityName);
+            }
+        }
+        return identityQName;
+    }
+
     private static AttributeIfc getReturnTypeAttribute(final DataSchemaNode child, final TypeProviderWrapper typeProviderWrapper,
             final String packageName) {
         if (child instanceof LeafSchemaNode) {
@@ -353,13 +375,13 @@ public class RuntimeBeanEntry {
     private static RuntimeBeanEntry createHierarchical(final String packageName,
             final ListSchemaNode listSchemaNode,
             final TypeProviderWrapper typeProviderWrapper, final Module currentModule,
-            final Map<QName, Set<RpcDefinition>> identitiesToRpcs) {
+            final SchemaContext ctx) {
 
         // supported are numeric types, strings, enums
         // get all attributes
         AttributesRpcsAndRuntimeBeans attributesRpcsAndRuntimeBeans = extractSubtree(
                 packageName, listSchemaNode, typeProviderWrapper,
-                currentModule, identitiesToRpcs);
+                currentModule, ctx);
 
         Optional<String> keyYangName;
         if (listSchemaNode.getKeyDefinition().isEmpty()) {
index 1503b84d64a263dff2654cb13c6fb46a7ea08fa2..98b1f752afbbe669a8dd01448b6609b751b1f461 100644 (file)
@@ -52,7 +52,7 @@ public class RuntimeBeanEntryTest extends AbstractYangTest {
                 .getUnknownSchemaNodes();
         Map<String, RuntimeBeanEntry> runtimeBeans = RuntimeBeanEntry
                 .extractClassNameToRuntimeBeanMap(PACKAGE_NAME, caseNode, "test-name", new TypeProviderWrapper(new
-                        TypeProviderImpl(context)), "test", jmxImplModule);
+                        TypeProviderImpl(context)), "test", jmxImplModule, context);
         assertEquals(1, runtimeBeans.size());
         RuntimeBeanEntry runtimeMXBean = runtimeBeans.get("testRuntimeMXBean");
         assertTrue(runtimeMXBean.isRoot());
index 5e37f5afcfe4cd8a1f15b78e6e878ea766b29bd1..2428b10941ee4c2a47f47d6f3f8a109c6fe05a14 100644 (file)
@@ -11,6 +11,7 @@
 package org.opendaylight.controller.config.yang.test.util;
 
 import com.google.common.collect.Lists;
+import java.math.BigInteger;
 import java.util.List;
 import org.opendaylight.controller.config.yang.test.impl.Asdf;
 import org.opendaylight.controller.config.yang.test.impl.Deep2;
@@ -43,11 +44,36 @@ public class NetconfTestImplModuleUtil {
                 return asdf;
             }
 
+            @Override
+            public BigInteger getCommonStat() {
+                return new BigInteger("54");
+            }
+
             @Override
             public String noArg(final String arg1) {
                 return arg1.toUpperCase();
             }
 
+            @Override
+            public Long commonRpcTwo() {
+                return 1L;
+            }
+
+            @Override
+            public String commonRpcThree() {
+                return "true";
+            }
+
+            @Override
+            public Boolean commonRpc() {
+                return true;
+            }
+
+            @Override
+            public void netconfImplRpcFromGrouping() {
+                // rpc from grouping within same yang module
+            }
+
         });
 
         for (int i = 0; i < module.getSimpleShort(); i++) {
index e7aa64d7a621cc5ecdfa4781c6389e576b7865c1..093d7b3f13673f0f0799030fe35c70597db7ba1e 100644 (file)
@@ -8,6 +8,7 @@ module config-test-impl {
     import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
     import rpc-context { prefix rpcx; revision-date 2013-06-17; }
     import test-types { prefix tt; revision-date 2013-11-27; }
+    import test-groups { prefix tg; revision-date 2014-12-08; }
 
     description
         "Testing IMPL";
@@ -347,6 +348,22 @@ module config-test-impl {
         }
     }
 
+    grouping netconf-impl-rpc {
+       rpcx:rpc-context-instance netconf-impl-rpc-ctx;
+    }
+
+    identity netconf-impl-rpc-ctx;
+
+    rpc netconf-impl-rpc-from-grouping {
+        input {
+            uses rpcx:rpc-context-ref {
+                refine context-instance {
+                    rpcx:rpc-context-instance "netconf-impl-rpc-ctx";
+                }
+            }
+        }
+    }
+
     augment "/config:modules/config:module/config:state" {
         case impl-netconf {
             when "/config:modules/config:module/config:type = 'impl-netconf'";
@@ -354,6 +371,11 @@ module config-test-impl {
                 // rpc
                 rpcx:rpc-context-instance "test-rpc";
 
+                // add some stats + rpc from groupings outside this module
+                uses tt:common-operational;
+                uses tg:common-operational-rpc;
+                uses netconf-impl-rpc;
+
                 // root runtime bean
                 leaf created-sessions {
                     type uint32;
diff --git a/opendaylight/config/yang-test/src/main/yang/types/test-groups.yang b/opendaylight/config/yang-test/src/main/yang/types/test-groups.yang
new file mode 100644 (file)
index 0000000..00f704b
--- /dev/null
@@ -0,0 +1,52 @@
+module test-groups {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:test:groups";
+    prefix "tg";
+
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
+    description
+        "Groupings generated for testing";
+
+    revision "2014-12-08";
+
+    grouping common-operational-rpc {
+        rpcx:rpc-context-instance common-rpc-ctx;
+        rpcx:rpc-context-instance common-rpc-ctx-two;
+    }
+
+    identity common-rpc-ctx;
+    identity common-rpc-ctx-two;
+
+    rpc common-rpc {
+        input {
+            uses rpcx:rpc-context-ref {
+                refine context-instance {
+                    rpcx:rpc-context-instance "common-rpc-ctx";
+                }
+            }
+        }
+
+        output {
+            leaf output {
+                type boolean;
+            }
+        }
+    }
+
+    rpc common-rpc-two {
+        input {
+            uses rpcx:rpc-context-ref {
+                refine context-instance {
+                    rpcx:rpc-context-instance "common-rpc-ctx-two";
+                }
+            }
+        }
+
+        output {
+            leaf output {
+                type uint32;
+            }
+        }
+    }
+}
index df5387be2c1f2581e2a44872ef596e62ec76d628..ee466b4034335d94a8cb15841354619f29f219e3 100644 (file)
@@ -3,6 +3,8 @@ module test-types {
     namespace "urn:opendaylight:params:xml:ns:yang:controller:config:test:types";
     prefix "tt";
 
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
     description
         "Types generated for testing";
 
@@ -40,4 +42,34 @@ module test-types {
     identity test-identity2 {
         base test-identity1;
     }
+
+    grouping common-operational {
+       leaf common-stat {
+           type uint64;
+       }
+       // This would not work, since it clashes with identity common-rpc-ctx from test-groups
+       // Both grouping add the same unknown node "rpcx:rpc-context-instance common-rpc-ctx-three;"
+       // and we cannot match the unknown node to the grouping that added it
+       //rpcx:rpc-context-instance common-rpc-ctx-three;
+       rpcx:rpc-context-instance common-rpc-ctx-three;
+    }
+
+    //identity common-rpc-ctx;
+    identity common-rpc-ctx-three;
+
+    rpc common-rpc-three {
+        input {
+            uses rpcx:rpc-context-ref {
+                refine context-instance {
+                    rpcx:rpc-context-instance "common-rpc-ctx-three";
+                }
+            }
+        }
+
+        output {
+            leaf output {
+                type string;
+            }
+        }
+    }
 }
index 5ed528e9bfe8c5144a5c96698bc234248d5fecac..beb3365f1c068487ddfb5cbb70883cb81ff14776 100644 (file)
@@ -712,7 +712,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
     private List<InputStream> getYangs() throws FileNotFoundException {
         List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
                 "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang", "/META-INF/yang/test-types.yang",
-                "/META-INF/yang/ietf-inet-types.yang");
+                "/META-INF/yang/test-groups.yang", "/META-INF/yang/ietf-inet-types.yang");
         final Collection<InputStream> yangDependencies = new ArrayList<>();
         for (String path : paths) {
             final InputStream is = Preconditions
index a724d1d9c5e4e8b6cec46cdb94f98a7158c48407..65810a6bdab8d840919e9f25b1d0961b499d0566 100644 (file)
@@ -187,6 +187,7 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
                 "/META-INF/yang/config-test.yang",
                 "/META-INF/yang/config-test-impl.yang",
                 "/META-INF/yang/test-types.yang",
+                "/META-INF/yang/test-groups.yang",
                 "/META-INF/yang/ietf-inet-types.yang");
 
         final Collection<InputStream> yangDependencies = new ArrayList<>();
index cc170358dd2c0e5e82fbbb644c889ebf9dc5c7ee..92c96d92f28962eeb88ccc961665d852cd39364c 100644 (file)
@@ -112,8 +112,8 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
         }
 
         notificationVerifier.assertNotificationCount(2);
-        notificationVerifier.assertNotificationContent(0, 0, 0, 8);
-        notificationVerifier.assertNotificationContent(1, 4, 3, 8);
+        notificationVerifier.assertNotificationContent(0, 0, 0, 9);
+        notificationVerifier.assertNotificationContent(1, 4, 3, 9);
 
         mockedAggregator.assertSnapshotCount(2);
         // Capabilities are stripped for persister