Merge "Bug 809: Enhancements to the toaster example"
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / ConfigRegistryImpl.java
index 19231705d1614f696e2e764260d971c59c513ecd..8f85972d050cd9d3dc0e8460c21baf3506913db8 100644 (file)
@@ -7,13 +7,16 @@
  */
 package org.opendaylight.controller.config.manager.impl;
 
+import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
-import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
@@ -27,6 +30,7 @@ import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
 import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -60,6 +64,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
 
     private final ModuleFactoriesResolver resolver;
     private final MBeanServer configMBeanServer;
+    private final CodecRegistry codecRegistry;
 
     @GuardedBy("this")
     private long version = 0;
@@ -103,23 +108,24 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     private List<ModuleFactory> lastListOfFactories = Collections.emptyList();
 
     @GuardedBy("this") // switched in every 2ndPC
-    private CloseableServiceReferenceReadableRegistry  readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+    private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
 
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            MBeanServer configMBeanServer) {
+                              MBeanServer configMBeanServer, CodecRegistry codecRegistry) {
         this(resolver, configMBeanServer,
-                new BaseJMXRegistrator(configMBeanServer));
+                new BaseJMXRegistrator(configMBeanServer), codecRegistry);
     }
 
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            MBeanServer configMBeanServer,
-            BaseJMXRegistrator baseJMXRegistrator) {
+                              MBeanServer configMBeanServer,
+                              BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
         this.resolver = resolver;
         this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
         this.configMBeanServer = configMBeanServer;
         this.baseJMXRegistrator = baseJMXRegistrator;
+        this.codecRegistry = codecRegistry;
         this.registryMBeanServer = MBeanServerFactory
                 .createMBeanServer("ConfigRegistry" + configMBeanServer.getDefaultDomain());
         this.transactionsMBeanServer = MBeanServerFactory
@@ -153,15 +159,28 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             }
         };
 
-        Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(
+        Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = new HashMap<>(
                 resolver.getAllFactories());
+
+        // add all factories that disappeared from SR but are still committed
+        for (ModuleInternalInfo moduleInternalInfo : currentConfig.getEntries()) {
+            String name = moduleInternalInfo.getModuleFactory().getImplementationName();
+            if (allCurrentFactories.containsKey(name) == false) {
+                logger.trace("Factory {} not found in SR, using reference from previous commit", name);
+                allCurrentFactories.put(name,
+                        Maps.immutableEntry(moduleInternalInfo.getModuleFactory(), moduleInternalInfo.getBundleContext()));
+            }
+        }
+        allCurrentFactories = Collections.unmodifiableMap(allCurrentFactories);
+
+        // closed by transaction controller
         ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(
                 transactionName), factory, allCurrentFactories);
-        ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+        SearchableServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
                 readableSRRegistry, txLookupRegistry, allCurrentFactories);
 
         ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl(
-                txLookupRegistry, version,
+                txLookupRegistry, version, codecRegistry,
                 versionCounter, allCurrentFactories, transactionsMBeanServer,
                 configMBeanServer, blankTransaction, writableRegistry);
         try {
@@ -170,7 +189,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             throw new IllegalStateException(e);
         }
         transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
-        transactionsHolder.add(transactionName, transactionController);
+        transactionsHolder.add(transactionName, transactionController, txLookupRegistry);
         return transactionController;
     }
 
@@ -178,19 +197,21 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      * {@inheritDoc}
      */
     @Override
