Merge "BUG-2288: deprecate old binding Notification API elements"
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / dependencyresolver / DependencyResolverImpl.java
index c229450c30138584e615e552843c1b0f10581dca..8948c56e9b1dfd1bcaa1b07c1d093235790193c4 100644 (file)
@@ -7,6 +7,20 @@
  */
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
+import static java.lang.String.format;
+
+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,23 +30,14 @@ 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
@@ -40,7 +45,7 @@ import static java.lang.String.format;
  */
 final class DependencyResolverImpl implements DependencyResolver,
         Comparable<DependencyResolverImpl> {
-    private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class);
+    private static final Logger LOG = LoggerFactory.getLogger(DependencyResolverImpl.class);
 
     private final ModulesHolder modulesHolder;
     private final ModuleIdentifier name;
@@ -48,16 +53,21 @@ final class DependencyResolverImpl implements DependencyResolver,
     @GuardedBy("this")
     private final Set<ModuleIdentifier> dependencies = new HashSet<>();
     private final ServiceReferenceReadableRegistry readableRegistry;
-    private final CodecRegistry codecRegistry;
+    private final BindingContextProvider bindingContextProvider;
+    private final String transactionName;
+    private final MBeanServer mBeanServer;
 
     DependencyResolverImpl(ModuleIdentifier currentModule,
                            TransactionStatus transactionStatus, ModulesHolder modulesHolder,
-                           ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
-        this.codecRegistry = codecRegistry;
+                           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;
     }
 
     /**
@@ -80,7 +90,8 @@ final class DependencyResolverImpl implements DependencyResolver,
 
         JmxAttributeValidationException.checkNotNull(dependentReadOnlyON,
                 "is null, expected dependency implementing "
-                        + expectedServiceInterface, jmxAttribute);
+                        + expectedServiceInterface, jmxAttribute
+        );
 
 
         // check that objectName belongs to this transaction - this should be
@@ -91,12 +102,14 @@ final class DependencyResolverImpl implements DependencyResolver,
         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);
+        ObjectName newDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
 
-        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil
+        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(newDependentReadOnlyON, ObjectNameUtil
                 .TYPE_MODULE);
 
         ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
@@ -109,8 +122,9 @@ final class DependencyResolverImpl implements DependencyResolver,
                             + "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
                             + "attribute %s",
                     foundFactory.getImplementationName(), foundFactory,
-                    expectedServiceInterface, dependentReadOnlyON,
-                    jmxAttribute);
+                    expectedServiceInterface, newDependentReadOnlyON,
+                    jmxAttribute
+            );
             throw new JmxAttributeValidationException(message, jmxAttribute);
         }
         synchronized (this) {
@@ -120,13 +134,14 @@ final class DependencyResolverImpl implements DependencyResolver,
 
     // translate 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
+        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 dependentReadOnlyON;
+        return translatedDependentReadOnlyON;
     }
 
     /**
@@ -136,28 +151,18 @@ final class DependencyResolverImpl implements DependencyResolver,
     @Override
     public <T> T resolveInstance(Class<T> 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();
+        Module module = resolveModuleInstance(dependentReadOnlyON, jmxAttribute);
 
-        ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
-                dependentReadOnlyON, 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(
                     "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 {
@@ -166,24 +171,54 @@ final class DependencyResolverImpl implements DependencyResolver,
             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);
         }
     }
 
+    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 <T extends BaseIdentity> Class<? extends T> resolveIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass) {
         final QName qName = QName.create(identityRef.getqNameOfIdentity());
-        IdentityCodec<?> identityCodec = codecRegistry.getIdentityCodec();
-        Class<? extends BaseIdentity> deserialized = identityCodec.deserialize(qName);
+        Class<?> deserialized  = bindingContextProvider.getBindingContext().getIdentityClass(qName);
         if (deserialized == null) {
             throw new IllegalStateException("Unable to retrieve identity class for " + qName + ", null response from "
-                    + codecRegistry);
+                    + bindingContextProvider.getBindingContext());
         }
         if (expectedBaseClass.isAssignableFrom(deserialized)) {
             return (Class<T>) deserialized;
         } else {
-            logger.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.",
+            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);
         }
@@ -200,7 +235,7 @@ final class DependencyResolverImpl implements DependencyResolver,
 
     @Override
     public int compareTo(DependencyResolverImpl o) {
-        transactionStatus.checkCommitted();
+        transactionStatus.checkCommitStarted();
         return Integer.compare(getMaxDependencyDepth(),
                 o.getMaxDependencyDepth());
     }
@@ -215,7 +250,11 @@ final class DependencyResolverImpl implements DependencyResolver,
     }
 
     void countMaxDependencyDepth(DependencyResolverManager manager) {
-        transactionStatus.checkCommitted();
+        // 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<ModuleIdentifier>());
@@ -258,4 +297,20 @@ final class DependencyResolverImpl implements DependencyResolver,
         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> T newMXBeanProxy(ObjectName name, Class<T> interfaceClass) {
+        ObjectName newName = translateServiceRefIfPossible(name);
+        // add transaction name
+        newName = ObjectNameUtil.withTransactionName(newName, transactionName);
+        return JMX.newMXBeanProxy(mBeanServer, newName, interfaceClass);
+    }
 }