ca318f32c9efbf94c1fdd1683d5ebdaeced7d93f
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / ConfigTransactionControllerImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.config.manager.impl;
9
10 import static com.google.common.base.Preconditions.checkNotNull;
11 import static java.lang.String.format;
12
13 import com.google.common.collect.Lists;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
21 import java.util.concurrent.atomic.AtomicBoolean;
22 import javax.annotation.Nullable;
23 import javax.annotation.concurrent.GuardedBy;
24 import javax.management.DynamicMBean;
25 import javax.management.InstanceAlreadyExistsException;
26 import javax.management.InstanceNotFoundException;
27 import javax.management.MBeanServer;
28 import javax.management.ObjectName;
29 import org.opendaylight.controller.config.api.DependencyResolver;
30 import org.opendaylight.controller.config.api.ModuleIdentifier;
31 import org.opendaylight.controller.config.api.ValidationException;
32 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
33 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
34 import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
35 import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
36 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWritableWrapper;
37 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
38 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
39 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
40 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
41 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
42 import org.opendaylight.controller.config.manager.impl.osgi.mapping.BindingContextProvider;
43 import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
44 import org.opendaylight.controller.config.spi.Module;
45 import org.opendaylight.controller.config.spi.ModuleFactory;
46 import org.opendaylight.yangtools.concepts.Identifiable;
47 import org.osgi.framework.BundleContext;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 /**
51  * This is a JMX bean representing current transaction. It contains
52  * transaction identifier, unique version and parent version for
53  * optimistic locking.
54  */
55 class ConfigTransactionControllerImpl implements
56         ConfigTransactionControllerInternal,
57         ConfigTransactionControllerImplMXBean,
58         Identifiable<TransactionIdentifier> {
59     private static final Logger LOG = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
60
61     private final ConfigTransactionLookupRegistry txLookupRegistry;
62     private final ObjectName controllerON;
63
64     private final long parentVersion, currentVersion;
65     private final HierarchicalConfigMBeanFactoriesHolder factoriesHolder;
66     private final DependencyResolverManager dependencyResolverManager;
67     private final TransactionStatus transactionStatus;
68     private final MBeanServer transactionsMBeanServer;
69     private final Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories;
70
71     /**
72      * Disables ability of {@link DynamicWritableWrapper} to change attributes
73      * during validation.
74      */
75     @GuardedBy("this")
76     private final AtomicBoolean configBeanModificationDisabled = new AtomicBoolean(
77             false);
78     private final ReadOnlyAtomicBoolean readOnlyAtomicBoolean = new ReadOnlyAtomicBooleanImpl(
79             configBeanModificationDisabled);
80     private final MBeanServer configMBeanServer;
81
82     private final boolean blankTransaction;
83
84     @GuardedBy("this")
85     private final SearchableServiceReferenceWritableRegistry writableSRRegistry;
86
87     public ConfigTransactionControllerImpl(ConfigTransactionLookupRegistry txLookupRegistry,
88                                            long parentVersion, BindingContextProvider bindingContextProvider, long currentVersion,
89                                            Map<String, Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories,
90                                            MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer,
91                                            boolean blankTransaction, SearchableServiceReferenceWritableRegistry  writableSRRegistry) {
92         this.txLookupRegistry = txLookupRegistry;
93         String transactionName = txLookupRegistry.getTransactionIdentifier().getName();
94         this.controllerON = ObjectNameUtil.createTransactionControllerON(transactionName);
95         this.parentVersion = parentVersion;
96         this.currentVersion = currentVersion;
97         this.currentlyRegisteredFactories = currentlyRegisteredFactories;
98         this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
99         this.transactionStatus = new TransactionStatus();
100         this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
101                 transactionStatus, writableSRRegistry, bindingContextProvider, transactionsMBeanServer);
102         this.transactionsMBeanServer = transactionsMBeanServer;
103         this.configMBeanServer = configMBeanServer;
104         this.blankTransaction = blankTransaction;
105         this.writableSRRegistry = writableSRRegistry;
106     }
107
108     @Override
109     public void copyExistingModulesAndProcessFactoryDiff(Collection<ModuleInternalInfo> existingModules, List<ModuleFactory> lastListOfFactories) {
110         // copy old configuration to this server
111         for (ModuleInternalInfo oldConfigInfo : existingModules) {
112             try {
113                 copyExistingModule(oldConfigInfo);
114             } catch (InstanceAlreadyExistsException e) {
115                 throw new IllegalStateException("Error while copying " + oldConfigInfo, e);
116             }
117         }
118         processDefaultBeans(lastListOfFactories);
119     }
120
121     private synchronized void processDefaultBeans(List<ModuleFactory> lastListOfFactories) {
122         transactionStatus.checkNotCommitStarted();
123         transactionStatus.checkNotAborted();
124
125         Set<ModuleFactory> oldSet = new HashSet<>(lastListOfFactories);
126         Set<ModuleFactory> newSet = new HashSet<>(factoriesHolder.getModuleFactories());
127
128         List<ModuleFactory> toBeAdded = new ArrayList<>();
129         List<ModuleFactory> toBeRemoved = new ArrayList<>();
130         for (ModuleFactory moduleFactory : factoriesHolder.getModuleFactories()) {
131             if (oldSet.contains(moduleFactory) == false) {
132                 toBeAdded.add(moduleFactory);
133             }
134         }
135         for (ModuleFactory moduleFactory : lastListOfFactories) {
136             if (newSet.contains(moduleFactory) == false) {
137                 toBeRemoved.add(moduleFactory);
138             }
139         }
140         // add default modules
141         for (ModuleFactory moduleFactory : toBeAdded) {
142             BundleContext bundleContext = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
143             Set<? extends Module> defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager,
144                     bundleContext);
145             for (Module module : defaultModules) {
146                 // ensure default module to be registered to jmx even if its module factory does not use dependencyResolverFactory
147                 DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(module.getIdentifier());
148                 final ObjectName objectName;
149                 try {
150                     boolean defaultBean = true;
151                     objectName = putConfigBeanToJMXAndInternalMaps(module.getIdentifier(), module, moduleFactory, null,
152                             dependencyResolver, defaultBean, bundleContext);
153                 } catch (InstanceAlreadyExistsException e) {
154                     throw new IllegalStateException(e);
155                 }
156
157                 // register default module as every possible service
158                 final Set<ServiceInterfaceAnnotation> serviceInterfaceAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(moduleFactory);
159                 for (String qname : InterfacesHelper.getQNames(serviceInterfaceAnnotations)) {
160                     try {
161                         saveServiceReference(qname, module.getIdentifier().getInstanceName(), objectName);
162                     } catch (InstanceNotFoundException e) {
163                         throw new IllegalStateException("Unable to register default module instance " + module + " as a service of " + qname, e);
164                     }
165                 }
166             }
167         }
168
169         // remove modules belonging to removed factories
170         for (ModuleFactory removedFactory : toBeRemoved) {
171             List<ModuleIdentifier> modulesOfRemovedFactory = dependencyResolverManager.findAllByFactory(removedFactory);
172             for (ModuleIdentifier name : modulesOfRemovedFactory) {
173                 // remove service refs
174                 final ModuleFactory moduleFactory = dependencyResolverManager.findModuleInternalTransactionalInfo(name).getModuleFactory();
175                 final Set<ServiceInterfaceAnnotation> serviceInterfaceAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(moduleFactory);
176                 for (String qname : InterfacesHelper.getQNames(serviceInterfaceAnnotations)) {
177                     try {
178                         removeServiceReference(qname, name.getInstanceName());
179                     } catch (InstanceNotFoundException e) {
180                         throw new IllegalStateException("Unable to UNregister default module instance " + name + " as a service of " + qname, e);
181                     }
182                 }
183
184                 // close module
185                 destroyModule(name);
186             }
187         }
188     }
189
190
191     private synchronized void copyExistingModule(ModuleInternalInfo oldConfigBeanInfo) throws InstanceAlreadyExistsException {
192
193         transactionStatus.checkNotCommitStarted();
194         transactionStatus.checkNotAborted();
195         ModuleIdentifier moduleIdentifier = oldConfigBeanInfo.getIdentifier();
196         dependencyResolverManager.assertNotExists(moduleIdentifier);
197
198         ModuleFactory moduleFactory;
199         BundleContext bc;
200         try {
201             moduleFactory = factoriesHolder.findByModuleName(moduleIdentifier.getFactoryName());
202             bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
203         } catch (InstanceNotFoundException e) {
204             throw new IllegalStateException(e);
205         }
206
207         Module module;
208         DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
209         try {
210
211             module = moduleFactory.createModule(
212                     moduleIdentifier.getInstanceName(), dependencyResolver,
213                     oldConfigBeanInfo.getReadableModule(), bc);
214         } catch (Exception e) {
215             throw new IllegalStateException(format(
216                     "Error while copying old configuration from %s to %s",
217                     oldConfigBeanInfo, moduleFactory), e);
218         }
219         putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module, moduleFactory, oldConfigBeanInfo, dependencyResolver,
220                 oldConfigBeanInfo.isDefaultBean(), bc);
221     }
222
223     @Override
224     public synchronized ObjectName createModule(String factoryName,
225                                                 String instanceName) throws InstanceAlreadyExistsException {
226
227         transactionStatus.checkNotCommitStarted();
228         transactionStatus.checkNotAborted();
229         ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
230         dependencyResolverManager.assertNotExists(moduleIdentifier);
231
232         // find factory
233         ModuleFactory moduleFactory;
234         try {
235             moduleFactory = factoriesHolder.findByModuleName(factoryName);
236         } catch (InstanceNotFoundException e) {
237             throw new IllegalArgumentException(e);
238         }
239         DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
240         BundleContext bundleContext = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
241         Module module = moduleFactory.createModule(instanceName, dependencyResolver,
242                 bundleContext);
243         boolean defaultBean = false;
244         return putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module,
245                 moduleFactory, null, dependencyResolver, defaultBean, bundleContext);
246     }
247
248     private synchronized ObjectName putConfigBeanToJMXAndInternalMaps(
249             ModuleIdentifier moduleIdentifier, Module module,
250             ModuleFactory moduleFactory,
251             @Nullable ModuleInternalInfo maybeOldConfigBeanInfo, DependencyResolver dependencyResolver,
252             boolean isDefaultBean, BundleContext bundleContext)
253             throws InstanceAlreadyExistsException {
254
255         LOG.debug("Adding module {} to transaction {}", moduleIdentifier, this);
256         if (moduleIdentifier.equals(module.getIdentifier()) == false) {
257             throw new IllegalStateException("Incorrect name reported by module. Expected "
258                     + moduleIdentifier + ", got " + module.getIdentifier());
259         }
260         if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false) {
261             throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected "
262                     + moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
263         }
264         DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
265                 module, moduleIdentifier, getTransactionIdentifier(),
266                 readOnlyAtomicBoolean, transactionsMBeanServer,
267                 configMBeanServer);
268
269         ObjectName writableON = ObjectNameUtil.createTransactionModuleON(
270                 getTransactionIdentifier().getName(), moduleIdentifier);
271         // put wrapper to jmx
272         TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
273                 .registerMBean(writableDynamicWrapper, writableON);
274
275         dependencyResolverManager.put(
276                 moduleIdentifier, module, moduleFactory,
277                 maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean, bundleContext);
278         return writableON;
279     }
280
281     @Override
282     public synchronized void destroyModule(ObjectName objectName) throws InstanceNotFoundException {
283         checkTransactionName(objectName);
284         ObjectNameUtil.checkDomain(objectName);
285         ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
286                 ObjectNameUtil.TYPE_MODULE);
287         destroyModule(moduleIdentifier);
288     }
289
290     private void checkTransactionName(ObjectName objectName) {
291         String foundTransactionName = ObjectNameUtil
292                 .getTransactionName(objectName);
293         if (getTransactionIdentifier().getName().equals(foundTransactionName) == false) {
294             throw new IllegalArgumentException("Wrong transaction name "
295                     + objectName);
296         }
297     }
298
299     private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) {
300         LOG.debug("Destroying module {} in transaction {}", moduleIdentifier, this);
301         transactionStatus.checkNotAborted();
302
303         ModuleInternalTransactionalInfo found = dependencyResolverManager.findModuleInternalTransactionalInfo(moduleIdentifier);
304         if (blankTransaction == false &&
305                 found.isDefaultBean()) {
306             LOG.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
307         }
308         // first remove refNames, it checks for objectname existence
309
310         try {
311             writableSRRegistry.removeServiceReferences(
312                     ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier));
313         } catch (InstanceNotFoundException e) {
314             LOG.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
315             throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
316         }
317
318         ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
319         // remove from jmx
320         removedTInfo.getTransactionModuleJMXRegistration().close();
321     }
322
323     @Override
324     public long getParentVersion() {
325         return parentVersion;
326     }
327
328     @Override
329     public long getVersion() {
330         return currentVersion;
331     }
332
333     @Override
334     public synchronized void validateConfig() throws ValidationException {
335         if (configBeanModificationDisabled.get()) {
336             throw new IllegalStateException("Cannot start validation");
337         }
338         configBeanModificationDisabled.set(true);
339         try {
340             validateNoLocks();
341         } finally {
342             configBeanModificationDisabled.set(false);
343         }
344     }
345
346     private void validateNoLocks() throws ValidationException {
347         transactionStatus.checkNotAborted();
348         LOG.trace("Validating transaction {}", getTransactionIdentifier());
349         // call validate()
350         List<ValidationException> collectedExceptions = new ArrayList<>();
351         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
352                 .getAllModules().entrySet()) {
353             ModuleIdentifier name = entry.getKey();
354             Module module = entry.getValue();
355             try {
356                 module.validate();
357             } catch (Exception e) {
358                 LOG.warn("Validation exception in {}", getTransactionName(),
359                         e);
360                 collectedExceptions.add(ValidationException
361                         .createForSingleException(name, e));
362             }
363         }
364         if (!collectedExceptions.isEmpty()) {
365             throw ValidationException
366                     .createFromCollectedValidationExceptions(collectedExceptions);
367         }
368         LOG.trace("Validated transaction {}", getTransactionIdentifier());
369     }
370
371     /**
372      * If this method passes validation, it will grab
373      * {@link TransactionStatus#secondPhaseCommitStarted} lock. This lock will
374      * prevent calling @{link #validateBeforeCommitAndLockTransaction},
375      * effectively only allowing to call {@link #secondPhaseCommit} after
376      * successful return of this method.
377      */
378     @Override
379     public synchronized CommitInfo validateBeforeCommitAndLockTransaction()
380             throws ValidationException {
381         transactionStatus.checkNotAborted();
382         transactionStatus.checkNotCommitStarted();
383         configBeanModificationDisabled.set(true);
384         try {
385             validateNoLocks();
386         } catch (ValidationException e) {
387             LOG.trace("Commit failed on validation");
388             configBeanModificationDisabled.set(false); // recoverable error
389             throw e;
390         }
391         // errors in this state are not recoverable. modules are not mutable
392         // anymore.
393         transactionStatus.setSecondPhaseCommitStarted();
394         return dependencyResolverManager.toCommitInfo();
395     }
396
397     /**
398      * {@inheritDoc}
399      */
400     @Override
401     public synchronized List<ModuleIdentifier> secondPhaseCommit() {
402         transactionStatus.checkNotAborted();
403         transactionStatus.checkCommitStarted();
404         if (configBeanModificationDisabled.get() == false) {
405             throw new IllegalStateException(
406                     "Internal error - validateBeforeCommitAndLockTransaction should be called "
407                             + "to obtain a lock");
408         }
409
410         LOG.trace("Committing transaction {}", getTransactionIdentifier());
411
412         Map<ModuleIdentifier, Module> allModules = dependencyResolverManager.getAllModules();
413
414         // call getInstance() on all Modules from top to bottom (from source to target of the dependency relation)
415         // The source of a dependency closes itself and calls getInstance recursively on the dependencies (in case of reconfiguration)
416         // This makes close() calls from top to bottom while createInstance() calls are performed bottom to top
417         List<ModuleIdentifier> sortedModuleIdentifiers = Lists.reverse(dependencyResolverManager.getSortedModuleIdentifiers());
418         for (ModuleIdentifier moduleIdentifier : sortedModuleIdentifiers) {
419             Module module = allModules.get(moduleIdentifier);
420
421             try {
422                 LOG.debug("About to commit {} in transaction {}",
423                         moduleIdentifier, getTransactionIdentifier());
424                 AutoCloseable instance = module.getInstance();
425                 checkNotNull(instance, "Instance is null:{} in transaction {}", moduleIdentifier, getTransactionIdentifier());
426             } catch (Exception e) {
427                 LOG.error("Commit failed on {} in transaction {}", moduleIdentifier,
428                         getTransactionIdentifier(), e);
429                 internalAbort();
430                 throw new IllegalStateException(
431                         format("Error - getInstance() failed for %s in transaction %s",
432                                 moduleIdentifier, getTransactionIdentifier()), e);
433             }
434         }
435
436         LOG.trace("Committed configuration {}", getTransactionIdentifier());
437         transactionStatus.setCommitted();
438
439         return sortedModuleIdentifiers;
440     }
441
442     @Override
443     public synchronized void abortConfig() {
444         transactionStatus.checkNotCommitStarted();
445         transactionStatus.checkNotAborted();
446         internalAbort();
447     }
448
449     private void internalAbort() {
450         LOG.trace("Aborting {}", this);
451         transactionStatus.setAborted();
452         close();
453     }
454
455     public void close() {
456         dependencyResolverManager.close();
457         txLookupRegistry.close();
458     }
459
460     @Override
461     public ObjectName getControllerObjectName() {
462         return controllerON;
463     }
464
465     @Override
466     public String getTransactionName() {
467         return getTransactionIdentifier().getName();
468     }
469
470     /**
471      * {@inheritDoc}
472      */
473     @Override
474     public Set<ObjectName> lookupConfigBeans() {
475         return txLookupRegistry.lookupConfigBeans();
476     }
477
478     /**
479      * {@inheritDoc}
480      */
481     @Override
482     public Set<ObjectName> lookupConfigBeans(String moduleName) {
483         return txLookupRegistry.lookupConfigBeans(moduleName);
484     }
485
486     /**
487      * {@inheritDoc}
488      */
489     @Override
490     public ObjectName lookupConfigBean(String moduleName, String instanceName)
491             throws InstanceNotFoundException {
492         return txLookupRegistry.lookupConfigBean(moduleName, instanceName);
493     }
494
495     /**
496      * {@inheritDoc}
497      */
498     @Override
499     public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
500         return txLookupRegistry.lookupConfigBeans(moduleName, instanceName);
501     }
502
503     /**
504      * {@inheritDoc}
505      */
506     @Override
507     public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
508         txLookupRegistry.checkConfigBeanExists(objectName);
509     }
510
511
512     /**
513      * {@inheritDoc}
514      */
515     @Override
516     public Set<ObjectName> lookupRuntimeBeans() {
517         return txLookupRegistry.lookupRuntimeBeans();
518     }
519
520     /**
521      * {@inheritDoc}
522      */
523     @Override
524     public Set<ObjectName> lookupRuntimeBeans(String moduleName,
525                                               String instanceName) {
526         return txLookupRegistry.lookupRuntimeBeans(moduleName, instanceName);
527     }
528
529     // --
530
531     /**
532      * {@inheritDoc}
533      */
534     @Override
535     public Set<String> getAvailableModuleNames() {
536         return factoriesHolder.getModuleNames();
537     }
538
539     @Override
540     public boolean isClosed() {
541         return transactionStatus.isAbortedOrCommitted();
542     }
543
544     @Override
545     public String toString() {
546         StringBuilder sb = new StringBuilder();
547         sb.append("transactionName=");
548         sb.append(getTransactionName());
549         return sb.toString();
550     }
551
552     // @VisibleForTesting
553
554     TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
555         return txLookupRegistry.getTxModuleJMXRegistrator();
556     }
557
558     public TransactionIdentifier getName() {
559         return getTransactionIdentifier();
560     }
561
562     @Override
563     public List<ModuleFactory> getCurrentlyRegisteredFactories() {
564         return new ArrayList<>(factoriesHolder.getModuleFactories());
565     }
566
567     @Override
568     public TransactionIdentifier getIdentifier() {
569         return getTransactionIdentifier();
570     }
571
572     @Override
573     public BundleContext getModuleFactoryBundleContext(String factoryName) {
574         Map.Entry<ModuleFactory, BundleContext> factoryBundleContextEntry = this.currentlyRegisteredFactories.get(factoryName);
575         if (factoryBundleContextEntry == null || factoryBundleContextEntry.getValue() == null) {
576             throw new NullPointerException("Bundle context of " + factoryName + " ModuleFactory not found.");
577         }
578         return factoryBundleContextEntry.getValue();
579     }
580
581     // service reference functionality:
582
583
584     @Override
585     public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
586         return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
587     }
588
589     @Override
590     public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
591         return writableSRRegistry.getServiceMapping();
592     }
593
594     @Override
595     public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
596         return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
597     }
598
599     @Override
600     public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
601         return writableSRRegistry.lookupServiceInterfaceNames(objectName);
602     }
603
604     @Override
605     public synchronized String getServiceInterfaceName(String namespace, String localName) {
606         return writableSRRegistry.getServiceInterfaceName(namespace, localName);
607     }
608
609     @Override
610     public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
611         return writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, moduleON);
612     }
613
614     @Override
615     public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException {
616         writableSRRegistry.removeServiceReference(serviceInterfaceName, refName);
617     }
618
619     @Override
620     public synchronized void removeAllServiceReferences() {
621         writableSRRegistry.removeAllServiceReferences();
622     }
623
624     @Override
625     public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
626         return writableSRRegistry.removeServiceReferences(objectName);
627     }
628
629     @Override
630     public SearchableServiceReferenceWritableRegistry  getWritableRegistry() {
631         return writableSRRegistry;
632     }
633
634     @Override
635     public TransactionIdentifier getTransactionIdentifier() {
636         return txLookupRegistry.getTransactionIdentifier();
637     }
638
639     @Override
640     public Set<String> getAvailableModuleFactoryQNames() {
641         return txLookupRegistry.getAvailableModuleFactoryQNames();
642     }
643
644     @Override
645     public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
646         writableSRRegistry.checkServiceReferenceExists(objectName);
647     }
648
649     @Override
650     public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
651         return writableSRRegistry.getServiceReference(serviceInterfaceQName, refName);
652     }
653 }