diff --git a/.travis.yml b/.travis.yml index 75bc8fbe53..cc278ca589 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,27 @@ language: cpp compiler: - gcc - clang env: + - BUILD_CONFIGURATION=0 - BUILD_CONFIGURATION=1 + - BUILD_CONFIGURATION=2 - BUILD_CONFIGURATION=3 + - BUILD_CONFIGURATION=4 - BUILD_CONFIGURATION=5 + - BUILD_CONFIGURATION=6 - BUILD_CONFIGURATION=7 + - BUILD_CONFIGURATION=8 - BUILD_CONFIGURATION=9 + - BUILD_CONFIGURATION=10 - BUILD_CONFIGURATION=11 + - BUILD_CONFIGURATION=12 - BUILD_CONFIGURATION=13 + - BUILD_CONFIGURATION=14 - BUILD_CONFIGURATION=15 - - BUILD_CONFIGURATION=17 - - BUILD_CONFIGURATION=19 - - BUILD_CONFIGURATION=21 - - BUILD_CONFIGURATION=23 - - BUILD_CONFIGURATION=25 - - BUILD_CONFIGURATION=27 - - BUILD_CONFIGURATION=29 - - BUILD_CONFIGURATION=31 branches: only: - master script: ctest -S ./CMake/usCTestScript_travis.cmake diff --git a/CMake/usCTestScript.cmake b/CMake/usCTestScript.cmake index 0a7f96535b..071307d494 100644 --- a/CMake/usCTestScript.cmake +++ b/CMake/usCTestScript.cmake @@ -1,134 +1,114 @@ macro(build_and_test) set(CTEST_SOURCE_DIRECTORY ${US_SOURCE_DIR}) set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/${CTEST_PROJECT_NAME}_${CTEST_DASHBOARD_NAME}") #if(NOT CTEST_BUILD_NAME) # set(CTEST_BUILD_NAME "${CMAKE_SYSTEM}_${CTEST_COMPILER}_${CTEST_DASHBOARD_NAME}") #endif() ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY}) ctest_start("Experimental") if(NOT EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt") file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "${CTEST_INITIAL_CACHE}") endif() ctest_configure(RETURN_VALUE res) if (res) message(FATAL_ERROR "CMake configure error") endif() ctest_build(RETURN_VALUE res) if (res) message(FATAL_ERROR "CMake build error") endif() ctest_test(RETURN_VALUE res PARALLEL_LEVEL ${CTEST_PARALLEL_LEVEL}) if (res) message(FATAL_ERROR "CMake test error") endif() if(WITH_MEMCHECK AND CTEST_MEMORYCHECK_COMMAND) ctest_memcheck() endif() if(WITH_COVERAGE AND CTEST_COVERAGE_COMMAND) ctest_coverage() endif() #ctest_submit() endmacro() -function(create_initial_cache var _shared _threading _sf _cxx11 _autoload) +function(create_initial_cache var _shared _threading _cxx11 _autoload) set(_initial_cache " US_BUILD_TESTING:BOOL=ON US_BUILD_SHARED_LIBS:BOOL=${_shared} US_ENABLE_THREADING_SUPPORT:BOOL=${_threading} - US_ENABLE_SERVICE_FACTORY_SUPPORT:BOOL=${_sf} US_USE_C++11:BOOL=${_cxx11} US_ENABLE_AUTOLOADING_SUPPORT:BOOL=${_autoload} ") if(_shared) set(_initial_cache "${_initial_cache} US_BUILD_EXAMPLES:BOOL=ON ") endif() set(${var} ${_initial_cache} PARENT_SCOPE) if(_shared) set(CTEST_DASHBOARD_NAME "shared") else() set(CTEST_DASHBOARD_NAME "static") endif() if(_threading) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-threading") endif() - if(_sf) - set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-servicefactory") - endif() if(_cxx11) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-cxx11") endif() if(_autoload) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-autoloading") endif() set(CTEST_DASHBOARD_NAME ${CTEST_DASHBOARD_NAME} PARENT_SCOPE) endfunction() #========================================================= set(CTEST_PROJECT_NAME CppMicroServices) if(NOT CTEST_PARALLEL_LEVEL) set(CTEST_PARALLEL_LEVEL 1) endif() -# SHARED THREADING SERVICE_FACTORY C++11 AUTOLOAD - -set(config0 0 0 0 0 0 ) -set(config1 0 0 0 0 1 ) -set(config2 0 0 0 1 0 ) -set(config3 0 0 0 1 1 ) -set(config4 0 0 1 0 0 ) -set(config5 0 0 1 0 1 ) -set(config6 0 0 1 1 0 ) -set(config7 0 0 1 1 1 ) -set(config8 0 1 0 0 0 ) -set(config9 0 1 0 0 1 ) -set(config10 0 1 0 1 0 ) -set(config11 0 1 0 1 1 ) -set(config12 0 1 1 0 0 ) -set(config13 0 1 1 0 1 ) -set(config14 0 1 1 1 0 ) -set(config15 0 1 1 1 1 ) -set(config16 1 0 0 0 0 ) -set(config17 1 0 0 0 1 ) -set(config18 1 0 0 1 0 ) -set(config19 1 0 0 1 1 ) -set(config20 1 0 1 0 0 ) -set(config21 1 0 1 0 1 ) -set(config22 1 0 1 1 0 ) -set(config23 1 0 1 1 1 ) -set(config24 1 1 0 0 0 ) -set(config25 1 1 0 0 1 ) -set(config26 1 1 0 1 0 ) -set(config27 1 1 0 1 1 ) -set(config28 1 1 1 0 0 ) -set(config29 1 1 1 0 1 ) -set(config30 1 1 1 1 0 ) -set(config31 1 1 1 1 1 ) +# SHARED THREADING C++11 AUTOLOAD + +set(config0 0 0 0 0 ) +set(config1 0 0 0 1 ) +set(config2 0 0 1 0 ) +set(config3 0 0 1 1 ) +set(config4 0 1 0 0 ) +set(config5 0 1 0 1 ) +set(config6 0 1 1 0 ) +set(config7 0 1 1 1 ) +set(config8 1 0 0 0 ) +set(config9 1 0 0 1 ) +set(config10 1 0 1 0 ) +set(config11 1 0 1 1 ) +set(config12 1 1 0 0 ) +set(config13 1 1 0 1 ) +set(config14 1 1 1 0 ) +set(config15 1 1 1 1 ) foreach(i ${US_BUILD_CONFIGURATION}) create_initial_cache(CTEST_INITIAL_CACHE ${config${i}}) message("Testing build configuration: ${CTEST_DASHBOARD_NAME}") build_and_test() endforeach() diff --git a/CMake/usCTestScript_custom.cmake b/CMake/usCTestScript_custom.cmake index cbdcba4727..755cb82719 100644 --- a/CMake/usCTestScript_custom.cmake +++ b/CMake/usCTestScript_custom.cmake @@ -1,24 +1,24 @@ find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) find_program(CTEST_GIT_COMMAND NAMES git) set(CTEST_SITE "bigeye") set(CTEST_DASHBOARD_ROOT "/tmp") #set(CTEST_COMPILER "gcc-4.5") set(CTEST_CMAKE_GENERATOR "Unix Makefiles") set(CTEST_BUILD_FLAGS "-j") set(CTEST_BUILD_CONFIGURATION Debug) set(CTEST_PARALLEL_LEVEL 4) set(US_TEST_SHARED 1) set(US_TEST_STATIC 1) set(US_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../") set(US_BUILD_CONFIGURATION ) -foreach(i RANGE 31) +foreach(i RANGE 15) list(APPEND US_BUILD_CONFIGURATION ${i}) endforeach() include(${US_SOURCE_DIR}/CMake/usCTestScript.cmake) diff --git a/src/module/usModuleSettings.cpp b/src/module/usModuleSettings.cpp index 6e82cc89a1..5cd8a18e18 100644 --- a/src/module/usModuleSettings.cpp +++ b/src/module/usModuleSettings.cpp @@ -1,171 +1,162 @@ /*============================================================================= 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 "usModuleSettings.h" #include "usThreads_p.h" #include "usStaticInit_p.h" #include #include #include #include #include US_BEGIN_NAMESPACE namespace { std::string RemoveTrailingPathSeparator(const std::string& in) { #ifdef US_PLATFORM_WINDOWS const char separator = '\\'; #else const char separator = '/'; #endif if (in.empty()) return in; std::string::const_iterator lastChar = --in.end(); while (lastChar != in.begin() && std::isspace(*lastChar)) lastChar--; if (*lastChar != separator) lastChar++; std::string::const_iterator firstChar = in.begin(); while (firstChar < lastChar && std::isspace(*firstChar)) firstChar++; return std::string(firstChar, lastChar); } } std::string ModuleSettings::CURRENT_MODULE_PATH() { static const std::string var = "us_current_module_path"; return var; } struct ModuleSettingsPrivate : public US_DEFAULT_THREADING { ModuleSettingsPrivate() : autoLoadPaths() #ifdef US_ENABLE_AUTOLOADING_SUPPORT , autoLoadingEnabled(true) #else , autoLoadingEnabled(false) #endif , autoLoadingDisabled(false) { autoLoadPaths.insert(ModuleSettings::CURRENT_MODULE_PATH()); char* envPaths = getenv("US_AUTOLOAD_PATHS"); if (envPaths != NULL) { std::stringstream ss(envPaths); std::string envPath; #ifdef US_PLATFORM_WINDOWS const char separator = ';'; #else const char separator = ':'; #endif while (std::getline(ss, envPath, separator)) { std::string normalizedEnvPath = RemoveTrailingPathSeparator(envPath); if (!normalizedEnvPath.empty()) { extraPaths.insert(normalizedEnvPath); } } } if (getenv("US_DISABLE_AUTOLOADING")) { autoLoadingDisabled = true; } } std::set autoLoadPaths; std::set extraPaths; bool autoLoadingEnabled; bool autoLoadingDisabled; }; US_GLOBAL_STATIC(ModuleSettingsPrivate, moduleSettingsPrivate) bool ModuleSettings::IsThreadingSupportEnabled() { #ifdef US_ENABLE_THREADING_SUPPORT return true; #else return false; #endif } -bool ModuleSettings::IsServiceFactorySupportEnabled() -{ -#ifdef US_ENABLE_SERVICE_FACTORY_SUPPORT - return true; -#else - return false; -#endif -} - bool ModuleSettings::IsAutoLoadingEnabled() { ModuleSettingsPrivate::Lock l(moduleSettingsPrivate()); #ifdef US_ENABLE_AUTOLOADING_SUPPORT return !moduleSettingsPrivate()->autoLoadingDisabled && moduleSettingsPrivate()->autoLoadingEnabled; #else return false; #endif } void ModuleSettings::SetAutoLoadingEnabled(bool enable) { ModuleSettingsPrivate::Lock l(moduleSettingsPrivate()); moduleSettingsPrivate()->autoLoadingEnabled = enable; } ModuleSettings::PathList ModuleSettings::GetAutoLoadPaths() { ModuleSettingsPrivate::Lock l(moduleSettingsPrivate()); ModuleSettings::PathList paths(moduleSettingsPrivate()->autoLoadPaths.begin(), moduleSettingsPrivate()->autoLoadPaths.end()); paths.insert(paths.end(), moduleSettingsPrivate()->extraPaths.begin(), moduleSettingsPrivate()->extraPaths.end()); std::sort(paths.begin(), paths.end()); paths.erase(std::unique(paths.begin(), paths.end()), paths.end()); return paths; } void ModuleSettings::SetAutoLoadPaths(const PathList& paths) { PathList normalizedPaths; normalizedPaths.resize(paths.size()); std::transform(paths.begin(), paths.end(), normalizedPaths.begin(), RemoveTrailingPathSeparator); ModuleSettingsPrivate::Lock l(moduleSettingsPrivate()); moduleSettingsPrivate()->autoLoadPaths.clear(); moduleSettingsPrivate()->autoLoadPaths.insert(normalizedPaths.begin(), normalizedPaths.end()); } void ModuleSettings::AddAutoLoadPath(const std::string& path) { ModuleSettingsPrivate::Lock l(moduleSettingsPrivate()); moduleSettingsPrivate()->autoLoadPaths.insert(RemoveTrailingPathSeparator(path)); } US_END_NAMESPACE diff --git a/src/module/usModuleSettings.h b/src/module/usModuleSettings.h index 0a687e2793..1efc9545b5 100644 --- a/src/module/usModuleSettings.h +++ b/src/module/usModuleSettings.h @@ -1,137 +1,131 @@ /*============================================================================= 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 USMODULESETTINGS_H #define USMODULESETTINGS_H #include "usConfig.h" #include #include US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * Query and set certain properties of the CppMicroServices library. * * The following environment variables influence the runtime behavior * of the CppMicroServices library: * * - \e US_DISABLE_AUTOLOADING If set, auto-loading of modules is disabled. * - \e US_AUTOLOAD_PATHS A ':' (Unix) or ';' (Windows) separated list of paths * from which modules should be auto-loaded. * * \remarks This class is thread safe. */ class US_EXPORT ModuleSettings { public: typedef std::vector PathList; /** * Returns a special string which can be used as an argument for a * AddAutoLoadPath() call. * * When a module is loaded and this string has been added as a path * to the list of auto-load paths the CppMicroServices library will * auto-load all modules from the currently being loaded module's * auto-load directory. * * \return A string to be used in AddAutoLoadPath(). * * \remarks The returned string is contained in the default set of * auto-load paths, unless a new set of paths is given by a call to * SetAutoLoadPaths(). * * \sa MicroServices_AutoLoading * \sa US_INITIALIZE_MODULE */ static std::string CURRENT_MODULE_PATH(); /** * \return \c true if threading support has been configured into the * CppMicroServices library, \c false otherwise. */ static bool IsThreadingSupportEnabled(); - /** - * \return \c true if support for service factories has been configured into the - * CppMicroServices library, \c false otherwise. - */ - static bool IsServiceFactorySupportEnabled(); - /** * \return \c true if support for module auto-loading is enabled, * \c false otherwise. * * \remarks This method will always return \c false if support for auto-loading * has not been configured into the CppMicroServices library or if it has been * disabled by defining the US_DISABLE_AUTOLOADING environment variable. */ static bool IsAutoLoadingEnabled(); /** * Enable or disable auto-loading support. * * \param enable If \c true, enable auto-loading support, disable it otherwise. * * \remarks Calling this method will have no effect if support for * auto-loading has not been configured into the CppMicroServices library of it * it has been disabled by defining the US_DISABLE_AUTOLOADING envrionment variable. */ static void SetAutoLoadingEnabled(bool enable); /** * \return A list of paths in the file-system from which modules will be * auto-loaded. */ static PathList GetAutoLoadPaths(); /** * Set a list of paths in the file-system from which modules should be * auto-loaded. * @param paths A list of absolute file-system paths. */ static void SetAutoLoadPaths(const PathList& paths); /** * Add a path in the file-system to the list of paths from which modules * will be auto-loaded. * * @param path The additional absolute auto-load path in the file-system. */ static void AddAutoLoadPath(const std::string& path); private: // purposely not implemented ModuleSettings(); ModuleSettings(const ModuleSettings&); ModuleSettings& operator=(const ModuleSettings&); }; US_END_NAMESPACE #endif // USMODULESETTINGS_H diff --git a/src/service/usServiceObjects.cpp b/src/service/usServiceObjects.cpp index 1595ec283d..a674477a36 100644 --- a/src/service/usServiceObjects.cpp +++ b/src/service/usServiceObjects.cpp @@ -1,209 +1,210 @@ /*============================================================================= 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 "usServiceObjects.h" #include "usServiceReferenceBasePrivate.h" #include US_BEGIN_NAMESPACE class ServiceObjectsBasePrivate { public: AtomicInt ref; ModuleContext* m_context; ServiceReferenceBase m_reference; // This is used by all ServiceObjects instances with S != void std::map m_serviceInstances; // This is used by ServiceObjects std::set m_serviceInterfaceMaps; ServiceObjectsBasePrivate(ModuleContext* context, const ServiceReferenceBase& reference) : m_context(context) , m_reference(reference) {} InterfaceMap GetServiceInterfaceMap() { InterfaceMap result; bool isPrototypeScope = m_reference.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(); if (isPrototypeScope) { result = m_reference.d->GetPrototypeService(m_context->GetModule()); } else { result = m_reference.d->GetServiceInterfaceMap(m_context->GetModule()); } return result; } }; ServiceObjectsBase::ServiceObjectsBase(ModuleContext* context, const ServiceReferenceBase& reference) : d(new ServiceObjectsBasePrivate(context, reference)) { if (!reference) { delete d; throw std::invalid_argument("The service reference is invalid"); } + d->ref.Ref(); } void* ServiceObjectsBase::GetService() const { if (!d->m_reference) { return NULL; } InterfaceMap im = d->GetServiceInterfaceMap(); void* result = im.find(d->m_reference.GetInterfaceId())->second; if (result) { d->m_serviceInstances.insert(std::make_pair(result, im)); } return result; } InterfaceMap ServiceObjectsBase::GetServiceInterfaceMap() const { InterfaceMap result; if (!d->m_reference) { return result; } result = d->GetServiceInterfaceMap(); if (!result.empty()) { d->m_serviceInterfaceMaps.insert(result); } return result; } void ServiceObjectsBase::UngetService(void* service) { if (service == NULL) { return; } std::map::iterator serviceIter = d->m_serviceInstances.find(service); if (serviceIter == d->m_serviceInstances.end()) { throw std::invalid_argument("The provided service has not been retrieved via this ServiceObjects instance"); } if (!d->m_reference.d->UngetPrototypeService(d->m_context->GetModule(), serviceIter->second)) { US_WARN << "Ungetting service unsuccessful"; } else { d->m_serviceInstances.erase(serviceIter); } } void ServiceObjectsBase::UngetService(const InterfaceMap& interfaceMap) { if (interfaceMap.empty()) { return; } std::set::iterator serviceIter = d->m_serviceInterfaceMaps.find(interfaceMap); if (serviceIter == d->m_serviceInterfaceMaps.end()) { throw std::invalid_argument("The provided service has not been retrieved via this ServiceObjects instance"); } if (!d->m_reference.d->UngetPrototypeService(d->m_context->GetModule(), interfaceMap)) { US_WARN << "Ungetting service unsuccessful"; } else { d->m_serviceInterfaceMaps.erase(serviceIter); } } ServiceReferenceBase ServiceObjectsBase::GetReference() const { return d->m_reference; } ServiceObjectsBase::ServiceObjectsBase(const ServiceObjectsBase& other) : d(other.d) { d->ref.Ref(); } ServiceObjectsBase::~ServiceObjectsBase() { if (!d->ref.Deref()) { delete d; } } ServiceObjectsBase& ServiceObjectsBase::operator =(const ServiceObjectsBase& other) { ServiceObjectsBasePrivate* curr_d = d; d = other.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } InterfaceMap ServiceObjects::GetService() const { return this->ServiceObjectsBase::GetServiceInterfaceMap(); } void ServiceObjects::UngetService(const InterfaceMap& service) { this->ServiceObjectsBase::UngetService(service); } ServiceReferenceU ServiceObjects::GetServiceReference() const { return this->ServiceObjectsBase::GetReference(); } ServiceObjects::ServiceObjects(ModuleContext* context, const ServiceReferenceU& reference) : ServiceObjectsBase(context, reference) {} US_END_NAMESPACE diff --git a/src/service/usServiceReferenceBasePrivate.cpp b/src/service/usServiceReferenceBasePrivate.cpp index adce2e1f36..164c966723 100644 --- a/src/service/usServiceReferenceBasePrivate.cpp +++ b/src/service/usServiceReferenceBasePrivate.cpp @@ -1,320 +1,320 @@ /*============================================================================= 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 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; + 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(); } US_END_NAMESPACE diff --git a/test/usServiceFactoryTest.cpp b/test/usServiceFactoryTest.cpp index 14c7a8feaa..fa75a65922 100644 --- a/test/usServiceFactoryTest.cpp +++ b/test/usServiceFactoryTest.cpp @@ -1,234 +1,236 @@ /*============================================================================= 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 #include #include #include #include #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif } // end unnamed namespace US_BEGIN_NAMESPACE struct TestModuleH { virtual ~TestModuleH() {} }; struct TestModuleH2 { virtual ~TestModuleH2() {} }; US_END_NAMESPACE US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH), "org.cppmicroservices.TestModuleH") US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH2), "org.cppmicroservices.TestModuleH2") void TestServiceFactoryModuleScope() { // Install and start test module H, a service factory and test that the methods // in that interface works. SharedLibrary target(LIB_PATH, "TestModuleH"); #ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what()) } Module* moduleH = ModuleRegistry::GetModule("TestModuleH Module"); US_TEST_CONDITION_REQUIRED(moduleH != 0, "Test for existing module TestModuleH") std::vector registeredRefs = moduleH->GetRegisteredServices(); US_TEST_CONDITION_REQUIRED(registeredRefs.size() == 2, "# of registered services") US_TEST_CONDITION(registeredRefs[0].GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_MODULE(), "service scope") US_TEST_CONDITION(registeredRefs[1].GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") #endif ModuleContext* mc = GetModuleContext(); // Check that a service reference exist const ServiceReferenceU sr1 = mc->GetServiceReference("org.cppmicroservices.TestModuleH"); US_TEST_CONDITION_REQUIRED(sr1, "Service shall be present.") US_TEST_CONDITION(sr1.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_MODULE(), "service scope") InterfaceMap service = mc->GetService(sr1); US_TEST_CONDITION_REQUIRED(service.size() >= 1, "GetService()") InterfaceMap::const_iterator serviceIter = service.find("org.cppmicroservices.TestModuleH"); US_TEST_CONDITION_REQUIRED(serviceIter != service.end(), "GetService()") US_TEST_CONDITION_REQUIRED(serviceIter->second != NULL, "GetService()") InterfaceMap service2 = mc->GetService(sr1); US_TEST_CONDITION(service == service2, "Same service pointer") #ifdef US_BUILD_SHARED_LIBS std::vector usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") US_TEST_CONDITION(usedRefs[0] == sr1, "service ref in use") InterfaceMap service3 = moduleH->GetModuleContext()->GetService(sr1); US_TEST_CONDITION(service != service3, "Different service pointer") US_TEST_CONDITION(moduleH->GetModuleContext()->UngetService(sr1), "UngetService()") #endif - US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1), "ungetService()") + US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == false, "ungetService()") + US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == true, "ungetService()") target.Unload(); } void TestServiceFactoryPrototypeScope() { // Install and start test module H, a service factory and test that the methods // in that interface works. SharedLibrary target(LIB_PATH, "TestModuleH"); #ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what()) } Module* moduleH = ModuleRegistry::GetModule("TestModuleH Module"); US_TEST_CONDITION_REQUIRED(moduleH != 0, "Test for existing module TestModuleH") #endif ModuleContext* mc = GetModuleContext(); // Check that a service reference exist const ServiceReference sr1 = mc->GetServiceReference(); US_TEST_CONDITION_REQUIRED(sr1, "Service shall be present.") US_TEST_CONDITION(sr1.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") ServiceObjects svcObjects = mc->GetServiceObjects(sr1); TestModuleH2* prototypeServiceH2 = svcObjects.GetService(); const ServiceReferenceU sr1void = mc->GetServiceReference(us_service_interface_iid()); ServiceObjects svcObjectsVoid = mc->GetServiceObjects(sr1void); InterfaceMap prototypeServiceH2Void = svcObjectsVoid.GetService(); US_TEST_CONDITION_REQUIRED(prototypeServiceH2Void.find(us_service_interface_iid()) != prototypeServiceH2Void.end(), "ServiceObjects::GetService()") #ifdef US_BUILD_SHARED_LIBS // There should be only one service in use US_TEST_CONDITION_REQUIRED(mc->GetModule()->GetServicesInUse().size() == 1, "services in use") #endif TestModuleH2* moduleScopeService = mc->GetService(sr1); US_TEST_CONDITION_REQUIRED(moduleScopeService && moduleScopeService != prototypeServiceH2, "GetService()") US_TEST_CONDITION_REQUIRED(prototypeServiceH2 != prototypeServiceH2Void.find(us_service_interface_iid())->second, "GetService()") svcObjectsVoid.UngetService(prototypeServiceH2Void); TestModuleH2* moduleScopeService2 = mc->GetService(sr1); US_TEST_CONDITION(moduleScopeService == moduleScopeService2, "Same service pointer") #ifdef US_BUILD_SHARED_LIBS std::vector usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") US_TEST_CONDITION(usedRefs[0] == sr1, "service ref in use") #endif std::string filter = "(" + ServiceConstants::SERVICE_ID() + "=" + sr1.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + ")"; const ServiceReference sr2 = mc->GetServiceReferences(filter).front(); US_TEST_CONDITION_REQUIRED(sr2, "Service shall be present.") US_TEST_CONDITION(sr2.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") US_TEST_CONDITION(any_cast(sr2.GetProperty(ServiceConstants::SERVICE_ID())) == any_cast(sr1.GetProperty(ServiceConstants::SERVICE_ID())), "same service id") try { svcObjects.UngetService(moduleScopeService2); US_TEST_FAILED_MSG(<< "std::invalid_argument exception expected") } catch (const std::invalid_argument&) { // this is expected } #ifdef US_BUILD_SHARED_LIBS // There should still be only one service in use usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") #endif ServiceObjects svcObjects2 = svcObjects; ServiceObjects svcObjects3 = mc->GetServiceObjects(sr1); try { svcObjects3.UngetService(prototypeServiceH2); US_TEST_FAILED_MSG(<< "std::invalid_argument exception expected") } catch (const std::invalid_argument&) { // this is expected } svcObjects2.UngetService(prototypeServiceH2); prototypeServiceH2 = svcObjects2.GetService(); TestModuleH2* prototypeServiceH2_2 = svcObjects3.GetService(); US_TEST_CONDITION_REQUIRED(prototypeServiceH2_2 && prototypeServiceH2_2 != prototypeServiceH2, "prototype service") svcObjects2.UngetService(prototypeServiceH2); svcObjects3.UngetService(prototypeServiceH2_2); - US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1), "ungetService()") + US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == false, "ungetService()") + US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == true, "ungetService()") target.Unload(); } int usServiceFactoryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceFactoryTest"); TestServiceFactoryModuleScope(); TestServiceFactoryPrototypeScope(); US_TEST_END() } diff --git a/usConfig.h.in b/usConfig.h.in index c855c1047d..17e0eb7b12 100644 --- a/usConfig.h.in +++ b/usConfig.h.in @@ -1,237 +1,236 @@ /* USCONFIG.h this file is generated. Do not change! */ #ifndef USCONFIG_H #define USCONFIG_H #cmakedefine US_BUILD_SHARED_LIBS #cmakedefine CppMicroServices_EXPORTS #cmakedefine US_ENABLE_AUTOLOADING_SUPPORT #cmakedefine US_ENABLE_THREADING_SUPPORT -#cmakedefine US_ENABLE_SERVICE_FACTORY_SUPPORT #cmakedefine US_ENABLE_RESOURCE_COMPRESSION #cmakedefine US_USE_CXX11 #cmakedefine US_GCC_RTTI_WORKAROUND_NEEDED ///------------------------------------------------------------------- // Version information //------------------------------------------------------------------- #define CppMicroServices_VERSION_MAJOR @CppMicroServices_VERSION_MAJOR@ #define CppMicroServices_VERSION_MINOR @CppMicroServices_VERSION_MINOR@ #define CppMicroServices_VERSION_PATH @CppMicroServices_VERSION_PATCH@ #define CppMicroServices_VERSION @CppMicroServices_VERSION@ #define CppMicroServices_VERSION_STR "@CppMicroServices_VERSION@" ///------------------------------------------------------------------- // Macros used by the unit tests //------------------------------------------------------------------- #define CppMicroServices_SOURCE_DIR "@CppMicroServices_SOURCE_DIR@" ///------------------------------------------------------------------- // Macros for import/export declarations //------------------------------------------------------------------- #if defined(WIN32) #define US_ABI_EXPORT __declspec(dllexport) #define US_ABI_IMPORT __declspec(dllimport) #define US_ABI_LOCAL #else #define US_ABI_EXPORT __attribute__ ((visibility ("default"))) #define US_ABI_IMPORT __attribute__ ((visibility ("default"))) #define US_ABI_LOCAL __attribute__ ((visibility ("hidden"))) #endif #ifdef US_BUILD_SHARED_LIBS // We are building a shared lib #ifdef CppMicroServices_EXPORTS #define US_EXPORT US_ABI_EXPORT #else #define US_EXPORT US_ABI_IMPORT #endif #else // We are building a static lib // Don't hide RTTI symbols of definitions in the C++ Micro Services // headers that are included in DSOs with hidden visibility #define US_EXPORT US_ABI_EXPORT #endif //------------------------------------------------------------------- // Namespace customization //------------------------------------------------------------------- #define US_NAMESPACE @US_NAMESPACE@ #ifndef US_NAMESPACE /* user namespace */ # define US_PREPEND_NAMESPACE(name) ::name # define US_USE_NAMESPACE # define US_BEGIN_NAMESPACE # define US_END_NAMESPACE # define US_FORWARD_DECLARE_CLASS(name) class name; # define US_FORWARD_DECLARE_STRUCT(name) struct name; #else /* user namespace */ # define US_PREPEND_NAMESPACE(name) ::US_NAMESPACE::name # define US_USE_NAMESPACE using namespace ::US_NAMESPACE; # define US_BEGIN_NAMESPACE namespace US_NAMESPACE { # define US_END_NAMESPACE } # define US_FORWARD_DECLARE_CLASS(name) \ US_BEGIN_NAMESPACE class name; US_END_NAMESPACE # define US_FORWARD_DECLARE_STRUCT(name) \ US_BEGIN_NAMESPACE struct name; US_END_NAMESPACE namespace US_NAMESPACE {} #endif /* user namespace */ //------------------------------------------------------------------- // Platform defines //------------------------------------------------------------------- #if defined(__APPLE__) #define US_PLATFORM_APPLE #endif #if defined(__linux__) #define US_PLATFORM_LINUX #endif #if defined(_WIN32) || defined(_WIN64) #define US_PLATFORM_WINDOWS #else #define US_PLATFORM_POSIX #endif //------------------------------------------------------------------- // Macros for suppressing warnings //------------------------------------------------------------------- #ifdef _MSC_VER #define US_MSVC_PUSH_DISABLE_WARNING(wn) \ __pragma(warning(push)) \ __pragma(warning(disable:wn)) #define US_MSVC_POP_WARNING \ __pragma(warning(pop)) #define US_MSVC_DISABLE_WARNING(wn) \ __pragma(warning(disable:wn)) #else #define US_MSVC_PUSH_DISABLE_WARNING(wn) #define US_MSVC_POP_WARNING #define US_MSVC_DISABLE_WARNING(wn) #endif // Do not warn about the usage of deprecated unsafe functions US_MSVC_DISABLE_WARNING(4996) //------------------------------------------------------------------- // Debuging & Logging //------------------------------------------------------------------- #cmakedefine US_ENABLE_DEBUG_OUTPUT US_BEGIN_NAMESPACE enum MsgType { DebugMsg = 0, InfoMsg = 1, WarningMsg = 2, ErrorMsg = 3 }; typedef void (*MsgHandler)(MsgType, const char *); US_EXPORT MsgHandler installMsgHandler(MsgHandler); US_END_NAMESPACE //------------------------------------------------------------------- // Hash Container //------------------------------------------------------------------- #ifdef US_USE_CXX11 #include #include #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ struct hash : std::unary_function { \ std::size_t operator()(const type& arg) const { #define US_HASH_FUNCTION_END } }; #define US_HASH_FUNCTION(type, arg) hash()(arg) #if defined(US_PLATFORM_WINDOWS) && (_MSC_VER < 1700) #define US_HASH_FUNCTION_FRIEND(type) friend class ::std::hash #else #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::hash #endif #define US_UNORDERED_MAP_TYPE ::std::unordered_map #define US_UNORDERED_SET_TYPE ::std::unordered_set #define US_HASH_FUNCTION_NAMESPACE ::std #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { #define US_HASH_FUNCTION_NAMESPACE_END } #elif defined(__GNUC__) #include #include #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ struct hash : std::unary_function { \ std::size_t operator()(const type& arg) const { #define US_HASH_FUNCTION_END } }; #define US_HASH_FUNCTION(type, arg) hash()(arg) #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::tr1::hash #define US_UNORDERED_MAP_TYPE ::std::tr1::unordered_map #define US_UNORDERED_SET_TYPE ::std::tr1::unordered_set #define US_HASH_FUNCTION_NAMESPACE ::std::tr1 #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { namespace tr1 { #define US_HASH_FUNCTION_NAMESPACE_END }} #elif _MSC_VER <= 1500 // Visual Studio 2008 and lower #include #include #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ inline std::size_t hash_value(const type& arg) { #define US_HASH_FUNCTION_END } #define US_HASH_FUNCTION(type, arg) hash_value(arg) #define US_HASH_FUNCTION_FRIEND(type) friend std::size_t stdext::hash_value(const type&) #define US_UNORDERED_MAP_TYPE ::stdext::hash_map #define US_UNORDERED_SET_TYPE ::stdext::hash_set #define US_HASH_FUNCTION_NAMESPACE ::stdext #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace stdext { #define US_HASH_FUNCTION_NAMESPACE_END } #endif //------------------------------------------------------------------- // Threading Configuration //------------------------------------------------------------------- #ifdef US_ENABLE_THREADING_SUPPORT #define US_DEFAULT_THREADING US_PREPEND_NAMESPACE(MultiThreaded) #else #define US_DEFAULT_THREADING US_PREPEND_NAMESPACE(SingleThreaded) #endif //------------------------------------------------------------------- // Header Availability //------------------------------------------------------------------- #cmakedefine HAVE_STDINT #endif // USCONFIG_H