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