Merge "Reduce verbosity/criticality of inconsistent yangstore messages"
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / ConfigRegistryImpl.java
index 97d57a459199e2bf0ee9912f64b6c505b0f395ca..39682fa6b470226400b47a6aa0fdbec24a4bf522 100644 (file)
@@ -7,32 +7,12 @@
  */
 package org.opendaylight.controller.config.manager.impl;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.annotation.concurrent.GuardedBy;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServer;
-import javax.management.MBeanServerFactory;
-import javax.management.ObjectName;
-
 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.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
@@ -44,23 +24,45 @@ import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistr
 import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager;
 import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager.OsgiRegistration;
 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;
 
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.annotation.concurrent.ThreadSafe;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 /**
  * Singleton that is responsible for creating and committing Config
  * Transactions. It is registered in Platform MBean Server.
  */
 @ThreadSafe
-public class ConfigRegistryImpl implements AutoCloseable,
-        ConfigRegistryImplMXBean {
-    private static final Logger logger = LoggerFactory
-            .getLogger(ConfigRegistryImpl.class);
+public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBean {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigRegistryImpl.class);
 
     private final ModuleFactoriesResolver resolver;
     private final MBeanServer configMBeanServer;
+    private final CodecRegistry codecRegistry;
+
     @GuardedBy("this")
     private long version = 0;
     @GuardedBy("this")
@@ -98,22 +100,29 @@ public class ConfigRegistryImpl implements AutoCloseable,
     // internal jmx server shared by all transactions
     private final MBeanServer transactionsMBeanServer;
 
+    // Used for finding new factory instances for default module functionality
+    @GuardedBy("this")
+    private List<ModuleFactory> lastListOfFactories = Collections.emptyList();
+
+    @GuardedBy("this") // switched in every 2ndPC
+    private CloseableServiceReferenceReadableRegistry  readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            BundleContext bundleContext, MBeanServer configMBeanServer) {
-        this(resolver, bundleContext, configMBeanServer,
-                new BaseJMXRegistrator(configMBeanServer));
+            MBeanServer configMBeanServer, CodecRegistry codecRegistry) {
+        this(resolver, configMBeanServer,
+                new BaseJMXRegistrator(configMBeanServer), codecRegistry);
     }
 
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            BundleContext bundleContext, MBeanServer configMBeanServer,
-            BaseJMXRegistrator baseJMXRegistrator) {
+            MBeanServer configMBeanServer,
+            BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
         this.resolver = resolver;
-        this.beanToOsgiServiceManager = new BeanToOsgiServiceManager(
-                bundleContext);
+        this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
         this.configMBeanServer = configMBeanServer;
         this.baseJMXRegistrator = baseJMXRegistrator;
+        this.codecRegistry = codecRegistry;
         this.registryMBeanServer = MBeanServerFactory
                 .createMBeanServer("ConfigRegistry" + configMBeanServer.getDefaultDomain());
         this.transactionsMBeanServer = MBeanServerFactory
@@ -125,35 +134,45 @@ public class ConfigRegistryImpl implements AutoCloseable,
      */
     @Override
     public synchronized ObjectName beginConfig() {
-        return beginConfigInternal().getControllerObjectName();
+        return beginConfig(false);
+    }
+
+    /**
+     * @param blankTransaction true if this transaction is created automatically by
+     *                         org.opendaylight.controller.config.manager.impl.osgi.BlankTransactionServiceTracker
+     */
+    public synchronized ObjectName beginConfig(boolean blankTransaction) {
+        return beginConfigInternal(blankTransaction).getControllerObjectName();
     }
 
-    private synchronized ConfigTransactionControllerInternal beginConfigInternal() {
+    private synchronized ConfigTransactionControllerInternal beginConfigInternal(boolean blankTransaction) {
         versionCounter++;
-        String transactionName = "ConfigTransaction-" + version + "-"
-                + versionCounter;
-        TransactionJMXRegistrator transactionRegistrator = baseJMXRegistrator
-                .createTransactionJMXRegistrator(transactionName);
+        final String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
+
+        TransactionJMXRegistratorFactory factory = new TransactionJMXRegistratorFactory() {
+            @Override
+            public TransactionJMXRegistrator create() {
+                return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName);
+            }
+        };
+
+        Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(
+                resolver.getAllFactories());
+        ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(
+                transactionName), factory, allCurrentFactories);
+        ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+                readableSRRegistry, txLookupRegistry, allCurrentFactories);
+
         ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl(
-                transactionName, transactionRegistrator, version,
-                versionCounter, resolver.getAllFactories(),
-                transactionsMBeanServer, configMBeanServer);
+                txLookupRegistry, version, codecRegistry,
+                versionCounter, allCurrentFactories, transactionsMBeanServer,
+                configMBeanServer, blankTransaction, writableRegistry);
         try {
-            transactionRegistrator.registerMBean(transactionController, transactionController.getControllerObjectName
-                    ());
+            txLookupRegistry.registerMBean(transactionController, transactionController.getControllerObjectName());
         } catch (InstanceAlreadyExistsException e) {
             throw new IllegalStateException(e);
         }
