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