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