-
-        // copy old configuration to this server
-        for (ModuleInternalInfo oldConfigInfo : currentConfig.getEntries()) {
-            try {
-                transactionController.copyExistingModule(oldConfigInfo);
-            } catch (InstanceAlreadyExistsException e) {
-                throw new IllegalStateException("Error while copying "
-                        + oldConfigInfo, e);
-            }
-        }
+        transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
         transactionsHolder.add(transactionName, transactionController);
         return transactionController;
     }
@@ -162,20 +181,15 @@ public class ConfigRegistryImpl implements AutoCloseable,
      * {@inheritDoc}
      */
     @Override
-    public synchronized CommitStatus commitConfig(
-            ObjectName transactionControllerON)
+    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);
+        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder.getCurrentTransactions();
+        ConfigTransactionControllerInternal configTransactionController = transactions.get(transactionName);
         if (configTransactionController == null) {
             throw new IllegalArgumentException(String.format(
                     "Transaction with name '%s' not found", transactionName));
@@ -190,33 +204,28 @@ public class ConfigRegistryImpl implements AutoCloseable,
         }
         // optimistic lock ok
 
-        CommitInfo commitInfo = configTransactionController
-                .validateBeforeCommitAndLockTransaction();
-        final ConfigRegistryImpl a = this;
+        CommitInfo commitInfo = configTransactionController.validateBeforeCommitAndLockTransaction();
+        lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
         // non recoverable from here:
         try {
-            final CommitStatus secondPhaseCommitStatus = secondPhaseCommit(
+            return secondPhaseCommit(
                     configTransactionController, commitInfo);
-
-            return secondPhaseCommitStatus;
         } catch (Throwable 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)
+            logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
+            if (t instanceof RuntimeException) {
                 throw (RuntimeException) t;
-            else if (t instanceof Error)
+            } else if (t instanceof Error) {
                 throw (Error) t;
-            else
+            } else {
                 throw new RuntimeException(t);
+            }
         }
     }
 
-    private CommitStatus secondPhaseCommit(
-            ConfigTransactionControllerInternal configTransactionController,
-            CommitInfo commitInfo) {
+    private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
+                                           CommitInfo commitInfo) {
 
         // close instances which were destroyed by the user, including
         // (hopefully) runtime beans
@@ -226,7 +235,7 @@ public class ConfigRegistryImpl implements AutoCloseable,
                                    // runtime jmx registrator),
             // also closes osgi registration and ModuleJMXRegistrator
             // registration
-            currentConfig.remove(toBeDestroyed.getName());
+            currentConfig.remove(toBeDestroyed.getIdentifier());
         }
 
         // set RuntimeBeanRegistrators on beans implementing
@@ -238,7 +247,7 @@ public class ConfigRegistryImpl implements AutoCloseable,
             RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator;
             if (entry.hasOldModule() == false) {
                 runtimeBeanRegistrator = baseJMXRegistrator
-                        .createRuntimeBeanRegistrator(entry.getName());
+                        .createRuntimeBeanRegistrator(entry.getIdentifier());
             } else {
                 // reuse old JMX registrator
                 runtimeBeanRegistrator = entry.getOldInternalInfo()
@@ -251,7 +260,7 @@ public class ConfigRegistryImpl implements AutoCloseable,
                         .setRuntimeBeanRegistrator(runtimeBeanRegistrator);
             }
             // save it to info so it is accessible afterwards
-            runtimeRegistrators.put(entry.getName(), runtimeBeanRegistrator);
+            runtimeRegistrators.put(entry.getIdentifier(), runtimeBeanRegistrator);
         }
 
         // can register runtime beans
@@ -279,8 +288,7 @@ public class ConfigRegistryImpl implements AutoCloseable,
             // determine if current instance was recreated or reused or is new
 
             // rules for closing resources:
-            // osgi registration - will be (re)created every time, so it needs
-            // to be closed here
+            // osgi registration - will be reused if possible.
             // module jmx registration - will be (re)created every time, needs
             // to be closed here
             // runtime jmx registration - should be taken care of by module
@@ -289,26 +297,28 @@ public class ConfigRegistryImpl implements AutoCloseable,
             ModuleJMXRegistrator newModuleJMXRegistrator = baseJMXRegistrator
                     .createModuleJMXRegistrator();
 
