*/
package org.opendaylight.controller.config.manager.impl;
-import static java.lang.String.format;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.GuardedBy;
-import javax.management.DynamicMBean;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
-import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator
- .TransactionModuleJMXRegistration;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static java.lang.String.format;
+
/**
* This is a JMX bean representing current transaction. It contains
* {@link #transactionIdentifier}, unique version and parent version for
*/
class ConfigTransactionControllerImpl implements
ConfigTransactionControllerInternal,
- ConfigTransactionControllerImplMXBean {
- private static final Logger logger = LoggerFactory
- .getLogger(ConfigTransactionControllerImpl.class);
+ ConfigTransactionControllerImplMXBean,
+ Identifiable<TransactionIdentifier>{
+ private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
private final TransactionIdentifier transactionIdentifier;
private final ObjectName controllerON;
private final DependencyResolverManager dependencyResolverManager;
private final TransactionStatus transactionStatus;
private final MBeanServer transactionsMBeanServer;
+ private final Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories;
/**
* Disables ability of {@link DynamicWritableWrapper} to change attributes
configBeanModificationDisabled);
private final MBeanServer configMBeanServer;
+ private final BundleContext bundleContext;
+
public ConfigTransactionControllerImpl(String transactionName,
- TransactionJMXRegistrator transactionRegistrator,
- long parentVersion, long currentVersion,
- List<? extends ModuleFactory> currentlyRegisteredFactories,
- MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer) {
+ TransactionJMXRegistrator transactionRegistrator,
+ long parentVersion, long currentVersion,
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories,
+ MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer, BundleContext bundleContext) {
this.transactionIdentifier = new TransactionIdentifier(transactionName);
this.controllerON = ObjectNameUtil
.createTransactionModuleJMXRegistrator();
this.parentVersion = parentVersion;
this.currentVersion = currentVersion;
- this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(
- currentlyRegisteredFactories);
+ this.currentlyRegisteredFactories = currentlyRegisteredFactories;
+ this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
this.transactionStatus = new TransactionStatus();
- this.dependencyResolverManager = new DependencyResolverManager(
- transactionName, transactionStatus);
+ this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus);
this.transactionsMBeanServer = transactionsMBeanServer;
this.configMBeanServer = configMBeanServer;
+ this.bundleContext = bundleContext;
}
@Override
- public synchronized void copyExistingModule(
+ public void copyExistingModulesAndProcessFactoryDiff(Collection<ModuleInternalInfo> existingModules, List<ModuleFactory> lastListOfFactories) {
+ // copy old configuration to this server
+ for (ModuleInternalInfo oldConfigInfo : existingModules) {
+ try {
+ copyExistingModule(oldConfigInfo);
+ } catch (InstanceAlreadyExistsException e) {
+ throw new IllegalStateException("Error while copying " + oldConfigInfo, e);
+ }
+ }
+ processDefaultBeans(lastListOfFactories);
+ }
+
+ private synchronized void processDefaultBeans(List<ModuleFactory> lastListOfFactories) {
+ transactionStatus.checkNotCommitStarted();
+ transactionStatus.checkNotAborted();
+
+ Set<ModuleFactory> oldSet = new HashSet<>(lastListOfFactories);
+ Set<ModuleFactory> newSet = new HashSet<>(factoriesHolder.getModuleFactories());
+
+ List<ModuleFactory> toBeAdded = new ArrayList<>();
+ List<ModuleFactory> toBeRemoved = new ArrayList<>();
+ for(ModuleFactory moduleFactory: factoriesHolder.getModuleFactories()) {
+ if (oldSet.contains(moduleFactory) == false){
+ toBeAdded.add(moduleFactory);
+ }
+ }
+ for(ModuleFactory moduleFactory: lastListOfFactories){
+ if (newSet.contains(moduleFactory) == false) {
+ toBeRemoved.add(moduleFactory);
+ }
+ }
+ // add default modules
+ for (ModuleFactory moduleFactory : toBeAdded) {
+ Set<? extends Module> defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager,
+ getModuleFactoryBundleContext(moduleFactory.getImplementationName()));
+ for (Module module : defaultModules) {
+ // ensure default module to be registered to jmx even if its module factory does not use dependencyResolverFactory
+ DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(module.getIdentifier());
+ try {
+ putConfigBeanToJMXAndInternalMaps(module.getIdentifier(), module, moduleFactory, null, dependencyResolver);
+ } catch (InstanceAlreadyExistsException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ // remove modules belonging to removed factories
+ for(ModuleFactory removedFactory: toBeRemoved){
+ List<ModuleIdentifier> modulesOfRemovedFactory = dependencyResolverManager.findAllByFactory(removedFactory);
+ for (ModuleIdentifier name : modulesOfRemovedFactory) {
+ destroyModule(name);
+ }
+ }
+ }
+
+
+ private synchronized void copyExistingModule(
ModuleInternalInfo oldConfigBeanInfo)
throws InstanceAlreadyExistsException {
transactionStatus.checkNotCommitStarted();
DependencyResolver dependencyResolver = dependencyResolverManager
.getOrCreate(moduleIdentifier);
try {
+ BundleContext bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
module = moduleFactory.createModule(
moduleIdentifier.getInstanceName(), dependencyResolver,
- oldConfigBeanInfo.getReadableModule());
+ oldConfigBeanInfo.getReadableModule(), bc);
} catch (Exception e) {
throw new IllegalStateException(format(
"Error while copying old configuration from %s to %s",
oldConfigBeanInfo, moduleFactory), e);
}
- putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module,
- moduleFactory, oldConfigBeanInfo);
+ putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module, moduleFactory, oldConfigBeanInfo, dependencyResolver);
}
@Override
transactionStatus.checkNotCommitStarted();
transactionStatus.checkNotAborted();
- ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName,
- instanceName);
+ ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
dependencyResolverManager.assertNotExists(moduleIdentifier);
// find factory
- ModuleFactory moduleFactory = factoriesHolder
- .findByModuleName(factoryName);
- DependencyResolver dependencyResolver = dependencyResolverManager
- .getOrCreate(moduleIdentifier);
- Module module = moduleFactory.createModule(instanceName,
- dependencyResolver);
+ ModuleFactory moduleFactory = factoriesHolder.findByModuleName(factoryName);
+ DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
+ Module module = moduleFactory.createModule(instanceName, dependencyResolver,
+ getModuleFactoryBundleContext(moduleFactory.getImplementationName()));
return putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module,
- moduleFactory, null);
+ moduleFactory, null, dependencyResolver);
}
private synchronized ObjectName putConfigBeanToJMXAndInternalMaps(
ModuleIdentifier moduleIdentifier, Module module,
ModuleFactory moduleFactory,
- @Nullable ModuleInternalInfo maybeOldConfigBeanInfo)
+ @Nullable ModuleInternalInfo maybeOldConfigBeanInfo, DependencyResolver dependencyResolver)
throws InstanceAlreadyExistsException {
+ logger.debug("Adding module {} to transaction {}", moduleIdentifier, this);
+ if (moduleIdentifier.equals(module.getIdentifier())==false) {
+ throw new IllegalStateException("Incorrect name reported by module. Expected "
+ + moduleIdentifier + ", got " + module.getIdentifier());
+ }
+ if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false ) {
+ throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected "
+ + moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
+ }
DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
module, moduleIdentifier, transactionIdentifier,
readOnlyAtomicBoolean, transactionsMBeanServer,
+ objectName);
}
ObjectNameUtil.checkDomain(objectName);
- transactionStatus.checkNotAborted();
ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
ObjectNameUtil.TYPE_MODULE);
- ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager
- .destroyModule(moduleIdentifier);
+ destroyModule(moduleIdentifier);
+ }
+
+ private void destroyModule(ModuleIdentifier moduleIdentifier) {
+ logger.debug("Destroying module {} in transaction {}", moduleIdentifier, this);
+ transactionStatus.checkNotAborted();
+ ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
// remove from jmx
removedTInfo.getTransactionModuleJMXRegistration().close();
}
ModuleIdentifier name = entry.getKey();
try {
logger.debug("About to commit {} in transaction {}",
- transactionIdentifier, name);
+ name, transactionIdentifier);
module.getInstance();
} catch (Exception e) {
logger.error("Commit failed on {} in transaction {}", name,
public TransactionIdentifier getName() {
return transactionIdentifier;
}
+
+ @Override
+ public List<ModuleFactory> getCurrentlyRegisteredFactories() {
+ return new ArrayList<>(factoriesHolder.getModuleFactories());
+ }
+
+ @Override
+ public TransactionIdentifier getIdentifier() {
+ return transactionIdentifier;
+ }
+
+ @Override
+ public BundleContext getModuleFactoryBundleContext(String factoryName) {
+ Map.Entry<ModuleFactory, BundleContext> factoryBundleContextEntry = this.currentlyRegisteredFactories.get(factoryName);
+ if (factoryBundleContextEntry == null || factoryBundleContextEntry.getValue() == null) {
+ throw new NullPointerException("Bundle context of " + factoryName + " ModuleFactory not found.");
+ }
+ return factoryBundleContextEntry.getValue();
+ }
}