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=f46113fb9a4d1db5eb0f132b6256d96c894715f3;hp=e3057a1179419bf6c42daafee1f48bbbd131e786;hb=f43b01b81319959b1907e3e04537f5169e7f33d8;hpb=33913d16da7b2e0fd0515c773c26e0072212f17a 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 e3057a1179..f46113fb9a 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013, 2017 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -7,6 +7,18 @@ */ 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; @@ -16,31 +28,21 @@ 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 org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry; -import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec; 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 * during validation. Tracks dependencies for ordering purposes. */ -final class DependencyResolverImpl implements DependencyResolver, - Comparable { - private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class); +public final class DependencyResolverImpl implements DependencyResolver, Comparable { + private static final Logger LOG = LoggerFactory.getLogger(DependencyResolverImpl.class); private final ModulesHolder modulesHolder; private final ModuleIdentifier name; @@ -48,201 +50,212 @@ final class DependencyResolverImpl implements DependencyResolver, @GuardedBy("this") private final Set dependencies = new HashSet<>(); private final ServiceReferenceReadableRegistry readableRegistry; - private final CodecRegistry codecRegistry; + private final BindingContextProvider bindingContextProvider; + private final String transactionName; + private final MBeanServer beanServer; + private Integer maxDependencyDepth; - DependencyResolverImpl(ModuleIdentifier currentModule, - TransactionStatus transactionStatus, ModulesHolder modulesHolder, - ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) { - this.codecRegistry = codecRegistry; + public DependencyResolverImpl(final ModuleIdentifier currentModule, final TransactionStatus transactionStatus, + final ModulesHolder modulesHolder, final ServiceReferenceReadableRegistry readableRegistry, + final BindingContextProvider bindingContextProvider, final String transactionName, + final MBeanServer beanServer) { + this.bindingContextProvider = bindingContextProvider; this.name = currentModule; this.transactionStatus = transactionStatus; this.modulesHolder = modulesHolder; this.readableRegistry = readableRegistry; + this.transactionName = transactionName; + this.beanServer = beanServer; } /** * {@inheritDoc} */ - //TODO: check for cycles + // TODO: check for cycles @Override - public void validateDependency( - Class expectedServiceInterface, - ObjectName dependentReadOnlyON, JmxAttribute jmxAttribute) { + public void validateDependency(final Class expectedServiceInterface, + final ObjectName dependentReadOnlyON, final JmxAttribute jmxAttribute) { - transactionStatus.checkNotCommitted(); + this.transactionStatus.checkNotCommitted(); if (expectedServiceInterface == null) { - throw new NullPointerException( - "Parameter 'expectedServiceInterface' is null"); + throw new NullPointerException("Parameter 'expectedServiceInterface' is null"); } if (jmxAttribute == null) { throw new NullPointerException("Parameter 'jmxAttribute' is null"); } JmxAttributeValidationException.checkNotNull(dependentReadOnlyON, - "is null, expected dependency implementing " - + expectedServiceInterface, jmxAttribute); - + "is null, expected dependency implementing " + expectedServiceInterface, jmxAttribute); // check that objectName belongs to this transaction - this should be // stripped // in DynamicWritableWrapper - boolean hasTransaction = ObjectNameUtil - .getTransactionName(dependentReadOnlyON) != null; - JmxAttributeValidationException.checkCondition( - hasTransaction == false, - format("ObjectName should not contain " - + "transaction name. %s set to %s. ", jmxAttribute, - dependentReadOnlyON), jmxAttribute); + final boolean hasTransaction = ObjectNameUtil.getTransactionName(dependentReadOnlyON) != null; + JmxAttributeValidationException.checkCondition(!hasTransaction, + String.format("ObjectName should not contain " + "transaction name. %s set to %s. ", jmxAttribute, + dependentReadOnlyON), + jmxAttribute); - dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); + final ObjectName newDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); - ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil - .TYPE_MODULE); + final ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(newDependentReadOnlyON, + ObjectNameUtil.TYPE_MODULE); - ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute); + final ModuleFactory foundFactory = this.modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute); - boolean implementsSI = foundFactory - .isModuleImplementingServiceInterface(expectedServiceInterface); - if (implementsSI == false) { - String message = format( + final boolean implementsSI = foundFactory.isModuleImplementingServiceInterface(expectedServiceInterface); + if (!implementsSI) { + final 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, dependentReadOnlyON, - jmxAttribute); + foundFactory.getImplementationName(), foundFactory, expectedServiceInterface, + newDependentReadOnlyON, jmxAttribute); throw new JmxAttributeValidationException(message, jmxAttribute); } synchronized (this) { - dependencies.add(moduleIdentifier); + this.dependencies.add(moduleIdentifier); } } - // transalate from serviceref to module ON - private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) { - if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) { - String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON); - String refName = ObjectNameUtil.getReferenceName(dependentReadOnlyON); - dependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name - readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName)); + // translate from serviceref to module ON + private ObjectName translateServiceRefIfPossible(final ObjectName dependentReadOnlyON) { + ObjectName translatedDependentReadOnlyON = dependentReadOnlyON; + if (ObjectNameUtil.isServiceReference(translatedDependentReadOnlyON)) { + final String serviceQName = ObjectNameUtil.getServiceQName(translatedDependentReadOnlyON); + final String refName = ObjectNameUtil.getReferenceName(translatedDependentReadOnlyON); + // strip again of transaction name + translatedDependentReadOnlyON = ObjectNameUtil.withoutTransactionName( + this.readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName)); } - return dependentReadOnlyON; + return translatedDependentReadOnlyON; } - /** - * {@inheritDoc} - */ - //TODO: check for cycles + // TODO: check for cycles @Override - public T resolveInstance(Class expectedType, ObjectName dependentReadOnlyON, - JmxAttribute jmxAttribute) { - if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) { - throw new IllegalArgumentException(format( - "Null parameters not allowed, got %s %s %s", expectedType, - dependentReadOnlyON, jmxAttribute)); - } - dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); - transactionStatus.checkCommitStarted(); - transactionStatus.checkNotCommitted(); + public T resolveInstance(final Class expectedType, final ObjectName dependentReadOnlyON, + final JmxAttribute jmxAttribute) { + final Module module = resolveModuleInstance(dependentReadOnlyON, jmxAttribute); - ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON( - dependentReadOnlyON, ObjectNameUtil.TYPE_MODULE); - Module module = modulesHolder.findModule(dependentModuleIdentifier, - jmxAttribute); synchronized (this) { - dependencies.add(dependentModuleIdentifier); + this.dependencies.add(module.getIdentifier()); } - AutoCloseable instance = module.getInstance(); + final AutoCloseable instance = module.getInstance(); if (instance == null) { - String message = format( - "Error while %s resolving instance %s. getInstance() returned null. " - + "Expected type %s , attribute %s", name, - dependentModuleIdentifier, expectedType, jmxAttribute); + final String message = String.format( + "Error while %s resolving instance %s. getInstance() returned null. Expected type %s, attribute %s", + this.name, module.getIdentifier(), expectedType, jmxAttribute); throw new JmxAttributeValidationException(message, jmxAttribute); } try { return expectedType.cast(instance); - } catch (ClassCastException e) { - String message = format( - "Instance cannot be cast to expected type. Instance class is %s , " - + "expected type %s , attribute %s", + } catch (final ClassCastException e) { + final String message = String.format( + "Instance cannot be cast to expected type. Instance class is %s, expected type %s , attribute %s", instance.getClass(), expectedType, jmxAttribute); throw new JmxAttributeValidationException(message, e, jmxAttribute); } } + private Module resolveModuleInstance(final ObjectName dependentReadOnlyON, final JmxAttribute jmxAttribute) { + Preconditions.checkArgument(dependentReadOnlyON != null, "dependentReadOnlyON"); + Preconditions.checkArgument(jmxAttribute != null, "jmxAttribute"); + final ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); + this.transactionStatus.checkCommitStarted(); + this.transactionStatus.checkNotCommitted(); + + final ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(translatedDependentReadOnlyON, + ObjectNameUtil.TYPE_MODULE); + + return Preconditions.checkNotNull(this.modulesHolder.findModule(dependentModuleIdentifier, jmxAttribute)); + } + + @Override + public boolean canReuseDependency(final ObjectName objectName, final JmxAttribute jmxAttribute) { + Preconditions.checkNotNull(objectName); + Preconditions.checkNotNull(jmxAttribute); + + final Module currentModule = resolveModuleInstance(objectName, jmxAttribute); + final ModuleIdentifier identifier = currentModule.getIdentifier(); + final ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = this.modulesHolder + .findModuleInternalTransactionalInfo(identifier); + + if (moduleInternalTransactionalInfo.hasOldModule()) { + final Module oldModule = moduleInternalTransactionalInfo.getOldInternalInfo().getReadableModule() + .getModule(); + return currentModule.canReuse(oldModule); + } + return false; + } + @Override - public Class resolveIdentity(IdentityAttributeRef identityRef, Class expectedBaseClass) { + public Class resolveIdentity(final IdentityAttributeRef identityRef, + final Class expectedBaseClass) { final QName qName = QName.create(identityRef.getqNameOfIdentity()); - IdentityCodec identityCodec = codecRegistry.getIdentityCodec(); - Class deserialized = identityCodec.deserialize(qName); + final Class deserialized = this.bindingContextProvider.getBindingContext().getIdentityClass(qName); if (deserialized == null) { throw new IllegalStateException("Unable to retrieve identity class for " + qName + ", null response from " - + codecRegistry); + + this.bindingContextProvider.getBindingContext()); } if (expectedBaseClass.isAssignableFrom(deserialized)) { return (Class) deserialized; - } else { - logger.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); } + 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); - } + public void validateIdentity(final IdentityAttributeRef identityRef, + final Class expectedBaseClass, final JmxAttribute jmxAttribute) { + resolveIdentity(identityRef, expectedBaseClass); } @Override - public int compareTo(DependencyResolverImpl o) { - transactionStatus.checkCommitted(); - return Integer.compare(getMaxDependencyDepth(), - o.getMaxDependencyDepth()); + public int compareTo(final DependencyResolverImpl dependencyResolverImpl) { + this.transactionStatus.checkCommitStarted(); + return Integer.compare(getMaxDependencyDepth(), dependencyResolverImpl.getMaxDependencyDepth()); } - private Integer maxDependencyDepth; - int getMaxDependencyDepth() { - if (maxDependencyDepth == null) { + if (this.maxDependencyDepth == null) { throw new IllegalStateException("Dependency depth was not computed"); } - return maxDependencyDepth; + return this.maxDependencyDepth; } - public void countMaxDependencyDepth(DependencyResolverManager manager) { - transactionStatus.checkCommitted(); - if (maxDependencyDepth == null) { - maxDependencyDepth = getMaxDepth(this, manager, - new LinkedHashSet()); + void countMaxDependencyDepth(final 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 + this.transactionStatus.checkCommitStarted(); + if (this.maxDependencyDepth == null) { + this.maxDependencyDepth = getMaxDepth(this, manager, new LinkedHashSet<>()); } } - private static int getMaxDepth(DependencyResolverImpl impl, - DependencyResolverManager manager, - LinkedHashSet chainForDetectingCycles) { + private static int getMaxDepth(final DependencyResolverImpl impl, final DependencyResolverManager manager, + final LinkedHashSet chainForDetectingCycles) { int maxDepth = 0; - LinkedHashSet chainForDetectingCycles2 = new LinkedHashSet<>( - chainForDetectingCycles); + final LinkedHashSet chainForDetectingCycles2 = new LinkedHashSet<>(chainForDetectingCycles); chainForDetectingCycles2.add(impl.getIdentifier()); - for (ModuleIdentifier dependencyName : impl.dependencies) { - DependencyResolverImpl dependentDRI = manager - .getOrCreate(dependencyName); + for (final ModuleIdentifier dependencyName : impl.dependencies) { + final DependencyResolverImpl dependentDRI = manager.getOrCreate(dependencyName); if (chainForDetectingCycles2.contains(dependencyName)) { - throw new IllegalStateException(format( - "Cycle detected, %s contains %s", - chainForDetectingCycles2, dependencyName)); + throw new IllegalStateException( + String.format("Cycle detected, %s contains %s", chainForDetectingCycles2, dependencyName)); } int subDepth; if (dependentDRI.maxDependencyDepth != null) { subDepth = dependentDRI.maxDependencyDepth; } else { - subDepth = getMaxDepth(dependentDRI, manager, - chainForDetectingCycles2); + subDepth = getMaxDepth(dependentDRI, manager, chainForDetectingCycles2); dependentDRI.maxDependencyDepth = subDepth; } if (subDepth + 1 > maxDepth) { @@ -255,6 +268,25 @@ final class DependencyResolverImpl implements DependencyResolver, @Override public ModuleIdentifier getIdentifier() { - return name; + return this.name; + } + + @Override + @SuppressWarnings("checkstyle:hiddenField") + public Object getAttribute(final ObjectName name, final String attribute) + throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException { + ObjectName newName = translateServiceRefIfPossible(name); + // add transaction name + newName = ObjectNameUtil.withTransactionName(newName, this.transactionName); + return this.beanServer.getAttribute(newName, attribute); + } + + @Override + @SuppressWarnings("checkstyle:hiddenField") + public T newMXBeanProxy(final ObjectName name, final Class interfaceClass) { + ObjectName newName = translateServiceRefIfPossible(name); + // add transaction name + newName = ObjectNameUtil.withTransactionName(newName, this.transactionName); + return JMX.newMXBeanProxy(this.beanServer, newName, interfaceClass); } }