diff --git a/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp b/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp index f78a4fd545..505fdc4cc0 100644 --- a/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp +++ b/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp @@ -1,324 +1,324 @@ /*============================================================================= 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 "usServiceReferenceBasePrivate.h" #include "usServiceFactory.h" #include "usServiceException.h" #include "usServiceRegistry_p.h" #include "usServiceRegistrationBasePrivate.h" #include "usModule.h" #include "usModulePrivate.h" #include #include #ifdef _MSC_VER #pragma warning(disable:4503) // decorated name length exceeded, name was truncated #endif US_BEGIN_NAMESPACE typedef ServiceRegistrationBasePrivate::MutexLocker MutexLocker; ServiceReferenceBasePrivate::ServiceReferenceBasePrivate(ServiceRegistrationBasePrivate* reg) : ref(1), registration(reg) { if(registration) registration->ref.Ref(); } ServiceReferenceBasePrivate::~ServiceReferenceBasePrivate() { if (registration && !registration->ref.Deref()) delete registration; } InterfaceMap ServiceReferenceBasePrivate::GetServiceFromFactory(Module* module, ServiceFactory* factory, bool isModuleScope) { assert(factory && "Factory service pointer is NULL"); InterfaceMap s; try { InterfaceMap smap = factory->GetService(module, ServiceRegistrationBase(registration)); if (smap.empty()) { US_WARN << "ServiceFactory produced null"; return smap; } const std::vector& classes = ref_any_cast >(registration->properties.Value(ServiceConstants::OBJECTCLASS())); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { if (smap.find(*i) == smap.end() && *i != "org.cppmicroservices.factory") { US_WARN << "ServiceFactory produced an object " "that did not implement: " << (*i); smap.clear(); return smap; } } s = smap; if (isModuleScope) { registration->moduleServiceInstance.insert(std::make_pair(module, smap)); } else { registration->prototypeServiceInstances[module].push_back(smap); } } catch (...) { US_WARN << "ServiceFactory threw an exception"; s.clear(); } return s; } InterfaceMap ServiceReferenceBasePrivate::GetPrototypeService(Module* module) { InterfaceMap s; { MutexLocker lock(registration->propsLock); if (registration->available) { ServiceFactory* factory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); s = GetServiceFromFactory(module, factory, false); } } return s; } void* ServiceReferenceBasePrivate::GetService(Module* module) { void* s = NULL; { MutexLocker lock(registration->propsLock); if (registration->available) { ServiceFactory* serviceFactory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); const int count = registration->dependents[module]; if (count == 0) { if (serviceFactory) { const InterfaceMap im = GetServiceFromFactory(module, serviceFactory, true); s = im.find(interfaceId)->second; } else { s = registration->GetService(interfaceId); } } else { if (serviceFactory) { // return the already produced instance s = registration->moduleServiceInstance[module][interfaceId]; } else { s = registration->GetService(interfaceId); } } if (s) { registration->dependents[module] = count + 1; } } } return s; } InterfaceMap ServiceReferenceBasePrivate::GetServiceInterfaceMap(Module* module) { InterfaceMap s; { MutexLocker lock(registration->propsLock); if (registration->available) { ServiceFactory* serviceFactory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); const int count = registration->dependents[module]; if (count == 0) { if (serviceFactory) { s = GetServiceFromFactory(module, serviceFactory, true); } else { s = registration->service; } } else { if (serviceFactory) { // return the already produced instance s = registration->moduleServiceInstance[module]; } else { s = registration->service; } } if (!s.empty()) { registration->dependents[module] = count + 1; } } } return s; } bool ServiceReferenceBasePrivate::UngetPrototypeService(Module* module, const InterfaceMap& service) { MutexLocker lock(registration->propsLock); ServiceRegistrationBasePrivate::ModuleToServicesMap::iterator iter = registration->prototypeServiceInstances.find(module); if (iter == registration->prototypeServiceInstances.end()) { return false; } std::list& prototypeServiceMaps = iter->second; for (std::list::iterator imIter = prototypeServiceMaps.begin(); imIter != prototypeServiceMaps.end(); ++imIter) { if (service == *imIter) { try { ServiceFactory* sf = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); sf->UngetService(module, ServiceRegistrationBase(registration), service); } catch (const std::exception& /*e*/) { US_WARN << "ServiceFactory threw an exception"; } prototypeServiceMaps.erase(imIter); if (prototypeServiceMaps.empty()) { registration->prototypeServiceInstances.erase(iter); } return true; } } return false; } bool ServiceReferenceBasePrivate::UngetService(Module* module, bool checkRefCounter) { MutexLocker lock(registration->propsLock); bool hadReferences = false; bool removeService = false; int count= registration->dependents[module]; if (count > 0) { hadReferences = true; } if(checkRefCounter) { if (count > 1) { registration->dependents[module] = count - 1; } else if(count == 1) { removeService = true; } } else { removeService = true; } if (removeService) { InterfaceMap sfi = registration->moduleServiceInstance[module]; registration->moduleServiceInstance.erase(module); if (!sfi.empty()) { try { ServiceFactory* sf = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); sf->UngetService(module, ServiceRegistrationBase(registration), sfi); } catch (const std::exception& /*e*/) { US_WARN << "ServiceFactory threw an exception"; } } registration->dependents.erase(module); } return hadReferences && removeService; } const ServicePropertiesImpl& ServiceReferenceBasePrivate::GetProperties() const { return registration->properties; } Any ServiceReferenceBasePrivate::GetProperty(const std::string& key, bool lock) const { if (lock) { MutexLocker lock(registration->propsLock); return registration->properties.Value(key); } else { return registration->properties.Value(key); } } bool ServiceReferenceBasePrivate::IsConvertibleTo(const std::string& interfaceId) const { - return registration->service.find(interfaceId) != registration->service.end(); + return registration ? registration->service.find(interfaceId) != registration->service.end() : false; } US_END_NAMESPACE diff --git a/Core/CppMicroServices/test/usServiceRegistryTest.cpp b/Core/CppMicroServices/test/usServiceRegistryTest.cpp index bd15ed18f2..8943242082 100644 --- a/Core/CppMicroServices/test/usServiceRegistryTest.cpp +++ b/Core/CppMicroServices/test/usServiceRegistryTest.cpp @@ -1,135 +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_USE_NAMESPACE struct ITestServiceA { virtual ~ITestServiceA() {} }; US_DECLARE_SERVICE_INTERFACE(ITestServiceA, "org.cppmicroservices.testing.ITestServiceA") int TestMultipleServiceRegistrations() { struct TestServiceA : public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; TestServiceA s2; ServiceRegistration reg1 = context->RegisterService(&s1); ServiceRegistration reg2 = context->RegisterService(&s2); std::vector > 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") + ServiceReference ref = context->GetServiceReference(); + US_TEST_CONDITION_REQUIRED(!ref, "Testing for invalid service reference") + return EXIT_SUCCESS; } int TestServicePropertiesUpdate() { struct TestServiceA : 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(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(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") 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") 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() }