X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fconfig%2Fconfig-manager%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fconfig%2Fmanager%2Fimpl%2FServiceReferenceRegistryImpl.java;h=52bb3f5ed1df99a678e9ad44357cef6eadc4b3cf;hp=7fedcdf71ce7ce28974cc06a1e72c42720b04248;hb=b80124e3f7b11cf2f5e5bd4a6b033d855ff4d0d4;hpb=7e6e19f57c11d6a35558f230f05b5b0d13b4ebe8 diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java index 7fedcdf71c..52bb3f5ed1 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java @@ -7,48 +7,62 @@ */ package org.opendaylight.controller.config.manager.impl; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; import org.opendaylight.controller.config.api.LookupRegistry; import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry; import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReference; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceMXBeanImpl; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceJMXRegistration; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactory; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactoryImpl; import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry { +public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceReadableRegistry, SearchableServiceReferenceWritableRegistry { private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class); private final Map factories; private final Map> factoryNamesToQNames; // validator of incoming ObjectNames - throws InstanceNotFoundException if not found either in registry or transaction private final LookupRegistry lookupRegistry; + private final ServiceReferenceRegistrator serviceReferenceRegistrator; // helper method for getting QName of SI from namespace + local name private final Map> namespacesToAnnotations; + private final Map serviceQNamesToAnnotations; // all Service Interface qNames for sanity checking private final Set allQNames; + Map> modulesToServiceRef = new HashMap<>(); + // actual reference database - private final Map> refNames; + private final Map refNames = new HashMap<>(); + private final boolean writable; + private final Map> mBeans = new HashMap<>(); /** * Static constructor for config registry. Since only transaction can write to this registry, it will * return blank state. */ - public static ServiceReferenceReadableRegistry createInitialSRLookupRegistry() { + public static CloseableServiceReferenceReadableRegistry createInitialSRLookupRegistry() { // since this is initial state, just throw exception: LookupRegistry lookupRegistry = new LookupRegistry() { @Override @@ -73,36 +87,99 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg @Override public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { - throw new InstanceNotFoundException("Cannot find " + objectName); + throw new InstanceNotFoundException("Cannot find " + objectName + " - Tried to use mocking registry"); } @Override public Set getAvailableModuleFactoryQNames() { throw new UnsupportedOperationException(); } + + @Override + public String toString() { + return "initial"; + } + }; + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactory(){ + @Override + public ServiceReferenceRegistrator create() { + return new ServiceReferenceRegistrator() { + @Override + public String getNullableTransactionName() { + throw new UnsupportedOperationException(); + } + + @Override + public ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object, ObjectName on) throws InstanceAlreadyExistsException { + throw new UnsupportedOperationException(); + } + + @Override + public void close() { + + } + }; + } }; return new ServiceReferenceRegistryImpl(Collections.emptyMap(), lookupRegistry, - Collections.>emptyMap()); + serviceReferenceRegistratorFactory, false); } /** * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data. */ - public static ServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry, - LookupRegistry lookupRegistry, Map> currentlyRegisteredFactories) { + public static SearchableServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry, + ConfigTransactionLookupRegistry txLookupRegistry, + Map> currentlyRegisteredFactories) { + if (txLookupRegistry == null) { + throw new IllegalArgumentException("txLookupRegistry is null"); + } ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry; Map factories = extractFactoriesMap(currentlyRegisteredFactories); - return new ServiceReferenceRegistryImpl(factories, lookupRegistry, Collections.unmodifiableMap(old.refNames)); + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl( + txLookupRegistry.getTxModuleJMXRegistrator(), txLookupRegistry.getTxModuleJMXRegistrator().getTransactionName()); + ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(factories, txLookupRegistry, + serviceReferenceRegistratorFactory, true); + copy(old, newRegistry, txLookupRegistry.getTransactionIdentifier().getName()); + return newRegistry; } /** * Copy back state to config registry after commit. */ - public static ServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, LookupRegistry lookupRegistry) { + public static CloseableServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, + LookupRegistry lookupRegistry, BaseJMXRegistrator baseJMXRegistrator) { ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry; + // even if factories do change, nothing in the mapping can change between transactions - return new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, Collections.unmodifiableMap(old.refNames)); + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl(baseJMXRegistrator); + ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, + serviceReferenceRegistratorFactory, false); + copy(old, newRegistry, null); + return newRegistry; + } + + /** + * Fill refNames and mBeans maps from old instance + */ + private static void copy(ServiceReferenceRegistryImpl old, ServiceReferenceRegistryImpl newRegistry, String nullableDstTransactionName) { + for (Entry> refNameEntry : old.mBeans.entrySet()) { + ObjectName currentImplementation; + ObjectName currentImplementationSrc = refNameEntry.getValue().getKey().getCurrentImplementation(); + if (nullableDstTransactionName != null) { + currentImplementation = ObjectNameUtil.withTransactionName(currentImplementationSrc, nullableDstTransactionName); + } else { + currentImplementation = ObjectNameUtil.withoutTransactionName(currentImplementationSrc); + } + try { + boolean skipChecks = true; + newRegistry.saveServiceReference(refNameEntry.getKey(), currentImplementation, skipChecks); + } catch (InstanceNotFoundException e) { + logger.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation); + throw new IllegalStateException("Possible code error", e); + } + } } private static Map extractFactoriesMap(Map> currentlyRegisteredFactories) { @@ -114,62 +191,66 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg } private ServiceReferenceRegistryImpl(Map factories, LookupRegistry lookupRegistry, - Map> refNamesToCopy) { + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory, + boolean writable) { this.factories = factories; + this.writable = writable; this.lookupRegistry = lookupRegistry; - Map> factoryNamesToQNames = new HashMap<>(); + + this.serviceReferenceRegistrator = serviceReferenceRegistratorFactory.create(); + + Map> modifiableFactoryNamesToQNames = new HashMap<>(); Set allAnnotations = new HashSet<>(); Set allQNames = new HashSet<>(); + + for (Entry entry : factories.entrySet()) { if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) { logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry); throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry); } Set siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue()); - Set qNames = new HashSet<>(); - for (ServiceInterfaceAnnotation sia: siAnnotations) { - qNames.add(sia.value()); - } + Set qNames = InterfacesHelper.getQNames(siAnnotations); allAnnotations.addAll(siAnnotations); allQNames.addAll(qNames); - factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames)); + modifiableFactoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames)); } - this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames); + this.factoryNamesToQNames = Collections.unmodifiableMap(modifiableFactoryNamesToQNames); this.allQNames = Collections.unmodifiableSet(allQNames); // fill namespacesToAnnotations - Map> namespacesToAnnotations = + Map> modifiableNamespacesToAnnotations = new HashMap<>(); + Map modifiableServiceQNamesToAnnotations = new HashMap<>(); for (ServiceInterfaceAnnotation sia : allAnnotations) { - Map ofNamespace = namespacesToAnnotations.get(sia.namespace()); + Map ofNamespace = modifiableNamespacesToAnnotations.get(sia.namespace()); if (ofNamespace == null) { ofNamespace = new HashMap<>(); - namespacesToAnnotations.put(sia.namespace(), ofNamespace); + modifiableNamespacesToAnnotations.put(sia.namespace(), ofNamespace); } if (ofNamespace.containsKey(sia.localName())) { logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}", - sia.namespace(), sia.localName(), namespacesToAnnotations); + sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations); throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName()); } ofNamespace.put(sia.localName(), sia); + modifiableServiceQNamesToAnnotations.put(sia.value(), sia); } - this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations); - // copy refNames - Map> deepCopy = new HashMap<>(); - for (Entry> outerROEntry: refNamesToCopy.entrySet()) { - Map innerWritableMap = new HashMap<>(); - deepCopy.put(outerROEntry.getKey(), innerWritableMap); - for (Entry innerROEntry: outerROEntry.getValue().entrySet()) { - innerWritableMap.put(innerROEntry.getKey(), innerROEntry.getValue()); - } - } - this.refNames = deepCopy; + this.namespacesToAnnotations = Collections.unmodifiableMap(modifiableNamespacesToAnnotations); + this.serviceQNamesToAnnotations = Collections.unmodifiableMap(modifiableServiceQNamesToAnnotations); logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames); - logger.trace("refNames:{}", refNames); } + @Override + public Map findServiceInterfaces(ModuleIdentifier moduleIdentifier) { + Map result = modulesToServiceRef.get(moduleIdentifier); + if (result == null) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(result); + } @Override - public Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + public synchronized Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { lookupRegistry.checkConfigBeanExists(objectName); String factoryName = ObjectNameUtil.getFactoryName(objectName); @@ -183,7 +264,7 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg } @Override - public String getServiceInterfaceName(String namespace, String localName) { + public synchronized String getServiceInterfaceName(String namespace, String localName) { Map ofNamespace = namespacesToAnnotations.get(namespace); if (ofNamespace == null) { logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations); @@ -197,23 +278,19 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg return sia.value(); } - - // reading: @Override - public Map> getServiceMapping() { + public synchronized Map> getServiceMapping() { Map> result = new HashMap<>(); - for (Entry> outerEntry: refNames.entrySet()) { - String qName = outerEntry.getKey(); - Map innerMap = new HashMap<>(); - result.put(qName, innerMap); - for (Entry innerEntry: outerEntry.getValue().entrySet()) { - ModuleIdentifier moduleIdentifier = innerEntry.getValue(); - ObjectName on; - on = getObjectName(moduleIdentifier); - innerMap.put(innerEntry.getKey(), on); + for (Entry entry: refNames.entrySet()) { + String qName = entry.getKey().getServiceInterfaceQName(); + Map innerMap = result.get(qName); + if (innerMap == null) { + innerMap = new HashMap<>(); + result.put(qName, innerMap); } + innerMap.put(entry.getKey().getRefName(), getObjectName(entry.getValue())); } return result; } @@ -230,116 +307,242 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg } @Override - public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { - Map innerMap = refNames.get(serviceInterfaceName); - if (innerMap == null) { - logger.error("Cannot find qname {} in {}", serviceInterfaceName, refName); - throw new IllegalArgumentException("Cannot find " + serviceInterfaceName); - } - ModuleIdentifier moduleIdentifier = innerMap.get(refName); + public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName); + ModuleIdentifier moduleIdentifier = refNames.get(serviceReference); if (moduleIdentifier == null) { - logger.error("Cannot find refName {} in {}, using qname {}", refName, innerMap, serviceInterfaceName); - throw new IllegalArgumentException("Cannot find module based on service reference " + refName); + logger.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName); + throw new IllegalArgumentException("Cannot find " + serviceReference); } return getObjectName(moduleIdentifier); } @Override - public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { - Map innerMap = refNames.get(serviceInterfaceName); + public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + Map> serviceMapping = getServiceMapping(); + Map innerMap = serviceMapping.get(serviceInterfaceQName); if (innerMap == null) { - logger.error("Cannot find qname {} in {}", serviceInterfaceName, refNames); - throw new IllegalArgumentException("Cannot find " + serviceInterfaceName); + logger.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames); + throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName); } - Map result = new HashMap<>(); - for (Entry entry: innerMap.entrySet()) { - ObjectName on = getObjectName(entry.getValue()); - result.put(entry.getKey(), on); + return innerMap; + } + + @Override + public synchronized ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName); + if (mBeans.containsKey(serviceReference) == false) { + throw new InstanceNotFoundException("Cannot find " + serviceReference); + } + return getServiceON(serviceReference); + } + + @Override + public synchronized void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + String actualTransactionName = ObjectNameUtil.getTransactionName(objectName); + String expectedTransactionName = serviceReferenceRegistrator.getNullableTransactionName(); + if (writable & actualTransactionName == null || (writable && actualTransactionName.equals(expectedTransactionName) == false)) { + throw new IllegalArgumentException("Mismatched transaction name in " + objectName); + } + String serviceQName = ObjectNameUtil.getServiceQName(objectName); + String referenceName = ObjectNameUtil.getReferenceName(objectName); + ServiceReference serviceReference = new ServiceReference(serviceQName, referenceName); + if (refNames.containsKey(serviceReference) == false) { + logger.warn("Cannot find {} in {}", serviceReference, refNames); + throw new InstanceNotFoundException("Service reference not found:" + objectName); } - return result; } // writing: + private void assertWritable() { + if (writable == false) { + throw new IllegalStateException("Cannot write to readable registry"); + } + } + @Override - public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException { + public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { + assertWritable(); + ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName); + return saveServiceReference(serviceReference, moduleON); + } + + private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON) + throws InstanceNotFoundException{ + return saveServiceReference(serviceReference, moduleON, false); + } + + private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON, + boolean skipChecks) throws InstanceNotFoundException { + // make sure it is found - lookupRegistry.checkConfigBeanExists(objectName); - String factoryName = ObjectNameUtil.getFactoryName(objectName); + if (skipChecks == false) { + lookupRegistry.checkConfigBeanExists(moduleON); + } + String factoryName = ObjectNameUtil.getFactoryName(moduleON); + String instanceName = ObjectNameUtil.getInstanceName(moduleON); + ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName); + // check that service interface name exist - Set serviceInterfaceQNames = factoryNamesToQNames.get(factoryName); + Set serviceInterfaceQNames = factoryNamesToQNames.get(moduleIdentifier.getFactoryName()); if (serviceInterfaceQNames == null) { - logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName); - throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName); + logger.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(), + factoryNamesToQNames, moduleIdentifier); + throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + moduleIdentifier.getFactoryName()); } // supplied serviceInterfaceName must exist in this collection - if (serviceInterfaceQNames.contains(serviceInterfaceName) == false) { - logger.error("Cannot find qname {} with factory name {}, found {}", serviceInterfaceName, factoryName, serviceInterfaceQNames); - throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName + " within factory " + factoryName ); + if (serviceInterfaceQNames.contains(serviceReference.getServiceInterfaceQName()) == false) { + logger.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceQName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames); + throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName() + " within factory " + moduleIdentifier.getFactoryName()); } - String instanceName = ObjectNameUtil.getInstanceName(objectName); - ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName); - Map ofQName = refNames.get(serviceInterfaceName); - // might be null - if (ofQName == null) { - ofQName = new HashMap<>(); - refNames.put(serviceInterfaceName, ofQName); + + + // create service reference object name, put to mBeans + ObjectName result = getServiceON(serviceReference); + Entry mxBeanEntry = mBeans.get(serviceReference); + if (mxBeanEntry == null) { + // create dummy mx bean + ServiceReferenceMXBeanImpl dummyMXBean = new ServiceReferenceMXBeanImpl(moduleON); + ServiceReferenceJMXRegistration dummyMXBeanRegistration; + try { + dummyMXBeanRegistration = serviceReferenceRegistrator.registerMBean(dummyMXBean, result); + } catch (InstanceAlreadyExistsException e) { + throw new IllegalStateException("Possible error in code. Cannot register " + result, e); + } + mBeans.put(serviceReference, createMXBeanEntry(dummyMXBean, dummyMXBeanRegistration)); + } else { + // update + mxBeanEntry.getKey().setCurrentImplementation(moduleON); + } + // save to refNames + refNames.put(serviceReference, moduleIdentifier); + Map refNamesToAnnotations = modulesToServiceRef.get(moduleIdentifier); + if (refNamesToAnnotations == null){ + refNamesToAnnotations = new HashMap<>(); + modulesToServiceRef.put(moduleIdentifier, refNamesToAnnotations); + } + + ServiceInterfaceAnnotation annotation = serviceQNamesToAnnotations.get(serviceReference.getServiceInterfaceQName()); + checkNotNull(annotation, "Possible error in code, cannot find annotation for " + serviceReference); + refNamesToAnnotations.put(annotation, serviceReference.getRefName()); + return result; + } + + private Entry createMXBeanEntry( + final ServiceReferenceMXBeanImpl mxBean, final ServiceReferenceJMXRegistration registration) { + return new Entry() { + @Override + public ServiceReferenceMXBeanImpl getKey() { + return mxBean; + } + + @Override + public ServiceReferenceJMXRegistration getValue() { + return registration; + } + + @Override + public ServiceReferenceJMXRegistration setValue(ServiceReferenceJMXRegistration value) { + throw new UnsupportedOperationException(); + } + }; + } + + private ObjectName getServiceON(ServiceReference serviceReference) { + if (writable) { + return ObjectNameUtil.createTransactionServiceON(serviceReferenceRegistrator.getNullableTransactionName(), + serviceReference.getServiceInterfaceQName(), serviceReference.getRefName()); + } else { + return ObjectNameUtil.createReadOnlyServiceON(serviceReference.getServiceInterfaceQName(), serviceReference.getRefName()); } - ofQName.put(refName, moduleIdentifier); } @Override - public boolean removeServiceReference(String serviceInterfaceName, String refName) { - // is the qname known? - if (allQNames.contains(serviceInterfaceName) == false) { - logger.error("Cannot find qname {} in {}", serviceInterfaceName, allQNames); - throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName); + public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException{ + ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName); + removeServiceReference(serviceReference); + } + + private synchronized void removeServiceReference(ServiceReference serviceReference) throws InstanceNotFoundException { + logger.debug("Removing service reference {} from {}", serviceReference, this); + assertWritable(); + // is the qName known? + if (allQNames.contains(serviceReference.getServiceInterfaceQName()) == false) { + logger.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceQName(), allQNames); + throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName()); + } + ModuleIdentifier removed = refNames.remove(serviceReference); + if (removed == null){ + throw new InstanceNotFoundException("Cannot find " + serviceReference.getServiceInterfaceQName()); } - Map ofQName = refNames.get(serviceInterfaceName); - if (ofQName == null) { - return false; + Entry entry = mBeans.remove(serviceReference); + if (entry == null) { + throw new IllegalStateException("Possible code error: cannot remove from mBeans: " + serviceReference); } - return ofQName.remove(refName) != null; + entry.getValue().close(); } @Override - public void removeAllServiceReferences() { - refNames.clear(); + public synchronized void removeAllServiceReferences() { + assertWritable(); + for (ServiceReference serviceReference: mBeans.keySet()) { + try { + removeServiceReference(serviceReference); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Possible error in code", e); + } + } } @Override - public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException { - lookupRegistry.checkConfigBeanExists(objectName); - String factoryName = ObjectNameUtil.getFactoryName(objectName); + public synchronized boolean removeServiceReferences(ObjectName moduleObjectName) throws InstanceNotFoundException { + lookupRegistry.checkConfigBeanExists(moduleObjectName); + String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName); // check that service interface name exist Set serviceInterfaceQNames = factoryNamesToQNames.get(factoryName); + return removeServiceReferences(moduleObjectName, serviceInterfaceQNames); + } + + + private boolean removeServiceReferences(ObjectName moduleObjectName, Set qNames) throws InstanceNotFoundException { + ObjectNameUtil.checkType(moduleObjectName, ObjectNameUtil.TYPE_MODULE); + assertWritable(); + Set serviceReferencesLinkingTo = findServiceReferencesLinkingTo(moduleObjectName, qNames); + for (ServiceReference sr : serviceReferencesLinkingTo) { + removeServiceReference(sr); + } + return serviceReferencesLinkingTo.isEmpty() == false; + } + + private Set findServiceReferencesLinkingTo(ObjectName moduleObjectName, Set serviceInterfaceQNames) { + String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName); if (serviceInterfaceQNames == null) { - logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName); + logger.warn("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName); throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName); } - String instanceName = ObjectNameUtil.getInstanceName(objectName); + String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName); ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName); - boolean found = false; - for(String qName: serviceInterfaceQNames){ - Map ofQName = refNames.get(qName); - if (ofQName != null) { - for(Iterator> it = ofQName.entrySet ().iterator(); it.hasNext();){ - Entry next = it.next(); - if (next.getValue().equals(moduleIdentifier)) { - found = true; - it.remove(); - } - } + Set result = new HashSet<>(); + for (Entry entry : refNames.entrySet()) { + if (entry.getValue().equals(moduleIdentifier)) { + result.add(entry.getKey()); } } - return found; + return result; } @Override public String toString() { return "ServiceReferenceRegistryImpl{" + + "lookupRegistry=" + lookupRegistry + "refNames=" + refNames + ", factoryNamesToQNames=" + factoryNamesToQNames + '}'; } + + @Override + public void close() { + serviceReferenceRegistrator.close(); + } }