Merge "Close Bug:443 - Implement ImmediateEventExecutor wrapper to config-subsystem."
authorTony Tkacik <ttkacik@cisco.com>
Tue, 25 Feb 2014 15:38:06 +0000 (15:38 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 25 Feb 2014 15:38:06 +0000 (15:38 +0000)
19 files changed:
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/Module.java
opendaylight/config/config-manager/pom.xml
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CommitInfo.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java [new file with mode: 0644]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java [moved from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DestroyedModule.java with 94% similarity]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModuleInternalTransactionalInfo.java [moved from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java with 75% similarity]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModulesHolder.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java [deleted file]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java

index dd11b7503f0e09d8af7710cf89bd6ccdaab0ec74..1b16ec828432624b120228c4cacfd91479a0406e 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.controller.config.spi;
 
-import javax.annotation.concurrent.NotThreadSafe;
-
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.yangtools.concepts.Identifiable;
 
+import javax.annotation.concurrent.NotThreadSafe;
+
 
 /**
  * Represents one service that is to be configured. These methods need to be
@@ -20,7 +20,7 @@ import org.opendaylight.yangtools.concepts.Identifiable;
  * ConfigBeans.
  * <p>
  * In order to guide dependency resolution, the setter method should be
- * annotated with {@link RequireInterface}.
+ * annotated with {@link org.opendaylight.controller.config.api.annotations.RequireInterface}.
  * </p>
  * <p>
  * Thread safety note: implementations of this interface are not required to be
@@ -43,10 +43,10 @@ public interface Module extends Identifiable<ModuleIdentifier>{
      * Returns 'live' object that was configured using this object. It is
      * allowed to call this method only after all ConfigBeans were validated. In
      * this method new resources might be opened or old instance might be
-     * modified. Note that when obtaining dependent Module using
-     * {@link org.opendaylight.controller.config.api.DependencyResolver#validateDependency(Class, javax.management.ObjectName, String)}
-     * a proxy will be created that will disallow calling this method before
-     * second commit phase begins.
+     * modified. This method must be implemented so that it returns same
+     * result for a single transaction. Since Module is created per transaction
+     * this means that it must be safe to cache result of first call.
+     *
      *
      * @return closeable instance: After bundle update the factory might be able
      *         to copy old configuration into new one without being able to cast
index 4857f2a2016127cc492ad6d87af45fff1ea4880f..7d7d9d697adb8de75638d8604eae81f28c35a481 100644 (file)
@@ -68,7 +68,6 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
index 9d086295e3c30fc9b5524357b8e0c1ca3dc96d0a..28732d8f68ea6e53832e954ff388681c608bc26b 100644 (file)
@@ -14,6 +14,8 @@ import java.util.Map;
 import javax.annotation.concurrent.Immutable;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 
 /**
  * Structure obtained during first phase commit, contains destroyed modules from
index 8f6a4654b26d2d9f2548c38e91ea9b82445b326f..dd510a1ed7099a3e087e7e4aa935b0881d6f84fb 100644 (file)
@@ -7,6 +7,7 @@
  */
 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;
@@ -14,6 +15,8 @@ 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.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;
@@ -119,13 +122,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                               MBeanServer configMBeanServer,
                               BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
         this.resolver = resolver;
-        beanToOsgiServiceManager = new BeanToOsgiServiceManager();
+        this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
         this.configMBeanServer = configMBeanServer;
         this.baseJMXRegistrator = baseJMXRegistrator;
         this.codecRegistry = codecRegistry;
-        registryMBeanServer = MBeanServerFactory
+        this.registryMBeanServer = MBeanServerFactory
                 .createMBeanServer("ConfigRegistry" + configMBeanServer.getDefaultDomain());
-        transactionsMBeanServer = MBeanServerFactory
+        this.transactionsMBeanServer = MBeanServerFactory
                 .createMBeanServer("ConfigTransactions" + configMBeanServer.getDefaultDomain());
     }
 
@@ -173,7 +176,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;
     }
 
