From 8eb2fc510df912207d98589b82a22d84bf8ada66 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Tue, 25 Nov 2014 18:02:02 +0100 Subject: [PATCH] Allow rpc definition for RuntimeMXBeans to come from groupings Change-Id: I796b43e8a4b01277bcb0c73f5ac86bc710839061 Signed-off-by: Maros Marsalek --- .../config/yang-jmx-generator/pom.xml | 4 + .../ModuleMXBeanEntryBuilder.java | 2 +- .../yangjmxgenerator/RuntimeBeanEntry.java | 142 ++++++++++-------- .../RuntimeBeanEntryTest.java | 2 +- .../test/util/NetconfTestImplModuleUtil.java | 26 ++++ .../src/main/yang/config-test-impl.yang | 22 +++ .../src/main/yang/types/test-groups.yang | 52 +++++++ .../src/main/yang/types/test-types.yang | 32 ++++ .../NetconfMappingTest.java | 2 +- .../netconf/it/AbstractNetconfConfigTest.java | 1 + .../it/NetconfConfigPersisterITTest.java | 4 +- 11 files changed, 224 insertions(+), 65 deletions(-) create mode 100644 opendaylight/config/yang-test/src/main/yang/types/test-groups.yang diff --git a/opendaylight/config/yang-jmx-generator/pom.xml b/opendaylight/config/yang-jmx-generator/pom.xml index 979b39688b..bfeb3f0f7a 100644 --- a/opendaylight/config/yang-jmx-generator/pom.xml +++ b/opendaylight/config/yang-jmx-generator/pom.xml @@ -34,6 +34,10 @@ org.opendaylight.yangtools binding-type-provider + + org.opendaylight.yangtools + yang-model-util + org.opendaylight.yangtools diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java index 80db46df2b..ed727c9a13 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java @@ -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(); } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java index b6ed824321..74981a9582 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java @@ -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 QNAME_FROM_NODE = new Function() { + @Override + public QName apply(final SchemaNode input) { + return input.getQName(); + } + }; + + private static final Function UNKNOWN_NODE_TO_STRING = new Function() { + @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 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> identitiesToRpcs = getIdentitiesToRpcs(currentModule); AttributesRpcsAndRuntimeBeans attributesRpcsAndRuntimeBeans = extractSubtree( packageName, container, typeProviderWrapper, currentModule, - identitiesToRpcs); + schemaContext); Map result = new HashMap<>(); List attributes; @@ -150,52 +172,41 @@ public class RuntimeBeanEntry { return result; } - private static Map> getIdentitiesToRpcs( - final Module currentModule) { - // currently only looks for local identities (found in currentModule) - Map> result = new HashMap<>(); - for (IdentitySchemaNode identity : currentModule.getIdentities()) { - // add all - result.put(identity.getQName(), new HashSet()); - } + private static Multimap getIdentitiesToRpcs( + final SchemaContext schemaCtx) { + Multimap 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 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 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 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> identitiesToRpcs) { + final SchemaContext ctx) { + + Multimap identitiesToRpcs = getIdentitiesToRpcs(ctx); List attributes = Lists.newArrayList(); List 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 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 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> identitiesToRpcs) { + final SchemaContext ctx) { // supported are numeric types, strings, enums // get all attributes AttributesRpcsAndRuntimeBeans attributesRpcsAndRuntimeBeans = extractSubtree( packageName, listSchemaNode, typeProviderWrapper, - currentModule, identitiesToRpcs); + currentModule, ctx); Optional keyYangName; if (listSchemaNode.getKeyDefinition().isEmpty()) { diff --git a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java index 1503b84d64..98b1f752af 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java +++ b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java @@ -52,7 +52,7 @@ public class RuntimeBeanEntryTest extends AbstractYangTest { .getUnknownSchemaNodes(); Map 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()); diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/util/NetconfTestImplModuleUtil.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/util/NetconfTestImplModuleUtil.java index 5e37f5afcf..2428b10941 100644 --- a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/util/NetconfTestImplModuleUtil.java +++ b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/util/NetconfTestImplModuleUtil.java @@ -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++) { diff --git a/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang b/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang index e7aa64d7a6..093d7b3f13 100644 --- a/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang +++ b/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang @@ -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 index 0000000000..00f704bed6 --- /dev/null +++ b/opendaylight/config/yang-test/src/main/yang/types/test-groups.yang @@ -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; + } + } + } +} diff --git a/opendaylight/config/yang-test/src/main/yang/types/test-types.yang b/opendaylight/config/yang-test/src/main/yang/types/test-types.yang index df5387be2c..ee466b4034 100644 --- a/opendaylight/config/yang-test/src/main/yang/types/test-types.yang +++ b/opendaylight/config/yang-test/src/main/yang/types/test-types.yang @@ -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; + } + } + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index 5ed528e9bf..beb3365f1c 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -712,7 +712,7 @@ public class NetconfMappingTest extends AbstractConfigTest { private List getYangs() throws FileNotFoundException { List 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 yangDependencies = new ArrayList<>(); for (String path : paths) { final InputStream is = Preconditions diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java index a724d1d9c5..65810a6bda 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java @@ -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 yangDependencies = new ArrayList<>(); diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java index cc170358dd..92c96d92f2 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java @@ -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 -- 2.36.6