+    @SuppressWarnings("PMD.AvoidCatchingThrowable")
     public synchronized CommitStatus commitConfig(ObjectName transactionControllerON)
             throws ConflictingVersionException, ValidationException {
         final String transactionName = ObjectNameUtil
                 .getTransactionName(transactionControllerON);
-        logger.info("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
+        logger.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
 
         // find ConfigTransactionController
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder.getCurrentTransactions();
-        ConfigTransactionControllerInternal configTransactionController = transactions.get(transactionName);
-        if (configTransactionController == null) {
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder.getCurrentTransactions();
+        Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry = transactions.get(transactionName);
+        if (configTransactionControllerEntry == null) {
             throw new IllegalArgumentException(String.format(
                     "Transaction with name '%s' not found", transactionName));
         }
+        ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
         // check optimistic lock
         if (version != configTransactionController.getParentVersion()) {
             throw new ConflictingVersionException(
@@ -205,31 +226,28 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
         // non recoverable from here:
         try {
-            return secondPhaseCommit(
-                    configTransactionController, commitInfo);
-        } catch (Throwable t) { // some libs throw Errors: e.g.
-                                // javax.xml.ws.spi.FactoryFinder$ConfigurationError
+            return secondPhaseCommit(configTransactionController, commitInfo, configTransactionControllerEntry.getValue());
+        } catch (Error | RuntimeException t) { // some libs throw Errors: e.g.
+            // javax.xml.ws.spi.FactoryFinder$ConfigurationError
             isHealthy = false;
             logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
             if (t instanceof RuntimeException) {
                 throw (RuntimeException) t;
-            } else if (t instanceof Error) {
-                throw (Error) t;
             } else {
-                throw new RuntimeException(t);
+                throw (Error) t;
             }
         }
     }
 
     private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
-                                           CommitInfo commitInfo) {
+                                           CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) {
 
         // close instances which were destroyed by the user, including
         // (hopefully) runtime beans
         for (DestroyedModule toBeDestroyed : commitInfo
                 .getDestroyedFromPreviousTransactions()) {
             toBeDestroyed.close(); // closes instance (which should close
-                                   // runtime jmx registrator),
+            // runtime jmx registrator),
             // also closes osgi registration and ModuleJMXRegistrator
             // registration
             currentConfig.remove(toBeDestroyed.getIdentifier());
@@ -251,7 +269,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                         .getRuntimeBeanRegistrator();
             }
             // set runtime jmx registrator if required
-            Module module = entry.getModule();
+            Module module = entry.getProxiedModule();
             if (module instanceof RuntimeBeanRegistratorAwareModule) {
                 ((RuntimeBeanRegistratorAwareModule) module)
                         .setRuntimeBeanRegistrator(runtimeBeanRegistrator);
@@ -261,8 +279,9 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         }
 
         // can register runtime beans
-        List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController
-                .secondPhaseCommit();
+        List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController.secondPhaseCommit();
+        txLookupRegistry.close();
+        configTransactionController.close();
 
         // copy configuration to read only mode
         List<ObjectName> newInstances = new LinkedList<>();
@@ -273,12 +292,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
 
         int orderingIdx = 0;
         for (ModuleIdentifier moduleIdentifier : orderedModuleIdentifiers) {
+            logger.trace("Registering {}", moduleIdentifier);
             ModuleInternalTransactionalInfo entry = commitInfo.getCommitted()
                     .get(moduleIdentifier);
-            if (entry == null)
+            if (entry == null) {
                 throw new NullPointerException("Module not found "
                         + moduleIdentifier);
-            Module module = entry.getModule();
+            }
+
             ObjectName primaryReadOnlyON = ObjectNameUtil
                     .createReadOnlyModuleON(moduleIdentifier);
 
@@ -295,13 +316,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                     .createModuleJMXRegistrator();
 
             OsgiRegistration osgiRegistration = null;
+            AutoCloseable instance = entry.getProxiedModule().getInstance();
             if (entry.hasOldModule()) {
                 ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
                 DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule();
                 currentConfig.remove(entry.getIdentifier());
 
                 // test if old instance == new instance
-                if (oldReadableConfigBean.getInstance().equals(module.getInstance())) {
+                if (oldReadableConfigBean.getInstance().equals(instance)) {
                     // reused old instance:
                     // wrap in readable dynamic mbean
                     reusedInstances.add(primaryReadOnlyON);
@@ -323,31 +345,28 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 // wrap in readable dynamic mbean
                 newInstances.add(primaryReadOnlyON);
             }
+            Module realModule = entry.getRealModule();
 
             DynamicReadableWrapper newReadableConfigBean = new DynamicReadableWrapper(
-                    module, module.getInstance(), moduleIdentifier,
+                    realModule, instance, moduleIdentifier,
                     registryMBeanServer, configMBeanServer);
 
             // register to JMX
             try {
-                newModuleJMXRegistrator.registerMBean(newReadableConfigBean,
-                        primaryReadOnlyON);
+                newModuleJMXRegistrator.registerMBean(newReadableConfigBean, primaryReadOnlyON);
             } catch (InstanceAlreadyExistsException e) {
-                throw new IllegalStateException(e);
+                throw new IllegalStateException("Possible code error, already registered:" + primaryReadOnlyON,e);
             }
 
-            // register to OSGi
+            // register services to OSGi
+            Map<String, ServiceInterfaceAnnotation> annotationMapping = configTransactionController.getWritableRegistry().findServiceInterfaces(moduleIdentifier);
+            BundleContext bc = configTransactionController.getModuleFactoryBundleContext(
+                    entry.getModuleFactory().getImplementationName());
             if (osgiRegistration == null) {
-                ModuleFactory moduleFactory = entry.getModuleFactory();
-                if(moduleFactory != null) {
-                    BundleContext bc = configTransactionController.
-                            getModuleFactoryBundleContext(moduleFactory.getImplementationName());
-                    osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
-                            newReadableConfigBean.getInstance(), entry.getIdentifier(), bc);
-                } else {
-                    throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
-                }
-
+                osgiRegistration = beanToOsgiServiceManager.registerToOsgi(
+                        newReadableConfigBean.getInstance(), moduleIdentifier, bc, annotationMapping);
+            } else {
+                osgiRegistration.updateRegistrations(annotationMapping, bc, instance);
             }
 
             RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = runtimeRegistrators
@@ -355,9 +374,9 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             ModuleInternalInfo newInfo = new ModuleInternalInfo(
                     entry.getIdentifier(), newReadableConfigBean, osgiRegistration,
                     runtimeBeanRegistrator, newModuleJMXRegistrator,
-                    orderingIdx, entry.isDefaultBean());
+                    orderingIdx, entry.isDefaultBean(), entry.getModuleFactory(), entry.getBundleContext());
 
-            newConfigEntries.put(module, newInfo);
+            newConfigEntries.put(realModule, newInfo);
             orderingIdx++;
         }
         currentConfig.addAll(newConfigEntries.values());
@@ -379,12 +398,12 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      */
     @Override
     public synchronized List<ObjectName> getOpenConfigs() {
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
                 .getCurrentTransactions();
         List<ObjectName> result = new ArrayList<>(transactions.size());
-        for (ConfigTransactionControllerInternal configTransactionController : transactions
+        for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
                 .values()) {
-            result.add(configTransactionController.getControllerObjectName());
+            result.add(configTransactionControllerEntry.getKey().getControllerObjectName());
         }
         return result;
     }
@@ -398,11 +417,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     @Override
     public synchronized void close() {
         // abort transactions
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
                 .getCurrentTransactions();
-        for (ConfigTransactionControllerInternal configTransactionController : transactions
+        for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
                 .values()) {
+
+            ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
             try {
+                configTransactionControllerEntry.getValue().close();
                 configTransactionController.abortConfig();
             } catch (RuntimeException e) {
                 logger.warn("Ignoring exception while aborting {}",
@@ -482,7 +504,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      */
     @Override
     public Set<ObjectName> lookupConfigBeans(String moduleName,
-            String instanceName) {
+                                             String instanceName) {
         ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
                 instanceName);
         return baseJMXRegistrator.queryNames(namePattern, null);
@@ -501,11 +523,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      */
     @Override
     public Set<ObjectName> lookupRuntimeBeans(String moduleName,
-            String instanceName) {
-        if (moduleName == null)
+                                              String instanceName) {
+        if (moduleName == null) {
             moduleName = "*";
-        if (instanceName == null)
+        }
+        if (instanceName == null) {
             instanceName = "*";
+        }
         ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern(
                 moduleName, instanceName);
         return baseJMXRegistrator.queryNames(namePattern, null);
@@ -643,18 +667,18 @@ class TransactionsHolder {
      * {@link ConfigTransactionControllerInternal} instances, because platform
      * MBeanServer transforms mbeans into another representation. Map is cleaned
      * every time current transactions are requested.
-     *
      */
     @GuardedBy("ConfigRegistryImpl.this")
-    private final Map<String /* transactionName */, ConfigTransactionControllerInternal> transactions = new HashMap<>();
+    private final Map<String /* transactionName */,
+            Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = new HashMap<>();
 
     /**
      * Can only be called from within synchronized method.
      */
     public void add(String transactionName,
-            ConfigTransactionControllerInternal transactionController) {
+                    ConfigTransactionControllerInternal transactionController, ConfigTransactionLookupRegistry txLookupRegistry) {
         Object oldValue = transactions.put(transactionName,
-                transactionController);
+                Maps.immutableEntry(transactionController, txLookupRegistry));
         if (oldValue != null) {
             throw new IllegalStateException(
                     "Error: two transactions with same name");
@@ -668,13 +692,13 @@ class TransactionsHolder {
      *
      * @return current view on transactions map.
      */
-    public Map<String, ConfigTransactionControllerInternal> getCurrentTransactions() {
+    public Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> getCurrentTransactions() {
         // first, remove closed transaction
-        for (Iterator<Entry<String, ConfigTransactionControllerInternal>> it = transactions
-                .entrySet().iterator(); it.hasNext();) {
-            Entry<String, ConfigTransactionControllerInternal> entry = it
+        for (Iterator<Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>>> it = transactions
+                .entrySet().iterator(); it.hasNext(); ) {
+            Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> entry = it
                     .next();
-            if (entry.getValue().isClosed()) {
+            if (entry.getValue().getKey().isClosed()) {
                 it.remove();
             }
         }