@@ -189,12 +192,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         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(
@@ -209,8 +213,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
         // non recoverable from here:
         try {
-            return secondPhaseCommit(
-                    configTransactionController, commitInfo);
+            return secondPhaseCommit(configTransactionController, commitInfo, configTransactionControllerEntry.getValue());
         } catch (Throwable t) { // some libs throw Errors: e.g.
             // javax.xml.ws.spi.FactoryFinder$ConfigurationError
             isHealthy = false;
@@ -220,13 +223,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             } else if (t instanceof Error) {
                 throw (Error) t;
             } else {
-                throw new IllegalStateException(t);
+                throw new RuntimeException(t);
             }
         }
     }
 
     private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
-                                           CommitInfo commitInfo) {
+                                           CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) {
 
         // close instances which were destroyed by the user, including
         // (hopefully) runtime beans
@@ -255,7 +258,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);
@@ -265,8 +268,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<>();
@@ -283,7 +287,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 throw new NullPointerException("Module not found "
                         + moduleIdentifier);
             }
-            Module module = entry.getModule();
+
             ObjectName primaryReadOnlyON = ObjectNameUtil
                     .createReadOnlyModuleON(moduleIdentifier);
 
@@ -300,13 +304,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);
@@ -328,9 +333,10 @@ 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
@@ -347,7 +353,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 if (moduleFactory != null) {
                     BundleContext bc = configTransactionController.
                             getModuleFactoryBundleContext(moduleFactory.getImplementationName());
-                    osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
+                    osgiRegistration = beanToOsgiServiceManager.registerToOsgi(realModule.getClass(),
                             newReadableConfigBean.getInstance(), entry.getIdentifier(), bc);
                 } else {
                     throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
@@ -362,7 +368,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                     runtimeBeanRegistrator, newModuleJMXRegistrator,
                     orderingIdx, entry.isDefaultBean());
 
-            newConfigEntries.put(module, newInfo);
+            newConfigEntries.put(realModule, newInfo);
             orderingIdx++;
         }
         currentConfig.addAll(newConfigEntries.values());
@@ -371,8 +377,8 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         version = configTransactionController.getVersion();
 
         // switch readable Service Reference Registry
-        readableSRRegistry.close();
-        readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
+        this.readableSRRegistry.close();
+        this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
                 configTransactionController.getWritableRegistry(), this, baseJMXRegistrator);
 
         return new CommitStatus(newInstances, reusedInstances,
@@ -384,12 +390,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;
     }
@@ -403,11 +409,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 {}",
@@ -652,15 +661,16 @@ class TransactionsHolder {
      * 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");
@@ -674,13 +684,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
+        for (Iterator<Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>>> it = transactions
                 .entrySet().iterator(); it.hasNext(); ) {
-            Entry<String, ConfigTransactionControllerInternal> entry = it
+            Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> entry = it
                     .next();
-            if (entry.getValue().isClosed()) {
+            if (entry.getValue().getKey().isClosed()) {
                 it.remove();
             }
         }
index f7afded51ff0c81468b0678c0b964485cd1b0b8c..84f76c993692055899f7aea55a477c44c970f576 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWritableWrapper;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
@@ -95,7 +96,8 @@ class ConfigTransactionControllerImpl implements
         this.currentlyRegisteredFactories = currentlyRegisteredFactories;
         this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
         this.transactionStatus = new TransactionStatus();
-        this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus, writableSRRegistry, codecRegistry);
+        this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
+                transactionStatus, writableSRRegistry, codecRegistry);
         this.transactionsMBeanServer = transactionsMBeanServer;
         this.configMBeanServer = configMBeanServer;
         this.blankTransaction = blankTransaction;
@@ -231,11 +233,10 @@ class ConfigTransactionControllerImpl implements
         // put wrapper to jmx
         TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
                 .registerMBean(writableDynamicWrapper, writableON);
-        ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+
+        dependencyResolverManager.put(
                 moduleIdentifier, module, moduleFactory,
                 maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean);
-
-        dependencyResolverManager.put(moduleInternalTransactionalInfo);
         return writableON;
     }
 
@@ -394,8 +395,6 @@ class ConfigTransactionControllerImpl implements
 
         logger.trace("Committed configuration {}", getTransactionIdentifier());
         transactionStatus.setCommitted();
-        // unregister this and all modules from jmx
-        close();
 
         return dependencyResolverManager.getSortedModuleIdentifiers();
     }
