BundleContext bundleContext, MBeanServer configMBeanServer,
BaseJMXRegistrator baseJMXRegistrator) {
this.resolver = resolver;
- this.beanToOsgiServiceManager = new BeanToOsgiServiceManager(
- bundleContext);
+ this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
this.bundleContext = bundleContext;
this.configMBeanServer = configMBeanServer;
this.baseJMXRegistrator = baseJMXRegistrator;
String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
TransactionJMXRegistrator transactionRegistrator = baseJMXRegistrator
.createTransactionJMXRegistrator(transactionName);
- List<ModuleFactory> allCurrentFactories = Collections.unmodifiableList(resolver.getAllFactories());
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(resolver.getAllFactories());
ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl(
transactionName, transactionRegistrator, version,
versionCounter, allCurrentFactories, transactionsMBeanServer, configMBeanServer, bundleContext);
// register to OSGi
if (osgiRegistration == null) {
- osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
- newReadableConfigBean.getInstance(), entry.getName());
+ ModuleFactory moduleFactory = entry.getModuleFactory();
+ if(moduleFactory != null) {
+ BundleContext bc = configTransactionController.
+ getModuleFactoryBundleContext(moduleFactory.getImplementationName());
+ osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
+ newReadableConfigBean.getInstance(), entry.getName(), bc);
+ } else {
+ throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
+ }
+
}
RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = runtimeRegistrators
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import java.util.ArrayList;
-import java.util.Collection;
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;
private final DependencyResolverManager dependencyResolverManager;
private final TransactionStatus transactionStatus;
private final MBeanServer transactionsMBeanServer;
- private final List<ModuleFactory> currentlyRegisteredFactories;
+ private final Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories;
/**
* Disables ability of {@link DynamicWritableWrapper} to change attributes
public ConfigTransactionControllerImpl(String transactionName,
TransactionJMXRegistrator transactionRegistrator,
long parentVersion, long currentVersion,
- List<ModuleFactory> currentlyRegisteredFactories,
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories,
MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer, BundleContext bundleContext) {
this.transactionIdentifier = new TransactionIdentifier(transactionName);
transactionStatus.checkNotAborted();
Set<ModuleFactory> oldSet = new HashSet<>(lastListOfFactories);
- Set<ModuleFactory> newSet = new HashSet<>(currentlyRegisteredFactories);
+ Set<ModuleFactory> newSet = new HashSet<>(factoriesHolder.getModuleFactories());
List<ModuleFactory> toBeAdded = new ArrayList<>();
List<ModuleFactory> toBeRemoved = new ArrayList<>();
- for(ModuleFactory moduleFactory: currentlyRegisteredFactories) {
+ for(ModuleFactory moduleFactory: factoriesHolder.getModuleFactories()) {
if (oldSet.contains(moduleFactory) == false){
toBeAdded.add(moduleFactory);
}
}
// add default modules
for (ModuleFactory moduleFactory : toBeAdded) {
- Set<? extends Module> defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager, bundleContext);
+ 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());
DependencyResolver dependencyResolver = dependencyResolverManager
.getOrCreate(moduleIdentifier);
try {
+ BundleContext bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
module = moduleFactory.createModule(
moduleIdentifier.getInstanceName(), dependencyResolver,
- oldConfigBeanInfo.getReadableModule(), bundleContext);
+ oldConfigBeanInfo.getReadableModule(), bc);
} catch (Exception e) {
throw new IllegalStateException(format(
"Error while copying old configuration from %s to %s",
// find factory
ModuleFactory moduleFactory = factoriesHolder.findByModuleName(factoryName);
DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
- Module module = moduleFactory.createModule(instanceName, dependencyResolver, bundleContext);
+ Module module = moduleFactory.createModule(instanceName, dependencyResolver,
+ getModuleFactoryBundleContext(moduleFactory.getImplementationName()));
return putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module,
moduleFactory, null, dependencyResolver);
}
@Override
public List<ModuleFactory> getCurrentlyRegisteredFactories() {
- return currentlyRegisteredFactories;
+ 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();
+ }
}
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
/**
* Defines contract between {@link ConfigTransactionControllerImpl} (producer)
boolean isClosed();
List<ModuleFactory> getCurrentlyRegisteredFactories();
+
+ BundleContext getModuleFactoryBundleContext(String factoryName);
}
*/
package org.opendaylight.controller.config.manager.impl.factoriesresolver;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Set;
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+import java.util.TreeSet;
+import java.util.Collection;
+import java.util.ArrayList;
+
/**
* Hold sorted ConfigMBeanFactories by their module names. Check that module
* names are globally unique.
private static final Logger logger = LoggerFactory
.getLogger(HierarchicalConfigMBeanFactoriesHolder.class);
- private final Map<String, ModuleFactory> moduleNamesToConfigBeanFactories;
+ private final Map<String, Map.Entry<ModuleFactory, BundleContext>> moduleNamesToConfigBeanFactories;
private final Set<String> moduleNames;
+ private final List<ModuleFactory> moduleFactories;
/**
* Create instance.
* if unique constraint on module names is violated
*/
public HierarchicalConfigMBeanFactoriesHolder(
- List<? extends ModuleFactory> list) {
- Map<String, ModuleFactory> moduleNamesToConfigBeanFactories = new HashMap<>();
- StringBuffer errors = new StringBuffer();
- for (ModuleFactory factory : list) {
- String moduleName = factory.getImplementationName();
- if (moduleName == null || moduleName.isEmpty()) {
- throw new IllegalStateException(
- "Invalid implementation name for " + factory);
- }
- logger.debug("Reading factory {} {}", moduleName, factory);
- String error = null;
- ModuleFactory conflicting = moduleNamesToConfigBeanFactories
- .get(moduleName);
- if (conflicting != null) {
- error = String
- .format("Module name is not unique. Found two conflicting factories with same name '%s': " +
- "\n\t%s\n\t%s\n", moduleName, conflicting, factory);
-
- }
-
- if (error == null) {
- moduleNamesToConfigBeanFactories.put(moduleName, factory);
- } else {
- errors.append(error);
- }
-
- }
- if (errors.length() > 0) {
- throw new IllegalArgumentException(errors.toString());
- }
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> factoriesMap) {
this.moduleNamesToConfigBeanFactories = Collections
- .unmodifiableMap(moduleNamesToConfigBeanFactories);
+ .unmodifiableMap(factoriesMap);
moduleNames = Collections.unmodifiableSet(new TreeSet<>(
moduleNamesToConfigBeanFactories.keySet()));
+ List<ModuleFactory> factories = new ArrayList<>(this.moduleNamesToConfigBeanFactories.size());
+ Collection<Map.Entry<ModuleFactory, BundleContext>> entryCollection = this.moduleNamesToConfigBeanFactories.values();
+ for (Map.Entry<ModuleFactory, BundleContext> entry : entryCollection) {
+ factories.add(entry.getKey());
+ }
+ this.moduleFactories = Collections.unmodifiableList(factories);
}
/**
* if factory is not found
*/
public ModuleFactory findByModuleName(String moduleName) {
- ModuleFactory result = moduleNamesToConfigBeanFactories.get(moduleName);
+ Map.Entry<ModuleFactory, BundleContext> result = moduleNamesToConfigBeanFactories.get(moduleName);
if (result == null) {
throw new IllegalArgumentException(
"ModuleFactory not found with module name: " + moduleName);
}
- return result;
+ return result.getKey();
}
public Set<String> getModuleNames() {
return moduleNames;
}
+ public List<ModuleFactory> getModuleFactories() {
+ return moduleFactories;
+ }
+
}
*/
package org.opendaylight.controller.config.manager.impl.factoriesresolver;
-import java.util.List;
-
import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
+
+import java.util.Map;
/**
* {@link org.opendaylight.controller.config.manager.impl.ConfigTransactionControllerImpl}
*/
public interface ModuleFactoriesResolver {
- List<ModuleFactory> getAllFactories();
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> getAllFactories();
}
*/
package org.opendaylight.controller.config.manager.impl.osgi;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Set;
-
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
/**
* Registers instantiated beans as OSGi services and unregisters these services
* if beans are destroyed.
static final String INSTANCE_NAME_OSGI_PROP = "instanceName";
static final String IMPLEMENTATION_NAME_OSGI_PROP = "implementationName";
- private final BundleContext bundleContext;
-
- public BeanToOsgiServiceManager(BundleContext context) {
- this.bundleContext = context;
- }
-
/**
* To be called for every created, reconfigured and recreated config bean.
* It is expected that before using this method OSGi service registry will
*/
public OsgiRegistration registerToOsgi(
Class<? extends Module> configBeanClass, AutoCloseable instance,
- ModuleIdentifier moduleIdentifier) {
+ ModuleIdentifier moduleIdentifier, BundleContext bundleContext) {
try {
final Set<Class<?>> configuresInterfaces = InterfacesHelper
.getOsgiRegistrationTypes(configBeanClass);
*/
package org.opendaylight.controller.config.manager.impl.osgi;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
/**
* Retrieves list of currently registered Module Factories using bundlecontext.
*/
public class BundleContextBackedModuleFactoriesResolver implements
ModuleFactoriesResolver {
+ private static final Logger logger = LoggerFactory
+ .getLogger(BundleContextBackedModuleFactoriesResolver.class);
private final BundleContext bundleContext;
public BundleContextBackedModuleFactoriesResolver(
}
@Override
- public List<ModuleFactory> getAllFactories() {
+ public Map<String, Map.Entry<ModuleFactory, BundleContext>> getAllFactories() {
Collection<ServiceReference<ModuleFactory>> serviceReferences;
try {
serviceReferences = bundleContext.getServiceReferences(
} catch (InvalidSyntaxException e) {
throw new IllegalStateException(e);
}
- List<ModuleFactory> result = new ArrayList<>(serviceReferences.size());
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> result = new HashMap<>(serviceReferences.size());
for (ServiceReference<ModuleFactory> serviceReference : serviceReferences) {
- ModuleFactory service = bundleContext.getService(serviceReference);
+ ModuleFactory factory = bundleContext.getService(serviceReference);
// null if the service is not registered, the service object
// returned by a ServiceFactory does not
// implement the classes under which it was registered or the
// ServiceFactory threw an exception.
- if (service != null) {
- result.add(service);
+ if(factory == null) {
+ throw new NullPointerException("ServiceReference of class" + serviceReference.getClass() + "not found.");
+ }
+ StringBuffer errors = new StringBuffer();
+ String moduleName = factory.getImplementationName();
+ if (moduleName == null || moduleName.isEmpty()) {
+ throw new IllegalStateException(
+ "Invalid implementation name for " + factory);
+ }
+ if (serviceReference.getBundle() == null || serviceReference.getBundle().getBundleContext() == null) {
+ throw new NullPointerException("Bundle context of " + factory + " ModuleFactory not found.");
+ }
+ logger.debug("Reading factory {} {}", moduleName, factory);
+ String error = null;
+ Map.Entry<ModuleFactory, BundleContext> conflicting = result.get(moduleName);
+ if (conflicting != null) {
+ error = String
+ .format("Module name is not unique. Found two conflicting factories with same name '%s': " +
+ "\n\t%s\n\t%s\n", moduleName, conflicting.getKey(), factory);
+
+ }
+
+ if (error == null) {
+ result.put(moduleName, new AbstractMap.SimpleImmutableEntry<>(factory,
+ serviceReference.getBundle().getBundleContext()));
+ } else {
+ errors.append(error);
+ }
+ if (errors.length() > 0) {
+ throw new IllegalArgumentException(errors.toString());
}
}
return result;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private ExtenderBundleTracker extenderBundleTracker;
private ConfigRegistryImpl configRegistry;
private ConfigRegistryJMXRegistrator configRegistryJMXRegistrator;
+ private ServiceRegistration configRegistryServiceRegistration;
@Override
public void start(BundleContext context) throws Exception {
bundleContextBackedModuleFactoriesResolver, context,
configMBeanServer);
+ // register config registry to OSGi
+ configRegistryServiceRegistration = context.registerService(ConfigRegistryImpl.class, configRegistry, null);
+
// register config registry to jmx
configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator(configMBeanServer);
configRegistryJMXRegistrator.registerToJMX(configRegistry);
"Exception while closing config registry jmx registrator",
e);
}
+ try {
+ configRegistryServiceRegistration.unregister();
+ } catch (Exception e) {
+ logger.warn("Exception while unregistering config registry", e);
+ }
}
}
*/
public static Set<Class<?>> getOsgiRegistrationTypes(
Class<? extends Module> configBeanClass) {
+ // TODO test with service interface hierarchy
Set<Class<?>> serviceInterfaces = getServiceInterfaces(configBeanClass);
Set<Class<?>> result = new HashSet<>();
for (Class<?> clazz : serviceInterfaces) {
@Test
public void testFailOnTwoFactoriesExportingSameImpl() {
ModuleFactory factory = new TestingFixedThreadPoolModuleFactory();
- ModuleFactoriesResolver resolver = new HardcodedModuleFactoriesResolver(
- factory, factory);
-
BundleContext context = mock(BundleContext.class);
-
- ConfigRegistryImpl configRegistry = new ConfigRegistryImpl(resolver,
- context, ManagementFactory.getPlatformMBeanServer());
+ ConfigRegistryImpl configRegistry = null;
try {
+ ModuleFactoriesResolver resolver = new HardcodedModuleFactoriesResolver(
+ factory, factory);
+
+ configRegistry = new ConfigRegistryImpl(resolver,
+ context, ManagementFactory.getPlatformMBeanServer());
+
configRegistry.beginConfig();
fail();
} catch (IllegalArgumentException e) {
*/
package org.opendaylight.controller.config.manager.impl;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import java.io.Closeable;
-import java.lang.management.ManagementFactory;
-import java.util.Dictionary;
-import java.util.Set;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
import org.junit.After;
import org.mockito.Matchers;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.io.Closeable;
+import java.lang.management.ManagementFactory;
+import java.util.Dictionary;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
/**
* Each test that relies on
* {@link org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl}
protected ConfigRegistryJMXClient configRegistryClient;
protected BaseJMXRegistrator baseJmxRegistrator;
protected InternalJMXRegistrator internalJmxRegistrator;
- protected BundleContext mockedContext;
+ protected BundleContext mockedContext = mock(BundleContext.class);
protected ServiceRegistration<?> mockedServiceRegistration;
// this method should be called in @Before
configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator(
platformMBeanServer);
- this.mockedContext = mock(BundleContext.class);
this.mockedServiceRegistration = mock(ServiceRegistration.class);
doNothing().when(mockedServiceRegistration).unregister();
doReturn(mockedServiceRegistration).when(mockedContext).registerService(
Matchers.any(String[].class), any(Closeable.class),
any(Dictionary.class));
+
internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer);
baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator);
import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.runtimembean.TestingRuntimeBean;
import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
baseJMXRegistrator = new BaseJMXRegistrator(
ManagementFactory.getPlatformMBeanServer());
transactionsMBeanServer = MBeanServerFactory.createMBeanServer();
- List<ModuleFactory> currentlyRegisteredFactories = new ArrayList<>();
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories = new HashMap<>();
TransactionJMXRegistrator jmxRegistrator123 = baseJMXRegistrator
.createTransactionJMXRegistrator(transactionName123);
*/
package org.opendaylight.controller.config.manager.impl.factoriesresolver;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import java.io.Closeable;
import java.util.Arrays;
+import java.util.Dictionary;
import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.AbstractMap;
-import org.opendaylight.controller.config.spi.ModuleFactory;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
public class HardcodedModuleFactoriesResolver implements ModuleFactoriesResolver {
- private final List<ModuleFactory> list;
+ private Map<String, Map.Entry<ModuleFactory, BundleContext>> factories;
+
+ public HardcodedModuleFactoriesResolver(BundleContext bundleContext, ModuleFactory... list) {
+ List<ModuleFactory> factoryList = Arrays.asList(list);
+ this.factories = new HashMap<>(factoryList.size());
+ for (ModuleFactory moduleFactory : list) {
+ StringBuffer errors = new StringBuffer();
+ String moduleName = moduleFactory.getImplementationName();
+ if (moduleName == null || moduleName.isEmpty()) {
+ throw new IllegalStateException(
+ "Invalid implementation name for " + moduleFactory);
+ }
+ String error = null;
+ Map.Entry<ModuleFactory, BundleContext> conflicting = factories.get(moduleName);
+ if (conflicting != null) {
+ error = String
+ .format("Module name is not unique. Found two conflicting factories with same name '%s': " +
+ "\n\t%s\n\t%s\n", moduleName, conflicting.getKey(), moduleFactory);
+
+ }
+
+ if (error == null) {
+ factories.put(moduleName, new AbstractMap.SimpleEntry<>(moduleFactory,
+ bundleContext));
+ } else {
+ errors.append(error);
+ }
+ if (errors.length() > 0) {
+ throw new IllegalArgumentException(errors.toString());
+ }
+ }
+ }
public HardcodedModuleFactoriesResolver(ModuleFactory... list) {
- this.list = Arrays.asList(list);
+ this(mockBundleContext(),list);
+ }
+
+ private static BundleContext mockBundleContext() {
+ BundleContext bundleContext = Mockito.mock(BundleContext.class);
+ ServiceRegistration<ModuleFactory> serviceRegistration = mock(ServiceRegistration.class);
+ doNothing().when(serviceRegistration).unregister();
+ doReturn(serviceRegistration).when(bundleContext).registerService(
+ Matchers.any(String[].class), any(Closeable.class),
+ any(Dictionary.class));
+ return bundleContext;
}
@Override
- public List<ModuleFactory> getAllFactories() {
- return list;
+ public Map<String, Map.Entry<ModuleFactory, BundleContext>> getAllFactories() {
+ return factories;
}
}