diff --git a/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp b/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp index 693e6666c0..c945abe64d 100644 --- a/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp +++ b/Core/Code/CppMicroServices/src/service/usServiceRegistration.cpp @@ -1,239 +1,244 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #ifdef US_ENABLE_SERVICE_FACTORY_SUPPORT #include US_BASECLASS_HEADER #endif #include "usServiceRegistration.h" #include "usServiceRegistrationPrivate.h" #include "usServiceListenerEntry_p.h" #include "usServiceRegistry_p.h" #include "usServiceFactory.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" #include US_BEGIN_NAMESPACE typedef ServiceRegistrationPrivate::MutexLocker MutexLocker; ServiceRegistration::ServiceRegistration() : d(0) { } ServiceRegistration::ServiceRegistration(const ServiceRegistration& reg) : d(reg.d) { if (d) d->ref.Ref(); } ServiceRegistration::ServiceRegistration(ServiceRegistrationPrivate* registrationPrivate) : d(registrationPrivate) { if (d) d->ref.Ref(); } ServiceRegistration::ServiceRegistration(ModulePrivate* module, US_BASECLASS_NAME* service, const ServiceProperties& props) : d(new ServiceRegistrationPrivate(module, service, props)) { } ServiceRegistration::operator bool() const { return d != 0; } ServiceRegistration& ServiceRegistration::operator=(int null) { if (null == 0) { if (d && !d->ref.Deref()) { delete d; } d = 0; } return *this; } ServiceRegistration::~ServiceRegistration() { if (d && !d->ref.Deref()) delete d; } ServiceReference ServiceRegistration::GetReference() const { if (!d) throw std::logic_error("ServiceRegistration object invalid"); if (!d->available) throw std::logic_error("Service is unregistered"); return d->reference; } void ServiceRegistration::SetProperties(const ServiceProperties& props) { if (!d) throw std::logic_error("ServiceRegistration object invalid"); MutexLocker lock(d->eventLock); ServiceListeners::ServiceListenerEntries before; // TBD, optimize the locking of services { //MutexLocker lock2(d->module->coreCtx->globalFwLock); - MutexLocker lock3(d->propsLock); if (d->available) { // NYI! Optimize the MODIFIED_ENDMATCH code int old_rank = 0; - Any any = d->properties[ServiceConstants::SERVICE_RANKING()]; - if (any.Type() == typeid(int)) old_rank = any_cast(any); + int new_rank = 0; - d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, before, false); - const std::list classes = ref_any_cast >(d->properties[ServiceConstants::OBJECTCLASS()]); - long int sid = any_cast(d->properties[ServiceConstants::SERVICE_ID()]); - d->properties = ServiceRegistry::CreateServiceProperties(props, classes, sid); + std::list classes; + { + MutexLocker lock3(d->propsLock); - int new_rank = 0; - any = d->properties[ServiceConstants::SERVICE_RANKING()]; - if (any.Type() == typeid(int)) new_rank = any_cast(any); + Any any = d->properties[ServiceConstants::SERVICE_RANKING()]; + if (any.Type() == typeid(int)) old_rank = any_cast(any); + + d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, before, false); + classes = ref_any_cast >(d->properties[ServiceConstants::OBJECTCLASS()]); + long int sid = any_cast(d->properties[ServiceConstants::SERVICE_ID()]); + d->properties = ServiceRegistry::CreateServiceProperties(props, classes, sid); + + any = d->properties[ServiceConstants::SERVICE_RANKING()]; + if (any.Type() == typeid(int)) new_rank = any_cast(any); + } if (old_rank != new_rank) { d->module->coreCtx->services.UpdateServiceRegistrationOrder(*this, classes); } } else { throw std::logic_error("Service is unregistered"); } } ServiceListeners::ServiceListenerEntries matchingListeners; d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, matchingListeners); d->module->coreCtx->listeners.ServiceChanged(matchingListeners, ServiceEvent(ServiceEvent::MODIFIED, d->reference), before); d->module->coreCtx->listeners.ServiceChanged(before, ServiceEvent(ServiceEvent::MODIFIED_ENDMATCH, d->reference)); } void ServiceRegistration::Unregister() { if (!d) throw std::logic_error("ServiceRegistration object invalid"); if (d->unregistering) return; // Silently ignore redundant unregistration. { MutexLocker lock(d->eventLock); if (d->unregistering) return; d->unregistering = true; if (d->available) { if (d->module) { d->module->coreCtx->services.RemoveServiceRegistration(*this); } } else { throw std::logic_error("Service is unregistered"); } } if (d->module) { ServiceListeners::ServiceListenerEntries listeners; d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, listeners); d->module->coreCtx->listeners.ServiceChanged( listeners, ServiceEvent(ServiceEvent::UNREGISTERING, d->reference)); } { MutexLocker lock(d->eventLock); { MutexLocker lock2(d->propsLock); d->available = false; #ifdef US_ENABLE_SERVICE_FACTORY_SUPPORT if (d->module) { ServiceRegistrationPrivate::ModuleToServicesMap::const_iterator end = d->serviceInstances.end(); for (ServiceRegistrationPrivate::ModuleToServicesMap::const_iterator i = d->serviceInstances.begin(); i != end; ++i) { US_BASECLASS_NAME* obj = i->second; try { // NYI, don't call inside lock dynamic_cast(d->service)->UngetService(i->first, *this, obj); } catch (const std::exception& /*ue*/) { US_WARN << "ServiceFactory UngetService implementation threw an exception"; } } } #endif d->module = 0; d->dependents.clear(); d->service = 0; d->serviceInstances.clear(); d->reference = 0; d->unregistering = false; } } } bool ServiceRegistration::operator<(const ServiceRegistration& o) const { if (!d) return true; return d->reference <(o.d->reference); } bool ServiceRegistration::operator==(const ServiceRegistration& registration) const { return d == registration.d; } ServiceRegistration& ServiceRegistration::operator=(const ServiceRegistration& registration) { ServiceRegistrationPrivate* curr_d = d; d = registration.d; if (d) d->ref.Ref(); if (curr_d && !curr_d->ref.Deref()) delete curr_d; return *this; } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp b/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp index 093e13f536..a2cbdf3507 100644 --- a/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp +++ b/Core/Code/CppMicroServices/test/usServiceRegistryTest.cpp @@ -1,138 +1,138 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usTestingMacros.h" #include #include #include #include US_BASECLASS_HEADER #include US_USE_NAMESPACE struct ITestServiceA { virtual ~ITestServiceA() {} }; US_DECLARE_SERVICE_INTERFACE(ITestServiceA, "org.cppmicroservices.testing.ITestServiceA") int TestMultipleServiceRegistrations() { struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; TestServiceA s2; ServiceRegistration reg1 = context->RegisterService(&s1); ServiceRegistration reg2 = context->RegisterService(&s2); std::list refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Testing for two registered ITestServiceA services") reg2.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 1, "Testing for one registered ITestServiceA services") reg1.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.empty(), "Testing for no ITestServiceA services") return EXIT_SUCCESS; } int TestServicePropertiesUpdate() { struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; ServiceProperties props; props["string"] = std::string("A std::string"); props["bool"] = false; const char* str = "A const char*"; props["const char*"] = str; ServiceRegistration reg1 = context->RegisterService(&s1, props); ServiceReference ref1 = context->GetServiceReference(); - US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count") + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 1, "Testing service count") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == false, "Testing bool property") // register second service with higher rank TestServiceA s2; ServiceProperties props2; props2[ServiceConstants::SERVICE_RANKING()] = 50; ServiceRegistration reg2 = context->RegisterService(&s2, props2); // Get the service with the highest rank, this should be s2. ServiceReference ref2 = context->GetServiceReference(); TestServiceA* service = dynamic_cast(context->GetService(ref2)); US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") props["bool"] = true; // change the service ranking props[ServiceConstants::SERVICE_RANKING()] = 100; reg1.SetProperties(props); - US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 2, "Testing service count") + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 2, "Testing service count") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == true, "Testing bool property") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty(ServiceConstants::SERVICE_RANKING())) == 100, "Testing updated ranking") // Service with the highest ranking should now be s1 service = dynamic_cast(context->GetService(ref1)); US_TEST_CONDITION_REQUIRED(service == &s1, "Testing highest service rank") reg1.Unregister(); - US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count") + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count") service = dynamic_cast(context->GetService(ref2)); US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") reg2.Unregister(); - US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").empty(), "Testing service count") + US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().empty(), "Testing service count") return EXIT_SUCCESS; } int usServiceRegistryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceRegistryTest"); US_TEST_CONDITION(TestMultipleServiceRegistrations() == EXIT_SUCCESS, "Testing service registrations: ") US_TEST_CONDITION(TestServicePropertiesUpdate() == EXIT_SUCCESS, "Testing service property update: ") US_TEST_END() }