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