2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.config.manager.impl;
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;
18 import java.util.Map.Entry;
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;
52 * This is a JMX bean representing current transaction. It contains
53 * transaction identifier, unique version and parent version for
56 class ConfigTransactionControllerImpl implements
57 ConfigTransactionControllerInternal,
58 ConfigTransactionControllerImplMXBean,
59 Identifiable<TransactionIdentifier> {
60 private static final Logger LOG = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
62 private final ConfigTransactionLookupRegistry txLookupRegistry;
63 private final ObjectName controllerON;
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;
73 * Disables ability of {@link DynamicWritableWrapper} to change attributes
77 private final AtomicBoolean configBeanModificationDisabled = new AtomicBoolean(
79 private final ReadOnlyAtomicBoolean readOnlyAtomicBoolean = new ReadOnlyAtomicBooleanImpl(
80 configBeanModificationDisabled);
81 private final MBeanServer configMBeanServer;
83 private final boolean blankTransaction;
86 private final SearchableServiceReferenceWritableRegistry writableSRRegistry;
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;
110 public void copyExistingModulesAndProcessFactoryDiff(Collection<ModuleInternalInfo> existingModules, List<ModuleFactory> lastListOfFactories) {
111 // copy old configuration to this server
112 for (ModuleInternalInfo oldConfigInfo : existingModules) {
114 copyExistingModule(oldConfigInfo);
115 } catch (InstanceAlreadyExistsException e) {
116 throw new IllegalStateException("Error while copying " + oldConfigInfo, e);
119 processDefaultBeans(lastListOfFactories);
122 private synchronized void processDefaultBeans(List<ModuleFactory> lastListOfFactories) {
123 transactionStatus.checkNotCommitStarted();
124 transactionStatus.checkNotAborted();
126 Set<ModuleFactory> oldSet = new HashSet<>(lastListOfFactories);
127 Set<ModuleFactory> newSet = new HashSet<>(factoriesHolder.getModuleFactories());
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);
136 for (ModuleFactory moduleFactory : lastListOfFactories) {
137 if (newSet.contains(moduleFactory) == false) {
138 toBeRemoved.add(moduleFactory);
141 // add default modules
142 for (ModuleFactory moduleFactory : toBeAdded) {
143 BundleContext bundleContext = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
144 Set<? extends Module> defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager,
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;
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);
158 // register default module as every possible service
159 final Set<ServiceInterfaceAnnotation> serviceInterfaceAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(moduleFactory);
160 for (String qname : InterfacesHelper.getQNames(serviceInterfaceAnnotations)) {
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);
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)) {
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);
192 private synchronized void copyExistingModule(ModuleInternalInfo oldConfigBeanInfo)
193 throws InstanceAlreadyExistsException {
195 transactionStatus.checkNotCommitStarted();
196 transactionStatus.checkNotAborted();
197 ModuleIdentifier moduleIdentifier = oldConfigBeanInfo.getIdentifier();
198 dependencyResolverManager.assertNotExists(moduleIdentifier);
200 ModuleFactory moduleFactory;
203 moduleFactory = factoriesHolder.findByModuleName(moduleIdentifier.getFactoryName());
204 bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
205 } catch (ModuleFactoryNotFoundException e) {
206 throw new IllegalStateException(e);
210 DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
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);
221 putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module, moduleFactory, oldConfigBeanInfo, dependencyResolver,
222 oldConfigBeanInfo.isDefaultBean(), bc);
226 public synchronized ObjectName createModule(String factoryName, String instanceName)
227 throws InstanceAlreadyExistsException {
229 transactionStatus.checkNotCommitStarted();
230 transactionStatus.checkNotAborted();
231 ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
232 dependencyResolverManager.assertNotExists(moduleIdentifier);
235 ModuleFactory moduleFactory = factoriesHolder.findByModuleName(factoryName);
237 DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
238 BundleContext bundleContext = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
239 Module module = moduleFactory.createModule(instanceName, dependencyResolver,
241 boolean defaultBean = false;
242 return putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module,
243 moduleFactory, null, dependencyResolver, defaultBean, bundleContext);
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);
254 ModuleInternalTransactionalInfo txInfo = dependencyResolverManager.findModuleInternalTransactionalInfo(moduleIdentifier);
255 Module realModule = txInfo.getRealModule();
256 if(realModule instanceof AbstractModule) {
257 ((AbstractModule<?>)realModule).setCanReuseInstance(false);
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 {
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());
273 if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false) {
274 throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected "
275 + moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
277 DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
278 module, moduleIdentifier, getTransactionIdentifier(),
279 readOnlyAtomicBoolean, transactionsMBeanServer,
282 ObjectName writableON = ObjectNameUtil.createTransactionModuleON(
283 getTransactionIdentifier().getName(), moduleIdentifier);
284 // put wrapper to jmx
285 TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
286 .registerMBean(writableDynamicWrapper, writableON);
288 dependencyResolverManager.put(
289 moduleIdentifier, module, moduleFactory,
290 maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean, bundleContext);
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);
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 "
312 private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) {
313 LOG.debug("Destroying module {} in transaction {}", moduleIdentifier, this);
314 transactionStatus.checkNotAborted();
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");
321 // first remove refNames, it checks for objectname existence
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);
331 ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
333 removedTInfo.getTransactionModuleJMXRegistration().close();
337 public long getParentVersion() {
338 return parentVersion;
342 public long getVersion() {
343 return currentVersion;
347 public synchronized void validateConfig() throws ValidationException {
348 if (configBeanModificationDisabled.get()) {
349 throw new IllegalStateException("Cannot start validation");
351 configBeanModificationDisabled.set(true);
355 configBeanModificationDisabled.set(false);
359 private void validateNoLocks() throws ValidationException {
360 transactionStatus.checkNotAborted();
361 LOG.trace("Validating transaction {}", getTransactionIdentifier());
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();
370 } catch (Exception e) {
371 LOG.warn("Validation exception in {}", getTransactionName(),
373 collectedExceptions.add(ValidationException
374 .createForSingleException(name, e));
377 if (!collectedExceptions.isEmpty()) {
378 throw ValidationException
379 .createFromCollectedValidationExceptions(collectedExceptions);
381 LOG.trace("Validated transaction {}", getTransactionIdentifier());
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.
392 public synchronized CommitInfo validateBeforeCommitAndLockTransaction()
393 throws ValidationException {
394 transactionStatus.checkNotAborted();
395 transactionStatus.checkNotCommitStarted();
396 configBeanModificationDisabled.set(true);
399 } catch (ValidationException e) {
400 LOG.trace("Commit failed on validation");
401 configBeanModificationDisabled.set(false); // recoverable error
404 // errors in this state are not recoverable. modules are not mutable
406 transactionStatus.setSecondPhaseCommitStarted();
407 return dependencyResolverManager.toCommitInfo();
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");
423 LOG.trace("Committing transaction {}", getTransactionIdentifier());
425 Map<ModuleIdentifier, Module> allModules = dependencyResolverManager.getAllModules();
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);
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);
443 throw new IllegalStateException(
444 format("Error - getInstance() failed for %s in transaction %s",
445 moduleIdentifier, getTransactionIdentifier()), e);
449 LOG.trace("Committed configuration {}", getTransactionIdentifier());
450 transactionStatus.setCommitted();
452 return sortedModuleIdentifiers;
456 public void abortConfig() {
457 transactionStatus.checkNotCommitStarted();
458 transactionStatus.checkNotAborted();
462 private void internalAbort() {
463 LOG.trace("Aborting {}", this);
464 transactionStatus.setAborted();
469 public void close() {
470 dependencyResolverManager.close();
471 txLookupRegistry.close();
475 public ObjectName getControllerObjectName() {
480 public String getTransactionName() {
481 return getTransactionIdentifier().getName();
488 public Set<ObjectName> lookupConfigBeans() {
489 return txLookupRegistry.lookupConfigBeans();
496 public Set<ObjectName> lookupConfigBeans(String moduleName) {
497 return txLookupRegistry.lookupConfigBeans(moduleName);
504 public ObjectName lookupConfigBean(String moduleName, String instanceName)
505 throws InstanceNotFoundException {
506 return txLookupRegistry.lookupConfigBean(moduleName, instanceName);
513 public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
514 return txLookupRegistry.lookupConfigBeans(moduleName, instanceName);
521 public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
522 txLookupRegistry.checkConfigBeanExists(objectName);
530 public Set<ObjectName> lookupRuntimeBeans() {
531 return txLookupRegistry.lookupRuntimeBeans();
538 public Set<ObjectName> lookupRuntimeBeans(String moduleName,
539 String instanceName) {
540 return txLookupRegistry.lookupRuntimeBeans(moduleName, instanceName);
549 public Set<String> getAvailableModuleNames() {
550 return factoriesHolder.getModuleNames();
554 public boolean isClosed() {
555 return transactionStatus.isAbortedOrCommitted();
559 public String toString() {
560 StringBuilder sb = new StringBuilder();
561 sb.append("transactionName=");
562 sb.append(getTransactionName());
563 return sb.toString();
566 // @VisibleForTesting
568 TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
569 return txLookupRegistry.getTxModuleJMXRegistrator();
572 public TransactionIdentifier getName() {
573 return getTransactionIdentifier();
577 public List<ModuleFactory> getCurrentlyRegisteredFactories() {
578 return new ArrayList<>(factoriesHolder.getModuleFactories());
582 public TransactionIdentifier getIdentifier() {
583 return getTransactionIdentifier();
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.");
592 return factoryBundleContextEntry.getValue();
595 // service reference functionality:
599 public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
600 return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
604 public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
605 return writableSRRegistry.getServiceMapping();
609 public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
610 return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
614 public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
615 return writableSRRegistry.lookupServiceInterfaceNames(objectName);
619 public synchronized String getServiceInterfaceName(String namespace, String localName) {
620 return writableSRRegistry.getServiceInterfaceName(namespace, localName);
624 public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
625 return writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, moduleON);
629 public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException {
630 writableSRRegistry.removeServiceReference(serviceInterfaceName, refName);
634 public synchronized void removeAllServiceReferences() {
635 writableSRRegistry.removeAllServiceReferences();
639 public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
640 return writableSRRegistry.removeServiceReferences(objectName);
644 public SearchableServiceReferenceWritableRegistry getWritableRegistry() {
645 return writableSRRegistry;
649 public TransactionIdentifier getTransactionIdentifier() {
650 return txLookupRegistry.getTransactionIdentifier();
654 public Set<String> getAvailableModuleFactoryQNames() {
655 return txLookupRegistry.getAvailableModuleFactoryQNames();
659 public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
660 writableSRRegistry.checkServiceReferenceExists(objectName);
664 public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
665 return writableSRRegistry.getServiceReference(serviceInterfaceQName, refName);