Add get-config commit edit-config to testtool
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / ServiceReferenceRegistryImpl.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
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import java.util.Set;
18 import javax.management.InstanceAlreadyExistsException;
19 import javax.management.InstanceNotFoundException;
20 import javax.management.ObjectName;
21 import org.opendaylight.controller.config.api.LookupRegistry;
22 import org.opendaylight.controller.config.api.ModuleIdentifier;
23 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
24 import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
25 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
26 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
27 import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
28 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReference;
29 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceMXBeanImpl;
30 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator;
31 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceJMXRegistration;
32 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactory;
33 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactoryImpl;
34 import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
35 import org.opendaylight.controller.config.spi.ModuleFactory;
36 import org.osgi.framework.BundleContext;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceReadableRegistry, SearchableServiceReferenceWritableRegistry {
41     private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class);
42
43     private final Map<String, ModuleFactory> factories;
44     private final Map<String, Set<String>> factoryNamesToQNames;
45     // validator of incoming ObjectNames - throws InstanceNotFoundException if not found either in registry or transaction
46     private final LookupRegistry lookupRegistry;
47     private final ServiceReferenceRegistrator serviceReferenceRegistrator;
48     // helper method for getting QName of SI from namespace + local name
49     private final Map<String /* namespace */, Map<String /* local name */, ServiceInterfaceAnnotation>> namespacesToAnnotations;
50     private final Map<String /* service qName */, ServiceInterfaceAnnotation> serviceQNamesToAnnotations;
51     // all Service Interface qNames for sanity checking
52     private final Set<String /* qName */> allQNames;
53     Map<ModuleIdentifier, Map<ServiceInterfaceAnnotation, String /* service ref name */>> modulesToServiceRef = new HashMap<>();
54
55
56     // actual reference database
57     private final Map<ServiceReference, ModuleIdentifier> refNames = new HashMap<>();
58     private final boolean writable;
59     private final Map<ServiceReference, Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration>> mBeans = new HashMap<>();
60
61     /**
62      * Static constructor for config registry. Since only transaction can write to this registry, it will
63      * return blank state.
64      */
65     public static CloseableServiceReferenceReadableRegistry createInitialSRLookupRegistry() {
66         // since this is initial state, just throw exception:
67         LookupRegistry lookupRegistry = new LookupRegistry() {
68             @Override
69             public Set<ObjectName> lookupConfigBeans() {
70                 throw new UnsupportedOperationException();
71             }
72
73             @Override
74             public Set<ObjectName> lookupConfigBeans(String moduleName) {
75                 throw new UnsupportedOperationException();
76             }
77
78             @Override
79             public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
80                 throw new UnsupportedOperationException();
81             }
82
83             @Override
84             public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException {
85                 throw new UnsupportedOperationException();
86             }
87
88             @Override
89             public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
90                 throw new InstanceNotFoundException("Cannot find " + objectName + " - Tried to use mocking registry");
91             }
92
93             @Override
94             public Set<String> getAvailableModuleFactoryQNames() {
95                 throw new UnsupportedOperationException();
96             }
97
98             @Override
99             public String toString() {
100                 return "initial";
101             }
102         };
103         ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactory(){
104             @Override
105             public ServiceReferenceRegistrator create() {
106                 return new ServiceReferenceRegistrator() {
107                     @Override
108                     public String getNullableTransactionName() {
109                         throw new UnsupportedOperationException();
110                     }
111
112                     @Override
113                     public ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object, ObjectName on) throws InstanceAlreadyExistsException {
114                         throw new UnsupportedOperationException();
115                     }
116
117                     @Override
118                     public void close() {
119
120                     }
121                 };
122             }
123         };
124         return new ServiceReferenceRegistryImpl(Collections.<String, ModuleFactory>emptyMap(), lookupRegistry,
125                 serviceReferenceRegistratorFactory, false);
126     }
127
128     /**
129      * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data.
130      */
131     public static SearchableServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry,
132                                                     ConfigTransactionLookupRegistry txLookupRegistry,
133                                                     Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
134
135         if (txLookupRegistry == null) {
136             throw new IllegalArgumentException("txLookupRegistry is null");
137         }
138         ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry;
139         Map<String, ModuleFactory> factories = extractFactoriesMap(currentlyRegisteredFactories);
140         ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl(
141                 txLookupRegistry.getTxModuleJMXRegistrator(), txLookupRegistry.getTxModuleJMXRegistrator().getTransactionName());
142         ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(factories, txLookupRegistry,
143                 serviceReferenceRegistratorFactory, true);
144         copy(old, newRegistry, txLookupRegistry.getTransactionIdentifier().getName());
145         return newRegistry;
146     }
147
148     /**
149      * Copy back state to config registry after commit.
150      */
151     public static CloseableServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry,
152                                                                             LookupRegistry lookupRegistry, BaseJMXRegistrator baseJMXRegistrator) {
153         ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry;
154
155         // even if factories do change, nothing in the mapping can change between transactions
156         ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl(baseJMXRegistrator);
157         ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(old.factories, lookupRegistry,
158                 serviceReferenceRegistratorFactory, false);
159         copy(old, newRegistry, null);
160         return newRegistry;
161     }
162
163     /**
164      * Fill refNames and mBeans maps from old instance
165      */
166     private static void copy(ServiceReferenceRegistryImpl old, ServiceReferenceRegistryImpl newRegistry, String nullableDstTransactionName) {
167         for (Entry<ServiceReference, Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration>> refNameEntry : old.mBeans.entrySet()) {
168             ObjectName currentImplementation;
169             ObjectName currentImplementationSrc = refNameEntry.getValue().getKey().getCurrentImplementation();
170             if (nullableDstTransactionName != null) {
171                 currentImplementation = ObjectNameUtil.withTransactionName(currentImplementationSrc, nullableDstTransactionName);
172             } else {
173                 currentImplementation = ObjectNameUtil.withoutTransactionName(currentImplementationSrc);
174             }
175             try {
176                 boolean skipChecks = true;
177                 newRegistry.saveServiceReference(refNameEntry.getKey(), currentImplementation, skipChecks);
178             } catch (InstanceNotFoundException e) {
179                 logger.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation);
180                 throw new IllegalStateException("Possible code error", e);
181             }
182         }
183     }
184
185     private static Map<String, ModuleFactory> extractFactoriesMap(Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
186         Map<String, ModuleFactory> result = new HashMap<>();
187         for (Entry<String, Entry<ModuleFactory, BundleContext>> entry : currentlyRegisteredFactories.entrySet()) {
188             result.put(entry.getKey(), entry.getValue().getKey());
189         }
190         return result;
191     }
192
193     private ServiceReferenceRegistryImpl(Map<String, ModuleFactory> factories, LookupRegistry lookupRegistry,
194                                          ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory,
195                                          boolean writable) {
196         this.factories = factories;
197         this.writable = writable;
198         this.lookupRegistry = lookupRegistry;
199
200         this.serviceReferenceRegistrator = serviceReferenceRegistratorFactory.create();
201
202         Map<String, Set<String /* QName */>> modifiableFactoryNamesToQNames = new HashMap<>();
203         Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
204         Set<String /* qName */> allQNames = new HashSet<>();
205
206
207         for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
208             if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) {
209                 logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
210                 throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry);
211             }
212             Set<ServiceInterfaceAnnotation> siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue());
213             Set<String> qNames = InterfacesHelper.getQNames(siAnnotations);
214             allAnnotations.addAll(siAnnotations);
215             allQNames.addAll(qNames);
216             modifiableFactoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
217         }
218         this.factoryNamesToQNames = Collections.unmodifiableMap(modifiableFactoryNamesToQNames);
219         this.allQNames = Collections.unmodifiableSet(allQNames);
220         // fill namespacesToAnnotations
221         Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> modifiableNamespacesToAnnotations =
222                 new HashMap<>();
223         Map<String /* service qName*/, ServiceInterfaceAnnotation> modifiableServiceQNamesToAnnotations = new HashMap<>();
224         for (ServiceInterfaceAnnotation sia : allAnnotations) {
225             Map<String, ServiceInterfaceAnnotation> ofNamespace = modifiableNamespacesToAnnotations.get(sia.namespace());
226             if (ofNamespace == null) {
227                 ofNamespace = new HashMap<>();
228                 modifiableNamespacesToAnnotations.put(sia.namespace(), ofNamespace);
229             }
230             if (ofNamespace.containsKey(sia.localName())) {
231                 logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
232                         sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations);
233                 throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
234             }
235             ofNamespace.put(sia.localName(), sia);
236             modifiableServiceQNamesToAnnotations.put(sia.value(), sia);
237         }
238         this.namespacesToAnnotations = Collections.unmodifiableMap(modifiableNamespacesToAnnotations);
239         this.serviceQNamesToAnnotations = Collections.unmodifiableMap(modifiableServiceQNamesToAnnotations);
240         logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
241     }
242
243     @Override
244     public Map<ServiceInterfaceAnnotation, String /* service ref name */> findServiceInterfaces(ModuleIdentifier moduleIdentifier) {
245         Map<ServiceInterfaceAnnotation, String /* service ref name */> result = modulesToServiceRef.get(moduleIdentifier);
246         if (result == null) {
247             return Collections.emptyMap();
248         }
249         return Collections.unmodifiableMap(result);
250     }
251
252     @Override
253     public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
254         lookupRegistry.checkConfigBeanExists(objectName);
255
256         String factoryName = ObjectNameUtil.getFactoryName(objectName);
257         Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
258         if (serviceInterfaceAnnotations == null) {
259             logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
260                     factoryName, objectName, factoryNamesToQNames);
261             throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
262         }
263         return serviceInterfaceAnnotations;
264     }
265
266     @Override
267     public synchronized String getServiceInterfaceName(String namespace, String localName) {
268         Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
269         if (ofNamespace == null) {
270             logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
271             throw new IllegalArgumentException("Cannot find namespace " + namespace);
272         }
273         ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
274         if (sia == null) {
275             logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
276             throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
277         }
278         return sia.value();
279     }
280
281     // reading:
282
283     @Override
284     public synchronized Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping() {
285         Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> result = new HashMap<>();
286         for (Entry<ServiceReference, ModuleIdentifier> entry: refNames.entrySet()) {
287             String qName = entry.getKey().getServiceInterfaceQName();
288             Map<String /* refName */, ObjectName> innerMap = result.get(qName);
289             if (innerMap == null) {
290                 innerMap = new HashMap<>();
291                 result.put(qName, innerMap);
292             }
293             innerMap.put(entry.getKey().getRefName(), getObjectName(entry.getValue()));
294         }
295         return result;
296     }
297
298     private ObjectName getObjectName(ModuleIdentifier moduleIdentifier) {
299         ObjectName on;
300         try {
301             on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
302         } catch (InstanceNotFoundException e) {
303             logger.error("Cannot find instance {}", moduleIdentifier);
304             throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
305         }
306         return on;
307     }
308
309     @Override
310     public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
311         ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName);
312         ModuleIdentifier moduleIdentifier = refNames.get(serviceReference);
313         if (moduleIdentifier == null) {
314             logger.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName);
315             throw new IllegalArgumentException("Cannot find " + serviceReference);
316         }
317         return getObjectName(moduleIdentifier);
318     }
319
320     @Override
321     public synchronized Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
322         Map<String, Map<String, ObjectName>> serviceMapping = getServiceMapping();
323         Map<String, ObjectName> innerMap = serviceMapping.get(serviceInterfaceQName);
324         if (innerMap == null) {
325             logger.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames);
326             throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName);
327         }
328         return innerMap;
329     }
330
331     @Override
332     public synchronized ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
333         ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName);
334         if (mBeans.containsKey(serviceReference) == false) {
335             throw new InstanceNotFoundException("Cannot find " + serviceReference);
336         }
337         return getServiceON(serviceReference);
338     }
339
340     @Override
341     public synchronized void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
342         String actualTransactionName = ObjectNameUtil.getTransactionName(objectName);
343         String expectedTransactionName = serviceReferenceRegistrator.getNullableTransactionName();
344         if (writable & actualTransactionName == null || (writable && actualTransactionName.equals(expectedTransactionName) == false)) {
345             throw new IllegalArgumentException("Mismatched transaction name in " + objectName);
346         }
347         String serviceQName = ObjectNameUtil.getServiceQName(objectName);
348         String referenceName = ObjectNameUtil.getReferenceName(objectName);
349         ServiceReference serviceReference = new ServiceReference(serviceQName, referenceName);
350         if (refNames.containsKey(serviceReference) == false) {
351             logger.warn("Cannot find {} in {}", serviceReference, refNames);
352             throw new InstanceNotFoundException("Service reference not found:" + objectName);
353         }
354     }
355
356     // writing:
357
358     private void assertWritable() {
359         if (writable == false) {
360             throw new IllegalStateException("Cannot write to readable registry");
361         }
362     }
363
364     @Override
365     public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON)  throws InstanceNotFoundException {
366         assertWritable();
367         ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName);
368         return saveServiceReference(serviceReference, moduleON);
369     }
370
371     private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON)
372             throws InstanceNotFoundException{
373         return saveServiceReference(serviceReference, moduleON, false);
374     }
375
376     private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON,
377                                                          boolean skipChecks) throws InstanceNotFoundException {
378
379         // make sure it is found
380         if (skipChecks == false) {
381             lookupRegistry.checkConfigBeanExists(moduleON);
382         }
383         String factoryName = ObjectNameUtil.getFactoryName(moduleON);
384         String instanceName = ObjectNameUtil.getInstanceName(moduleON);
385         ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
386
387         // check that service interface name exist
388         Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(moduleIdentifier.getFactoryName());
389         if (serviceInterfaceQNames == null) {
390             logger.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(),
391                     factoryNamesToQNames, moduleIdentifier);
392             throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + moduleIdentifier.getFactoryName());
393         }
394         // supplied serviceInterfaceName must exist in this collection
395         if (serviceInterfaceQNames.contains(serviceReference.getServiceInterfaceQName()) == false) {
396             logger.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceQName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames);
397             throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName() + " within factory " + moduleIdentifier.getFactoryName());
398         }
399
400
401         // create service reference object name, put to mBeans
402         ObjectName result = getServiceON(serviceReference);
403         Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> mxBeanEntry = mBeans.get(serviceReference);
404         if (mxBeanEntry == null) {
405             // create dummy mx bean
406             ServiceReferenceMXBeanImpl dummyMXBean = new ServiceReferenceMXBeanImpl(moduleON);
407             ServiceReferenceJMXRegistration dummyMXBeanRegistration;
408             try {
409                 dummyMXBeanRegistration = serviceReferenceRegistrator.registerMBean(dummyMXBean, result);
410             } catch (InstanceAlreadyExistsException e) {
411                 throw new IllegalStateException("Possible error in code. Cannot register " + result, e);
412             }
413             mBeans.put(serviceReference, createMXBeanEntry(dummyMXBean, dummyMXBeanRegistration));
414         } else {
415             // update
416             mxBeanEntry.getKey().setCurrentImplementation(moduleON);
417         }
418         // save to refNames
419         refNames.put(serviceReference, moduleIdentifier);
420         Map<ServiceInterfaceAnnotation, String /* service ref name */> refNamesToAnnotations = modulesToServiceRef.get(moduleIdentifier);
421         if (refNamesToAnnotations == null){
422             refNamesToAnnotations = new HashMap<>();
423             modulesToServiceRef.put(moduleIdentifier, refNamesToAnnotations);
424         }
425
426         ServiceInterfaceAnnotation annotation = serviceQNamesToAnnotations.get(serviceReference.getServiceInterfaceQName());
427         checkNotNull(annotation, "Possible error in code, cannot find annotation for " + serviceReference);
428         refNamesToAnnotations.put(annotation, serviceReference.getRefName());
429         return result;
430     }
431
432     private Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> createMXBeanEntry(
433             final ServiceReferenceMXBeanImpl mxBean, final ServiceReferenceJMXRegistration registration) {
434         return new Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration>() {
435             @Override
436             public ServiceReferenceMXBeanImpl getKey() {
437                 return mxBean;
438             }
439
440             @Override
441             public ServiceReferenceJMXRegistration getValue() {
442                 return registration;
443             }
444
445             @Override
446             public ServiceReferenceJMXRegistration setValue(ServiceReferenceJMXRegistration value) {
447                 throw new UnsupportedOperationException();
448             }
449         };
450     }
451
452     private ObjectName getServiceON(ServiceReference serviceReference) {
453         if (writable) {
454             return ObjectNameUtil.createTransactionServiceON(serviceReferenceRegistrator.getNullableTransactionName(),
455                     serviceReference.getServiceInterfaceQName(), serviceReference.getRefName());
456         } else {
457             return ObjectNameUtil.createReadOnlyServiceON(serviceReference.getServiceInterfaceQName(), serviceReference.getRefName());
458         }
459     }
460
461     @Override
462     public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException{
463         ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName);
464         removeServiceReference(serviceReference);
465     }
466
467     private synchronized void removeServiceReference(ServiceReference serviceReference) throws InstanceNotFoundException {
468         logger.debug("Removing service reference {} from {}", serviceReference, this);
469         assertWritable();
470         // is the qName known?
471         if (allQNames.contains(serviceReference.getServiceInterfaceQName()) == false) {
472             logger.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceQName(), allQNames);
473             throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName());
474         }
475         ModuleIdentifier removed = refNames.remove(serviceReference);
476         if (removed == null){
477             throw new InstanceNotFoundException("Cannot find " + serviceReference.getServiceInterfaceQName());
478         }
479         Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> entry = mBeans.remove(serviceReference);
480         if (entry == null) {
481             throw new IllegalStateException("Possible code error: cannot remove from mBeans: " + serviceReference);
482         }
483         entry.getValue().close();
484     }
485
486     @Override
487     public synchronized void removeAllServiceReferences() {
488         assertWritable();
489         for (ServiceReference serviceReference: mBeans.keySet()) {
490             try {
491                 removeServiceReference(serviceReference);
492             } catch (InstanceNotFoundException e) {
493                 throw new IllegalStateException("Possible error in code", e);
494             }
495         }
496     }
497
498     @Override
499     public synchronized boolean removeServiceReferences(ObjectName moduleObjectName) throws InstanceNotFoundException {
500         lookupRegistry.checkConfigBeanExists(moduleObjectName);
501         String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName);
502         // check that service interface name exist
503         Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
504         return removeServiceReferences(moduleObjectName, serviceInterfaceQNames);
505     }
506
507
508     private boolean removeServiceReferences(ObjectName moduleObjectName, Set<String> qNames) throws InstanceNotFoundException {
509         ObjectNameUtil.checkType(moduleObjectName, ObjectNameUtil.TYPE_MODULE);
510         assertWritable();
511         Set<ServiceReference> serviceReferencesLinkingTo = findServiceReferencesLinkingTo(moduleObjectName, qNames);
512         for (ServiceReference sr : serviceReferencesLinkingTo) {
513             removeServiceReference(sr);
514         }
515         return serviceReferencesLinkingTo.isEmpty() == false;
516     }
517
518     private Set<ServiceReference> findServiceReferencesLinkingTo(ObjectName moduleObjectName, Set<String> serviceInterfaceQNames) {
519         String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName);
520         if (serviceInterfaceQNames == null) {
521             logger.warn("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName);
522             throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
523         }
524         String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName);
525         ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
526         Set<ServiceReference> result = new HashSet<>();
527         for (Entry<ServiceReference, ModuleIdentifier> entry : refNames.entrySet()) {
528             if (entry.getValue().equals(moduleIdentifier)) {
529                 result.add(entry.getKey());
530             }
531         }
532         return result;
533     }
534
535     @Override
536     public String toString() {
537         return "ServiceReferenceRegistryImpl{" +
538                 "lookupRegistry=" + lookupRegistry +
539                 "refNames=" + refNames +
540                 ", factoryNamesToQNames=" + factoryNamesToQNames +
541                 '}';
542     }
543
544     @Override
545     public void close() {
546         serviceReferenceRegistrator.close();
547     }
548 }