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