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