@@ -413,8 +412,7 @@ class ConfigTransactionControllerImpl implements
     }
 
     public void close() {
-        //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
-        txLookupRegistry.close();
+        dependencyResolverManager.close();
     }
 
     @Override
@@ -572,6 +570,7 @@ class ConfigTransactionControllerImpl implements
         return writableSRRegistry;
     }
 
+    @Override
     public TransactionIdentifier getTransactionIdentifier() {
         return txLookupRegistry.getTransactionIdentifier();
     }
index 82bae44a01b60148b9105e4e8ef98cc1530daf9f..f6164e32561d7ad5688abde93ac6cb4bc96cbec1 100644 (file)
@@ -23,7 +23,7 @@ import org.osgi.framework.BundleContext;
  * and {@link ConfigRegistryImpl} (consumer).
  */
 interface ConfigTransactionControllerInternal extends
-        ConfigTransactionControllerImplMXBean {
+        ConfigTransactionControllerImplMXBean, AutoCloseable {
 
 
 
@@ -75,4 +75,8 @@ interface ConfigTransactionControllerInternal extends
 
     ServiceReferenceWritableRegistry getWritableRegistry();
 
+    TransactionIdentifier getTransactionIdentifier();
+
+    @Override
+    void close();
 }
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java
new file mode 100644 (file)
index 0000000..ba7ab7f
--- /dev/null
@@ -0,0 +1,122 @@
+package org.opendaylight.controller.config.manager.impl;
+
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+import java.util.concurrent.TimeUnit;
+
+public class DeadlockMonitor implements AutoCloseable {
+    private static final Logger logger = LoggerFactory.getLogger(DeadlockMonitorRunnable.class);
+
+    private static final long WARN_AFTER_MILLIS = 5000;
+
+    private final TransactionIdentifier transactionIdentifier;
+    private final DeadlockMonitorRunnable thread;
+    @GuardedBy("this")
+    private ModuleIdentifierWithNanos moduleIdentifierWithNanos = new ModuleIdentifierWithNanos();
+
+    public DeadlockMonitor(TransactionIdentifier transactionIdentifier) {
+        this.transactionIdentifier = transactionIdentifier;
+        thread = new DeadlockMonitorRunnable();
+        thread.start();
+    }
+
+    public synchronized void setCurrentlyInstantiatedModule(ModuleIdentifier currentlyInstantiatedModule) {
+        this.moduleIdentifierWithNanos = new ModuleIdentifierWithNanos(currentlyInstantiatedModule);
+    }
+
+    public boolean isAlive() {
+        return thread.isAlive();
+    }
+
+    @Override
+    public void close() {
+        thread.interrupt();
+    }
+
+    @Override
+    public String toString() {
+        return "DeadlockMonitor{" + transactionIdentifier + '}';
+    }
+
+    private class DeadlockMonitorRunnable extends Thread {
+
+        private DeadlockMonitorRunnable() {
+            super(DeadlockMonitor.this.toString());
+        }
+
+        @Override
+        public void run() {
+            ModuleIdentifierWithNanos old = new ModuleIdentifierWithNanos(); // null moduleId
+            while (this.isInterrupted() == false) {
+                ModuleIdentifierWithNanos copy = new ModuleIdentifierWithNanos(DeadlockMonitor.this.moduleIdentifierWithNanos);
+                if (old.moduleIdentifier == null) {
+                    // started
+                    old = copy;
+                } else if (old.moduleIdentifier != null && old.equals(copy)) {
+                    // is the getInstance() running longer than WARN_AFTER_MILLIS ?
+                    long runningTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - copy.nanoTime);
+                    if (runningTime > WARN_AFTER_MILLIS) {
+                        logger.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime);
+                    }
+                }
+                try {
+                    sleep(1000);
+                } catch (InterruptedException e) {
+                    interrupt();
+                }
+            }
+            logger.trace("Exiting {}", this);
+        }
+
+        @Override
+        public String toString() {
+            return "DeadLockMonitorRunnable{" + transactionIdentifier + "}";
+        }
+    }
+
+    private class ModuleIdentifierWithNanos {
+        @Nullable
+        private final ModuleIdentifier moduleIdentifier;
+        private final long nanoTime;
+
+        private ModuleIdentifierWithNanos() {
+            moduleIdentifier = null;
+            nanoTime = System.nanoTime();
+        }
+
+        private ModuleIdentifierWithNanos(ModuleIdentifier moduleIdentifier) {
+            this.moduleIdentifier = moduleIdentifier;
+            nanoTime = System.nanoTime();
+        }
+
+        private ModuleIdentifierWithNanos(ModuleIdentifierWithNanos copy) {
+            moduleIdentifier = copy.moduleIdentifier;
+            nanoTime = copy.nanoTime;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            ModuleIdentifierWithNanos that = (ModuleIdentifierWithNanos) o;
+
+            if (nanoTime != that.nanoTime) return false;
+            if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null)
+                return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = moduleIdentifier != null ? moduleIdentifier.hashCode() : 0;
+            result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
+            return result;
+        }
+    }
+}
index 941aec10969fd90c700d257579b02c88520e40e9..fd6262cb8cf34f222b70c0e643bf9edc688d46b5 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.config.manager.impl;
 import javax.annotation.Nullable;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
 import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
