diff --git a/Core/CppMicroServices/src/util/usFunctor_p.h b/Core/CppMicroServices/src/util/usFunctor_p.h index ba4daeb92e..0fc5a5c78b 100644 --- a/Core/CppMicroServices/src/util/usFunctor_p.h +++ b/Core/CppMicroServices/src/util/usFunctor_p.h @@ -1,144 +1,160 @@ /*============================================================================= 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. =============================================================================*/ #ifndef USFUNCTOR_H #define USFUNCTOR_H #include US_BEGIN_NAMESPACE template class FunctorImpl { public: virtual void operator()(Arg) = 0; virtual FunctorImpl* Clone() const = 0; bool operator==(const FunctorImpl& o) const { return typeid(*this) == typeid(o) && IsEqual(o); } virtual ~FunctorImpl() {} + virtual void* target() const = 0; + private: virtual bool IsEqual(const FunctorImpl& o) const = 0; }; template class FunctorHandler : public FunctorImpl { public: FunctorHandler(const Fun& fun) : m_Fun(fun) {} FunctorHandler* Clone() const { return new FunctorHandler(*this); } void operator()(Arg a) { m_Fun(a); } + void* target() const + { + void* result = NULL; + std::memcpy(&result, &m_Fun, sizeof(void*)); + return result; + } + private: bool IsEqual(const FunctorImpl& o) const { return this->m_Fun == static_cast(o).m_Fun; } Fun m_Fun; }; template class MemFunHandler : public FunctorImpl { public: MemFunHandler(const PointerToObj& pObj, PointerToMemFn pMemFn) : m_pObj(pObj), m_pMemFn(pMemFn) {} MemFunHandler* Clone() const { return new MemFunHandler(*this); } void operator()(Arg a) { ((*m_pObj).*m_pMemFn)(a); } + void* target() const + { + void* result = NULL; + std::memcpy(&result, &m_pMemFn, sizeof(void*)); + return result; + } + private: bool IsEqual(const FunctorImpl& o) const { return this->m_pObj == static_cast(o).m_pObj && this->m_pMemFn == static_cast(o).m_pMemFn; } PointerToObj m_pObj; PointerToMemFn m_pMemFn; }; template class Functor { public: Functor() : m_Impl(0) {} template Functor(const Fun& fun) : m_Impl(new FunctorHandler(fun)) {} template Functor(const PtrObj& p, MemFn memFn) : m_Impl(new MemFunHandler(p, memFn)) {} Functor(const Functor& f) : m_Impl(f.m_Impl->Clone()) {} Functor& operator=(const Functor& f) { Impl* tmp = f.m_Impl->Clone(); std::swap(tmp, m_Impl); delete tmp; } bool operator==(const Functor& f) const { return (*m_Impl) == (*f.m_Impl); } ~Functor() { delete m_Impl; } void operator()(Arg a) { (*m_Impl)(a); } void* target() const { - return reinterpret_cast(m_Impl); + return m_Impl->target(); } private: typedef FunctorImpl Impl; Impl* m_Impl; }; US_END_NAMESPACE #endif // USFUNCTOR_H diff --git a/Core/CppMicroServices/test/usServiceTrackerTest.cpp b/Core/CppMicroServices/test/usServiceTrackerTest.cpp index bcf834347d..894a903821 100644 --- a/Core/CppMicroServices/test/usServiceTrackerTest.cpp +++ b/Core/CppMicroServices/test/usServiceTrackerTest.cpp @@ -1,283 +1,286 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include "usServiceControlInterface.h" #include US_USE_NAMESPACE bool CheckConvertibility(const std::vector& refs, std::vector::const_iterator idBegin, std::vector::const_iterator idEnd) { std::vector ids; ids.assign(idBegin, idEnd); for (std::vector::const_iterator sri = refs.begin(); sri != refs.end(); ++sri) { for (std::vector::iterator idIter = ids.begin(); idIter != ids.end(); ++idIter) { if (sri->IsConvertibleTo(*idIter)) { ids.erase(idIter); break; } } } return ids.empty(); } struct MyInterfaceOne { virtual ~MyInterfaceOne() {} }; US_DECLARE_SERVICE_INTERFACE(MyInterfaceOne, "org.cppmicroservices.servicetrackertest.MyInterfaceOne") struct MyInterfaceTwo { virtual ~MyInterfaceTwo() {} }; US_DECLARE_SERVICE_INTERFACE(MyInterfaceTwo, "org.cppmicroservices.servicetrackertest.MyInterfaceTwo") class MyCustomizer : public us::ServiceTrackerCustomizer { public: MyCustomizer(us::ModuleContext* context) : m_context(context) {} virtual MyInterfaceOne* AddingService(const ServiceReferenceType& reference) { US_TEST_CONDITION_REQUIRED(reference, "AddingService() valid reference") return m_context->GetService(reference); } virtual void ModifiedService(const ServiceReferenceType& reference, MyInterfaceOne* service) { US_TEST_CONDITION(reference, "ModifiedService() valid reference") US_TEST_CONDITION(service, "ModifiedService() valid service") } virtual void RemovedService(const ServiceReferenceType& reference, MyInterfaceOne* service) { US_TEST_CONDITION(reference, "RemovedService() valid reference") US_TEST_CONDITION(service, "RemovedService() valid service") } private: us::ModuleContext* m_context; }; void TestFilterString() { us::ModuleContext* context = us::GetModuleContext(); MyCustomizer customizer(context); us::LDAPFilter filter("(" + us::ServiceConstants::SERVICE_ID() + ">=0)"); us::ServiceTracker tracker(context, filter, &customizer); tracker.Open(); struct MyServiceOne : public MyInterfaceOne {}; struct MyServiceTwo : public MyInterfaceTwo {}; MyServiceOne serviceOne; MyServiceTwo serviceTwo; - context->RegisterService(&serviceOne); - context->RegisterService(&serviceTwo); + ServiceRegistration reg1 = context->RegisterService(&serviceOne); + ServiceRegistration reg2 = context->RegisterService(&serviceTwo); US_TEST_CONDITION(tracker.GetServiceReferences().size() == 1, "tracking count") + + reg1.Unregister(); + reg2.Unregister(); } void TestServiceTracker() { #ifdef US_PLATFORM_WINDOWS const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif ModuleContext* mc = GetModuleContext(); SharedLibrary libS(LIB_PATH, "TestModuleS"); #ifdef US_BUILD_SHARED_LIBS // Start the test target to get a service published. try { libS.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() ); } #endif // 1. Create a ServiceTracker with ServiceTrackerCustomizer == null std::string s1("org.cppmicroservices.TestModuleSService"); ServiceReferenceU servref = mc->GetServiceReference(s1 + "0"); US_TEST_CONDITION_REQUIRED(servref != 0, "Test if registered service of id org.cppmicroservices.TestModuleSService0"); ServiceReference servCtrlRef = mc->GetServiceReference(); US_TEST_CONDITION_REQUIRED(servCtrlRef != 0, "Test if constrol service was registered"); ServiceControlInterface* serviceController = mc->GetService(servCtrlRef); US_TEST_CONDITION_REQUIRED(serviceController != 0, "Test valid service controller"); std::auto_ptr > st1(new ServiceTracker(mc, servref)); // 2. Check the size method with an unopened service tracker US_TEST_CONDITION_REQUIRED(st1->Size() == 0, "Test if size == 0"); // 3. Open the service tracker and see what it finds, // expect to find one instance of the implementation, // "org.cppmicroservices.TestModuleSService0" st1->Open(); std::vector sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 1, "Checking ServiceTracker size"); US_TEST_CONDITION_REQUIRED(s1 + "0" == sa2[0].GetInterfaceId(), "Checking service implementation name"); // 5. Close this service tracker st1->Close(); // 6. Check the size method, now when the servicetracker is closed US_TEST_CONDITION_REQUIRED(st1->Size() == 0, "Checking ServiceTracker size"); // 7. Check if we still track anything , we should get null sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.empty(), "Checking ServiceTracker size"); // 8. A new Servicetracker, this time with a filter for the object std::string fs = std::string("(") + ServiceConstants::OBJECTCLASS() + "=" + s1 + "*" + ")"; LDAPFilter f1(fs); st1.reset(new ServiceTracker(mc, f1)); // add a service serviceController->ServiceControl(1, "register", 7); // 9. Open the service tracker and see what it finds, // expect to find two instances of references to // "org.cppmicroservices.TestModuleSService*" // i.e. they refer to the same piece of code std::vector ids; ids.push_back((s1 + "0")); ids.push_back((s1 + "1")); ids.push_back((s1 + "2")); ids.push_back((s1 + "3")); st1->Open(); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 2, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.begin()+2), "Check for expected interface id [0]"); US_TEST_CONDITION_REQUIRED(sa2[1].IsConvertibleTo(s1 + "1"), "Check for expected interface id [1]"); // 10. Get libTestModuleS to register one more service and see if it appears serviceController->ServiceControl(2, "register", 1); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 3, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.begin()+3), "Check for expected interface id [2]"); // 11. Get libTestModuleS to register one more service and see if it appears serviceController->ServiceControl(3, "register", 2); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 4, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.end()), "Check for expected interface id [3]"); // 12. Get libTestModuleS to unregister one service and see if it disappears serviceController->ServiceControl(3, "unregister", 0); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 3, "Checking service reference count"); // 13. Get the highest ranking service reference, it should have ranking 7 ServiceReferenceU h1 = st1->GetServiceReference(); int rank = any_cast(h1.GetProperty(ServiceConstants::SERVICE_RANKING())); US_TEST_CONDITION_REQUIRED(rank == 7, "Check service rank"); // 14. Get the service of the highest ranked service reference InterfaceMap o1 = st1->GetService(h1); US_TEST_CONDITION_REQUIRED(!o1.empty(), "Check for non-null service"); // 14a Get the highest ranked service, directly this time InterfaceMap o3 = st1->GetService(); US_TEST_CONDITION_REQUIRED(!o3.empty(), "Check for non-null service"); US_TEST_CONDITION_REQUIRED(o1 == o3, "Check for equal service instances"); // 15. Now release the tracking of that service and then try to get it // from the servicetracker, which should yield a null object serviceController->ServiceControl(1, "unregister", 7); InterfaceMap o2 = st1->GetService(h1); US_TEST_CONDITION_REQUIRED(o2.empty(), "Checkt that service is null"); // 16. Get all service objects this tracker tracks, it should be 2 std::vector ts1 = st1->GetServices(); US_TEST_CONDITION_REQUIRED(ts1.size() == 2, "Check service count"); // 17. Test the remove method. // First register another service, then remove it being tracked serviceController->ServiceControl(1, "register", 7); h1 = st1->GetServiceReference(); std::vector sa3 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa3.size() == 3, "Check service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa3, ids.begin(), ids.begin()+3), "Check for expected interface id [0]"); st1->Remove(h1); // remove tracking on one servref sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 2, "Check service reference count"); // 18. Test the addingService method,add a service reference // 19. Test the removedService method, remove a service reference // 20. Test the waitForService method InterfaceMap o9 = st1->WaitForService(50); US_TEST_CONDITION_REQUIRED(!o9.empty(), "Checking WaitForService method"); } int usServiceTrackerTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceTrackerTest") TestFilterString(); TestServiceTracker(); US_TEST_END() }