Fix ModuleFactory not found errors
[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 import com.google.common.collect.Lists;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.Set;
20 import java.util.concurrent.atomic.AtomicBoolean;
21 import javax.annotation.Nullable;
22 import javax.annotation.concurrent.GuardedBy;
23 import javax.management.DynamicMBean;
24 import javax.management.InstanceAlreadyExistsException;
25 import javax.management.InstanceNotFoundException;
26 import javax.management.MBeanServer;
27 import javax.management.ObjectName;
28 import org.opendaylight.controller.config.api.DependencyResolver;
29 import org.opendaylight.controller.config.api.ModuleFactoryNotFoundException;
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)
192             throws InstanceAlreadyExistsException {
193
194         transactionStatus.checkNotCommitStarted();
195         transactionStatus.checkNotAborted();
196         ModuleIdentifier moduleIdentifier = oldConfigBeanInfo.getIdentifier();
197         dependencyResolverManager.assertNotExists(moduleIdentifier);
198
199         ModuleFactory moduleFactory;
200         BundleContext bc;
201         try {
202             moduleFactory = factoriesHolder.findByModuleName(moduleIdentifier.getFactoryName());
203             bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
204         } catch (ModuleFactoryNotFoundException e) {
205             throw new IllegalStateException(e);
206         }
207
208         Module module;
209         DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
210         try {
211
212             module = moduleFactory.createModule(
213                     moduleIdentifier.getInstanceName(), dependencyResolver,
214                     oldConfigBeanInfo.getReadableModule(), bc);
215         } catch (Exception e) {
216             throw new IllegalStateException(format(
217                     "Error while copying old configuration from %s to %s",
218                     oldConfigBeanInfo, moduleFactory), e);
219         }
220         putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module, moduleFactory, oldConfigBeanInfo, dependencyResolver,
221                 oldConfigBeanInfo.isDefaultBean(), bc);
222     }
223
224     @Override
225     public synchronized ObjectName createModule(String factoryName, String instanceName)
226             throws InstanceAlreadyExistsException {
227
228         transactionStatus.checkNotCommitStarted();
229         transactionStatus.checkNotAborted();
230         ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
231         dependencyResolverManager.assertNotExists(moduleIdentifier);
232
233         // find factory
234         ModuleFactory moduleFactory = factoriesHolder.findByModuleName(factoryName);
235
236         DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
237         BundleContext bundleContext = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
238         Module module = moduleFactory.createModule(instanceName, dependencyResolver,
239                 bundleContext);
240         boolean defaultBean = false;
241         return putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module,
242                 moduleFactory, null, dependencyResolver, defaultBean, bundleContext);
243     }
244
245     private synchronized ObjectName putConfigBeanToJMXAndInternalMaps(
246             ModuleIdentifier moduleIdentifier, Module module,
247             ModuleFactory moduleFactory,
248             @Nullable ModuleInternalInfo maybeOldConfigBeanInfo, DependencyResolver dependencyResolver,
249             boolean isDefaultBean, BundleContext bundleContext)
250             throws InstanceAlreadyExistsException {
251
252         LOG.debug("Adding module {} to transaction {}", moduleIdentifier, this);
253         if (moduleIdentifier.equals(module.getIdentifier()) == false) {
254             throw new IllegalStateException("Incorrect name reported by module. Expected "
255                     + moduleIdentifier + ", got " + module.getIdentifier());
256         }
257         if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false) {
258             throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected "
259                     + moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
260         }
261         DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
262                 module, moduleIdentifier, getTransactionIdentifier(),
263                 readOnlyAtomicBoolean, transactionsMBeanServer,
264                 configMBeanServer);
265
266         ObjectName writableON = ObjectNameUtil.createTransactionModuleON(
267                 getTransactionIdentifier().getName(), moduleIdentifier);
268         // put wrapper to jmx
269         TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
270                 .registerMBean(writableDynamicWrapper, writableON);
271
272         dependencyResolverManager.put(
273                 moduleIdentifier, module, moduleFactory,
274                 maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean, bundleContext);
275         return writableON;
276     }
277
278     @Override
279     public synchronized void destroyModule(ObjectName objectName) throws InstanceNotFoundException {
280         checkTransactionName(objectName);
281         ObjectNameUtil.checkDomain(objectName);
282         ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
283                 ObjectNameUtil.TYPE_MODULE);
284         destroyModule(moduleIdentifier);
285     }
286
287     private void checkTransactionName(ObjectName objectName) {
288         String foundTransactionName = ObjectNameUtil
289                 .getTransactionName(objectName);
290         if (getTransactionIdentifier().getName().equals(foundTransactionName) == false) {
291             throw new IllegalArgumentException("Wrong transaction name "
292                     + objectName);
293         }
294     }
295
296     private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) {
297         LOG.debug("Destroying module {} in transaction {}", moduleIdentifier, this);
298         transactionStatus.checkNotAborted();
299
300         ModuleInternalTransactionalInfo found = dependencyResolverManager.findModuleInternalTransactionalInfo(moduleIdentifier);
301         if (blankTransaction == false &&
302                 found.isDefaultBean()) {
303             LOG.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
304         }
305         // first remove refNames, it checks for objectname existence
306
307         try {
308             writableSRRegistry.removeServiceReferences(
309                     ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier));
310         } catch (InstanceNotFoundException e) {
311             LOG.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
312             throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
313         }
314
315         ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
316         // remove from jmx
317         removedTInfo.getTransactionModuleJMXRegistration().close();
318     }
319
320     @Override
321     public long getParentVersion() {
322         return parentVersion;
323     }
324
325     @Override
326     public long getVersion() {
327         return currentVersion;
328     }
329
330     @Override
331     public synchronized void validateConfig() throws ValidationException {
332         if (configBeanModificationDisabled.get()) {
333             throw new IllegalStateException("Cannot start validation");
334         }
335         configBeanModificationDisabled.set(true);
336         try {
337             validateNoLocks();
338         } finally {
339             configBeanModificationDisabled.set(false);
340         }
341     }
342
343     private void validateNoLocks() throws ValidationException {
344         transactionStatus.checkNotAborted();
345         LOG.trace("Validating transaction {}", getTransactionIdentifier());
346         // call validate()
347         List<ValidationException> collectedExceptions = new ArrayList<>();
348         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
349                 .getAllModules().entrySet()) {
350             ModuleIdentifier name = entry.getKey();
351             Module module = entry.getValue();
352             try {
353                 module.validate();
354             } catch (Exception e) {
355                 LOG.warn("Validation exception in {}", getTransactionName(),
356                         e);
357                 collectedExceptions.add(ValidationException
358                         .createForSingleException(name, e));
359             }
360         }
361         if (!collectedExceptions.isEmpty()) {
362             throw ValidationException
363                     .createFromCollectedValidationExceptions(collectedExceptions);
364         }
365         LOG.trace("Validated transaction {}", getTransactionIdentifier());
366     }
367
368     /**
369      * If this method passes validation, it will grab
370      * {@link TransactionStatus#secondPhaseCommitStarted} lock. This lock will
371      * prevent calling @{link #validateBeforeCommitAndLockTransaction},
372      * effectively only allowing to call {@link #secondPhaseCommit} after
373      * successful return of this method.
374      */
375     @Override
376     public synchronized CommitInfo validateBeforeCommitAndLockTransaction()
377             throws ValidationException {
378         transactionStatus.checkNotAborted();
379         transactionStatus.checkNotCommitStarted();
380         configBeanModificationDisabled.set(true);
381         try {
382             validateNoLocks();
383         } catch (ValidationException e) {
384             LOG.trace("Commit failed on validation");
385             configBeanModificationDisabled.set(false); // recoverable error
386             throw e;
387         }
388         // errors in this state are not recoverable. modules are not mutable
389         // anymore.
390         transactionStatus.setSecondPhaseCommitStarted();
391         return dependencyResolverManager.toCommitInfo();
392     }
393
394     /**
395      * {@inheritDoc}
396      */
397     @Override
398     public synchronized List<ModuleIdentifier> secondPhaseCommit() {
399         transactionStatus.checkNotAborted();
400         transactionStatus.checkCommitStarted();
401         if (configBeanModificationDisabled.get() == false) {
402             throw new IllegalStateException(
403                     "Internal error - validateBeforeCommitAndLockTransaction should be called "
404                             + "to obtain a lock");
405         }
406
407         LOG.trace("Committing transaction {}", getTransactionIdentifier());
408
409         Map<ModuleIdentifier, Module> allModules = dependencyResolverManager.getAllModules();
410
411         // call getInstance() on all Modules from top to bottom (from source to target of the dependency relation)
412         // The source of a dependency closes itself and calls getInstance recursively on the dependencies (in case of reconfiguration)
413         // This makes close() calls from top to bottom while createInstance() calls are performed bottom to top
414         List<ModuleIdentifier> sortedModuleIdentifiers = Lists.reverse(dependencyResolverManager.getSortedModuleIdentifiers());
415         for (ModuleIdentifier moduleIdentifier : sortedModuleIdentifiers) {
416             Module module = allModules.get(moduleIdentifier);
417
418             try {
419                 LOG.debug("About to commit {} in transaction {}",
420                         moduleIdentifier, getTransactionIdentifier());
421                 AutoCloseable instance = module.getInstance();
422                 checkNotNull(instance, "Instance is null:{} in transaction {}", moduleIdentifier, getTransactionIdentifier());
423             } catch (Exception e) {
424                 LOG.error("Commit failed on {} in transaction {}", moduleIdentifier,
425                         getTransactionIdentifier(), e);
426                 internalAbort();
427                 throw new IllegalStateException(
428                         format("Error - getInstance() failed for %s in transaction %s",
429                                 moduleIdentifier, getTransactionIdentifier()), e);
430             }
431         }
432
433         LOG.trace("Committed configuration {}", getTransactionIdentifier());
434         transactionStatus.setCommitted();
435
436         return sortedModuleIdentifiers;
437     }
438
439     @Override
440     public synchronized void abortConfig() {
441         transactionStatus.checkNotCommitStarted();
442         transactionStatus.checkNotAborted();
443         internalAbort();
444     }
445
446     private void internalAbort() {
447         LOG.trace("Aborting {}", this);
448         transactionStatus.setAborted();
449         close();
450     }
451
452     @Override
453     public void close() {
454         dependencyResolverManager.close();
455         txLookupRegistry.close();
456     }
457
458     @Override
459     public ObjectName getControllerObjectName() {
460         return controllerON;
461     }
462
463     @Override
464     public String getTransactionName() {
465         return getTransactionIdentifier().getName();
466     }
467
468     /**
469      * {@inheritDoc}
470      */
471     @Override
472     public Set<ObjectName> lookupConfigBeans() {
473         return txLookupRegistry.lookupConfigBeans();
474     }
475
476     /**
477      * {@inheritDoc}
478      */
479     @Override
480     public Set<ObjectName> lookupConfigBeans(String moduleName) {
481         return txLookupRegistry.lookupConfigBeans(moduleName);
482     }
483
484     /**
485      * {@inheritDoc}
486      */
487     @Override
488     public ObjectName lookupConfigBean(String moduleName, String instanceName)
489             throws InstanceNotFoundException {
490         return txLookupRegistry.lookupConfigBean(moduleName, instanceName);
491     }
492
493     /**
494      * {@inheritDoc}
495      */
496     @Override
497     public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
498         return txLookupRegistry.lookupConfigBeans(moduleName, instanceName);
499     }
500
501     /**
502      * {@inheritDoc}
503      */
504     @Override
505     public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
506         txLookupRegistry.checkConfigBeanExists(objectName);
507     }
508
509
510     /**
511      * {@inheritDoc}
512      */
513     @Override
514     public Set<ObjectName> lookupRuntimeBeans() {
515         return txLookupRegistry.lookupRuntimeBeans();
516     }
517
518     /**
519      * {@inheritDoc}
520      */
521     @Override
522     public Set<ObjectName> lookupRuntimeBeans(String moduleName,
523                                               String instanceName) {
524         return txLookupRegistry.lookupRuntimeBeans(moduleName, instanceName);
525     }
526
527     // --
528
529     /**
530      * {@inheritDoc}
531      */
532     @Override
533     public Set<String> getAvailableModuleNames() {
534         return factoriesHolder.getModuleNames();
535     }
536
537     @Override
538     public boolean isClosed() {
539         return transactionStatus.isAbortedOrCommitted();
540     }
541
542     @Override
543     public String toString() {
544         StringBuilder sb = new StringBuilder();
545         sb.append("transactionName=");
546         sb.append(getTransactionName());
547         return sb.toString();
548     }
549
550     // @VisibleForTesting
551
552     TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
553         return txLookupRegistry.getTxModuleJMXRegistrator();
554     }
555
556     public TransactionIdentifier getName() {
557         return getTransactionIdentifier();
558     }
559
560     @Override
561     public List<ModuleFactory> getCurrentlyRegisteredFactories() {
562         return new ArrayList<>(factoriesHolder.getModuleFactories());
563     }
564
565     @Override
566     public TransactionIdentifier getIdentifier() {
567         return getTransactionIdentifier();
568     }
569
570     @Override
571     public BundleContext getModuleFactoryBundleContext(String factoryName) {
572         Map.Entry<ModuleFactory, BundleContext> factoryBundleContextEntry = this.currentlyRegisteredFactories.get(factoryName);
573         if (factoryBundleContextEntry == null || factoryBundleContextEntry.getValue() == null) {
574             throw new NullPointerException("Bundle context of " + factoryName + " ModuleFactory not found.");
575         }
576         return factoryBundleContextEntry.getValue();
577     }
578
579     // service reference functionality:
580
581
582     @Override
583     public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
584         return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
585     }
586
587     @Override
588     public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
589         return writableSRRegistry.getServiceMapping();
590     }
591
592     @Override
593     public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
594         return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
595     }
596
597     @Override
598     public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
599         return writableSRRegistry.lookupServiceInterfaceNames(objectName);
600     }
601
602     @Override
603     public synchronized String getServiceInterfaceName(String namespace, String localName) {
604         return writableSRRegistry.getServiceInterfaceName(namespace, localName);
605     }
606
607     @Override
608     public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
609         return writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, moduleON);
610     }
611
612     @Override
613     public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException {
614         writableSRRegistry.removeServiceReference(serviceInterfaceName, refName);
615     }
616
617     @Override
618     public synchronized void removeAllServiceReferences() {
619         writableSRRegistry.removeAllServiceReferences();
620     }
621
622     @Override
623     public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
624         return writableSRRegistry.removeServiceReferences(objectName);
625     }
626
627     @Override
628     public SearchableServiceReferenceWritableRegistry  getWritableRegistry() {
629         return writableSRRegistry;
630     }
631
632     @Override
633     public TransactionIdentifier getTransactionIdentifier() {
634         return txLookupRegistry.getTransactionIdentifier();
635     }
636
637     @Override
638     public Set<String> getAvailableModuleFactoryQNames() {
639         return txLookupRegistry.getAvailableModuleFactoryQNames();
640     }
641
642     @Override
643     public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
644         writableSRRegistry.checkServiceReferenceExists(objectName);
645     }
646
647     @Override
648     public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
649         return writableSRRegistry.getServiceReference(serviceInterfaceQName, refName);
650     }
651 }