index e3057a1179419bf6c42daafee1f48bbbd131e786..c229450c30138584e615e552843c1b0f10581dca 100644 (file)
@@ -118,7 +118,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         }
     }
 
-    // transalate from serviceref to module ON
+    // translate from serviceref to module ON
     private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
         if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
             String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
@@ -214,7 +214,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         return maxDependencyDepth;
     }
 
-    public void countMaxDependencyDepth(DependencyResolverManager manager) {
+    void countMaxDependencyDepth(DependencyResolverManager manager) {
         transactionStatus.checkCommitted();
         if (maxDependencyDepth == null) {
             maxDependencyDepth = getMaxDepth(this, manager,
@@ -257,4 +257,5 @@ final class DependencyResolverImpl implements DependencyResolver,
     public ModuleIdentifier getIdentifier() {
         return name;
     }
+
 }
index c115934d370dc29b4c80dbe18dc33fb75ed6c5c9..b99bf8330e5be412a6965ff78ccad4bb4b520c14 100644 (file)
@@ -7,45 +7,57 @@
  */
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.DependencyResolverFactory;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
 
 import javax.annotation.concurrent.GuardedBy;
 import javax.management.InstanceAlreadyExistsException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static com.google.common.base.Preconditions.checkState;
+
 /**
  * Holds information about modules being created and destroyed within this
  * transaction. Observes usage of DependencyResolver within modules to figure
  * out dependency tree.
  */
-public class DependencyResolverManager implements TransactionHolder, DependencyResolverFactory {
+public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
     @GuardedBy("this")
     private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
     private final ModulesHolder modulesHolder;
     private final TransactionStatus transactionStatus;
     private final ServiceReferenceReadableRegistry readableRegistry;
     private final CodecRegistry codecRegistry;
+    private final DeadlockMonitor deadlockMonitor;
 
-    public DependencyResolverManager(String transactionName,
+    public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
                                      TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
-        this.modulesHolder = new ModulesHolder(transactionName);
+        this.modulesHolder = new ModulesHolder(transactionIdentifier);
         this.transactionStatus = transactionStatus;
         this.readableRegistry = readableRegistry;
         this.codecRegistry = codecRegistry;
+        this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
     }
 
     @Override
@@ -88,7 +100,6 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
         return result;
     }
 
-    @Override
     public ModuleInternalTransactionalInfo destroyModule(
             ModuleIdentifier moduleIdentifier) {
         transactionStatus.checkNotCommitted();
@@ -99,45 +110,85 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
     }
 
     // protect write access
-    @Override
+
     public void put(
-            ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
+            final ModuleIdentifier moduleIdentifier,
+            final Module module,
+            ModuleFactory moduleFactory,
+            ModuleInternalInfo maybeOldInternalInfo,
+            TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+            boolean isDefaultBean) {
         transactionStatus.checkNotCommitted();
+
+        Class<? extends Module> moduleClass = Module.class;
+        if (module instanceof RuntimeBeanRegistratorAwareModule) {
+            moduleClass = RuntimeBeanRegistratorAwareModule.class;
+        }
+        Module proxiedModule = Reflection.newProxy(moduleClass, new AbstractInvocationHandler() {
+            // optimization: subsequent calls to getInstance MUST return the same value during transaction,
+            // so it is safe to cache the response
+            private Object cachedInstance;
+
+            @Override
+            protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+                boolean isGetInstance = method.getName().equals("getInstance");
+                if (isGetInstance) {
+                    if (cachedInstance != null) {
+                        return cachedInstance;
+                    }
+
+                    checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
+                    deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
+                }
+                try {
+                    Object response = method.invoke(module, args);
+                    if (isGetInstance) {
+                        cachedInstance = response;
+                    }
+                    return response;
+                } catch(InvocationTargetException e) {
+                    throw e.getCause();
+                } finally {
+                    if (isGetInstance) {
+                        deadlockMonitor.setCurrentlyInstantiatedModule(null);
+                    }
+                }
+            }
+        });
+
+
+        ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+                moduleIdentifier, proxiedModule, moduleFactory,
+                maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module);
         modulesHolder.put(moduleInternalTransactionalInfo);
     }
 
     // wrapped methods:
 
-    @Override
     public CommitInfo toCommitInfo() {
         return modulesHolder.toCommitInfo();
     }
 
-    @Override
     public Module findModule(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting) {
+                             JmxAttribute jmxAttributeForReporting) {
         return modulesHolder.findModule(moduleIdentifier,
                 jmxAttributeForReporting);
     }
 
-    @Override
     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
         return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
     }
 
