Fix race conditions between config-manager and persister.
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / ConfigTransactionControllerImpl.java
index 343d45a236e99bd9208ff4846d13c1e0a43bc571..a9ab664fd6d44cd19a4b38c02248a96d938b41b9 100644 (file)
@@ -34,12 +34,13 @@ import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import static java.lang.String.format;
@@ -64,7 +65,7 @@ class ConfigTransactionControllerImpl implements
     private final DependencyResolverManager dependencyResolverManager;
     private final TransactionStatus transactionStatus;
     private final MBeanServer transactionsMBeanServer;
-    private final List<ModuleFactory> currentlyRegisteredFactories;
+    private final Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories;
 
     /**
      * Disables ability of {@link DynamicWritableWrapper} to change attributes
@@ -82,7 +83,7 @@ class ConfigTransactionControllerImpl implements
     public ConfigTransactionControllerImpl(String transactionName,
                                            TransactionJMXRegistrator transactionRegistrator,
                                            long parentVersion, long currentVersion,
-                                           List<ModuleFactory> currentlyRegisteredFactories,
+                                           Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories,
                                            MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer, BundleContext bundleContext) {
 
         this.transactionIdentifier = new TransactionIdentifier(transactionName);
@@ -120,11 +121,11 @@ class ConfigTransactionControllerImpl implements
         transactionStatus.checkNotAborted();
 
         Set<ModuleFactory> oldSet = new HashSet<>(lastListOfFactories);
-        Set<ModuleFactory> newSet = new HashSet<>(currentlyRegisteredFactories);
+        Set<ModuleFactory> newSet = new HashSet<>(factoriesHolder.getModuleFactories());
 
         List<ModuleFactory> toBeAdded = new ArrayList<>();
         List<ModuleFactory> toBeRemoved = new ArrayList<>();
-        for(ModuleFactory moduleFactory: currentlyRegisteredFactories) {
+        for(ModuleFactory moduleFactory: factoriesHolder.getModuleFactories()) {
             if (oldSet.contains(moduleFactory) == false){
                 toBeAdded.add(moduleFactory);
             }
@@ -136,10 +137,13 @@ class ConfigTransactionControllerImpl implements
         }
         // add default modules
         for (ModuleFactory moduleFactory : toBeAdded) {
-            Set<? extends Module> defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager, bundleContext);
+            Set<? extends Module> defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager,
+                    getModuleFactoryBundleContext(moduleFactory.getImplementationName()));
             for (Module module : defaultModules) {
+                // ensure default module to be registered to jmx even if its module factory does not use dependencyResolverFactory
+                DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(module.getIdentifier());
                 try {
-                    putConfigBeanToJMXAndInternalMaps(module.getIdentifier(), module, moduleFactory, null);
+                    putConfigBeanToJMXAndInternalMaps(module.getIdentifier(), module, moduleFactory, null, dependencyResolver);
                 } catch (InstanceAlreadyExistsException e) {
                     throw new IllegalStateException(e);
                 }
@@ -171,15 +175,16 @@ class ConfigTransactionControllerImpl implements
         DependencyResolver dependencyResolver = dependencyResolverManager
                 .getOrCreate(moduleIdentifier);
         try {
+            BundleContext bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
             module = moduleFactory.createModule(
                     moduleIdentifier.getInstanceName(), dependencyResolver,
-                    oldConfigBeanInfo.getReadableModule(), bundleContext);
+                    oldConfigBeanInfo.getReadableModule(), bc);
         } catch (Exception e) {
             throw new IllegalStateException(format(
                     "Error while copying old configuration from %s to %s",
                     oldConfigBeanInfo, moduleFactory), e);
         }
-        putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module, moduleFactory, oldConfigBeanInfo);
+        putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module, moduleFactory, oldConfigBeanInfo, dependencyResolver);
     }
 
     @Override
@@ -194,21 +199,27 @@ class ConfigTransactionControllerImpl implements
         // find factory
         ModuleFactory moduleFactory = factoriesHolder.findByModuleName(factoryName);
         DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
-        Module module = moduleFactory.createModule(instanceName, dependencyResolver, bundleContext);
+        Module module = moduleFactory.createModule(instanceName, dependencyResolver,
+                getModuleFactoryBundleContext(moduleFactory.getImplementationName()));
         return putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module,
-                moduleFactory, null);
+                moduleFactory, null, dependencyResolver);
     }
 
     private synchronized ObjectName putConfigBeanToJMXAndInternalMaps(
             ModuleIdentifier moduleIdentifier, Module module,
             ModuleFactory moduleFactory,
-            @Nullable ModuleInternalInfo maybeOldConfigBeanInfo)
+            @Nullable ModuleInternalInfo maybeOldConfigBeanInfo, DependencyResolver dependencyResolver)
             throws InstanceAlreadyExistsException {
+
         logger.debug("Adding module {} to transaction {}", moduleIdentifier, this);
         if (moduleIdentifier.equals(module.getIdentifier())==false) {
             throw new IllegalStateException("Incorrect name reported by module. Expected "
              + moduleIdentifier + ", got " + module.getIdentifier());
         }
+        if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false ) {
+            throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected "
+                    + moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
+        }
         DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
                 module, moduleIdentifier, transactionIdentifier,
                 readOnlyAtomicBoolean, transactionsMBeanServer,
@@ -224,8 +235,6 @@ class ConfigTransactionControllerImpl implements
                 maybeOldConfigBeanInfo, transactionModuleJMXRegistration);
 
         dependencyResolverManager.put(moduleInternalTransactionalInfo);
-        // ensure default module to be registered to jmx even if its module factory does not use dependencyResolverFactory
-        dependencyResolverManager.getOrCreate(moduleIdentifier);
         return writableON;
     }
 
@@ -461,11 +470,20 @@ class ConfigTransactionControllerImpl implements
 
     @Override
     public List<ModuleFactory> getCurrentlyRegisteredFactories() {
-        return currentlyRegisteredFactories;
+        return new ArrayList<>(factoriesHolder.getModuleFactories());
     }
 
     @Override
     public TransactionIdentifier getIdentifier() {
         return transactionIdentifier;
     }
+
+    @Override
+    public BundleContext getModuleFactoryBundleContext(String factoryName) {
+        Map.Entry<ModuleFactory, BundleContext> factoryBundleContextEntry = this.currentlyRegisteredFactories.get(factoryName);
+        if (factoryBundleContextEntry == null || factoryBundleContextEntry.getValue() == null) {
+            throw new NullPointerException("Bundle context of " + factoryName + " ModuleFactory not found.");
+        }
+        return factoryBundleContextEntry.getValue();
+    }
 }