From: Maros Marsalek Date: Mon, 16 Dec 2013 11:15:11 +0000 (+0100) Subject: Fix list of dependencies mapping for readable/writable jmx wrappers X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~175^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=e278727eef66cfa1f16bd8c78ac1718e744b774d Fix list of dependencies mapping for readable/writable jmx wrappers Attributes for list of dependencies can be accessed from (testing) code Change-Id: I966912210a74bef40a7e6a74d506dbc72a41f34c Signed-off-by: Maros Marsalek --- diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java index ba2c1089c2..6f0d1b2682 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java @@ -7,16 +7,14 @@ */ package org.opendaylight.controller.config.manager.impl.dynamicmbean; -import static java.lang.String.format; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.annotations.Description; +import org.opendaylight.controller.config.api.annotations.RequireInterface; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; +import org.opendaylight.controller.config.spi.Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.management.Attribute; import javax.management.AttributeList; @@ -40,15 +38,17 @@ import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.ReflectionException; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.opendaylight.controller.config.api.annotations.Description; -import org.opendaylight.controller.config.api.annotations.RequireInterface; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; -import org.opendaylight.controller.config.spi.Module; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.lang.String.format; /** * Contains common code for readable/rw dynamic mbean wrappers. Routes all @@ -246,6 +246,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } catch (InstanceNotFoundException e) { new MBeanException(e); } + if (obj instanceof ObjectName) { AttributeHolder attributeHolder = attributeHolderMap .get(attributeName); @@ -254,8 +255,42 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } return obj; } + + + if(isDependencyListAttr(attributeName, obj)) { + obj = fixDependencyListAttribute(obj); + } + return obj; + } + + private Object fixDependencyListAttribute(Object attribute) { + if(attribute.getClass().isArray() == false) + throw new IllegalArgumentException("Unexpected attribute type, should be an array, but was " + attribute.getClass()); + + for (int i = 0; i < Array.getLength(attribute); i++) { + + Object on = Array.get(attribute, i); + if(on instanceof ObjectName == false) + throw new IllegalArgumentException("Unexpected attribute type, should be an ObjectName, but was " + on.getClass()); + on = fixObjectName((ObjectName) on); + + Array.set(attribute, i, on); + } + + return attribute; + } + + private boolean isDependencyListAttr(String attributeName, Object attribute) { + if (attributeHolderMap.containsKey(attributeName) == false) + return false; + + AttributeHolder attributeHolder = attributeHolderMap.get(attributeName); + boolean isDepList = true; + isDepList &= attributeHolder.getRequireInterfaceOrNull() != null; + isDepList &= attribute instanceof ObjectName[]; + return isDepList; } protected ObjectName fixObjectName(ObjectName on) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java index 109ab10ac2..9dd6a2269e 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java @@ -7,18 +7,17 @@ */ package org.opendaylight.controller.config.manager.impl.dynamicmbean; -import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import org.opendaylight.controller.config.api.annotations.Description; +import org.opendaylight.controller.config.api.annotations.RequireInterface; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.management.MBeanAttributeInfo; import javax.management.ObjectName; - -import org.opendaylight.controller.config.api.annotations.Description; -import org.opendaylight.controller.config.api.annotations.RequireInterface; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.List; +import java.util.Set; @Immutable class AttributeHolder { @@ -32,6 +31,14 @@ class AttributeHolder { private final RequireInterface requireInterfaceAnnotation; private final String attributeType; + public static final Set> PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER = new HashSet<>(); + + static { + PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(ObjectName.class); + PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(ObjectName[].class); + PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(List.class); + } + public AttributeHolder(String name, Object object, String returnType, boolean writable, @Nullable RequireInterface requireInterfaceAnnotation, @@ -114,12 +121,12 @@ class AttributeHolder { static RequireInterface findRequireInterfaceAnnotation(final Method setter, Set> inspectedInterfaces) { - // only allow setX(ObjectName y) or setX(ObjectName[] y) to continue - if (setter.getParameterTypes().length != 1 - || (setter.getParameterTypes()[0].equals(ObjectName.class) == false && setter - .getParameterTypes()[0].equals(ObjectName[].class) == false)) { + // only allow setX(ObjectName y) or setX(ObjectName[] y) or setX(List y) to continue + + if (setter.getParameterTypes().length > 1) + return null; + if(PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false) return null; - } List foundRequireInterfaces = AnnotationsHelper .findMethodAnnotationInSuperClassesAndIfcs(setter, RequireInterface.class, inspectedInterfaces); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java index a1cd6b0133..2ab04e53e3 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java @@ -7,7 +7,13 @@ */ package org.opendaylight.controller.config.manager.impl.dynamicmbean; -import java.lang.reflect.Method; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.TransactionIdentifier; +import org.opendaylight.controller.config.spi.Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.concurrent.ThreadSafe; import javax.management.Attribute; @@ -20,14 +26,7 @@ import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.ReflectionException; - -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.opendaylight.controller.config.api.ValidationException; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.TransactionIdentifier; -import org.opendaylight.controller.config.spi.Module; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.lang.reflect.Method; /** * Wraps {@link org.opendaylight.controller.config.spi.Module} instance in a @@ -92,16 +91,11 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { try { if (attribute.getValue() instanceof ObjectName) { - AttributeHolder attributeHolder = attributeHolderMap - .get(attribute.getName()); - if (attributeHolder.getRequireInterfaceOrNull() != null) { - attribute = new Attribute(attribute.getName(), - fixObjectName((ObjectName) attribute.getValue())); - } else { - attribute = new Attribute(attribute.getName(), - attribute.getValue()); - } + attribute = fixDependencyAttribute(attribute); + } else if(attribute.getValue() instanceof ObjectName[]) { + attribute = fixDependencyListAttribute(attribute); } + internalServer.setAttribute(objectNameInternal, attribute); } catch (InstanceNotFoundException e) { throw new MBeanException(e); @@ -109,6 +103,39 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { } + private Attribute fixDependencyListAttribute(Attribute attribute) { + AttributeHolder attributeHolder = attributeHolderMap + .get(attribute.getName()); + if (attributeHolder.getRequireInterfaceOrNull() != null) { + attribute = new Attribute(attribute.getName(), + fixObjectNames((ObjectName[]) attribute.getValue())); + } + return attribute; + } + + private Attribute fixDependencyAttribute(Attribute attribute) { + AttributeHolder attributeHolder = attributeHolderMap + .get(attribute.getName()); + if (attributeHolder.getRequireInterfaceOrNull() != null) { + attribute = new Attribute(attribute.getName(), + fixObjectName((ObjectName) attribute.getValue())); + } else { + attribute = new Attribute(attribute.getName(), + attribute.getValue()); + } + return attribute; + } + + private ObjectName[] fixObjectNames(ObjectName[] dependencies) { + int i = 0; + + for (ObjectName dependencyOn : dependencies) { + dependencies[i++] = fixObjectName(dependencyOn); + } + + return dependencies; + } + @Override public AttributeList setAttributes(AttributeList attributes) { AttributeList result = new AttributeList(); diff --git a/opendaylight/config/yang-test/pom.xml b/opendaylight/config/yang-test/pom.xml index 149348df4b..b1f7013abe 100644 --- a/opendaylight/config/yang-test/pom.xml +++ b/opendaylight/config/yang-test/pom.xml @@ -30,8 +30,34 @@ slf4j-api - org.opendaylight.yangtools.model - ietf-inet-types + org.opendaylight.yangtools.model + ietf-inet-types + + + org.opendaylight.bgpcep + mockito-configuration + test + + + ${project.groupId} + config-manager + test + + + ${project.groupId} + config-manager + test-jar + test + + + org.opendaylight.controller + config-util + test + + + junit + junit + test diff --git a/opendaylight/config/yang-test/src/test/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleTest.java b/opendaylight/config/yang-test/src/test/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleTest.java new file mode 100644 index 0000000000..50e1d4bb6a --- /dev/null +++ b/opendaylight/config/yang-test/src/test/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleTest.java @@ -0,0 +1,89 @@ +package org.opendaylight.controller.config.yang.test.impl; + +import com.google.common.collect.Lists; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; +import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; +import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.List; + +public class NetconfTestImplModuleTest extends AbstractConfigTest { + + public static final String TESTING_DEP_PREFIX = "testing-dep"; + private NetconfTestImplModuleFactory factory; + private final String instanceName = "n1"; + + @Before + public void setUp() { + + factory = new NetconfTestImplModuleFactory(); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory, + new DepTestImplModuleFactory())); + } + + @Test + public void testDependencyList() throws InstanceAlreadyExistsException, ValidationException, + ConflictingVersionException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + + ObjectName on = createInstance(transaction, instanceName, 4); + transaction.validateConfig(); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertBeanCount(4 + 1, DepTestImplModuleFactory.NAME); + assertStatus(status, 1 + 4 + 1, 0, 0); + + transaction = configRegistryClient.createTransaction(); + + NetconfTestImplModuleMXBean proxy = transaction.newMXBeanProxy(ObjectNameUtil.withoutTransactionName(on), + NetconfTestImplModuleMXBean.class); + proxy.getComplexList(); + List testingDeps = proxy.getTestingDeps(); + ObjectName testingDep = proxy.getTestingDep(); + + Assert.assertEquals(TESTING_DEP_PREFIX, ObjectNameUtil.getInstanceName(testingDep)); + assertTestingDeps(testingDeps, 4); + + transaction.abortConfig(); + } + + private void assertTestingDeps(List testingDeps, int i) { + Assert.assertEquals(i, testingDeps.size()); + + int c = 1; + for (ObjectName testingDep : testingDeps) { + Assert.assertEquals(TESTING_DEP_PREFIX + Integer.toString(c++), ObjectNameUtil.getInstanceName(testingDep)); + } + } + + + private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName, int depsCount) + throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName); + NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, NetconfTestImplModuleMXBean.class); + + ObjectName dep = transaction.createModule(DepTestImplModuleFactory.NAME, TESTING_DEP_PREFIX); + mxBean.setTestingDep(dep); + + ArrayList testingDeps = Lists.newArrayList(); + for (int i = 0; i < depsCount; i++) { + dep = transaction.createModule(DepTestImplModuleFactory.NAME, TESTING_DEP_PREFIX + Integer.toString(i + 1)); + testingDeps.add(dep); + } + mxBean.setTestingDeps(testingDeps); + + return nameCreated; + } + +}