-    @Override
     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting) {
+                                           JmxAttribute jmxAttributeForReporting) {
         return modulesHolder.findModuleFactory(moduleIdentifier,
                 jmxAttributeForReporting);
     }
 
-    @Override
     public Map<ModuleIdentifier, Module> getAllModules() {
         return modulesHolder.getAllModules();
     }
 
-    @Override
     public void assertNotExists(ModuleIdentifier moduleIdentifier)
             throws InstanceAlreadyExistsException {
         modulesHolder.assertNotExists(moduleIdentifier);
@@ -145,11 +196,16 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
 
     public List<ModuleIdentifier> findAllByFactory(ModuleFactory factory) {
         List<ModuleIdentifier> result = new ArrayList<>();
-        for( ModuleInternalTransactionalInfo  info : modulesHolder.getAllInfos()) {
+        for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
             if (factory.equals(info.getModuleFactory())) {
                 result.add(info.getIdentifier());
             }
         }
         return result;
     }
+
+    public void close() {
+        deadlockMonitor.close();
+    }
+
 }
@@ -5,7 +5,7 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.config.manager.impl;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
@@ -31,7 +31,7 @@ public class DestroyedModule implements AutoCloseable,
     private final OsgiRegistration osgiRegistration;
     private final int orderingIdx;
 
