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