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