*/
package org.opendaylight.controller.config.api;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import javax.management.ObjectName;
-
/**
* Each new {@link org.opendaylight.controller.config.spi.Module} can receive
* resolver from {@link org.opendaylight.controller.config.spi.ModuleFactory}
* To be used during validation phase to validate serice interface of
* dependent module.
*
- * @param expectedServiceInterface
- * MBean/MXBean interface which will back the proxy object.
- * @param objectName
- * ObjectName of dependent module without transaction name
- * (platformON).
- * @param jmxAttribute
- * @throws {@link IllegalArgumentException} when module is not found
- * @throws {@link IllegalStateException} if module does not export this
- * service interface.
+ * @param expectedServiceInterface MBean/MXBean interface which will back the proxy object.
+ * @param objectName ObjectName of dependent module without transaction name
+ * (platformON).
+ * @param jmxAttribute for reporting
+ * @throws IllegalArgumentException when module is not found
+ * @throws IllegalStateException if module does not export this
+ * service interface.
*/
void validateDependency(
Class<? extends AbstractServiceInterface> expectedServiceInterface,
* To be used during commit phase to wire actual dependencies.
*
* @return dependency instance using
- * {@link org.opendaylight.controller.config.spi.Module#getInstance()}
- * @throws {@link IllegalArgumentException} when module is not found
+ * {@link org.opendaylight.controller.config.spi.Module#getInstance()}
+ * @throws IllegalArgumentException when module is not found
*/
<T> T resolveInstance(Class<T> expectedType, ObjectName objectName,
- JmxAttribute jmxAttribute);
-
- // TODO finish javadoc
+ JmxAttribute jmxAttribute);
/**
* To be used during commit phase to resolve identity-ref config attributes.
*/
<T extends BaseIdentity> Class<? extends T> resolveIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass);
+
+ /**
+ * Validate identity-ref config attribute.
+ */
<T extends BaseIdentity> void validateIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass, JmxAttribute jmxAttribute);
+ /**
+ * Can be used during validation or commit phase to get attribute value of dependent module.
+ *
+ * @param name either direct ObjectName of a Module (type=Module) or service reference (type=ServiceReference) of dependent Module
+ * @param attribute String identifying attribute name in JMX. Note that attributes start with upper case. See {@link org.opendaylight.controller.config.api.JmxAttribute#getAttributeName()}
+ */
+ Object getAttribute(ObjectName name, String attribute)
+ throws MBeanException, AttributeNotFoundException,
+ InstanceNotFoundException, ReflectionException;
+
+
+ /**
+ * Helper method around {@link javax.management.JMX#newMXBeanProxy(javax.management.MBeanServerConnection, javax.management.ObjectName, Class)} }.
+ * Returns MXBean proxy for dependent module. Can be used during validation or commit phase to inspect dependent module's attributes.
+ *
+ * @param objectName either direct ObjectName of a Module (type=Module) or service reference (type=ServiceReference) of dependent Module
+ * @param interfaceClass MXBean interface to be used as a proxy
+ * @param <T> type of proxy for type safe return value
+ * @return instance of MXBean proxy
+ */
+ <T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass);
+
}
this.attributeName = attributeName;
}
+ /**
+ * Name of attribute in JMX.
+ */
public String getAttributeName() {
return attributeName;
}
*/
package org.opendaylight.controller.config.manager.impl;
+import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import java.util.ArrayList;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import static com.google.common.base.Preconditions.checkNotNull;
/**
* This is a JMX bean representing current transaction. It contains
* transaction identifier, unique version and parent version for
this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
this.transactionStatus = new TransactionStatus();
this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
- transactionStatus, writableSRRegistry, codecRegistry);
+ transactionStatus, writableSRRegistry, codecRegistry, transactionsMBeanServer);
this.transactionsMBeanServer = transactionsMBeanServer;
this.configMBeanServer = configMBeanServer;
this.blankTransaction = blankTransaction;
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
+import static java.lang.String.format;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.annotation.concurrent.GuardedBy;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.IdentityAttributeRef;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.annotation.concurrent.GuardedBy;
-import javax.management.ObjectName;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import static java.lang.String.format;
-
/**
* Protect {@link org.opendaylight.controller.config.spi.Module#getInstance()}
* by creating proxy that would throw exception if those methods are called
private final Set<ModuleIdentifier> dependencies = new HashSet<>();
private final ServiceReferenceReadableRegistry readableRegistry;
private final CodecRegistry codecRegistry;
+ private final String transactionName;
+ private final MBeanServer mBeanServer;
DependencyResolverImpl(ModuleIdentifier currentModule,
TransactionStatus transactionStatus, ModulesHolder modulesHolder,
- ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
+ ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry,
+ String transactionName, MBeanServer mBeanServer) {
this.codecRegistry = codecRegistry;
this.name = currentModule;
this.transactionStatus = transactionStatus;
this.modulesHolder = modulesHolder;
this.readableRegistry = readableRegistry;
+ this.transactionName = transactionName;
+ this.mBeanServer = mBeanServer;
}
/**
JmxAttributeValidationException.checkNotNull(dependentReadOnlyON,
"is null, expected dependency implementing "
- + expectedServiceInterface, jmxAttribute);
+ + expectedServiceInterface, jmxAttribute
+ );
// check that objectName belongs to this transaction - this should be
JmxAttributeValidationException.checkCondition(
hasTransaction == false,
format("ObjectName should not contain "
- + "transaction name. %s set to %s. ", jmxAttribute,
- dependentReadOnlyON), jmxAttribute);
+ + "transaction name. %s set to %s. ", jmxAttribute,
+ dependentReadOnlyON
+ ), jmxAttribute
+ );
dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+ "attribute %s",
foundFactory.getImplementationName(), foundFactory,
expectedServiceInterface, dependentReadOnlyON,
- jmxAttribute);
+ jmxAttribute
+ );
throw new JmxAttributeValidationException(message, jmxAttribute);
}
synchronized (this) {
String message = format(
"Error while %s resolving instance %s. getInstance() returned null. "
+ "Expected type %s , attribute %s", name,
- dependentModuleIdentifier, expectedType, jmxAttribute);
+ dependentModuleIdentifier, expectedType, jmxAttribute
+ );
throw new JmxAttributeValidationException(message, jmxAttribute);
}
try {
String message = format(
"Instance cannot be cast to expected type. Instance class is %s , "
+ "expected type %s , attribute %s",
- instance.getClass(), expectedType, jmxAttribute);
+ instance.getClass(), expectedType, jmxAttribute
+ );
throw new JmxAttributeValidationException(message, e, jmxAttribute);
}
}
return name;
}
+ @Override
+ public Object getAttribute(ObjectName name, String attribute)
+ throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
+ name = translateServiceRefIfPossible(name);
+ // add transaction name
+ name = ObjectNameUtil.withTransactionName(name, transactionName);
+ return mBeanServer.getAttribute(name, attribute);
+ }
+
+ @Override
+ public <T> T newMXBeanProxy(ObjectName name, Class<T> interfaceClass) {
+ name = translateServiceRefIfPossible(name);
+ // add transaction name
+ name = ObjectNameUtil.withTransactionName(name, transactionName);
+ return JMX.newMXBeanProxy(mBeanServer, name, interfaceClass);
+ }
}
import java.util.Map;
import javax.annotation.concurrent.GuardedBy;
import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.JmxAttribute;
public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
@GuardedBy("this")
private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
+ private final TransactionIdentifier transactionIdentifier;
private final ModulesHolder modulesHolder;
private final TransactionStatus transactionStatus;
private final ServiceReferenceReadableRegistry readableRegistry;
private final CodecRegistry codecRegistry;
private final DeadlockMonitor deadlockMonitor;
+ private final MBeanServer mBeanServer;
public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
- TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
+ TransactionStatus transactionStatus,
+ ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry,
+ MBeanServer mBeanServer) {
+ this.transactionIdentifier = transactionIdentifier;
this.modulesHolder = new ModulesHolder(transactionIdentifier);
this.transactionStatus = transactionStatus;
this.readableRegistry = readableRegistry;
this.codecRegistry = codecRegistry;
this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
+ this.mBeanServer = mBeanServer;
}
@Override
DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name);
if (dependencyResolver == null) {
transactionStatus.checkNotCommitted();
- dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry, codecRegistry);
+ dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry,
+ codecRegistry, transactionIdentifier.getName(), mBeanServer);
moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver);
}
return dependencyResolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.AbstractLockedPlatformMBeanServerTest;
import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
import org.opendaylight.controller.config.manager.impl.TransactionStatus;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
-public class DependencyResolverManagerTest {
+public class DependencyResolverManagerTest extends AbstractLockedPlatformMBeanServerTest {
final ModuleIdentifier apspName = new ModuleIdentifier("apsp", "apsp"); // depends
// on:
public void setUp() {
transactionStatus = mock(TransactionStatus.class);
ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
- tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry, null);
+ tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry,
+ null, platformMBeanServer);
doNothing().when(transactionStatus).checkCommitStarted();
doNothing().when(transactionStatus).checkNotCommitted();
}
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.common.base.Strings;
+import java.io.Closeable;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.management.ObjectName;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.annotations.RequireInterface;
import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolIfc;
import org.opendaylight.controller.config.spi.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.management.ObjectName;
-import java.io.Closeable;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
/**
* Represents service that has dependency to thread pool.
*/
checkState("Commit was not triggered".equals(e.getMessage()),
e.getMessage());
}
+
+ // test retrieving dependent module's attribute
+ int threadCount;
+ try {
+ threadCount = (Integer)dependencyResolver.getAttribute(threadPoolON, "ThreadCount");
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ checkState(threadCount > 0);
+ TestingThreadPoolConfigMXBean proxy = dependencyResolver.newMXBeanProxy(threadPoolON, TestingThreadPoolConfigMXBean.class);
+ checkState(threadCount == proxy.getThreadCount());
}
@Override
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.internal.matchers.StringContains.containsString;
+
+import java.util.Map;
+import javax.management.ObjectName;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPImpl;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import javax.management.ObjectName;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.internal.matchers.StringContains.containsString;
-
public class DependentWiringTest extends AbstractParallelAPSPTest {
private final String fixed1 = "fixed1";
private final String apsp1 = "apsp-parallel";
parallelAPSPRuntimeProxy.getMaxNumberOfThreads());
}
+
+ @Test
+ public void testUsingServiceReferences() throws Exception {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName threadPoolON = createFixed1(transaction, 10);
+ transaction.lookupConfigBean(getThreadPoolImplementationName(), fixed1);
+ String refName = "ref";
+ ObjectName serviceReferenceON = transaction.saveServiceReference(TestingThreadPoolServiceInterface.QNAME, refName,
+ threadPoolON);
+ createParallelAPSP(transaction, serviceReferenceON);
+ transaction.commit();
+
+ }
}