*/
package org.opendaylight.controller.config.manager.impl;
+import com.google.common.collect.Maps;
+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.ServiceReferenceReadableRegistry;
-import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
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.osgi.mapping.BindingContextProvider;
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.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);
+ private static final Logger LOG = LoggerFactory.getLogger(ConfigRegistryImpl.class);
private final ModuleFactoriesResolver resolver;
private final MBeanServer configMBeanServer;
-
- @GuardedBy("this")
- private final BundleContext bundleContext;
+ private final BindingContextProvider bindingContextProvider;
@GuardedBy("this")
private long version = 0;
// 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 ServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+ private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
// constructor
public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
- BundleContext bundleContext, MBeanServer configMBeanServer) {
- this(resolver, bundleContext, configMBeanServer,
- new BaseJMXRegistrator(configMBeanServer));
+ MBeanServer configMBeanServer, BindingContextProvider bindingContextProvider) {
+ this(resolver, configMBeanServer,
+ new BaseJMXRegistrator(configMBeanServer), bindingContextProvider);
}
// constructor
public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
- BundleContext bundleContext, MBeanServer configMBeanServer,
- BaseJMXRegistrator baseJMXRegistrator) {
+ MBeanServer configMBeanServer,
+ BaseJMXRegistrator baseJMXRegistrator, BindingContextProvider bindingContextProvider) {
this.resolver = resolver;
this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
- this.bundleContext = bundleContext;
this.configMBeanServer = configMBeanServer;
this.baseJMXRegistrator = baseJMXRegistrator;
+ this.bindingContextProvider = bindingContextProvider;
this.registryMBeanServer = MBeanServerFactory
.createMBeanServer("ConfigRegistry" + configMBeanServer.getDefaultDomain());
this.transactionsMBeanServer = MBeanServerFactory
}
};
- ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(
- transactionName), factory);
- Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = new HashMap<>(
resolver.getAllFactories());
- ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+
+ // add all factories that disappeared from SR but are still committed
+ for (ModuleInternalInfo moduleInternalInfo : currentConfig.getEntries()) {
+ String name = moduleInternalInfo.getModuleFactory().getImplementationName();
+ if (allCurrentFactories.containsKey(name) == false) {
+ LOG.trace("Factory {} not found in SR, using reference from previous commit", name);
+ allCurrentFactories.put(name,
+ Maps.immutableEntry(moduleInternalInfo.getModuleFactory(), moduleInternalInfo.getBundleContext()));
+ }
+ }
+ allCurrentFactories = Collections.unmodifiableMap(allCurrentFactories);
+
+ // closed by transaction controller
+ ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(
+ transactionName), factory, allCurrentFactories);
+ SearchableServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
readableSRRegistry, txLookupRegistry, allCurrentFactories);
ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl(
- txLookupRegistry, version,
+ txLookupRegistry, version, bindingContextProvider,
versionCounter, allCurrentFactories, transactionsMBeanServer,
configMBeanServer, blankTransaction, writableRegistry);
try {
throw new IllegalStateException(e);
}
transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
- transactionsHolder.add(transactionName, transactionController);
+ transactionsHolder.add(transactionName, transactionController, txLookupRegistry);
return transactionController;
}
throws ConflictingVersionException, ValidationException {
final String transactionName = ObjectNameUtil
.getTransactionName(transactionControllerON);
- logger.info("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
+ LOG.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(
lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
// non recoverable from here:
try {
- return secondPhaseCommit(
- configTransactionController, commitInfo);
- } catch (Throwable t) { // some libs throw Errors: e.g.
- // javax.xml.ws.spi.FactoryFinder$ConfigurationError
+ return secondPhaseCommit(configTransactionController, commitInfo, configTransactionControllerEntry.getValue());
+ } catch (Error | RuntimeException t) { // some libs throw Errors: e.g.
+ // javax.xml.ws.spi.FactoryFinder$ConfigurationError
isHealthy = false;
- logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
+ LOG.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
} else {
- throw new RuntimeException(t);
+ throw (Error) t;
}
}
}
private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
- CommitInfo commitInfo) {
+ CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) {
// close instances which were destroyed by the user, including
// (hopefully) runtime beans
for (DestroyedModule toBeDestroyed : commitInfo
.getDestroyedFromPreviousTransactions()) {
toBeDestroyed.close(); // closes instance (which should close
- // runtime jmx registrator),
+ // runtime jmx registrator),
// also closes osgi registration and ModuleJMXRegistrator
// registration
currentConfig.remove(toBeDestroyed.getIdentifier());
.getRuntimeBeanRegistrator();
}
// set runtime jmx registrator if required
- Module module = entry.getModule();
+ Module module = entry.getProxiedModule();
if (module instanceof RuntimeBeanRegistratorAwareModule) {
((RuntimeBeanRegistratorAwareModule) module)
.setRuntimeBeanRegistrator(runtimeBeanRegistrator);
}
// 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<>();
int orderingIdx = 0;
for (ModuleIdentifier moduleIdentifier : orderedModuleIdentifiers) {
+ LOG.trace("Registering {}", moduleIdentifier);
ModuleInternalTransactionalInfo entry = commitInfo.getCommitted()
.get(moduleIdentifier);
- if (entry == null)
+ if (entry == null) {
throw new NullPointerException("Module not found "
+ moduleIdentifier);
- Module module = entry.getModule();
+ }
+
ObjectName primaryReadOnlyON = ObjectNameUtil
.createReadOnlyModuleON(moduleIdentifier);
.createModuleJMXRegistrator();
OsgiRegistration osgiRegistration = null;
+ AutoCloseable instance = entry.getProxiedModule().getInstance();
if (entry.hasOldModule()) {
ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
- DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo
- .getReadableModule();
+ 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);
// wrap in readable dynamic mbean
newInstances.add(primaryReadOnlyON);
}
+ Module realModule = entry.getRealModule();
DynamicReadableWrapper newReadableConfigBean = new DynamicReadableWrapper(
- module, module.getInstance(), moduleIdentifier,
+ realModule, instance, moduleIdentifier,
registryMBeanServer, configMBeanServer);
// register to JMX
try {
- newModuleJMXRegistrator.registerMBean(newReadableConfigBean,
- primaryReadOnlyON);
+ newModuleJMXRegistrator.registerMBean(newReadableConfigBean, primaryReadOnlyON);
} catch (InstanceAlreadyExistsException e) {
- throw new IllegalStateException(e);
+ throw new IllegalStateException("Possible code error, already registered:" + primaryReadOnlyON,e);
}
- // register to OSGi
+ // register services to OSGi
+ Map<ServiceInterfaceAnnotation, String /* service ref name */> annotationMapping = configTransactionController.getWritableRegistry().findServiceInterfaces(moduleIdentifier);
+ BundleContext bc = configTransactionController.getModuleFactoryBundleContext(
+ entry.getModuleFactory().getImplementationName());
if (osgiRegistration == null) {
- ModuleFactory moduleFactory = entry.getModuleFactory();
- if(moduleFactory != null) {
- BundleContext bc = configTransactionController.
- getModuleFactoryBundleContext(moduleFactory.getImplementationName());
- osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
- newReadableConfigBean.getInstance(), entry.getIdentifier(), bc);
- } else {
- throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
- }
-
+ osgiRegistration = beanToOsgiServiceManager.registerToOsgi(
+ newReadableConfigBean.getInstance(), moduleIdentifier, bc, annotationMapping);
+ } else {
+ osgiRegistration.updateRegistrations(annotationMapping, bc, instance);
}
RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = runtimeRegistrators
ModuleInternalInfo newInfo = new ModuleInternalInfo(
entry.getIdentifier(), newReadableConfigBean, osgiRegistration,
runtimeBeanRegistrator, newModuleJMXRegistrator,
- orderingIdx, entry.isDefaultBean());
+ orderingIdx, entry.isDefaultBean(), entry.getModuleFactory(), entry.getBundleContext());
- newConfigEntries.put(module, newInfo);
+ newConfigEntries.put(realModule, newInfo);
orderingIdx++;
}
currentConfig.addAll(newConfigEntries.values());
version = configTransactionController.getVersion();
// switch readable Service Reference Registry
- this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(configTransactionController.getWritableRegistry(), this);
+ this.readableSRRegistry.close();
+ this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
+ configTransactionController.getWritableRegistry(), this, baseJMXRegistrator);
return new CommitStatus(newInstances, reusedInstances,
recreatedInstances);
*/
@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;
}
@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 {}",
+ LOG.warn("Ignoring exception while aborting {}",
configTransactionController, e);
}
}
- // destroy all live objects one after another in order of the dependency
- // hierarchy
+ // destroy all live objects one after another in order of the dependency hierarchy, from top to bottom
List<DestroyedModule> destroyedModules = currentConfig
.getModulesToBeDestroyed();
for (DestroyedModule destroyedModule : destroyedModules) {
*/
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName,
- String instanceName) {
+ String instanceName) {
ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
instanceName);
return baseJMXRegistrator.queryNames(namePattern, null);
*/
@Override
public Set<ObjectName> lookupRuntimeBeans(String moduleName,
- String instanceName) {
- if (moduleName == null)
- moduleName = "*";
- if (instanceName == null)
- instanceName = "*";
+ String instanceName) {
+ String finalModuleName = moduleName == null ? "*" : moduleName;
+ String finalInstanceName = instanceName == null ? "*" : instanceName;
ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern(
- moduleName, instanceName);
+ finalModuleName, finalInstanceName);
return baseJMXRegistrator.queryNames(namePattern, null);
}
// service reference functionality:
@Override
- public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
- return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+ public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
}
@Override
}
@Override
- public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
- return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+ public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
}
@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 +
+ '}';
+ }
}
/**
* Service Registry.
*/
public void addAll(Collection<ModuleInternalInfo> configInfos) {
- if (currentConfig.size() > 0) {
+ if (!currentConfig.isEmpty()) {
throw new IllegalStateException(
"Error - some config entries were not removed: "
+ currentConfig);
}
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);
}
}
Collections.sort(result);
return result;
}
+
+
}
/**
* {@link ConfigTransactionControllerInternal} instances, because platform
* MBeanServer transforms mbeans into another representation. Map is cleaned
* every time current transactions are requested.
- *
*/
@GuardedBy("ConfigRegistryImpl.this")
- private final Map<String /* transactionName */, ConfigTransactionControllerInternal> transactions = new HashMap<>();
+ private final Map<String /* transactionName */,
+ Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = new HashMap<>();
/**
* Can only be called from within synchronized method.
*/
public void add(String transactionName,
- ConfigTransactionControllerInternal transactionController) {
+ ConfigTransactionControllerInternal transactionController, ConfigTransactionLookupRegistry txLookupRegistry) {
Object oldValue = transactions.put(transactionName,
- transactionController);
+ Maps.immutableEntry(transactionController, txLookupRegistry));
if (oldValue != null) {
throw new IllegalStateException(
"Error: two transactions with same name");
*
* @return current view on transactions map.
*/
- public Map<String, ConfigTransactionControllerInternal> getCurrentTransactions() {
+ public Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> getCurrentTransactions() {
// first, remove closed transaction
- for (Iterator<Entry<String, ConfigTransactionControllerInternal>> it = transactions
- .entrySet().iterator(); it.hasNext();) {
- Entry<String, ConfigTransactionControllerInternal> entry = it
+ for (Iterator<Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>>> it = transactions
+ .entrySet().iterator(); it.hasNext(); ) {
+ Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> entry = it
.next();
- if (entry.getValue().isClosed()) {
+ if (entry.getValue().getKey().isClosed()) {
it.remove();
}
}