+            OsgiRegistration osgiRegistration = null;
             if (entry.hasOldModule()) {
                 ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
-                DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo
-                        .getReadableModule();
-                currentConfig.remove(entry.getName());
+                DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule();
+                currentConfig.remove(entry.getIdentifier());
 
                 // test if old instance == new instance
-                if (oldReadableConfigBean.getInstance().equals(
-                        module.getInstance())) {
+                if (oldReadableConfigBean.getInstance().equals(module.getInstance())) {
                     // reused old instance:
                     // wrap in readable dynamic mbean
                     reusedInstances.add(primaryReadOnlyON);
+                    osgiRegistration = oldInternalInfo.getOsgiRegistration();
                 } else {
                     // recreated instance:
                     // it is responsibility of module to call the old instance -
                     // we just need to unregister configbean
                     recreatedInstances.add(primaryReadOnlyON);
+
+                    // close old osgi registration
+                    oldInternalInfo.getOsgiRegistration().close();
                 }
-                // close old osgi registration in any case
-                oldInternalInfo.getOsgiRegistration().close();
+
                 // close old module jmx registrator
                 oldInternalInfo.getModuleJMXRegistrator().close();
             } else {
@@ -330,17 +340,25 @@ public class ConfigRegistryImpl implements AutoCloseable,
             }
 
             // register to OSGi
-            OsgiRegistration osgiRegistration = beanToOsgiServiceManager
-                    .registerToOsgi(module.getClass(),
-                            newReadableConfigBean.getInstance(),
-                            entry.getName());
+            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.");
+                }
+
+            }
 
             RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = runtimeRegistrators
-                    .get(entry.getName());
+                    .get(entry.getIdentifier());
             ModuleInternalInfo newInfo = new ModuleInternalInfo(
-                    entry.getName(), newReadableConfigBean, osgiRegistration,
+                    entry.getIdentifier(), newReadableConfigBean, osgiRegistration,
                     runtimeBeanRegistrator, newModuleJMXRegistrator,
-                    orderingIdx);
+                    orderingIdx, entry.isDefaultBean());
 
             newConfigEntries.put(module, newInfo);
             orderingIdx++;
@@ -349,6 +367,12 @@ public class ConfigRegistryImpl implements AutoCloseable,
 
         // update version
         version = configTransactionController.getVersion();
+
+        // switch readable Service Reference Registry
+        this.readableSRRegistry.close();
+        this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
+                configTransactionController.getWritableRegistry(), this, baseJMXRegistrator);
+
         return new CommitStatus(newInstances, reusedInstances,
                 recreatedInstances);
     }
@@ -371,7 +395,7 @@ public class ConfigRegistryImpl implements AutoCloseable,
     /**
      * Abort open transactions and unregister read only modules. Since this
      * class is not responsible for registering itself under
-     * {@link ConfigRegistryMXBean#OBJECT_NAME}, it will not unregister itself
+     * {@link org.opendaylight.controller.config.api.ConfigRegistry#OBJECT_NAME}, it will not unregister itself
      * here.
      */
     @Override
@@ -490,6 +514,66 @@ public class ConfigRegistryImpl implements AutoCloseable,
         return baseJMXRegistrator.queryNames(namePattern, null);
     }
 
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        ObjectNameUtil.checkDomain(objectName);
+        ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE);
+        String transactionName = ObjectNameUtil.getTransactionName(objectName);
+        if (transactionName != null) {
+            throw new IllegalArgumentException("Transaction attribute not supported in registry, wrong ObjectName: " + objectName);
+        }
+        // make sure exactly one match is found:
+        LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName));
+    }
+
+    // service reference functionality:
+    @Override
+    public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+        return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
+    }
+
+    @Override
+    public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
+        return readableSRRegistry.getServiceMapping();
+    }
+
+    @Override
+    public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+        return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
+    }
+
+    @Override
+    public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        return readableSRRegistry.lookupServiceInterfaceNames(objectName);
+    }
+
+    @Override
+    public synchronized String getServiceInterfaceName(String namespace, String localName) {
+        return readableSRRegistry.getServiceInterfaceName(namespace, localName);
+    }
+
+    @Override
+    public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+        readableSRRegistry.checkServiceReferenceExists(objectName);
+    }
+
+    @Override
+    public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+        return readableSRRegistry.getServiceReference(serviceInterfaceQName, refName);
+    }
+
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        return ModuleQNameUtil.getQNames(resolver.getAllFactories());
+    }
+
+    @Override
+    public String toString() {
+        return "ConfigRegistryImpl{" +
+                "versionCounter=" + versionCounter +
+                ", version=" + version +
+                '}';
+    }
 }
 
 /**
@@ -515,12 +599,12 @@ class ConfigHolder {
     }
 
     private void add(ModuleInternalInfo configInfo) {
-        ModuleInternalInfo oldValue = currentConfig.put(configInfo.getName(),
+        ModuleInternalInfo oldValue = currentConfig.put(configInfo.getIdentifier(),
                 configInfo);
         if (oldValue != null) {
             throw new IllegalStateException(
                     "Cannot overwrite module with same name:"
-                            + configInfo.getName() + ":" + configInfo);
+                            + configInfo.getIdentifier() + ":" + configInfo);
         }
     }
 
@@ -547,6 +631,8 @@ class ConfigHolder {
         Collections.sort(result);
         return result;
     }
+
+
 }
 
 /**