Merge "Trigger a GC once initial configuration has been pushed"
[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
280             if (found.isDefaultBean()) {
281                 logger.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
282             }
283         }
284         // first remove refNames, it checks for objectname existence
285
286         try {
287             writableSRRegistry.removeServiceReferences(
288                     ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier));
289         } catch (InstanceNotFoundException e) {
290             logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
291             throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
292         }
293
294         ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
295         // remove from jmx
296         removedTInfo.getTransactionModuleJMXRegistration().close();
297     }
298
299     @Override
300     public long getParentVersion() {
301         return parentVersion;
302     }
303
304     @Override
305     public long getVersion() {
306         return currentVersion;
307     }
308
309     @Override
310     public synchronized void validateConfig() throws ValidationException {
311         if (configBeanModificationDisabled.get()) {
312             throw new IllegalStateException("Cannot start validation");
313         }
314         configBeanModificationDisabled.set(true);
315         try {
316             validate_noLocks();
317         } finally {
318             configBeanModificationDisabled.set(false);
319         }
320     }
321
322     private void validate_noLocks() throws ValidationException {
323         transactionStatus.checkNotAborted();
324         logger.trace("Validating transaction {}", getTransactionIdentifier());
325         // call validate()
326         List<ValidationException> collectedExceptions = new ArrayList<>();
327         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
328                 .getAllModules().entrySet()) {
329             ModuleIdentifier name = entry.getKey();
330             Module module = entry.getValue();
331             try {
332                 module.validate();
333             } catch (Exception e) {
334                 logger.warn("Validation exception in {}", getTransactionName(),
335                         e);
336                 collectedExceptions.add(ValidationException
337                         .createForSingleException(name, e));
338             }
339         }
340         if (collectedExceptions.size() > 0) {
341             throw ValidationException
342                     .createFromCollectedValidationExceptions(collectedExceptions);
343         }
344         logger.trace("Validated transaction {}", getTransactionIdentifier());
345     }
346
347     /**
348      * If this method passes validation, it will grab
349      * {@link TransactionStatus#secondPhaseCommitStarted} lock. This lock will
350      * prevent calling @{link #validateBeforeCommitAndLockTransaction},
351      * effectively only allowing to call {@link #secondPhaseCommit} after
352      * successful return of this method.
353      */
354     @Override
355     public synchronized CommitInfo validateBeforeCommitAndLockTransaction()
356             throws ValidationException {
357         transactionStatus.checkNotAborted();
358         transactionStatus.checkNotCommitStarted();
359         configBeanModificationDisabled.set(true);
360         try {
361             validate_noLocks();
362         } catch (ValidationException e) {
363             logger.trace("Commit failed on validation");
364             configBeanModificationDisabled.set(false); // recoverable error
365             throw e;
366         }
367         // errors in this state are not recoverable. modules are not mutable
368         // anymore.
369         transactionStatus.setSecondPhaseCommitStarted();
370         return dependencyResolverManager.toCommitInfo();
371     }
372
373     /**
374      * {@inheritDoc}
375      */
376     @Override
377     public synchronized List<ModuleIdentifier> secondPhaseCommit() {
378         transactionStatus.checkNotAborted();
379         transactionStatus.checkCommitStarted();
380         if (configBeanModificationDisabled.get() == false) {
381             throw new IllegalStateException(
382                     "Internal error - validateBeforeCommitAndLockTransaction should be called "
383                             + "to obtain a lock");
384         }
385
386         logger.trace("Committing transaction {}", getTransactionIdentifier());
387
388         // call getInstance()
389         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
390                 .getAllModules().entrySet()) {
391             Module module = entry.getValue();
392             ModuleIdentifier name = entry.getKey();
393             try {
394                 logger.debug("About to commit {} in transaction {}",
395                         name, getTransactionIdentifier());
396                 AutoCloseable instance = module.getInstance();
397                 checkNotNull(instance, "Instance is null:{} in transaction {}", name, getTransactionIdentifier());
398             } catch (Exception e) {
399                 logger.error("Commit failed on {} in transaction {}", name,
400                         getTransactionIdentifier(), e);
401                 internalAbort();
402                 throw new IllegalStateException(
403                         format("Error - getInstance() failed for %s in transaction %s",
404                                 name, getTransactionIdentifier()), e);
405             }
406         }
407
408         // count dependency order
409
410         logger.trace("Committed configuration {}", getTransactionIdentifier());
411         transactionStatus.setCommitted();
412
413         return dependencyResolverManager.getSortedModuleIdentifiers();
414     }
415
416     @Override
417     public synchronized void abortConfig() {
418         transactionStatus.checkNotCommitStarted();
419         transactionStatus.checkNotAborted();
420         internalAbort();
421     }
422
423     private void internalAbort() {
424         logger.trace("Aborting {}", this);
425         transactionStatus.setAborted();
426         close();
427     }
428
429     public void close() {
430         dependencyResolverManager.close();
431         txLookupRegistry.close();
432     }
433
434     @Override
435     public ObjectName getControllerObjectName() {
436         return controllerON;
437     }
438
439     @Override
440     public String getTransactionName() {
441         return getTransactionIdentifier().getName();
442     }
443
444     /**
445      * {@inheritDoc}
446      */
447     @Override
448     public Set<ObjectName> lookupConfigBeans() {
449         return txLookupRegistry.lookupConfigBeans();
450     }
451
452     /**
453      * {@inheritDoc}
454      */
455     @Override
456     public Set<ObjectName> lookupConfigBeans(String moduleName) {
457         return txLookupRegistry.lookupConfigBeans(moduleName);
458     }
459
460     /**
461      * {@inheritDoc}
462      */
463     @Override
464     public ObjectName lookupConfigBean(String moduleName, String instanceName)
465             throws InstanceNotFoundException {
466         return txLookupRegistry.lookupConfigBean(moduleName, instanceName);
467     }
468
469     /**
470      * {@inheritDoc}
471      */
472     @Override
473     public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
474         return txLookupRegistry.lookupConfigBeans(moduleName, instanceName);
475     }
476
477     /**
478      * {@inheritDoc}
479      */
480     @Override
481     public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
482         txLookupRegistry.checkConfigBeanExists(objectName);
483     }
484     // --
485
486     /**
487      * {@inheritDoc}
488      */
489     @Override
490     public Set<String> getAvailableModuleNames() {
491         return factoriesHolder.getModuleNames();
492     }
493
494     @Override
495     public boolean isClosed() {
496         return transactionStatus.isAbortedOrCommitted();
497     }
498
499     @Override
500     public String toString() {
501         StringBuilder sb = new StringBuilder();
502         sb.append("transactionName=");
503         sb.append(getTransactionName());
504         return sb.toString();
505     }
506
507     // @VisibleForTesting
508
509     TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
510         return txLookupRegistry.getTxModuleJMXRegistrator();
511     }
512
513     public TransactionIdentifier getName() {
514         return getTransactionIdentifier();
515     }
516
517     @Override
518     public List<ModuleFactory> getCurrentlyRegisteredFactories() {
519         return new ArrayList<>(factoriesHolder.getModuleFactories());
520     }
521
522     @Override
523     public TransactionIdentifier getIdentifier() {
524         return getTransactionIdentifier();
525     }
526
527     @Override
528     public BundleContext getModuleFactoryBundleContext(String factoryName) {
529         Map.Entry<ModuleFactory, BundleContext> factoryBundleContextEntry = this.currentlyRegisteredFactories.get(factoryName);
530         if (factoryBundleContextEntry == null || factoryBundleContextEntry.getValue() == null) {
531             throw new NullPointerException("Bundle context of " + factoryName + " ModuleFactory not found.");
532         }
533         return factoryBundleContextEntry.getValue();
534     }
535
536     // service reference functionality:
537
538
539     @Override
540     public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
541         return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
542     }
543
544     @Override
545     public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
546         return writableSRRegistry.getServiceMapping();
547     }
548
549     @Override
550     public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
551         return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
552     }
553
554     @Override
555     public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
556         return writableSRRegistry.lookupServiceInterfaceNames(objectName);
557     }
558
559     @Override
560     public synchronized String getServiceInterfaceName(String namespace, String localName) {
561         return writableSRRegistry.getServiceInterfaceName(namespace, localName);
562     }
563
564     @Override
565     public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
566         return writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, moduleON);
567     }
568
569     @Override
570     public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException {
571         writableSRRegistry.removeServiceReference(serviceInterfaceName, refName);
572     }
573
574     @Override
575     public synchronized void removeAllServiceReferences() {
576         writableSRRegistry.removeAllServiceReferences();
577     }
578
579     @Override
580     public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
581         return writableSRRegistry.removeServiceReferences(objectName);
582     }
583
584     @Override
585     public SearchableServiceReferenceWritableRegistry  getWritableRegistry() {
586         return writableSRRegistry;
587     }
588
589     @Override
590     public TransactionIdentifier getTransactionIdentifier() {
591         return txLookupRegistry.getTransactionIdentifier();
592     }
593
594     @Override
595     public Set<String> getAvailableModuleFactoryQNames() {
596         return txLookupRegistry.getAvailableModuleFactoryQNames();
597     }
598
599     @Override
600     public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
601         writableSRRegistry.checkServiceReferenceExists(objectName);
602     }
603
604     @Override
605     public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
606         return writableSRRegistry.getServiceReference(serviceInterfaceQName, refName);
607     }
608 }