Merge "BUG-2243 Fixing invalid hello message handling"
[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 import com.google.common.collect.ImmutableMap;
12 import com.google.common.collect.ImmutableSet;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.Set;
19 import javax.management.InstanceAlreadyExistsException;
20 import javax.management.InstanceNotFoundException;
21 import javax.management.ObjectName;
22 import org.opendaylight.controller.config.api.LookupRegistry;
23 import org.opendaylight.controller.config.api.ModuleIdentifier;
24 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
25 import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
26 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
27 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
28 import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
29 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReference;
30 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceMXBeanImpl;
31 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator;
32 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceJMXRegistration;
33 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactory;
34 import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactoryImpl;
35 import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
36 import org.opendaylight.controller.config.spi.ModuleFactory;
37 import org.osgi.framework.BundleContext;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
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<ServiceInterfaceAnnotation, String /* service ref name */>> 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(final String moduleName) {
76                 throw new UnsupportedOperationException();
77             }
78
79             @Override
80             public Set<ObjectName> lookupConfigBeans(final String moduleName, final String instanceName) {
81                 throw new UnsupportedOperationException();
82             }
83
84             @Override
85             public ObjectName lookupConfigBean(final String moduleName, final String instanceName) throws InstanceNotFoundException {
86                 throw new UnsupportedOperationException();
87             }
88
89             @Override
90             public void checkConfigBeanExists(final 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(final ServiceReferenceMXBeanImpl object, final 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(final ServiceReferenceReadableRegistry oldReadableRegistry,
133                                                     final ConfigTransactionLookupRegistry txLookupRegistry,
134                                                     final 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(final ServiceReferenceWritableRegistry oldWritableRegistry,
153                                                                             final LookupRegistry lookupRegistry, final 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(final ServiceReferenceRegistryImpl old, final ServiceReferenceRegistryImpl newRegistry, final 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(final 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(final Map<String, ModuleFactory> factories, final LookupRegistry lookupRegistry,
195                                          final ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory,
196                                          final 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 */> allQNameSet = 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 = InterfacesHelper.getQNames(siAnnotations);
215             allAnnotations.addAll(siAnnotations);
216             allQNameSet.addAll(qNames);
217             modifiableFactoryNamesToQNames.put(entry.getKey(), qNames);
218         }
219         this.factoryNamesToQNames = ImmutableMap.copyOf(modifiableFactoryNamesToQNames);
220         this.allQNames = ImmutableSet.copyOf(allQNameSet);
221         // fill namespacesToAnnotations
222         Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> modifiableNamespacesToAnnotations =
223                 new HashMap<>();
224         Map<String /* service qName*/, ServiceInterfaceAnnotation> modifiableServiceQNamesToAnnotations = new HashMap<>();
225         for (ServiceInterfaceAnnotation sia : allAnnotations) {
226             Map<String, ServiceInterfaceAnnotation> ofNamespace = modifiableNamespacesToAnnotations.get(sia.namespace());
227             if (ofNamespace == null) {
228                 ofNamespace = new HashMap<>();
229                 modifiableNamespacesToAnnotations.put(sia.namespace(), ofNamespace);
230             }
231             if (ofNamespace.containsKey(sia.localName())) {
232                 LOGGER.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
233                         sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations);
234                 throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
235             }
236             ofNamespace.put(sia.localName(), sia);
237             modifiableServiceQNamesToAnnotations.put(sia.value(), sia);
238         }
239         this.namespacesToAnnotations = ImmutableMap.copyOf(modifiableNamespacesToAnnotations);
240         this.serviceQNamesToAnnotations = ImmutableMap.copyOf(modifiableServiceQNamesToAnnotations);
241         LOGGER.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
242     }
243
244     @Override
245     public Map<ServiceInterfaceAnnotation, String /* service ref name */> findServiceInterfaces(final ModuleIdentifier moduleIdentifier) {
246         Map<ServiceInterfaceAnnotation, String /* service ref name */> result = modulesToServiceRef.get(moduleIdentifier);
247         if (result == null) {
248             return Collections.emptyMap();
249         }
250         return Collections.unmodifiableMap(result);
251     }
252
253     @Override
254     public synchronized Set<String> lookupServiceInterfaceNames(final ObjectName objectName) throws InstanceNotFoundException {
255         lookupRegistry.checkConfigBeanExists(objectName);
256
257         String factoryName = ObjectNameUtil.getFactoryName(objectName);
258         Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
259         if (serviceInterfaceAnnotations == null) {
260             LOGGER.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
261                     factoryName, objectName, factoryNamesToQNames);
262             throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
263         }
264         return serviceInterfaceAnnotations;
265     }
266
267     @Override
268     public synchronized String getServiceInterfaceName(final String namespace, final String localName) {
269         Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
270         if (ofNamespace == null) {
271             LOGGER.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
272             throw new IllegalArgumentException("Cannot find namespace " + namespace);
273         }
274         ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
275         if (sia == null) {
276             LOGGER.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
277             throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
278         }
279         return sia.value();
280     }
281
282     // reading:
283
284     @Override
285     public synchronized Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping() {
286         Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> result = new HashMap<>();
287         for (Entry<ServiceReference, ModuleIdentifier> entry: refNames.entrySet()) {
288             String qName = entry.getKey().getServiceInterfaceQName();
289             Map<String /* refName */, ObjectName> innerMap = result.get(qName);
290             if (innerMap == null) {
291                 innerMap = new HashMap<>();
292                 result.put(qName, innerMap);
293             }
294             innerMap.put(entry.getKey().getRefName(), getObjectName(entry.getValue()));
295         }
296         return result;
297     }
298
299     private ObjectName getObjectName(final ModuleIdentifier moduleIdentifier) {
300         ObjectName on;
301         try {
302             on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
303         } catch (InstanceNotFoundException e) {
304             LOGGER.error("Cannot find instance {}", moduleIdentifier);
305             throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
306         }
307         return on;
308     }
309
310     @Override
311     public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(final String serviceInterfaceQName, final String refName) {
312         ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName);
313         ModuleIdentifier moduleIdentifier = refNames.get(serviceReference);
314         if (moduleIdentifier == null) {
315             LOGGER.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName);
316             throw new IllegalArgumentException("Cannot find " + serviceReference);
317         }
318         return getObjectName(moduleIdentifier);
319     }
320
321     @Override
322     public synchronized Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(final String serviceInterfaceQName) {
323         Map<String, Map<String, ObjectName>> serviceMapping = getServiceMapping();
324         Map<String, ObjectName> innerMap = serviceMapping.get(serviceInterfaceQName);
325         if (innerMap == null) {
326             LOGGER.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames);
327             throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName);
328         }
329         return innerMap;
330     }
331
332     @Override
333     public synchronized ObjectName getServiceReference(final String serviceInterfaceQName, final String refName) throws InstanceNotFoundException {
334         ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName);
335         if (mBeans.containsKey(serviceReference) == false) {
336             throw new InstanceNotFoundException("Cannot find " + serviceReference);
337         }
338         return getServiceON(serviceReference);
339     }
340
341     @Override
342     public synchronized void checkServiceReferenceExists(final ObjectName objectName) throws InstanceNotFoundException {
343         String actualTransactionName = ObjectNameUtil.getTransactionName(objectName);
344         String expectedTransactionName = serviceReferenceRegistrator.getNullableTransactionName();
345         if (writable & actualTransactionName == null || (writable && actualTransactionName.equals(expectedTransactionName) == false)) {
346             throw new IllegalArgumentException("Mismatched transaction name in " + objectName);
347         }
348         String serviceQName = ObjectNameUtil.getServiceQName(objectName);
349         String referenceName = ObjectNameUtil.getReferenceName(objectName);
350         ServiceReference serviceReference = new ServiceReference(serviceQName, referenceName);
351         if (refNames.containsKey(serviceReference) == false) {
352             LOGGER.warn("Cannot find {} in {}", serviceReference, refNames);
353             throw new InstanceNotFoundException("Service reference not found:" + objectName);
354         }
355     }
356
357     // writing:
358
359     private void assertWritable() {
360         if (writable == false) {
361             throw new IllegalStateException("Cannot write to readable registry");
362         }
363     }
364
365     @Override
366     public synchronized ObjectName saveServiceReference(final String serviceInterfaceName, final String refName, final ObjectName moduleON)  throws InstanceNotFoundException {
367         assertWritable();
368         ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName);
369         return saveServiceReference(serviceReference, moduleON);
370     }
371
372     private synchronized ObjectName saveServiceReference(final ServiceReference serviceReference, final ObjectName moduleON)
373             throws InstanceNotFoundException{
374         return saveServiceReference(serviceReference, moduleON, false);
375     }
376
377     private synchronized ObjectName saveServiceReference(final ServiceReference serviceReference, final ObjectName moduleON,
378                                                          final boolean skipChecks) throws InstanceNotFoundException {
379
380         // make sure it is found
381         if (skipChecks == false) {
382             lookupRegistry.checkConfigBeanExists(moduleON);
383         }
384         String factoryName = ObjectNameUtil.getFactoryName(moduleON);
385         String instanceName = ObjectNameUtil.getInstanceName(moduleON);
386         ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
387
388         // check that service interface name exist
389         Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(moduleIdentifier.getFactoryName());
390         if (serviceInterfaceQNames == null) {
391             LOGGER.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(),
392                     factoryNamesToQNames, moduleIdentifier);
393             throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + moduleIdentifier.getFactoryName());
394         }
395         // supplied serviceInterfaceName must exist in this collection
396         if (serviceInterfaceQNames.contains(serviceReference.getServiceInterfaceQName()) == false) {
397             LOGGER.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceQName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames);
398             throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName() + " within factory " + moduleIdentifier.getFactoryName());
399         }
400
401
402         // create service reference object name, put to mBeans
403         ObjectName result = getServiceON(serviceReference);
404         Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> mxBeanEntry = mBeans.get(serviceReference);
405         if (mxBeanEntry == null) {
406             // create dummy mx bean
407             ServiceReferenceMXBeanImpl dummyMXBean = new ServiceReferenceMXBeanImpl(moduleON);
408             ServiceReferenceJMXRegistration dummyMXBeanRegistration;
409             try {
410                 dummyMXBeanRegistration = serviceReferenceRegistrator.registerMBean(dummyMXBean, result);
411             } catch (InstanceAlreadyExistsException e) {
412                 throw new IllegalStateException("Possible error in code. Cannot register " + result, e);
413             }
414             mBeans.put(serviceReference, createMXBeanEntry(dummyMXBean, dummyMXBeanRegistration));
415         } else {
416             // update
417             mxBeanEntry.getKey().setCurrentImplementation(moduleON);
418         }
419         // save to refNames
420         refNames.put(serviceReference, moduleIdentifier);
421         Map<ServiceInterfaceAnnotation, String /* service ref name */> refNamesToAnnotations = modulesToServiceRef.get(moduleIdentifier);
422         if (refNamesToAnnotations == null){
423             refNamesToAnnotations = new HashMap<>();
424             modulesToServiceRef.put(moduleIdentifier, refNamesToAnnotations);
425         }
426
427         ServiceInterfaceAnnotation annotation = serviceQNamesToAnnotations.get(serviceReference.getServiceInterfaceQName());
428         checkNotNull(annotation, "Possible error in code, cannot find annotation for " + serviceReference);
429         refNamesToAnnotations.put(annotation, serviceReference.getRefName());
430         return result;
431     }
432
433     private Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> createMXBeanEntry(
434             final ServiceReferenceMXBeanImpl mxBean, final ServiceReferenceJMXRegistration registration) {
435         return new Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration>() {
436             @Override
437             public ServiceReferenceMXBeanImpl getKey() {
438                 return mxBean;
439             }
440
441             @Override
442             public ServiceReferenceJMXRegistration getValue() {
443                 return registration;
444             }
445
446             @Override
447             public ServiceReferenceJMXRegistration setValue(final ServiceReferenceJMXRegistration value) {
448                 throw new UnsupportedOperationException();
449             }
450         };
451     }
452
453     private ObjectName getServiceON(final ServiceReference serviceReference) {
454         if (writable) {
455             return ObjectNameUtil.createTransactionServiceON(serviceReferenceRegistrator.getNullableTransactionName(),
456                     serviceReference.getServiceInterfaceQName(), serviceReference.getRefName());
457         } else {
458             return ObjectNameUtil.createReadOnlyServiceON(serviceReference.getServiceInterfaceQName(), serviceReference.getRefName());
459         }
460     }
461
462     @Override
463     public synchronized void removeServiceReference(final String serviceInterfaceName, final String refName) throws InstanceNotFoundException{
464         ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName);
465         removeServiceReference(serviceReference);
466     }
467
468     private synchronized void removeServiceReference(final ServiceReference serviceReference) throws InstanceNotFoundException {
469         LOGGER.debug("Removing service reference {} from {}", serviceReference, this);
470         assertWritable();
471         // is the qName known?
472         if (allQNames.contains(serviceReference.getServiceInterfaceQName()) == false) {
473             LOGGER.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceQName(), allQNames);
474             throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName());
475         }
476         ModuleIdentifier removed = refNames.remove(serviceReference);
477         if (removed == null){
478             throw new InstanceNotFoundException("Cannot find " + serviceReference.getServiceInterfaceQName());
479         }
480         Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> entry = mBeans.remove(serviceReference);
481         if (entry == null) {
482             throw new IllegalStateException("Possible code error: cannot remove from mBeans: " + serviceReference);
483         }
484         entry.getValue().close();
485     }
486
487     @Override
488     public synchronized void removeAllServiceReferences() {
489         assertWritable();
490         for (ServiceReference serviceReference: mBeans.keySet()) {
491             try {
492                 removeServiceReference(serviceReference);
493             } catch (InstanceNotFoundException e) {
494                 throw new IllegalStateException("Possible error in code", e);
495             }
496         }
497     }
498
499     @Override
500     public synchronized boolean removeServiceReferences(final ObjectName moduleObjectName) throws InstanceNotFoundException {
501         lookupRegistry.checkConfigBeanExists(moduleObjectName);
502         String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName);
503         // check that service interface name exist
504         Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
505         return removeServiceReferences(moduleObjectName, serviceInterfaceQNames);
506     }
507
508
509     private boolean removeServiceReferences(final ObjectName moduleObjectName, final Set<String> qNames) throws InstanceNotFoundException {
510         ObjectNameUtil.checkType(moduleObjectName, ObjectNameUtil.TYPE_MODULE);
511         assertWritable();
512         Set<ServiceReference> serviceReferencesLinkingTo = findServiceReferencesLinkingTo(moduleObjectName, qNames);
513         for (ServiceReference sr : serviceReferencesLinkingTo) {
514             removeServiceReference(sr);
515         }
516         return serviceReferencesLinkingTo.isEmpty() == false;
517     }
518
519     private Set<ServiceReference> findServiceReferencesLinkingTo(final ObjectName moduleObjectName, final Set<String> serviceInterfaceQNames) {
520         String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName);
521         if (serviceInterfaceQNames == null) {
522             LOGGER.warn("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName);
523             throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
524         }
525         String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName);
526         ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
527         Set<ServiceReference> result = new HashSet<>();
528         for (Entry<ServiceReference, ModuleIdentifier> entry : refNames.entrySet()) {
529             if (entry.getValue().equals(moduleIdentifier)) {
530                 result.add(entry.getKey());
531             }
532         }
533         return result;
534     }
535
536     @Override
537     public String toString() {
538         return "ServiceReferenceRegistryImpl{" +
539                 "lookupRegistry=" + lookupRegistry +
540                 "refNames=" + refNames +
541                 ", factoryNamesToQNames=" + factoryNamesToQNames +
542                 '}';
543     }
544
545     @Override
546     public void close() {
547         serviceReferenceRegistrator.close();
548     }
549 }