-    DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
+    public DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
             ModuleJMXRegistrator oldJMXRegistrator,
             OsgiRegistration osgiRegistration, int orderingIdx) {
         this.identifier = identifier;
@@ -5,9 +5,10 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.config.manager.impl;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
@@ -18,24 +19,25 @@ import javax.annotation.Nullable;
 
 public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdentifier> {
     private final ModuleIdentifier name;
-    private final Module module;
+    private final Module proxiedModule, realModule;
     private final ModuleFactory moduleFactory;
     @Nullable
     private final ModuleInternalInfo maybeOldInternalInfo;
     private final TransactionModuleJMXRegistration transactionModuleJMXRegistration;
     private final boolean isDefaultBean;
 
-    ModuleInternalTransactionalInfo(ModuleIdentifier name, Module module,
-                                    ModuleFactory moduleFactory,
-                                    ModuleInternalInfo maybeOldInternalInfo,
-                                    TransactionModuleJMXRegistration transactionModuleJMXRegistration,
-                                    boolean isDefaultBean) {
+    public ModuleInternalTransactionalInfo(ModuleIdentifier name, Module proxiedModule,
+                                           ModuleFactory moduleFactory,
+                                           ModuleInternalInfo maybeOldInternalInfo,
+                                           TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+                                           boolean isDefaultBean, Module realModule) {
         this.name = name;
-        this.module = module;
+        this.proxiedModule = proxiedModule;
         this.moduleFactory = moduleFactory;
         this.maybeOldInternalInfo = maybeOldInternalInfo;
         this.transactionModuleJMXRegistration = transactionModuleJMXRegistration;
         this.isDefaultBean = isDefaultBean;
+        this.realModule = realModule;
     }
 
 
@@ -56,8 +58,8 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
     }
 
 
-    public Module getModule() {
-        return module;
+    public Module getProxiedModule() {
+        return proxiedModule;
     }
 
     public ModuleFactory getModuleFactory() {
@@ -84,4 +86,8 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
     public boolean isDefaultBean() {
         return isDefaultBean;
     }
+
+    public Module getRealModule() {
+        return realModule;
+    }
 }
index 7c7d9f95a4e71899ff5feec39bdb5433ebc6baa6..81cc34ac970f8540943b12cf1d45549329b95e46 100644 (file)
@@ -11,8 +11,7 @@ import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.DestroyedModule;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 
@@ -30,19 +29,19 @@ import java.util.Set;
 /**
  * Represents modules to be committed.
  */
-class ModulesHolder implements TransactionHolder {
-    private final String transactionName;
+class ModulesHolder {
+    private final TransactionIdentifier transactionIdentifier;
     @GuardedBy("this")
     private final Map<ModuleIdentifier, ModuleInternalTransactionalInfo> commitMap = new HashMap<>();
 
     @GuardedBy("this")
     private final Set<ModuleInternalTransactionalInfo> unorderedDestroyedFromPreviousTransactions = new HashSet<>();
 
-    ModulesHolder(String transactionName) {
-        this.transactionName = transactionName;
+    ModulesHolder(TransactionIdentifier transactionIdentifier) {
+        this.transactionIdentifier = transactionIdentifier;
     }
 
-    @Override
+
     public CommitInfo toCommitInfo() {
         List<DestroyedModule> orderedDestroyedFromPreviousTransactions = new ArrayList<>(
                 unorderedDestroyedFromPreviousTransactions.size());
@@ -62,43 +61,38 @@ class ModulesHolder implements TransactionHolder {
                 .get(moduleIdentifier);
         JmxAttributeValidationException.checkNotNull(
                 moduleInternalTransactionalInfo, "Module " + moduleIdentifier
-                        + "" + " not found in transaction " + transactionName,
+                        + "" + " not found in transaction " + transactionIdentifier,
                 jmxAttributeForReporting);
         return moduleInternalTransactionalInfo;
     }
 
-    @Override
     public Module findModule(ModuleIdentifier moduleIdentifier,
             JmxAttribute jmxAttributeForReporting) {
         return findModuleInternalTransactionalInfo(moduleIdentifier,
-                jmxAttributeForReporting).getModule();
+                jmxAttributeForReporting).getProxiedModule();
     }
 
-    @Override
     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
             JmxAttribute jmxAttributeForReporting) {
         return findModuleInternalTransactionalInfo(moduleIdentifier,
                 jmxAttributeForReporting).getModuleFactory();
     }
 
-    @Override
     public Map<ModuleIdentifier, Module> getAllModules() {
         Map<ModuleIdentifier, Module> result = new HashMap<>();
         for (ModuleInternalTransactionalInfo entry : commitMap.values()) {
             ModuleIdentifier name = entry.getIdentifier();
-            result.put(name, entry.getModule());
+            result.put(name, entry.getProxiedModule());
         }
         return result;
     }
 
-    @Override
     public void put(
             ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
         commitMap.put(moduleInternalTransactionalInfo.getIdentifier(),
                 moduleInternalTransactionalInfo);
     }
 
-    @Override
     public ModuleInternalTransactionalInfo destroyModule(
             ModuleIdentifier moduleIdentifier) {
         ModuleInternalTransactionalInfo found = commitMap.remove(moduleIdentifier);
@@ -111,7 +105,6 @@ class ModulesHolder implements TransactionHolder {
         return found;
     }
 
-    @Override
     public void assertNotExists(ModuleIdentifier moduleIdentifier)
             throws InstanceAlreadyExistsException {
         if (commitMap.containsKey(moduleIdentifier)) {
@@ -124,7 +117,6 @@ class ModulesHolder implements TransactionHolder {
         return commitMap.values();
     }
 
-    @Override
     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
         ModuleInternalTransactionalInfo found = commitMap.get(moduleIdentifier);
         if (found == null) {
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java
deleted file mode 100644 (file)
index bccd453..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2013 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,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.manager.impl.dependencyresolver;
-
-import org.opendaylight.controller.config.api.JmxAttribute;
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
-import org.opendaylight.controller.config.spi.Module;
-import org.opendaylight.controller.config.spi.ModuleFactory;
-
-import javax.management.InstanceAlreadyExistsException;
-import java.util.Map;
-
-interface TransactionHolder {
-    CommitInfo toCommitInfo();
-
-    Module findModule(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting);
-
-    ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting);
-
-    Map<ModuleIdentifier, Module> getAllModules();
-
-    void put(ModuleInternalTransactionalInfo moduleInternalTransactionalInfo);
-
-    ModuleInternalTransactionalInfo destroyModule(
-            ModuleIdentifier moduleIdentifier);
-
-    void assertNotExists(ModuleIdentifier moduleIdentifier)
-            throws InstanceAlreadyExistsException;
-
-    ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier);
-
-}
index 8ba290f30632e10101cc2185367844d29ee73f19..a8fdfda7d7201f9cb00f50f590265e64825d2751 100644 (file)
@@ -20,7 +20,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -98,31 +97,26 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Co
             errorMessage = logMessage("Class {} does not implement {} in bundle {}", clazz, YangModelBindingProvider.class, bundle);
             throw new IllegalStateException(errorMessage);
         }
-
+        YangModelBindingProvider instance;
         try {
-            Object instance = clazz.newInstance();
-            Object result = clazz.getMethod(GET_MODULE_INFO_METHOD).invoke(instance);
-
-            if (YangModuleInfo.class.isAssignableFrom(result.getClass()) == false) {
-                errorMessage = logMessage("Error invoking method not found {} in bundle {}, reason {}",
-                        GET_MODULE_INFO_METHOD, bundle, "Not assignable from " + YangModuleInfo.class);
-            } else {
-                return (YangModuleInfo) result;
-            }
-
+            Object instanceObj = clazz.newInstance();
+            instance = YangModelBindingProvider.class.cast(instanceObj);
         } catch (InstantiationException e) {
             errorMessage = logMessage("Could not instantiate {} in bundle {}, reason {}", moduleInfoClass, bundle, e);
+            throw new IllegalStateException(errorMessage, e);
         } catch (IllegalAccessException e) {
             errorMessage = logMessage("Illegal access during instatiation of class {} in bundle {}, reason {}",
                     moduleInfoClass, bundle, e);
-        } catch (NoSuchMethodException e) {
-            errorMessage = logMessage("Method not found {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD, bundle, e);
-        } catch (InvocationTargetException e) {
-            errorMessage = logMessage("Error invoking method {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD,
-                    bundle, e);
+            throw new IllegalStateException(errorMessage, e);
         }
+        try{
+            return instance.getModuleInfo();
+        } catch (NoClassDefFoundError e) {
 
-        throw new IllegalStateException(errorMessage);
+
+            logger.error("Error while executing getModuleInfo on {}", instance, e);
+            throw e;
+        }
     }
 
     private static Class<?> loadClass(String moduleInfoClass, Bundle bundle) {
index 63a66e96eb152c1dfe37caf592f2d0d4778e52c6..123e52f6759e2ec9321c81aa36c6e655ddcb9c7f 100644 (file)
@@ -7,24 +7,27 @@
  */
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-
-import java.util.Arrays;
-import java.util.List;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 
 public class DependencyResolverManagerTest {
 
@@ -42,7 +45,7 @@ public class DependencyResolverManagerTest {
     public void setUp() {
         transactionStatus = mock(TransactionStatus.class);
         ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
-        tested = new DependencyResolverManager("txName", transactionStatus, mockedRegistry, null);
+        tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry, null);
         doNothing().when(transactionStatus).checkCommitStarted();
         doNothing().when(transactionStatus).checkNotCommitted();
     }
@@ -87,10 +90,18 @@ public class DependencyResolverManagerTest {
 
     private static void mockGetInstance(DependencyResolverManager tested,
             ModuleIdentifier moduleIdentifier) {
-        ModuleInternalTransactionalInfo mock = mock(ModuleInternalTransactionalInfo.class);
-        doReturn(moduleIdentifier).when(mock).getIdentifier();
-        doReturn(mockedModule()).when(mock).getModule();
-        tested.put(mock);
+
+        ModuleFactory moduleFactory = mock(ModuleFactory.class);
+        ModuleInternalInfo maybeOldInternalInfo = null;
+        TransactionModuleJMXRegistration transactionModuleJMXRegistration = null;
+        boolean isDefaultBean = false;
+
+        tested.put(moduleIdentifier,
+        mockedModule(),
+         moduleFactory,
+         maybeOldInternalInfo,
+         transactionModuleJMXRegistration,
+         isDefaultBean);
     }
 
     private static Module mockedModule() {
index f4ba5ef887e359b9e5a6ab324ac58cc359ae565f..df6dce124339991a50c0016d30dd87cc76168e88 100644 (file)
@@ -7,15 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.parallelapsp;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.io.Closeable;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.management.ObjectName;
-
+import com.google.common.base.Strings;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
@@ -26,7 +18,13 @@ import org.opendaylight.controller.config.spi.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.management.ObjectName;
+import java.io.Closeable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
 
 /**
  * Represents service that has dependency to thread pool.
index 4e9ce009b420ad05b4c697144fd215c310cca6db..28408abed2fb564c05688302cc0d3b20be0465a9 100644 (file)
@@ -326,7 +326,7 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
     }
 
     @Test
-    public void testAbort() {
+    public void testAbort() throws InstanceAlreadyExistsException, ValidationException {
         ConfigTransactionJMXClient transaction = configRegistryClient
                 .createTransaction();
         assertEquals(1, configRegistryClient.getOpenConfigs().size());
@@ -336,14 +336,14 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
             transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
                     fixed1);
             fail();
-        } catch (Exception e) {
-            assertTrue(e.getCause() instanceof InstanceNotFoundException);
+        } catch (IllegalStateException e) {
+            assertEquals("Configuration was aborted", e.getMessage());
         }
         try {
             transaction.validateConfig();
             fail();
-        } catch (Exception e) {
-            assertTrue(e.getCause() instanceof InstanceNotFoundException);
+        } catch (IllegalStateException e) {
+            assertEquals("Configuration was aborted", e.getMessage());
         }
         assertEquals(0, configRegistryClient.getOpenConfigs().size());
     }
index 83029c44e665ec77bc5796535353277fe481ea43..5642cc7188788fd74a7aeccf7ca8ffa97abd009e 100644 (file)
@@ -25,7 +25,8 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
     private static final Logger logger = LoggerFactory.getLogger(Activator.class);
 
     private BundleContext context;
-    ServiceRegistration osgiRegistration;
+    private ServiceRegistration osgiRegistration;
+    private ConfigRegistryLookupThread configRegistryLookup = null;
 
     @Override
     public void start(BundleContext context) throws Exception {
@@ -36,20 +37,42 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
 
     @Override
     public void stop(BundleContext context) throws Exception {
+        if (configRegistryLookup != null) {
+            configRegistryLookup.interrupt();
+        }
     }
 
     @Override
     public synchronized void onYangStoreAdded(YangStoreService yangStoreService) {
-        checkState(osgiRegistration == null, "More than one onYangStoreAdded received");
-        NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
-        logger.debug("Registering into OSGi");
-        osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
-                new Hashtable<String, Object>());
+        checkState(configRegistryLookup  == null, "More than one onYangStoreAdded received");
+        configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
+        configRegistryLookup.start();
     }
 
     @Override
     public synchronized void onYangStoreRemoved() {
-        osgiRegistration.unregister();
+        configRegistryLookup.interrupt();
+        if (osgiRegistration != null) {
+            osgiRegistration.unregister();
+        }
         osgiRegistration = null;
+        configRegistryLookup = null;
+    }
+
+    private class ConfigRegistryLookupThread extends Thread {
+        private final YangStoreService yangStoreService;
+
+        private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
+            super("config-registry-lookup");
+            this.yangStoreService = yangStoreService;
+        }
+
+        @Override
+        public void run() {
+            NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
+            logger.debug("Registering into OSGi");
+            osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
+                    new Hashtable<String, Object>());
+        }
     }
 }