X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fconfig%2Fconfig-manager%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fconfig%2Fmanager%2Fimpl%2Fdependencyresolver%2FDependencyResolverImpl.java;h=d667f13ec601e23d6b0cb77447dba63a13c9ec56;hp=760fe50e28f533021684f1d1a0bb25685272fac8;hb=6227570f6482136b72a26675d43c8bb88279503e;hpb=213aae87ecaccb43f3d909e0455db43511ace381 diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java index 760fe50e28..d667f13ec6 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java @@ -7,23 +7,34 @@ */ package org.opendaylight.controller.config.manager.impl.dependencyresolver; +import com.google.common.base.Preconditions; +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.opendaylight.controller.config.api.JmxAttributeValidationException; import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.TransactionStatus; +import org.opendaylight.controller.config.manager.impl.osgi.mapping.BindingContextProvider; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; - -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; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.common.QName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Protect {@link org.opendaylight.controller.config.spi.Module#getInstance()} @@ -31,18 +42,31 @@ import static java.lang.String.format; * during validation. Tracks dependencies for ordering purposes. */ final class DependencyResolverImpl implements DependencyResolver, - Comparable { + Comparable { + private static final Logger LOG = LoggerFactory.getLogger(DependencyResolverImpl.class); + private final ModulesHolder modulesHolder; private final ModuleIdentifier name; private final TransactionStatus transactionStatus; @GuardedBy("this") private final Set dependencies = new HashSet<>(); + private final ServiceReferenceReadableRegistry readableRegistry; + private final BindingContextProvider bindingContextProvider; + private final String transactionName; + private final MBeanServer mBeanServer; + private Integer maxDependencyDepth; DependencyResolverImpl(ModuleIdentifier currentModule, - TransactionStatus transactionStatus, ModulesHolder modulesHolder) { + TransactionStatus transactionStatus, ModulesHolder modulesHolder, + ServiceReferenceReadableRegistry readableRegistry, BindingContextProvider bindingContextProvider, + String transactionName, MBeanServer mBeanServer) { + this.bindingContextProvider = bindingContextProvider; this.name = currentModule; this.transactionStatus = transactionStatus; this.modulesHolder = modulesHolder; + this.readableRegistry = readableRegistry; + this.transactionName = transactionName; + this.mBeanServer = mBeanServer; } /** @@ -52,46 +76,54 @@ final class DependencyResolverImpl implements DependencyResolver, @Override public void validateDependency( Class expectedServiceInterface, - ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) { + ObjectName dependentReadOnlyON, JmxAttribute jmxAttribute) { transactionStatus.checkNotCommitted(); if (expectedServiceInterface == null) { throw new NullPointerException( "Parameter 'expectedServiceInterface' is null"); } - if (jmxAttribute == null) + if (jmxAttribute == null) { throw new NullPointerException("Parameter 'jmxAttribute' is null"); + } + + JmxAttributeValidationException.checkNotNull(dependentReadOnlyON, + "is null, expected dependency implementing " + + expectedServiceInterface, jmxAttribute + ); - JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON, - "is null, " + "expected dependency implementing " - + expectedServiceInterface, jmxAttribute); // check that objectName belongs to this transaction - this should be // stripped // in DynamicWritableWrapper boolean hasTransaction = ObjectNameUtil - .getTransactionName(dependentModuleReadOnlyON) != null; + .getTransactionName(dependentReadOnlyON) != null; JmxAttributeValidationException.checkCondition( - hasTransaction == false, - format("ObjectName should not contain " - + "transaction name. %s set to %s. ", jmxAttribute, - dependentModuleReadOnlyON), jmxAttribute); + !hasTransaction, + String.format("ObjectName should not contain " + + "transaction name. %s set to %s. ", jmxAttribute, + dependentReadOnlyON + ), jmxAttribute + ); + + ObjectName newDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); - ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil + ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(newDependentReadOnlyON, ObjectNameUtil .TYPE_MODULE); ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute); boolean implementsSI = foundFactory .isModuleImplementingServiceInterface(expectedServiceInterface); - if (implementsSI == false) { - String message = format( + if (!implementsSI) { + String message = String.format( "Found module factory does not expose expected service interface. " + "Module name is %s : %s, expected service interface %s, dependent module ON %s , " + "attribute %s", foundFactory.getImplementationName(), foundFactory, - expectedServiceInterface, dependentModuleReadOnlyON, - jmxAttribute); + expectedServiceInterface, newDependentReadOnlyON, + jmxAttribute + ); throw new JmxAttributeValidationException(message, jmxAttribute); } synchronized (this) { @@ -99,58 +131,114 @@ final class DependencyResolverImpl implements DependencyResolver, } } + // translate from serviceref to module ON + private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) { + ObjectName translatedDependentReadOnlyON = dependentReadOnlyON; + if (ObjectNameUtil.isServiceReference(translatedDependentReadOnlyON)) { + String serviceQName = ObjectNameUtil.getServiceQName(translatedDependentReadOnlyON); + String refName = ObjectNameUtil.getReferenceName(translatedDependentReadOnlyON); + translatedDependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name + readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName)); + } + return translatedDependentReadOnlyON; + } + /** * {@inheritDoc} */ //TODO: check for cycles @Override - public T resolveInstance(Class expectedType, ObjectName dependentON, - JmxAttribute jmxAttribute) { - if (expectedType == null || dependentON == null || jmxAttribute == null) { - throw new IllegalArgumentException(format( - "Null parameters not allowed, got {} {} {}", expectedType, - dependentON, jmxAttribute)); - } - - transactionStatus.checkCommitStarted(); - transactionStatus.checkNotCommitted(); + public T resolveInstance(Class expectedType, ObjectName dependentReadOnlyON, + JmxAttribute jmxAttribute) { + Module module = resolveModuleInstance(dependentReadOnlyON, jmxAttribute); - ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON( - dependentON, ObjectNameUtil.TYPE_MODULE); - Module module = modulesHolder.findModule(dependentModuleIdentifier, - jmxAttribute); synchronized (this) { - dependencies.add(dependentModuleIdentifier); + dependencies.add(module.getIdentifier()); } AutoCloseable instance = module.getInstance(); if (instance == null) { - String message = format( + String message = String.format( "Error while %s resolving instance %s. getInstance() returned null. " + "Expected type %s , attribute %s", name, - dependentModuleIdentifier, expectedType, jmxAttribute); + module.getIdentifier(), expectedType, jmxAttribute + ); throw new JmxAttributeValidationException(message, jmxAttribute); } try { - T result = expectedType.cast(instance); - return result; + return expectedType.cast(instance); } catch (ClassCastException e) { - String message = format( + String message = String.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); } } + private Module resolveModuleInstance(ObjectName dependentReadOnlyON, + JmxAttribute jmxAttribute) { + Preconditions.checkArgument(dependentReadOnlyON != null ,"dependentReadOnlyON"); + Preconditions.checkArgument(jmxAttribute != null, "jmxAttribute"); + ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); + transactionStatus.checkCommitStarted(); + transactionStatus.checkNotCommitted(); + + ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON( + translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE); + + return Preconditions.checkNotNull(modulesHolder.findModule(dependentModuleIdentifier, jmxAttribute)); + } + + @Override + public boolean canReuseDependency(ObjectName objectName, JmxAttribute jmxAttribute) { + Preconditions.checkNotNull(objectName); + Preconditions.checkNotNull(jmxAttribute); + + Module currentModule = resolveModuleInstance(objectName, jmxAttribute); + ModuleIdentifier identifier = currentModule.getIdentifier(); + ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = modulesHolder.findModuleInternalTransactionalInfo(identifier); + + if(moduleInternalTransactionalInfo.hasOldModule()) { + Module oldModule = moduleInternalTransactionalInfo.getOldInternalInfo().getReadableModule().getModule(); + return currentModule.canReuse(oldModule); + } + return false; + } + + @Override + public Class resolveIdentity(IdentityAttributeRef identityRef, Class expectedBaseClass) { + final QName qName = QName.create(identityRef.getqNameOfIdentity()); + Class deserialized = bindingContextProvider.getBindingContext().getIdentityClass(qName); + if (deserialized == null) { + throw new IllegalStateException("Unable to retrieve identity class for " + qName + ", null response from " + + bindingContextProvider.getBindingContext()); + } + if (expectedBaseClass.isAssignableFrom(deserialized)) { + return (Class) deserialized; + } else { + LOG.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.", + identityRef, deserialized, expectedBaseClass); + throw new IllegalArgumentException("Deserialized identity " + deserialized + " cannot be cast to " + expectedBaseClass); + } + } + + @Override + public void validateIdentity(IdentityAttributeRef identityRef, Class expectedBaseClass, JmxAttribute jmxAttribute) { + try { + resolveIdentity(identityRef, expectedBaseClass); + } catch (Exception e) { + throw JmxAttributeValidationException.wrap(e, jmxAttribute); + } + } + @Override public int compareTo(DependencyResolverImpl o) { - transactionStatus.checkCommitted(); + transactionStatus.checkCommitStarted(); return Integer.compare(getMaxDependencyDepth(), o.getMaxDependencyDepth()); } - private Integer maxDependencyDepth; - int getMaxDependencyDepth() { if (maxDependencyDepth == null) { throw new IllegalStateException("Dependency depth was not computed"); @@ -158,17 +246,21 @@ final class DependencyResolverImpl implements DependencyResolver, return maxDependencyDepth; } - public void countMaxDependencyDepth(DependencyResolverManager manager) { - transactionStatus.checkCommitted(); + void countMaxDependencyDepth(DependencyResolverManager manager) { + // We can calculate the dependency after second phase commit was started + // Second phase commit starts after validation and validation adds the dependencies into the dependency resolver, which are necessary for the calculation + // FIXME generated code for abstract module declares validate method as non-final + // Overriding the validate would cause recreate every time instead of reuse + also possibly wrong close order if there is another module depending + transactionStatus.checkCommitStarted(); if (maxDependencyDepth == null) { maxDependencyDepth = getMaxDepth(this, manager, - new LinkedHashSet()); + new LinkedHashSet<>()); } } private static int getMaxDepth(DependencyResolverImpl impl, - DependencyResolverManager manager, - LinkedHashSet chainForDetectingCycles) { + DependencyResolverManager manager, + LinkedHashSet chainForDetectingCycles) { int maxDepth = 0; LinkedHashSet chainForDetectingCycles2 = new LinkedHashSet<>( chainForDetectingCycles); @@ -177,8 +269,8 @@ final class DependencyResolverImpl implements DependencyResolver, DependencyResolverImpl dependentDRI = manager .getOrCreate(dependencyName); if (chainForDetectingCycles2.contains(dependencyName)) { - throw new IllegalStateException(format( - "Cycle detected, {} contains {}", + throw new IllegalStateException(String.format( + "Cycle detected, %s contains %s", chainForDetectingCycles2, dependencyName)); } int subDepth; @@ -201,4 +293,21 @@ final class DependencyResolverImpl implements DependencyResolver, public ModuleIdentifier getIdentifier() { return name; } + + @Override + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException { + ObjectName newName = translateServiceRefIfPossible(name); + // add transaction name + newName = ObjectNameUtil.withTransactionName(newName, transactionName); + return mBeanServer.getAttribute(newName, attribute); + } + + @Override + public T newMXBeanProxy(ObjectName name, Class interfaceClass) { + ObjectName newName = translateServiceRefIfPossible(name); + // add transaction name + newName = ObjectNameUtil.withTransactionName(newName, transactionName); + return JMX.newMXBeanProxy(mBeanServer, newName, interfaceClass); + } }