diff --git a/Core/CppMicroServices/.travis.yml b/Core/CppMicroServices/.travis.yml index cc278ca589..a1b3311ec7 100644 --- a/Core/CppMicroServices/.travis.yml +++ b/Core/CppMicroServices/.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 branches: only: - master -script: ctest -S ./CMake/usCTestScript_travis.cmake +script: ctest -VV -S ./CMake/usCTestScript_travis.cmake diff --git a/Core/CppMicroServices/CMakeLists.txt b/Core/CppMicroServices/CMakeLists.txt index 2b7c22c5f1..2e43cb7b22 100644 --- a/Core/CppMicroServices/CMakeLists.txt +++ b/Core/CppMicroServices/CMakeLists.txt @@ -1,383 +1,382 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 1) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) cmake_minimum_required(VERSION 2.8) cmake_policy(VERSION 2.8) cmake_policy(SET CMP0017 NEW) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CMakeParseArguments) include(CMakePackageConfigHelpers) include(CheckCXXSourceCompiles) include(usFunctionCheckCompilerFlags) include(usFunctionEmbedResources) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) include(usFunctionGenerateExecutableInit) #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) set(CppMicroServices_EXPORTS 1) endif() endif() # Determine the name of the install component for "SDK" artifacts. # The default is "sdk" if(NOT DEFINED US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT sdk) elseif(US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT ${US_SDK_INSTALL_COMPONENT}) endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_ENABLE_DEBUG_OUTPUT OFF BOOL "Enable debug messages" ADVANCED) us_cache_var(US_ENABLE_RESOURCE_COMPRESSION ON BOOL "Enable resource compression" ADVANCED) us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") if(WIN32 AND NOT CYGWIN) set(default_runtime_install_dir bin/) set(default_library_install_dir bin/) set(default_archive_install_dir lib/) set(default_header_install_dir include/) set(default_auxiliary_install_dir share/) else() set(default_runtime_install_dir bin/) set(default_library_install_dir lib/${PROJECT_NAME}) set(default_archive_install_dir lib/${PROJECT_NAME}) set(default_header_install_dir include/${PROJECT_NAME}) set(default_auxiliary_install_dir share/${PROJECT_NAME}) endif() us_cache_var(RUNTIME_INSTALL_DIR ${default_runtime_install_dir} STRING "Relative install location for binaries" ADVANCED) us_cache_var(LIBRARY_INSTALL_DIR ${default_library_install_dir} STRING "Relative install location for libraries" ADVANCED) us_cache_var(ARCHIVE_INSTALL_DIR ${default_archive_install_dir} STRING "Relative install location for archives" ADVANCED) us_cache_var(HEADER_INSTALL_DIR ${default_header_install_dir} STRING "Relative install location for headers" ADVANCED) us_cache_var(AUXILIARY_INSTALL_DIR ${default_auxiliary_install_dir} STRING "Relative install location for auxiliary files" ADVANCED) if(MSVC10 OR MSVC11 OR MSVC12) # Visual Studio 2010 and newer have support for C++11 enabled by default set(US_USE_C++11 1) else() us_cache_var(US_USE_C++11 OFF BOOL "Enable the use of C++11 features" ADVANCED) endif() us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ micro services entities") us_cache_var(US_HEADER_PREFIX "" STRING "The file name prefix for the public C++ micro services header files") set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) set(${PROJECT_NAME}_MODULE_INIT_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/CMake/usModuleInit.cpp") set(${PROJECT_NAME}_EXECUTABLE_INIT_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/CMake/usExecutableInit.cpp") #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- set(US_C_FLAGS) set(US_C_FLAGS_RELEASE) set(US_CXX_FLAGS) set(US_CXX_FLAGS_RELEASE) # This is used as a preprocessor define set(US_USE_CXX11 ${US_USE_C++11}) # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() if(US_USE_C++11) usFunctionCheckCompilerFlags("-std=c++0x" US_CXX_FLAGS) endif() endif() if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) if(${GCC_VERSION} VERSION_LESS "4.0.0") message(FATAL_ERROR "gcc version ${GCC_VERSION} not supported. Please use gcc >= 4.") endif() # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols set(US_CXX_FLAGS "-Wl,--enable-auto-import ${US_CXX_FLAGS}") # we need to define a Windows version set(US_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${US_CXX_FLAGS}") else() # Enable visibility support if(NOT ${GCC_VERSION} VERSION_LESS "4.5") usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" US_CXX_FLAGS) else() set(US_GCC_RTTI_WORKAROUND_NEEDED 1) endif() endif() usFunctionCheckCompilerFlags("-O1 -D_FORTIFY_SOURCE=2" _fortify_source_flag) if(_fortify_source_flag) set(US_CXX_FLAGS_RELEASE "${US_CXX_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2") endif() - elseif(MSVC) - set(US_CXX_FLAGS "/MP /wd4996 ${US_CXX_FLAGS}") + set(US_CXX_FLAGS "/MP /wd4996 /wd4251 /wd4503 ${US_CXX_FLAGS}") endif() if(NOT US_IS_EMBEDDED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${US_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") set(CMAKE_C_FLAGS_REALEASE "${CMAKE_C_FLAGS_RELEASE} ${US_C_FLAGS_RELEASE}") endif() #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() #----------------------------------------------------------------------------- # US Header Checks #----------------------------------------------------------------------------- include(CheckIncludeFile) CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT) #----------------------------------------------------------------------------- # US include dirs and libraries #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ) set(US_INTERNAL_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src/util ${CMAKE_CURRENT_SOURCE_DIR}/src/service ${CMAKE_CURRENT_SOURCE_DIR}/src/module ) # link library for third party libs if(US_IS_EMBEDDED) set(US_LIBRARY_TARGET ${US_EMBEDDING_LIBRARY}) else() set(US_LIBRARY_TARGET ${PROJECT_NAME}) endif() # link libraries for the CppMicroServices lib set(US_LINK_LIBRARIES ) if(UNIX) list(APPEND US_LINK_LIBRARIES dl) endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(us_config_h_file "${PROJECT_BINARY_DIR}/include/usConfig.h") configure_file(usConfig.h.in ${us_config_h_file}) set(US_RCC_EXECUTABLE_NAME usResourceCompiler) set(CppMicroServices_RCC_EXECUTABLE_NAME ${US_RCC_EXECUTABLE_NAME}) add_subdirectory(tools) add_subdirectory(src) #----------------------------------------------------------------------------- # US testing #----------------------------------------------------------------------------- if(US_BUILD_TESTING) enable_testing() add_subdirectory(test) endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(documentation) #----------------------------------------------------------------------------- # Last configuration and install steps #----------------------------------------------------------------------------- if(NOT US_IS_EMBEDDED) export(TARGETS ${PROJECT_NAME} ${US_RCC_EXECUTABLE_NAME} FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake) install(EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${AUXILIARY_INSTALL_DIR}/CMake/) endif() set(_install_cmake_scripts ${${PROJECT_NAME}_MODULE_INIT_TEMPLATE} ${${PROJECT_NAME}_EXECUTABLE_INIT_TEMPLATE} ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CMakeParseArguments.cmake ${CMAKE_CURRENT_SOURCE_DIR}/CMake/usFunctionGenerateModuleInit.cmake ${CMAKE_CURRENT_SOURCE_DIR}/CMake/usFunctionGenerateExecutableInit.cmake ${CMAKE_CURRENT_SOURCE_DIR}/CMake/usFunctionEmbedResources.cmake ) install(FILES ${_install_cmake_scripts} DESTINATION ${AUXILIARY_INSTALL_DIR}/CMake/ ) # Configure CppMicroServicesConfig.cmake for the build tree set(PACKAGE_CONFIG_INCLUDE_DIR ${US_INCLUDE_DIRS}) set(PACKAGE_CONFIG_RUNTIME_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(PACKAGE_CONFIG_CMAKE_DIR ${PROJECT_SOURCE_DIR}/CMake) if(US_IS_EMBEDDED) set(PACKAGE_EMBEDDED "if(@PROJECT_NAME@_IS_EMBEDDED) set(@PROJECT_NAME@_INTERNAL_INCLUDE_DIRS @US_INTERNAL_INCLUDE_DIRS@) set(@PROJECT_NAME@_SOURCES @US_SOURCES@) set(@PROJECT_NAME@_PUBLIC_HEADERS @US_PUBLIC_HEADERS@) set(@PROJECT_NAME@_PRIVATE_HEADERS @US_PRIVATE_HEADERS@) endif()") else() set(PACKAGE_EMBEDDED ) endif() configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) # Configure CppMicroServicesConfig.cmake for the install tree set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) set(CONFIG_RUNTIME_DIR ${RUNTIME_INSTALL_DIR}) set(CONFIG_CMAKE_DIR ${AUXILIARY_INSTALL_DIR}/CMake) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${AUXILIARY_INSTALL_DIR}/CMake/ PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_DIR CONFIG_CMAKE_DIR NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) # Version information configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${AUXILIARY_INSTALL_DIR}/CMake/ ${US_SDK_INSTALL_COMPONENT} ) #----------------------------------------------------------------------------- # Build the examples #----------------------------------------------------------------------------- option(US_BUILD_EXAMPLES "Build example projects" OFF) if(US_BUILD_EXAMPLES) if(NOT US_BUILD_SHARED_LIBS) message(WARNING "Examples are not available if US_BUILD_SHARED_LIBS is OFF") else() set(CppMicroServices_DIR ${PROJECT_BINARY_DIR}) add_subdirectory(examples) endif() endif() diff --git a/Core/CppMicroServices/documentation/CMakeDoxygenFilter.cpp b/Core/CppMicroServices/documentation/CMakeDoxygenFilter.cpp index 7aba552149..5da36ee54b 100644 --- a/Core/CppMicroServices/documentation/CMakeDoxygenFilter.cpp +++ b/Core/CppMicroServices/documentation/CMakeDoxygenFilter.cpp @@ -1,494 +1,493 @@ /*============================================================================= 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 //-------------------------------------- // Utilitiy classes and functions //-------------------------------------- struct ci_char_traits : public std::char_traits // just inherit all the other functions // that we don't need to override { static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); } static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); } static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); } static bool gt(char c1, char c2) { return toupper(c1) > toupper(c2); } static int compare(const char* s1, const char* s2, std::size_t n) { while (n-- > 0) { if (lt(*s1, *s2)) return -1; if (gt(*s1, *s2)) return 1; ++s1; ++s2; } return 0; } static const char* find(const char* s, int n, char a) { while (n-- > 0 && toupper(*s) != toupper(a)) { ++s; } return s; } }; typedef std::basic_string ci_string; //-------------------------------------- // Lexer //-------------------------------------- class CMakeLexer { public: enum Token { TOK_EOF = -1, TOK_EOL = -2, // commands TOK_MACRO = -3, TOK_ENDMACRO = -4, TOK_FUNCTION = -5, TOK_ENDFUNCTION = -6, TOK_DOXYGEN_COMMENT = -7, TOK_SET = -8, TOK_STRING_LITERAL = -100, TOK_NUMBER_LITERAL = -102, // primary TOK_IDENTIFIER = -200 }; CMakeLexer(std::istream& is) : _lastChar(' '), _is(is), _line(1), _col(1) {} int getToken() { // skip whitespace while (isspace(_lastChar) && _lastChar != '\r' && _lastChar != '\n') { _lastChar = getChar(); } if (isalpha(_lastChar) || _lastChar == '_') { _identifier = _lastChar; while (isalnum(_lastChar = getChar()) || _lastChar == '-' || _lastChar == '_') { _identifier += _lastChar; } if (_identifier == "set") return TOK_SET; if (_identifier == "function") return TOK_FUNCTION; if (_identifier == "macro") return TOK_MACRO; if (_identifier == "endfunction") return TOK_ENDFUNCTION; if (_identifier == "endmacro") return TOK_ENDMACRO; return TOK_IDENTIFIER; } if (isdigit(_lastChar)) { // very lax!! number detection _identifier = _lastChar; while (isalnum(_lastChar = getChar()) || _lastChar == '.' || _lastChar == ',') { _identifier += _lastChar; } return TOK_NUMBER_LITERAL; } if (_lastChar == '#') { _lastChar = getChar(); if (_lastChar == '!') { // found a doxygen comment marker _identifier.clear(); _lastChar = getChar(); while (_lastChar != EOF && _lastChar != '\n' && _lastChar != '\r') { _identifier += _lastChar; _lastChar = getChar(); } return TOK_DOXYGEN_COMMENT; } // skip the comment while (_lastChar != EOF && _lastChar != '\n' && _lastChar != '\r') { _lastChar = getChar(); } } if (_lastChar == '"') { _lastChar = getChar(); _identifier.clear(); while (_lastChar != EOF && _lastChar != '"') { _identifier += _lastChar; _lastChar = getChar(); } // eat the closing " _lastChar = getChar(); return TOK_STRING_LITERAL; } // don't eat the EOF if (_lastChar == EOF) return TOK_EOF; // don't eat the EOL if (_lastChar == '\r' || _lastChar == '\n') { if (_lastChar == '\r') _lastChar = getChar(); if (_lastChar == '\n') _lastChar = getChar(); return TOK_EOL; } // return the character as its ascii value int thisChar = _lastChar; _lastChar = getChar(); return thisChar; } std::string getIdentifier() const { return std::string(_identifier.c_str()); } int curLine() const { return _line; } int curCol() const { return _col; } int getChar() { int c = _is.get(); updateLoc(c); return c; } private: void updateLoc(int c) { if (c == '\n' || c == '\r') { ++_line; _col = 1; } else { ++_col; } } ci_string _identifier; int _lastChar; std::istream& _is; int _line; int _col; }; //-------------------------------------- // Parser //-------------------------------------- class CMakeParser { public: CMakeParser(std::istream& is, std::ostream& os) - : _is(is), _os(os), _lexer(is), _curToken(CMakeLexer::TOK_EOF), _lastToken(CMakeLexer::TOK_EOF) + : _os(os), _lexer(is), _curToken(CMakeLexer::TOK_EOF), _lastToken(CMakeLexer::TOK_EOF) { } int curToken() { return _curToken; } int nextToken() { _lastToken = _curToken; _curToken = _lexer.getToken(); while (_curToken == CMakeLexer::TOK_EOL) { // Try to preserve lines in output to allow correct line number referencing by doxygen. _os << std::endl; _curToken = _lexer.getToken(); } return _curToken; } void handleMacro() { if(!parseMacro()) { // skip token for error recovery nextToken(); } } void handleFunction() { if(!parseFunction()) { // skip token for error recovery nextToken(); } } void handleSet() { // SET(var ...) following a documentation block is assumed to be a variable declaration. if (_lastToken != CMakeLexer::TOK_DOXYGEN_COMMENT) { // No comment block before nextToken(); } else if(!parseSet()) { // skip token for error recovery nextToken(); } } void handleDoxygenComment() { _os << "///" << _lexer.getIdentifier(); nextToken(); } void handleTopLevelExpression() { // skip token nextToken(); } private: void printError(const char* str) { std::cerr << "Error: " << str << " (at line " << _lexer.curLine() << ", col " << _lexer.curCol() << ")"; } bool parseMacro() { if (nextToken() != '(') { printError("Expected '(' after MACRO"); return false; } nextToken(); std::string macroName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || macroName.empty()) { printError("Expected macro name"); return false; } _os << macroName << '('; if (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << _lexer.getIdentifier(); while (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << ", " << _lexer.getIdentifier(); } } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ");"; } // eat the ')' nextToken(); return true; } bool parseSet() { if (nextToken() != '(') { printError("Expected '(' after SET"); return false; } nextToken(); std::string variableName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || variableName.empty()) { printError("Expected variable name"); return false; } _os << "CMAKE_VARIABLE " << variableName; nextToken(); while ((curToken() == CMakeLexer::TOK_IDENTIFIER) || (curToken() == CMakeLexer::TOK_STRING_LITERAL) || (curToken() == CMakeLexer::TOK_NUMBER_LITERAL)) { nextToken(); } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ";"; } // eat the ')' nextToken(); return true; } bool parseFunction() { if (nextToken() != '(') { printError("Expected '(' after FUNCTION"); return false; } nextToken(); std::string funcName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || funcName.empty()) { printError("Expected function name"); return false; } _os << funcName << '('; if (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << _lexer.getIdentifier(); while (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << ", " << _lexer.getIdentifier(); } } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ");"; } // eat the ')' nextToken(); return true; } - std::istream& _is; std::ostream& _os; CMakeLexer _lexer; int _curToken; int _lastToken; }; #define STRINGIFY(a) #a #define DOUBLESTRINGIFY(a) STRINGIFY(a) int main(int argc, char** argv) { assert(argc > 1); for (int i = 1; i < argc; ++i) { std::ifstream ifs(argv[i]); std::ostream& os = std::cout; #ifdef USE_NAMESPACE os << "namespace " << DOUBLESTRINGIFY(USE_NAMESPACE) << " {\n"; #endif CMakeParser parser(ifs, os); parser.nextToken(); while (ifs.good()) { switch (parser.curToken()) { case CMakeLexer::TOK_EOF: return ifs.get(); // eat EOF case CMakeLexer::TOK_MACRO: parser.handleMacro(); break; case CMakeLexer::TOK_FUNCTION: parser.handleFunction(); break; case CMakeLexer::TOK_SET: parser.handleSet(); break; case CMakeLexer::TOK_DOXYGEN_COMMENT: parser.handleDoxygenComment(); break; default: parser.handleTopLevelExpression(); break; } } #ifdef USE_NAMESPACE os << "}\n"; #endif } return EXIT_SUCCESS; } diff --git a/Core/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md b/Core/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md index 8319e6bd7a..99f4d7d581 100644 --- a/Core/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md +++ b/Core/CppMicroServices/documentation/doxygen/standalone/BuildInstructions.md @@ -1,59 +1,59 @@ Build Instructions {#BuildInstructions} ================== The C++ Micro Services library provides [CMake][cmake] build scripts which allow the generation of platform and IDE specific project files. The library should compile on many different platforms. Below is a list of tested compiler/OS combinations: - GCC 4.5 (Ubuntu 11.04 and MacOS X 10.6) - GCC 4.7 (Ubuntu 12.10) - Visual Studio 2008, 2010, and 2012 - Clang 3.0 (Ubuntu 12.10 and MacOS X 10.6) Prerequisites ------------- - [CMake][cmake] 2.8 (Visual Studio 2010 and 2012 users should use the latest CMake version available) Configuring the Build --------------------- When building the C++ Micro Services library, you have a few configuration options at hand. ### General build options - **CMAKE_INSTALL_PREFIX** The installation path. - **US_BUILD_SHARED_LIBS** Specify if the library should be build shared or static. See \ref MicroServices_StaticModules for detailed information about static CppMicroServices modules. - **US_BUILD_TESTING** Build unit tests and code snippets. - **US_ENABLE_AUTOLOADING_SUPPORT** - Enable auto-loading of modules located in special sup-directories. See \ref MicroServices_AutoLoading + Enable auto-loading of modules located in special sub-directories. See \ref MicroServices_AutoLoading for detailed information about this feature. - **US_ENABLE_THREADING_SUPPORT** Enable the use of synchronization primitives (atomics and pthread mutexes or Windows primitives) - to make the API thread-safe. If you are application is not multi-threaded, turn this option OFF + to make the API thread-safe. If your application is not multi-threaded, turn this option OFF to get maximum performance. - **US_USE_C++11 (advanced)** Enable the usage of C++11 constructs. - **US_ENABLE_RESOURCE_COMPRESSION (advanced)** Enable compression of embedded resources. See \ref MicroServices_Resources for detailed information about the resource system. ### Customizing naming conventions - **US_NAMESPACE** The default namespace is `us` but you may override this at will. - **US_HEADER_PREFIX** By default, all public headers have a "us" prefix. You may specify an arbitrary prefix to match your naming conventions. The above options are mainly useful when embedding the C++ Micro Services source code in your own library and you want to make it look like native source code. [cmake]: http://www.cmake.org diff --git a/Core/CppMicroServices/documentation/snippets/uServices-resources/main.cpp b/Core/CppMicroServices/documentation/snippets/uServices-resources/main.cpp index 474c344374..45eaa61658 100644 --- a/Core/CppMicroServices/documentation/snippets/uServices-resources/main.cpp +++ b/Core/CppMicroServices/documentation/snippets/uServices-resources/main.cpp @@ -1,86 +1,85 @@ #include #include #include #include #include #include US_USE_NAMESPACE void resourceExample() { //! [1] // Get this module's Module object Module* module = GetModuleContext()->GetModule(); ModuleResource resource = module->GetResource("config.properties"); if (resource.IsValid()) { // Create a ModuleResourceStream object ModuleResourceStream resourceStream(resource); // Read the contents line by line std::string line; while (std::getline(resourceStream, line)) { // Process the content std::cout << line << std::endl; } } else { // Error handling } //! [1] } void parseComponentDefinition(std::istream&) { } void extenderPattern() { //! [2] // Get all loaded modules - std::vector modules; - ModuleRegistry::GetLoadedModules(modules); + std::vector modules = ModuleRegistry::GetLoadedModules(); // Check if a module defines a "service-component" property // and use its value to retrieve an embedded resource containing // a component description. for(std::size_t i = 0; i < modules.size(); ++i) { Module* const module = modules[i]; std::string componentPath = module->GetProperty("service-component").ToString(); if (!componentPath.empty()) { ModuleResource componentResource = module->GetResource(componentPath); if (!componentResource.IsValid() || componentResource.IsDir()) continue; // Create a std::istream compatible object and parse the // component description. ModuleResourceStream resStream(componentResource); parseComponentDefinition(resStream); } } //! [2] } int main(int /*argc*/, char* /*argv*/[]) { //! [0] ModuleContext* moduleContext = GetModuleContext(); Module* module = moduleContext->GetModule(); // List all XML files in the config directory std::vector xmlFiles = module->FindResources("config", "*.xml", false); // Find the resource named vertex_shader.txt starting at the root directory std::vector shaders = module->FindResources("", "vertex_shader.txt", true); //! [0] return 0; } #include US_INITIALIZE_EXECUTABLE("uServices-snippet-resources") diff --git a/Core/CppMicroServices/documentation/snippets/uServices-servicetracker/main.cpp b/Core/CppMicroServices/documentation/snippets/uServices-servicetracker/main.cpp index 0c1bc68bef..5961f956da 100644 --- a/Core/CppMicroServices/documentation/snippets/uServices-servicetracker/main.cpp +++ b/Core/CppMicroServices/documentation/snippets/uServices-servicetracker/main.cpp @@ -1,110 +1,110 @@ #include #include US_USE_NAMESPACE struct IFooService {}; US_DECLARE_SERVICE_INTERFACE(IFooService, "org.cppmicroservices.snippets.IFooService") ///! [tt] struct MyTrackedClass { /* ... */ }; //! [tt] //! [ttt] struct MyTrackedClassTraits : public TrackedTypeTraitsBase { static bool IsValid(const TrackedType&) { // Dummy implementation return true; } static void Dispose(TrackedType&) {} static TrackedType DefaultValue() { return TrackedType(); } }; //! [ttt] //! [customizer] struct MyTrackingCustomizer : public ServiceTrackerCustomizer { - virtual MyTrackedClass AddingService(const ServiceReferenceT&) + virtual MyTrackedClass AddingService(const ServiceReferenceType&) { return MyTrackedClass(); } - virtual void ModifiedService(const ServiceReferenceT&, MyTrackedClass) + virtual void ModifiedService(const ServiceReferenceType&, MyTrackedClass) { } - virtual void RemovedService(const ServiceReferenceT&, MyTrackedClass) + virtual void RemovedService(const ServiceReferenceType&, MyTrackedClass) { } }; //! [customizer] struct MyTrackingPointerCustomizer : public ServiceTrackerCustomizer { - virtual MyTrackedClass* AddingService(const ServiceReferenceT&) + virtual MyTrackedClass* AddingService(const ServiceReferenceType&) { return new MyTrackedClass(); } - virtual void ModifiedService(const ServiceReferenceT&, MyTrackedClass*) + virtual void ModifiedService(const ServiceReferenceType&, MyTrackedClass*) { } - virtual void RemovedService(const ServiceReferenceT&, MyTrackedClass*) + virtual void RemovedService(const ServiceReferenceType&, MyTrackedClass*) { } }; // For compilation test purposes only struct MyTrackingCustomizerVoid : public ServiceTrackerCustomizer { - virtual MyTrackedClass AddingService(const ServiceReferenceT&) + virtual MyTrackedClass AddingService(const ServiceReferenceType&) { return MyTrackedClass(); } - virtual void ModifiedService(const ServiceReferenceT&, MyTrackedClass) + virtual void ModifiedService(const ServiceReferenceType&, MyTrackedClass) { } - virtual void RemovedService(const ServiceReferenceT&, MyTrackedClass) + virtual void RemovedService(const ServiceReferenceType&, MyTrackedClass) { } }; int main(int /*argc*/, char* /*argv*/[]) { { //! [tracker] MyTrackingCustomizer myCustomizer; ServiceTracker tracker(GetModuleContext(), &myCustomizer); //! [tracker] } { //! [tracker2] MyTrackingPointerCustomizer myCustomizer; ServiceTracker > tracker(GetModuleContext(), &myCustomizer); //! [tracker2] } // For compilation test purposes only MyTrackingCustomizerVoid myCustomizer2; ServiceTracker tracker2(GetModuleContext(), &myCustomizer2); ServiceTracker > tracker3(GetModuleContext()); return 0; } #include US_INITIALIZE_EXECUTABLE("uServices-modulecontext") diff --git a/Core/CppMicroServices/examples/CMakeLists.txt b/Core/CppMicroServices/examples/CMakeLists.txt index 745bd869c3..f7ed1bdd07 100644 --- a/Core/CppMicroServices/examples/CMakeLists.txt +++ b/Core/CppMicroServices/examples/CMakeLists.txt @@ -1,137 +1,164 @@ project(CppMicroServicesExamples) cmake_minimum_required(VERSION 2.8) find_package(CppMicroServices NO_MODULE REQUIRED) include_directories(${CppMicroServices_INCLUDE_DIRS}) #----------------------------------------------------------------------------- # Set C/CXX flags #----------------------------------------------------------------------------- if(${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CppMicroServices_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${CppMicroServices_CXX_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CppMicroServices_CXX_FLAGS_DEBUG}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CppMicroServices_C_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${CppMicroServices_C_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${CppMicroServices_C_FLAGS_DEBUG}") endif() #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(CppMicroServicesExamples_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(CppMicroServicesExamples_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(CppMicroServicesExamples_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${CppMicroServicesExamples_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() function(CreateExample _name) add_library(Example-${_name} SHARED ${ARGN}) if(${_name}_DEPENDS) foreach(_dep ${${_name}_DEPENDS}) include_directories(${CppMicroServicesExamples_SOURCE_DIR}/${_dep}) target_link_libraries(Example-${_name} Example-${_dep}) endforeach() endif() target_link_libraries(Example-${_name} ${CppMicroServices_LIBRARIES}) set_target_properties(Example-${_name} PROPERTIES LABELS Examples OUTPUT_NAME ${_name} ) endfunction() add_subdirectory(eventlistener) add_subdirectory(dictionaryservice) add_subdirectory(frenchdictionary) add_subdirectory(dictionaryclient) add_subdirectory(dictionaryclient2) add_subdirectory(dictionaryclient3) add_subdirectory(spellcheckservice) add_subdirectory(spellcheckclient) add_subdirectory(driver) #----------------------------------------------------------------------------- # Test if examples compile against an install tree and if the # Makefile example compiles #----------------------------------------------------------------------------- if(US_BUILD_TESTING) enable_testing() set(_example_tests ) set(_install_dir "${CppMicroServices_BINARY_DIR}/install_test/${CMAKE_INSTALL_PREFIX}") add_test(NAME usInstallCleanTest COMMAND ${CMAKE_COMMAND} -E remove_directory "${_install_dir}") add_test(NAME usInstallTest WORKING_DIRECTORY ${CppMicroServices_BINARY_DIR} COMMAND ${CMAKE_COMMAND} --build ${CppMicroServices_BINARY_DIR} --target install) set_tests_properties(usInstallTest PROPERTIES ENVIRONMENT "DESTDIR=${CppMicroServices_BINARY_DIR}/install_test" DEPENDS usInstallCleanTest) set(_examples_binary_dir "${CppMicroServices_BINARY_DIR}/examples_build") add_test(NAME usExamplesCleanTest COMMAND ${CMAKE_COMMAND} -E remove_directory "${_examples_binary_dir}") add_test(NAME usExamplesCreateDirTest COMMAND ${CMAKE_COMMAND} -E make_directory "${_examples_binary_dir}") set_tests_properties(usExamplesCreateDirTest PROPERTIES DEPENDS usExamplesCleanTest) - add_test(NAME usExamplesConfigureTest - WORKING_DIRECTORY ${_examples_binary_dir} - COMMAND ${CMAKE_COMMAND} - -G ${CMAKE_GENERATOR} - -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} - "-DCppMicroServices_DIR:PATH=${_install_dir}/${CONFIG_CMAKE_DIR}" - "${CMAKE_CURRENT_LIST_DIR}") - set_tests_properties(usExamplesConfigureTest PROPERTIES - DEPENDS "usInstallTest;usExamplesCreateDirTest") - - add_test(NAME usExamplesBuildTest - WORKING_DIRECTORY ${_examples_binary_dir} - COMMAND ${CMAKE_COMMAND} --build .) - set_tests_properties(usExamplesBuildTest PROPERTIES - DEPENDS usExamplesConfigureTest) - list(APPEND _example_tests usInstallCleanTest usInstallTest usExamplesCleanTest - usExamplesCreateDirTest usExamplesConfigureTest usExamplesBuildTest) + usExamplesCreateDirTest) + + if(CMAKE_CONFIGURATION_TYPES) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + add_test(NAME usExamplesConfigureTest-${config} CONFIGURATIONS ${config} + WORKING_DIRECTORY ${_examples_binary_dir} + COMMAND ${CMAKE_COMMAND} + -D CMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER} + -D CMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} + -G ${CMAKE_GENERATOR} + "-DCppMicroServices_DIR:PATH=${_install_dir}/${CONFIG_CMAKE_DIR}" + "${CMAKE_CURRENT_LIST_DIR}") + set_tests_properties(usExamplesConfigureTest-${config} PROPERTIES + DEPENDS "usInstallTest;usExamplesCreateDirTest") + + add_test(NAME usExamplesBuildTest-${config} CONFIGURATIONS ${config} + WORKING_DIRECTORY ${_examples_binary_dir} + COMMAND ${CMAKE_COMMAND} --build . --config ${config}) + set_tests_properties(usExamplesBuildTest-${config} PROPERTIES + DEPENDS usExamplesConfigureTest-${config}) + + list(APPEND _example_tests usExamplesConfigureTest-${config} usExamplesBuildTest-${config}) + endforeach() + else() + add_test(NAME usExamplesConfigureTest-${CMAKE_BUILD_TYPE} + WORKING_DIRECTORY ${_examples_binary_dir} + COMMAND ${CMAKE_COMMAND} + -D CMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -D CMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER} + -D CMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} + -G ${CMAKE_GENERATOR} + "-DCppMicroServices_DIR:PATH=${_install_dir}/${CONFIG_CMAKE_DIR}" + "${CMAKE_CURRENT_LIST_DIR}") + set_tests_properties(usExamplesConfigureTest-${CMAKE_BUILD_TYPE} PROPERTIES + DEPENDS "usInstallTest;usExamplesCreateDirTest") + + add_test(NAME usExamplesBuildTest-${CMAKE_BUILD_TYPE} + WORKING_DIRECTORY ${_examples_binary_dir} + COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}) + set_tests_properties(usExamplesBuildTest-${CMAKE_BUILD_TYPE} PROPERTIES + DEPENDS usExamplesConfigureTest-${CMAKE_BUILD_TYPE}) + + list(APPEND _example_tests usExamplesConfigureTest-${CMAKE_BUILD_TYPE} usExamplesBuildTest-${CMAKE_BUILD_TYPE}) + endif() # The makefile is Linux specific, so only try to build the Makefile example # if we are on a proper system if(UNIX AND NOT APPLE) find_program(MAKE_COMMAND NAMES make gmake) find_program(CXX_COMMAND NAMES g++) mark_as_advanced(MAKE_COMMAND CXX_COMMAND) if(MAKE_COMMAND AND CXX_COMMAND) add_test(NAME usMakefileExampleCleanTest WORKING_DIRECTORY ${CppMicroServices_SOURCE_DIR}/examples/makefile COMMAND ${MAKE_COMMAND} clean) add_test(NAME usMakefileExampleTest WORKING_DIRECTORY ${CppMicroServices_SOURCE_DIR}/examples/makefile COMMAND ${MAKE_COMMAND}) set_tests_properties(usMakefileExampleTest PROPERTIES DEPENDS "usMakefileExampleCleanTest;usInstallTest" ENVIRONMENT "CppMicroServices_ROOT=${CppMicroServices_BINARY_DIR}/install_test${CMAKE_INSTALL_PREFIX};CppMicroServices_CXX_FLAGS=${CppMicroServices_CXX_FLAGS}") list(APPEND _example_tests usMakefileExampleCleanTest usMakefileExampleTest) endif() endif() if(US_TEST_LABELS) set_tests_properties(${_example_tests} PROPERTIES LABELS "${US_TEST_LABELS}") endif() endif() diff --git a/Core/CppMicroServices/examples/driver/main.cpp b/Core/CppMicroServices/examples/driver/main.cpp index f4dcfa7649..dc78d71414 100644 --- a/Core/CppMicroServices/examples/driver/main.cpp +++ b/Core/CppMicroServices/examples/driver/main.cpp @@ -1,300 +1,298 @@ /*============================================================================= 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 "usCppMicroServicesExampleDriverConfig.h" #if defined(US_PLATFORM_POSIX) #include #elif defined(US_PLATFORM_WINDOWS) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #else #error Unsupported platform #endif #include #include #include #include #include #include #include US_USE_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 std::map GetExampleModules() { std::map names; names.insert(std::make_pair("Event Listener", "eventlistener")); names.insert(std::make_pair("Dictionary Service", "dictionaryservice")); names.insert(std::make_pair("French Dictionary", "frenchdictionary")); names.insert(std::make_pair("Dictionary Client", "dictionaryclient")); names.insert(std::make_pair("Dictionary Client 2", "dictionaryclient2")); names.insert(std::make_pair("Dictionary Client 3", "dictionaryclient3")); names.insert(std::make_pair("Spell Check Service", "spellcheckservice")); names.insert(std::make_pair("Spell Check Client", "spellcheckclient")); return names; } int main(int /*argc*/, char** /*argv*/) { char cmd[256]; std::map availableModules = GetExampleModules(); /* module path -> lib handle */ std::map libraryHandles; SharedLibrary sharedLib(LIB_PATH, ""); std::cout << "> "; while(std::cin.getline(cmd, sizeof(cmd))) { std::string strCmd(cmd); if (strCmd == "q") { break; } else if (strCmd == "h") { std::cout << std::left << std::setw(15) << "h" << " This help text\n" << std::setw(15) << "l " << " Load the module with id or name \n" << std::setw(15) << "u " << " Unload the module with id \n" << std::setw(15) << "s" << " Print status information\n" << std::setw(15) << "q" << " Quit\n" << std::flush; } else if (strCmd.find("l ") != std::string::npos) { std::string idOrName; idOrName.assign(strCmd.begin()+2, strCmd.end()); std::stringstream ss(idOrName); long int id = -1; ss >> id; if (id > 0) { Module* module = ModuleRegistry::GetModule(id); if (!module) { std::cout << "Error: unknown id" << std::endl; } else if (module->IsLoaded()) { std::cout << "Info: module already loaded" << std::endl; } else { try { std::map::iterator libIter = libraryHandles.find(module->GetLocation()); if (libIter != libraryHandles.end()) { libIter->second.Load(); } else { // The module has been loaded previously due to a // linker dependency SharedLibrary libHandle(module->GetLocation()); libHandle.Load(); libraryHandles.insert(std::make_pair(libHandle.GetFilePath(), libHandle)); } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } } else { Module* module = ModuleRegistry::GetModule(idOrName); if (!module) { try { std::map::iterator libIter = libraryHandles.find(sharedLib.GetFilePath(idOrName)); if (libIter != libraryHandles.end()) { libIter->second.Load(); } else { bool libFound = false; for (std::map::const_iterator availableModuleIter = availableModules.begin(); availableModuleIter != availableModules.end(); ++availableModuleIter) { if (availableModuleIter->second == idOrName) { libFound = true; } } if (!libFound) { std::cout << "Error: unknown example module" << std::endl; } else { SharedLibrary libHandle(LIB_PATH, idOrName); libHandle.Load(); libraryHandles.insert(std::make_pair(libHandle.GetFilePath(), libHandle)); } } - std::vector modules; - ModuleRegistry::GetModules(modules); + std::vector modules = ModuleRegistry::GetModules(); for (std::vector::const_iterator moduleIter = modules.begin(); moduleIter != modules.end(); ++moduleIter) { availableModules.erase((*moduleIter)->GetName()); } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } else if (!module->IsLoaded()) { try { const std::string modulePath = module->GetLocation(); std::map::iterator libIter = libraryHandles.find(modulePath); if (libIter != libraryHandles.end()) { libIter->second.Load(); } else { SharedLibrary libHandle(LIB_PATH, idOrName); libHandle.Load(); libraryHandles.insert(std::make_pair(libHandle.GetFilePath(), libHandle)); } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } else if (module) { std::cout << "Info: module already loaded" << std::endl; } } } else if (strCmd.find("u ") != std::string::npos) { std::stringstream ss(strCmd); ss.ignore(2); long int id = -1; ss >> id; if (id == 1) { std::cout << "Info: Unloading not possible" << std::endl; } else { Module* const module = ModuleRegistry::GetModule(id); if (module) { std::map::iterator libIter = libraryHandles.find(module->GetLocation()); if (libIter == libraryHandles.end()) { std::cout << "Info: Unloading not possible. The module was loaded by a dependent module." << std::endl; } else { try { libIter->second.Unload(); // Check if it has really been unloaded if (module->IsLoaded()) { std::cout << "Info: The module is still referenced by another loaded module. It will be unloaded when all dependent modules are unloaded." << std::endl; } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } } else { std::cout << "Error: unknown id" << std::endl; } } } else if (strCmd == "s") { - std::vector modules; - ModuleRegistry::GetModules(modules); + std::vector modules = ModuleRegistry::GetModules(); std::cout << std::left; std::cout << "Id | " << std::setw(20) << "Name" << " | " << std::setw(9) << "Status" << std::endl; std::cout << "-----------------------------------\n"; for (std::map::const_iterator nameIter = availableModules.begin(); nameIter != availableModules.end(); ++nameIter) { std::cout << " - | " << std::setw(20) << nameIter->second << " | " << std::setw(9) << "-" << std::endl; } for (std::vector::const_iterator moduleIter = modules.begin(); moduleIter != modules.end(); ++moduleIter) { std::cout << std::right << std::setw(2) << (*moduleIter)->GetModuleId() << std::left << " | "; std::cout << std::setw(20) << (*moduleIter)->GetName() << " | "; std::cout << std::setw(9) << ((*moduleIter)->IsLoaded() ? "LOADED" : "UNLOADED"); std::cout << std::endl; } } else { std::cout << "Unknown command: " << strCmd << " (type 'h' for help)" << std::endl; } std::cout << "> "; } return 0; } diff --git a/Core/CppMicroServices/src/CMakeLists.txt b/Core/CppMicroServices/src/CMakeLists.txt index 3ec45cab71..37a740200f 100644 --- a/Core/CppMicroServices/src/CMakeLists.txt +++ b/Core/CppMicroServices/src/CMakeLists.txt @@ -1,192 +1,212 @@ #----------------------------------------------------------------------------- # US source files #----------------------------------------------------------------------------- set(_srcs util/usAny.cpp util/jsoncpp.cpp util/usLDAPProp.cpp util/usSharedLibrary.cpp - util/usThreads.cpp util/usUncompressResourceData.c util/usUncompressResourceData.cpp util/usUtils.cpp service/usLDAPExpr.cpp service/usLDAPFilter.cpp service/usServiceException.cpp service/usServiceEvent.cpp + service/usServiceEventListenerHook.cpp + service/usServiceFindHook.cpp + service/usServiceHooks.cpp service/usServiceListenerEntry.cpp service/usServiceListenerEntry_p.h + service/usServiceListenerHook.cpp service/usServiceListeners.cpp service/usServiceListeners_p.h service/usServiceObjects.cpp service/usServiceProperties.cpp service/usServicePropertiesImpl.cpp service/usServiceReferenceBase.cpp service/usServiceReferenceBasePrivate.cpp service/usServiceRegistrationBase.cpp service/usServiceRegistrationBasePrivate.cpp service/usServiceRegistry.cpp service/usServiceRegistry_p.h + module/usCoreModuleActivator.cpp module/usCoreModuleContext_p.h module/usCoreModuleContext.cpp module/usModuleContext.cpp module/usModule.cpp module/usModuleEvent.cpp + module/usModuleEventHook.cpp + module/usModuleFindHook.cpp + module/usModuleHooks.cpp module/usModuleInfo.cpp module/usModuleManifest.cpp module/usModulePrivate.cpp module/usModuleRegistry.cpp module/usModuleResource.cpp module/usModuleResourceBuffer.cpp module/usModuleResourceStream.cpp module/usModuleResourceTree.cpp module/usModuleSettings.cpp module/usModuleUtils.cpp module/usModuleVersion.cpp ) set(_private_headers util/usAtomicInt_p.h util/usFunctor_p.h + util/usListenerFunctors_p.h + util/usLog_p.h util/usStaticInit_p.h util/usThreads_p.h util/usUtils_p.h + util/usWaitCondition_p.h util/dirent_win32_p.h util/stdint_p.h util/stdint_vc_p.h + service/usServiceHooks_p.h + service/usServiceListenerHook_p.h service/usServicePropertiesImpl_p.h service/usServiceTracker.tpp service/usServiceTrackerPrivate.h service/usServiceTrackerPrivate.tpp service/usTrackedService_p.h service/usTrackedServiceListener_p.h service/usTrackedService.tpp module/usModuleAbstractTracked_p.h module/usModuleAbstractTracked.tpp + module/usModuleHooks_p.h module/usModuleResourceBuffer_p.h module/usModuleResourceTree_p.h module/usModuleUtils_p.h ) set(_public_headers util/usAny.h util/usLDAPProp.h util/usSharedData.h util/usSharedLibrary.h + util/usShrinkableMap.h + util/usShrinkableVector.h util/usUncompressResourceData.h service/usLDAPFilter.h service/usPrototypeServiceFactory.h service/usServiceEvent.h + service/usServiceEventListenerHook.h service/usServiceException.h service/usServiceFactory.h + service/usServiceFindHook.h service/usServiceInterface.h + service/usServiceListenerHook.h service/usServiceObjects.h service/usServiceProperties.h service/usServiceReference.h service/usServiceReferenceBase.h service/usServiceRegistration.h service/usServiceRegistrationBase.h service/usServiceTracker.h service/usServiceTrackerCustomizer.h module/usGetModuleContext.h module/usModule.h module/usModuleActivator.h module/usModuleContext.h module/usModuleEvent.h + module/usModuleEventHook.h + module/usModuleFindHook.h module/usModuleImport.h module/usModuleInfo.h module/usModuleInitialization.h module/usModuleRegistry.h module/usModuleResource.h module/usModuleResourceStream.h module/usModuleSettings.h module/usModuleVersion.h ) if(US_IS_EMBEDDED) set(US_SOURCES ) get_filename_component(_path_prefix "${PROJECT_SOURCE_DIR}" NAME) set(_path_prefix "${_path_prefix}/src") foreach(_src ${_srcs} ${_public_headers} ${_private_headers}) list(APPEND US_SOURCES ${_path_prefix}/${_src}) endforeach() set(US_SOURCES ${US_SOURCES} PARENT_SCOPE) endif() #----------------------------------------------------------------------------- # Create library (only if not in embedded mode) #----------------------------------------------------------------------------- if(NOT US_IS_EMBEDDED) include_directories(${US_INTERNAL_INCLUDE_DIRS}) usFunctionGenerateModuleInit(_srcs NAME ${PROJECT_NAME}) usFunctionEmbedResources(_srcs LIBRARY_NAME ${PROJECT_NAME} ROOT_DIR resources FILES manifest.json) add_library(${PROJECT_NAME} ${_srcs} ${_public_headers} ${_private_headers} ${us_config_h_file}) if(US_LINK_FLAGS) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "${US_LINK_FLAGS}") endif() set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY COMPILE_DEFINITIONS US_FORCE_MODULE_INIT) set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION ${${PROJECT_NAME}_VERSION} ) if(US_LINK_LIBRARIES) target_link_libraries(${PROJECT_NAME} ${US_LINK_LIBRARIES}) endif() endif() #----------------------------------------------------------------------------- # Configure public header wrappers #----------------------------------------------------------------------------- set(US_PUBLIC_HEADERS ${_public_headers}) if(US_HEADER_PREFIX) set(US_PUBLIC_HEADERS ) foreach(_public_header ${_public_headers}) get_filename_component(_public_header_basename ${_public_header} NAME_WE) set(_us_public_header ${_public_header_basename}.h) string(SUBSTRING "${_public_header_basename}" 2 -1 _public_header_basename) set(_header_wrapper "${PROJECT_BINARY_DIR}/include/${US_HEADER_PREFIX}${_public_header_basename}.h") configure_file(${PROJECT_SOURCE_DIR}/CMake/usPublicHeaderWrapper.h.in ${_header_wrapper} @ONLY) list(APPEND US_PUBLIC_HEADERS ${_header_wrapper}) endforeach() endif() foreach(_header ${_public_headers} ${_private_headers}) get_filename_component(_header_name "${_header}" NAME) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${_header} "${PROJECT_BINARY_DIR}/include/${_header_name}") endforeach() if(NOT US_IS_EMBEDDED) set_property(TARGET ${PROJECT_NAME} PROPERTY PUBLIC_HEADER ${US_PUBLIC_HEADERS}) set_property(TARGET ${PROJECT_NAME} PROPERTY PRIVATE_HEADER ${_private_headers} ${us_config_h_file}) else() set(US_PUBLIC_HEADERS ${US_PUBLIC_HEADERS} PARENT_SCOPE) set(US_PRIVATE_HEADERS ${US_PRIVATE_HEADERS} PARENT_SCOPE) endif() #----------------------------------------------------------------------------- # Install support (only if not in embedded mode) #----------------------------------------------------------------------------- if(NOT US_IS_EMBEDDED) install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} PUBLIC_HEADER DESTINATION ${HEADER_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} PRIVATE_HEADER DESTINATION ${HEADER_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT}) endif() diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp b/Core/CppMicroServices/src/module/usCoreModuleActivator.cpp similarity index 69% copy from Core/CppMicroServices/src/module/usCoreModuleContext.cpp copy to Core/CppMicroServices/src/module/usCoreModuleActivator.cpp index b2d4d9896c..4dd03e8eba 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp +++ b/Core/CppMicroServices/src/module/usCoreModuleActivator.cpp @@ -1,46 +1,47 @@ /*============================================================================= 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 "usModuleActivator.h" -#include +#include "usModule.h" +#include "usModulePrivate.h" #include "usCoreModuleContext_p.h" -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4355) -#endif - US_BEGIN_NAMESPACE -CoreModuleContext::CoreModuleContext() - : services(this) +class CoreModuleActivator : public ModuleActivator { -} -CoreModuleContext::~CoreModuleContext() -{ -} + void Load(ModuleContext* mc) + { + mc->GetModule()->d->coreCtx->Init(); + } + + void Unload(ModuleContext* /*mc*/) + { + //mc->GetModule()->d->coreCtx->Uninit(); + } + +}; US_END_NAMESPACE -#ifdef _MSC_VER -#pragma warning(pop) -#endif +US_EXPORT_MODULE_ACTIVATOR(CppMicroServices, US_PREPEND_NAMESPACE(CoreModuleActivator)) diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp b/Core/CppMicroServices/src/module/usCoreModuleContext.cpp index b2d4d9896c..75b6b514f5 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp +++ b/Core/CppMicroServices/src/module/usCoreModuleContext.cpp @@ -1,46 +1,53 @@ /*============================================================================= 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 "usCoreModuleContext_p.h" -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4355) -#endif +US_MSVC_DISABLE_WARNING(4355) + +#include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE CoreModuleContext::CoreModuleContext() - : services(this) + : listeners(this) + , services(this) + , serviceHooks(this) + , moduleHooks(this) { } CoreModuleContext::~CoreModuleContext() { } -US_END_NAMESPACE +void CoreModuleContext::Init() +{ + serviceHooks.Open(); +} -#ifdef _MSC_VER -#pragma warning(pop) -#endif +void CoreModuleContext::Uninit() +{ + serviceHooks.Close(); +} + +US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext_p.h b/Core/CppMicroServices/src/module/usCoreModuleContext_p.h index 7f230f9ee5..15d16a2377 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext_p.h +++ b/Core/CppMicroServices/src/module/usCoreModuleContext_p.h @@ -1,60 +1,76 @@ /*============================================================================= 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 USCOREMODULECONTEXT_H #define USCOREMODULECONTEXT_H #include "usServiceListeners_p.h" #include "usServiceRegistry_p.h" +#include "usModuleHooks_p.h" +#include "usServiceHooks_p.h" US_BEGIN_NAMESPACE /** * This class is not part of the public API. */ class CoreModuleContext { public: /** * All listeners in this framework. */ ServiceListeners listeners; /** * All registered services in this framework. */ ServiceRegistry services; + /** + * All service hooks. + */ + ServiceHooks serviceHooks; + + /** + * All module hooks. + */ + ModuleHooks moduleHooks; + /** * Contruct a core context * */ CoreModuleContext(); ~CoreModuleContext(); + void Init(); + + void Uninit(); + }; US_END_NAMESPACE #endif // USCOREMODULECONTEXT_H diff --git a/Core/CppMicroServices/src/module/usModule.cpp b/Core/CppMicroServices/src/module/usModule.cpp index f12b12b6e4..27eaf082cd 100644 --- a/Core/CppMicroServices/src/module/usModule.cpp +++ b/Core/CppMicroServices/src/module/usModule.cpp @@ -1,319 +1,315 @@ /*============================================================================= 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 "usModule.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usModulePrivate.h" #include "usModuleResource.h" #include "usModuleSettings.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE const std::string& Module::PROP_ID() { static const std::string s("module.id"); return s; } const std::string& Module::PROP_NAME() { static const std::string s("module.name"); return s; } const std::string& Module::PROP_LOCATION() { static const std::string s("module.location"); return s; } const std::string& Module::PROP_VERSION() { static const std::string s("module.version"); return s; } const std::string&Module::PROP_VENDOR() { static const std::string s("module.vendor"); return s; } const std::string&Module::PROP_DESCRIPTION() { static const std::string s("module.description"); return s; } const std::string&Module::PROP_AUTOLOAD_DIR() { static const std::string s("module.autoload_dir"); return s; } Module::Module() : d(0) { } Module::~Module() { delete d; } void Module::Init(CoreModuleContext* coreCtx, ModuleInfo* info) { ModulePrivate* mp = new ModulePrivate(this, coreCtx, info); std::swap(mp, d); delete mp; } void Module::Uninit() { - if (d->moduleContext) + if (d->moduleContext != NULL) { + //d->coreCtx->listeners.HooksModuleStopped(d->moduleContext); + d->RemoveModuleResources(); delete d->moduleContext; d->moduleContext = 0; + d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); + + d->moduleActivator = 0; } - d->moduleActivator = 0; } bool Module::IsLoaded() const { return d->moduleContext != 0; } void Module::Start() { if (d->moduleContext) { US_WARN << "Module " << d->info.name << " already started."; return; } d->moduleContext = new ModuleContext(this->d); // try // { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADING, this)); // try to get a ModuleActivator instance if (d->info.activatorHook) { try { d->moduleActivator = d->info.activatorHook(); } catch (...) { US_ERROR << "Creating the module activator of " << d->info.name << " failed"; throw; } d->moduleActivator->Load(d->moduleContext); } d->StartStaticModules(); #ifdef US_ENABLE_AUTOLOADING_SUPPORT if (ModuleSettings::IsAutoLoadingEnabled()) { AutoLoadModules(d->info); } #endif d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADED, this)); // } // catch (...) // { // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); // d->RemoveModuleResources(); // delete d->moduleContext; // d->moduleContext = 0; // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); // US_ERROR << "Calling the module activator Load() method of " << d->info.name << " failed!"; // throw; // } } void Module::Stop() { if (d->moduleContext == 0) { US_WARN << "Module " << d->info.name << " already stopped."; return; } try { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); d->StopStaticModules(); if (d->moduleActivator) { d->moduleActivator->Unload(d->moduleContext); } } catch (...) { US_WARN << "Calling the module activator Unload() method of " << d->info.name << " failed!"; try { - d->RemoveModuleResources(); + this->Uninit(); } catch (...) {} - delete d->moduleContext; - d->moduleContext = 0; - - d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); - throw; } - d->RemoveModuleResources(); - delete d->moduleContext; - d->moduleContext = 0; - d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); + this->Uninit(); } ModuleContext* Module::GetModuleContext() const { return d->moduleContext; } long Module::GetModuleId() const { return d->info.id; } std::string Module::GetLocation() const { return d->info.location; } std::string Module::GetName() const { return d->info.name; } ModuleVersion Module::GetVersion() const { return d->version; } Any Module::GetProperty(const std::string& key) const { return d->moduleManifest.GetValue(key); } std::vector Module::GetPropertyKeys() const { return d->moduleManifest.GetKeys(); } std::vector Module::GetRegisteredServices() const { std::vector sr; std::vector res; d->coreCtx->services.GetRegisteredByModule(d, sr); for (std::vector::const_iterator i = sr.begin(); i != sr.end(); ++i) { res.push_back(i->GetReference()); } return res; } std::vector Module::GetServicesInUse() const { std::vector sr; std::vector res; d->coreCtx->services.GetUsedByModule(const_cast(this), sr); for (std::vector::const_iterator i = sr.begin(); i != sr.end(); ++i) { res.push_back(i->GetReference()); } return res; } ModuleResource Module::GetResource(const std::string& path) const { if (d->resourceTreePtrs.empty()) { return ModuleResource(); } for (std::size_t i = 0; i < d->resourceTreePtrs.size(); ++i) { if (!d->resourceTreePtrs[i]->IsValid()) continue; ModuleResource result(path, d->resourceTreePtrs[i], d->resourceTreePtrs); if (result) return result; } return ModuleResource(); } std::vector Module::FindResources(const std::string& path, const std::string& filePattern, bool recurse) const { std::vector result; if (d->resourceTreePtrs.empty()) return result; for (std::size_t i = 0; i < d->resourceTreePtrs.size(); ++i) { if (!d->resourceTreePtrs[i]->IsValid()) continue; std::vector nodes; d->resourceTreePtrs[i]->FindNodes(path, filePattern, recurse, nodes); for (std::vector::iterator nodeIter = nodes.begin(); nodeIter != nodes.end(); ++nodeIter) { result.push_back(ModuleResource(*nodeIter, d->resourceTreePtrs[i], d->resourceTreePtrs)); } } return result; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const Module& module) { os << "Module[" << "id=" << module.GetModuleId() << ", loc=" << module.GetLocation() << ", name=" << module.GetName() << "]"; return os; } std::ostream& operator<<(std::ostream& os, Module const * module) { return operator<<(os, *module); } diff --git a/Core/CppMicroServices/src/module/usModule.h b/Core/CppMicroServices/src/module/usModule.h index b92e2239cb..bc6e4b36db 100644 --- a/Core/CppMicroServices/src/module/usModule.h +++ b/Core/CppMicroServices/src/module/usModule.h @@ -1,368 +1,369 @@ /*============================================================================= 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 USMODULE_H #define USMODULE_H #include "usModuleVersion.h" #include US_BEGIN_NAMESPACE class Any; class CoreModuleContext; struct ModuleInfo; class ModuleContext; class ModuleResource; class ModulePrivate; template class ServiceReference; typedef ServiceReference ServiceReferenceU; /** * \ingroup MicroServices * * Represents a CppMicroServices module. * *

* A %Module object is the access point to a CppMicroServices module. * Each CppMicroServices module has an associated %Module object. * *

* A module has unique identity, a long, chosen by the * framework. This identity does not change during the lifecycle of a module. * *

* A module can be in one of two states: *

    *
  • LOADED *
  • UNLOADED *
*

* You can determine the current state by using IsLoaded(). * *

* A module can only execute code when its state is LOADED. * An UNLOADED module is a * zombie and can only be reached because it was loaded before. However, * unloaded modules can be loaded again. * *

* The framework is the only entity that is allowed to create * %Module objects. * * @remarks This class is thread safe. */ class US_EXPORT Module { public: /** * Returns the property key for looking up this module's id. * The property value is of type \c long. * * @return The id property key. */ static const std::string& PROP_ID(); /** * Returns the property key for looking up this module's name. * The property value is of type \c std::string. * * @return The name property key. */ static const std::string& PROP_NAME(); /** * Returns the property key for looking up this module's * location the file system. * The property value is of type \c std::string. * * @return The location property key. */ static const std::string& PROP_LOCATION(); /** * Returns the property key with a value of \c module.version for looking * up this module's version identifier. * The property value is of type \c std::string. * * @return The version property key. */ static const std::string& PROP_VERSION(); /** * Returns the property key with a value of \c module.vendor for looking * up this module's vendor information. * The property value is of type \c std::string. * * @return The version property key. */ static const std::string& PROP_VENDOR(); /** * Returns the property key with a value of \c module.description for looking * up this module's description. * The property value is of type \c std::string. * * @return The version property key. */ static const std::string& PROP_DESCRIPTION(); /** * Returns the property key with a value of \c module.autoload_dir for looking * up this module's auto-load directory. * The property value is of type \c std::string. * * @return The version property key. */ static const std::string& PROP_AUTOLOAD_DIR(); ~Module(); /** * Returns this module's current state. * *

* A module can be in only one state at any time. * * @return true if the module is LOADED * false if it is UNLOADED */ bool IsLoaded() const; /** * Returns this module's {@link ModuleContext}. The returned * ModuleContext can be used by the caller to act on behalf * of this module. * *

* If this module is not in the LOADED state, then this * module has no valid ModuleContext. This method will * return 0 if this module has no valid * ModuleContext. * * @return A ModuleContext for this module or * 0 if this module has no valid * ModuleContext. */ ModuleContext* GetModuleContext() const; /** * Returns this module's unique identifier. This module is assigned a unique * identifier by the framework when it was loaded. * *

* A module's unique identifier has the following attributes: *

    *
  • Is unique. *
  • Is a long. *
  • Its value is not reused for another module, even after a module is * unloaded. *
  • Does not change while a module remains loaded. *
  • Does not change when a module is reloaded. *
* *

* This method continues to return this module's unique identifier while * this module is in the UNLOADED state. * * @return The unique identifier of this module. */ long GetModuleId() const; /** * Returns this module's location. * *

* The location is the full path to the module's shared library. * This method continues to return this module's location * while this module is in the UNLOADED state. * * @return The string representation of this module's location. */ std::string GetLocation() const; /** * Returns the name of this module as specified by the * US_CREATE_MODULE CMake macro. The module * name together with a version must identify a unique module. * *

* This method continues to return this module's name while * this module is in the UNLOADED state. * * @return The name of this module. */ std::string GetName() const; /** * Returns the version of this module as specified by the * US_INITIALIZE_MODULE CMake macro. If this module does not have a * specified version then {@link ModuleVersion::EmptyVersion} is returned. * *

* This method continues to return this module's version while * this module is in the UNLOADED state. * * @return The version of this module. */ ModuleVersion GetVersion() const; /** * Returns the value of the specified property for this module. The * method returns an empty Any if the property is not found. * * @param key The name of the requested property. * @return The value of the requested property, or an empty string * if the property is undefined. * * @sa GetPropertyKeys() * @sa \ref MicroServices_ModuleProperties */ Any GetProperty(const std::string& key) const; /** * Returns a list of top-level property keys for this module. * * @return A list of available property keys. * * @sa \ref MicroServices_ModuleProperties */ std::vector GetPropertyKeys() const; /** * Returns this module's ServiceReference list for all services it * has registered or an empty list if this module has no registered * services. * * The list is valid at the time of the call to this method, however, * as the framework is a very dynamic environment, services can be * modified or unregistered at anytime. * * @return A list of ServiceReference objects for services this * module has registered. */ std::vector GetRegisteredServices() const; /** * Returns this module's ServiceReference list for all services it is * using or returns an empty list if this module is not using any * services. A module is considered to be using a service if its use * count for that service is greater than zero. * * The list is valid at the time of the call to this method, however, * as the framework is a very dynamic environment, services can be * modified or unregistered at anytime. * * @return A list of ServiceReference objects for all services this * module is using. */ std::vector GetServicesInUse() const; /** * Returns the resource at the specified \c path in this module. * The specified \c path is always relative to the root of this module and may * begin with '/'. A path value of "/" indicates the root of this module. * * \note In case of other modules being statically linked into this module, * the \c path can be ambiguous and returns the first resource matching the * provided \c path according to the order of the static module names in the * #US_LOAD_IMPORTED_MODULES macro. * * @param path The path name of the resource. * @return A ModuleResource object for the given \c path. If the \c path cannot * be found in this module or the module's state is \c UNLOADED, an invalid * ModuleResource object is returned. */ ModuleResource GetResource(const std::string& path) const; /** * Returns resources in this module and its statically linked modules. * * This method is intended to be used to obtain configuration, setup, localization * and other information from this module. * * This method can either return only resources in the specified \c path or recurse * into subdirectories returning resources in the directory tree beginning at the * specified path. * * Examples: * \snippet uServices-resources/main.cpp 0 * * \note In case of modules statically linked into this module, the returned * ModuleResource objects can represent the same resource path, coming from * different static modules. The order of the ModuleResource objects in the * returned container matches the order of the static module names in the * #US_LOAD_IMPORTED_MODULES macro. * * @param path The path name in which to look. The path is always relative to the root * of this module and may begin with '/'. A path value of "/" indicates the root of this module. * @param filePattern The resource name pattern for selecting entries in the specified path. * The pattern is only matched against the last element of the resource path. Substring * matching is supported using the wildcard charachter ('*'). If \c filePattern is empty, * this is equivalent to "*" and matches all resources. * @param recurse If \c true, recurse into subdirectories. Otherwise only return resources * from the specified path. * @return A vector of ModuleResource objects for each matching entry. The objects are sorted * such that resources from this module are returned first followed by the resources from * statically linked modules in the load order as specified in #US_LOAD_IMPORTED_MODULES. */ std::vector FindResources(const std::string& path, const std::string& filePattern, bool recurse) const; private: + friend class CoreModuleActivator; friend class ModuleRegistry; friend class ServiceReferencePrivate; ModulePrivate* d; Module(); void Init(CoreModuleContext* coreCtx, ModuleInfo* info); void Uninit(); void Start(); void Stop(); // purposely not implemented Module(const Module &); Module& operator=(const Module&); }; US_END_NAMESPACE /** * \ingroup MicroServices */ US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(Module)& module); /** * \ingroup MicroServices */ US_EXPORT std::ostream& operator<<(std::ostream& os, US_PREPEND_NAMESPACE(Module) const * module); #endif // USMODULE_H diff --git a/Core/CppMicroServices/src/module/usModuleAbstractTracked.tpp b/Core/CppMicroServices/src/module/usModuleAbstractTracked.tpp index add70a7b1c..f3809cd50c 100644 --- a/Core/CppMicroServices/src/module/usModuleAbstractTracked.tpp +++ b/Core/CppMicroServices/src/module/usModuleAbstractTracked.tpp @@ -1,316 +1,316 @@ /*============================================================================= 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 US_BEGIN_NAMESPACE template const bool ModuleAbstractTracked::DEBUG_OUTPUT = false; template ModuleAbstractTracked::ModuleAbstractTracked() { closed = false; } template ModuleAbstractTracked::~ModuleAbstractTracked() { } template void ModuleAbstractTracked::SetInitial(const std::vector& initiallist) { std::copy(initiallist.begin(), initiallist.end(), std::back_inserter(initial)); if (DEBUG_OUTPUT) { for(typename std::list::const_iterator item = initial.begin(); item != initial.end(); ++item) { US_DEBUG << "ModuleAbstractTracked::setInitial: " << (*item); } } } template void ModuleAbstractTracked::TrackInitial() { while (true) { S item; { - typename Self::Lock l(this); + Lock(this); if (closed || (initial.size() == 0)) { /* * if there are no more initial items */ return; /* we are done */ } /* * move the first item from the initial list to the adding list * within this synchronized block. */ item = initial.front(); initial.pop_front(); if (TTT::IsValid(tracked[item])) { /* if we are already tracking this item */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackInitial[already tracked]: " << item; continue; /* skip this item */ } if (std::find(adding.begin(), adding.end(), item) != adding.end()) { /* * if this item is already in the process of being added. */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackInitial[already adding]: " << item; continue; /* skip this item */ } adding.push_back(item); } US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackInitial: " << item; TrackAdding(item, R()); /* * Begin tracking it. We call trackAdding * since we have already put the item in the * adding list. */ } } template void ModuleAbstractTracked::Close() { closed = true; } template void ModuleAbstractTracked::Track(S item, R related) { T object = TTT::DefaultValue(); { - typename Self::Lock l(this); + Lock(this); if (closed) { return; } object = tracked[item]; if (!TTT::IsValid(object)) { /* we are not tracking the item */ if (std::find(adding.begin(), adding.end(),item) != adding.end()) { /* if this item is already in the process of being added. */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::track[already adding]: " << item; return; } adding.push_back(item); /* mark this item is being added */ } else { /* we are currently tracking this item */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::track[modified]: " << item; Modified(); /* increment modification count */ } } if (!TTT::IsValid(object)) { /* we are not tracking the item */ TrackAdding(item, related); } else { /* Call customizer outside of synchronized region */ CustomizerModified(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to * let it propagate */ } } template void ModuleAbstractTracked::Untrack(S item, R related) { T object = TTT::DefaultValue(); { - typename Self::Lock l(this); + Lock(this); std::size_t initialSize = initial.size(); initial.remove(item); if (initialSize != initial.size()) { /* if this item is already in the list * of initial references to process */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::untrack[removed from initial]: " << item; return; /* we have removed it from the list and it will not be * processed */ } std::size_t addingSize = adding.size(); adding.remove(item); if (addingSize != adding.size()) { /* if the item is in the process of * being added */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::untrack[being added]: " << item; return; /* * in case the item is untracked while in the process of * adding */ } object = tracked[item]; /* * must remove from tracker before * calling customizer callback */ tracked.erase(item); if (!TTT::IsValid(object)) { /* are we actually tracking the item */ return; } Modified(); /* increment modification count */ } US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::untrack[removed]: " << item; /* Call customizer outside of synchronized region */ CustomizerRemoved(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to let it * propagate */ } template std::size_t ModuleAbstractTracked::Size() const { return tracked.size(); } template bool ModuleAbstractTracked::IsEmpty() const { return tracked.empty(); } template typename ModuleAbstractTracked::T ModuleAbstractTracked::GetCustomizedObject(S item) const { typename TrackingMap::const_iterator i = tracked.find(item); if (i != tracked.end()) return i->second; return T(); } template void ModuleAbstractTracked::GetTracked(std::vector& items) const { for (typename TrackingMap::const_iterator i = tracked.begin(); i != tracked.end(); ++i) { items.push_back(i->first); } } template void ModuleAbstractTracked::Modified() { trackingCount.Ref(); } template int ModuleAbstractTracked::GetTrackingCount() const { return trackingCount; } template void ModuleAbstractTracked::CopyEntries(TrackingMap& map) const { map.insert(tracked.begin(), tracked.end()); } template bool ModuleAbstractTracked::CustomizerAddingFinal(S item, const T& custom) { - typename Self::Lock l(this); + Lock(this); std::size_t addingSize = adding.size(); adding.remove(item); if (addingSize != adding.size() && !closed) { /* * if the item was not untracked during the customizer * callback */ if (TTT::IsValid(custom)) { tracked[item] = custom; Modified(); /* increment modification count */ this->NotifyAll(); /* notify any waiters */ } return false; } else { return true; } } template void ModuleAbstractTracked::TrackAdding(S item, R related) { US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackAdding:" << item; T object = TTT::DefaultValue(); bool becameUntracked = false; /* Call customizer outside of synchronized region */ try { object = CustomizerAdding(item, related); becameUntracked = this->CustomizerAddingFinal(item, object); } catch (...) { /* * If the customizer throws an exception, it will * propagate after the cleanup code. */ this->CustomizerAddingFinal(item, object); throw; } /* * The item became untracked during the customizer callback. */ if (becameUntracked && TTT::IsValid(object)) { US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackAdding[removed]: " << item; /* Call customizer outside of synchronized region */ CustomizerRemoved(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to * let it propagate */ } } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/module/usModuleAbstractTracked_p.h b/Core/CppMicroServices/src/module/usModuleAbstractTracked_p.h index 9bdb4f157b..426679e51a 100644 --- a/Core/CppMicroServices/src/module/usModuleAbstractTracked_p.h +++ b/Core/CppMicroServices/src/module/usModuleAbstractTracked_p.h @@ -1,293 +1,293 @@ /*============================================================================= 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 USMODULEABSTRACTTRACKED_H #define USMODULEABSTRACTTRACKED_H #include #include "usAtomicInt_p.h" #include "usAny.h" US_BEGIN_NAMESPACE /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. * * Abstract class to track items. If a Tracker is reused (closed then reopened), * then a new ModuleAbstractTracked object is used. This class acts as a map of tracked * item -> customized object. Subclasses of this class will act as the listener * object for the tracker. This class is used to synchronize access to the * tracked items. This is not a public class. It is only for use by the * implementation of the Tracker class. * * @tparam S The tracked item. It is the key. * @tparam T The value mapped to the tracked item. * @tparam R The reason the tracked item is being tracked or untracked. * @ThreadSafe */ template -class ModuleAbstractTracked : public US_DEFAULT_THREADING > +class ModuleAbstractTracked : public MultiThreaded { public: typedef typename TTT::TrackedType T; /* set this to true to compile in debug messages */ static const bool DEBUG_OUTPUT; // = false; typedef std::map TrackingMap; /** * ModuleAbstractTracked constructor. */ ModuleAbstractTracked(); virtual ~ModuleAbstractTracked(); /** * Set initial list of items into tracker before events begin to be * received. * * This method must be called from Tracker's open method while synchronized * on this object in the same synchronized block as the add listener call. * * @param list The initial list of items to be tracked. null * entries in the list are ignored. * @GuardedBy this */ void SetInitial(const std::vector& list); /** * Track the initial list of items. This is called after events can begin to * be received. * * This method must be called from Tracker's open method while not * synchronized on this object after the add listener call. * */ void TrackInitial(); /** * Called by the owning Tracker object when it is closed. */ void Close(); /** * Begin to track an item. * * @param item S to be tracked. * @param related Action related object. */ void Track(S item, R related); /** * Discontinue tracking the item. * * @param item S to be untracked. * @param related Action related object. */ void Untrack(S item, R related); /** * Returns the number of tracked items. * * @return The number of tracked items. * * @GuardedBy this */ std::size_t Size() const; /** * Returns if the tracker is empty. * * @return Whether the tracker is empty. * * @GuardedBy this */ bool IsEmpty() const; /** * Return the customized object for the specified item * * @param item The item to lookup in the map * @return The customized object for the specified item. * * @GuardedBy this */ T GetCustomizedObject(S item) const; /** * Return the list of tracked items. * * @return The tracked items. * @GuardedBy this */ void GetTracked(std::vector& items) const; /** * Increment the modification count. If this method is overridden, the * overriding method MUST call this method to increment the tracking count. * * @GuardedBy this */ virtual void Modified(); /** * Returns the tracking count for this ServiceTracker object. * * The tracking count is initialized to 0 when this object is opened. Every * time an item is added, modified or removed from this object the tracking * count is incremented. * * @GuardedBy this * @return The tracking count for this object. */ int GetTrackingCount() const; /** * Copy the tracked items and associated values into the specified map. * * @param map The map into which to copy the tracked items and associated * values. This map must not be a user provided map so that user code * is not executed while synchronized on this. * @return The specified map. * @GuardedBy this */ void CopyEntries(TrackingMap& map) const; /** * Call the specific customizer adding method. This method must not be * called while synchronized on this object. * * @param item S to be tracked. * @param related Action related object. * @return Customized object for the tracked item or null if * the item is not to be tracked. */ virtual T CustomizerAdding(S item, const R& related) = 0; /** * Call the specific customizer modified method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ virtual void CustomizerModified(S item, const R& related, T object) = 0; /** * Call the specific customizer removed method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ virtual void CustomizerRemoved(S item, const R& related, T object) = 0; /** * List of items in the process of being added. This is used to deal with * nesting of events. Since events may be synchronously delivered, events * can be nested. For example, when processing the adding of a service and * the customizer causes the service to be unregistered, notification to the * nested call to untrack that the service was unregistered can be made to * the track method. * * Since the std::vector implementation is not synchronized, all access to * this list must be protected by the same synchronized object for * thread-safety. * * @GuardedBy this */ std::list adding; /** * true if the tracked object is closed. * * This field is volatile because it is set by one thread and read by * another. */ volatile bool closed; /** * Initial list of items for the tracker. This is used to correctly process * the initial items which could be modified before they are tracked. This * is necessary since the initial set of tracked items are not "announced" * by events and therefore the event which makes the item untracked could be * delivered before we track the item. * * An item must not be in both the initial and adding lists at the same * time. An item must be moved from the initial list to the adding list * "atomically" before we begin tracking it. * * Since the LinkedList implementation is not synchronized, all access to * this list must be protected by the same synchronized object for * thread-safety. * * @GuardedBy this */ std::list initial; /** * Common logic to add an item to the tracker used by track and * trackInitial. The specified item must have been placed in the adding list * before calling this method. * * @param item S to be tracked. * @param related Action related object. */ void TrackAdding(S item, R related); private: typedef ModuleAbstractTracked Self; /** * Map of tracked items to customized objects. * * @GuardedBy this */ TrackingMap tracked; /** * Modification count. This field is initialized to zero and incremented by * modified. * * @GuardedBy this */ AtomicInt trackingCount; bool CustomizerAddingFinal(S item, const T& custom); }; US_END_NAMESPACE #include "usModuleAbstractTracked.tpp" #endif // USMODULEABSTRACTTRACKED_H diff --git a/Core/CppMicroServices/src/module/usModuleContext.cpp b/Core/CppMicroServices/src/module/usModuleContext.cpp index de01d5658e..e00e39a2b0 100644 --- a/Core/CppMicroServices/src/module/usModuleContext.cpp +++ b/Core/CppMicroServices/src/module/usModuleContext.cpp @@ -1,161 +1,168 @@ /*============================================================================= 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 "usModuleContext.h" #include "usModuleRegistry.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistry_p.h" #include "usServiceReferenceBasePrivate.h" US_BEGIN_NAMESPACE class ModuleContextPrivate { public: ModuleContextPrivate(ModulePrivate* module) : module(module) {} ModulePrivate* module; }; ModuleContext::ModuleContext(ModulePrivate* module) : d(new ModuleContextPrivate(module)) {} ModuleContext::~ModuleContext() { delete d; } Module* ModuleContext::GetModule() const { return d->module->q; } Module* ModuleContext::GetModule(long id) const { - return ModuleRegistry::GetModule(id); + return d->module->coreCtx->moduleHooks.FilterModule(this, ModuleRegistry::GetModule(id)); } -void ModuleContext::GetModules(std::vector& modules) const +Module*ModuleContext::GetModule(const std::string& name) { - ModuleRegistry::GetModules(modules); + return ModuleRegistry::GetModule(name); +} + +std::vector ModuleContext::GetModules() const +{ + std::vector modules = ModuleRegistry::GetModules(); + d->module->coreCtx->moduleHooks.FilterModules(this, modules); + return modules; } ServiceRegistrationU ModuleContext::RegisterService(const InterfaceMap& service, const ServiceProperties& properties) { return d->module->coreCtx->services.RegisterService(d->module, service, properties); } std::vector ModuleContext::GetServiceReferences(const std::string& clazz, const std::string& filter) { std::vector result; std::vector refs; d->module->coreCtx->services.Get(clazz, filter, d->module, refs); for (std::vector::const_iterator iter = refs.begin(); iter != refs.end(); ++iter) { result.push_back(ServiceReferenceU(*iter)); } return result; } ServiceReferenceU ModuleContext::GetServiceReference(const std::string& clazz) { return d->module->coreCtx->services.Get(d->module, clazz); } void* ModuleContext::GetService(const ServiceReferenceBase& reference) { if (!reference) { throw std::invalid_argument("Default constructed ServiceReference is not a valid input to GetService()"); } return reference.d->GetService(d->module->q); } InterfaceMap ModuleContext::GetService(const ServiceReferenceU& reference) { if (!reference) { throw std::invalid_argument("Default constructed ServiceReference is not a valid input to GetService()"); } return reference.d->GetServiceInterfaceMap(d->module->q); } bool ModuleContext::UngetService(const ServiceReferenceBase& reference) { ServiceReferenceBase ref = reference; return ref.d->UngetService(d->module->q, true); } void ModuleContext::AddServiceListener(const ServiceListener& delegate, const std::string& filter) { d->module->coreCtx->listeners.AddServiceListener(this, delegate, NULL, filter); } void ModuleContext::RemoveServiceListener(const ServiceListener& delegate) { d->module->coreCtx->listeners.RemoveServiceListener(this, delegate, NULL); } void ModuleContext::AddModuleListener(const ModuleListener& delegate) { d->module->coreCtx->listeners.AddModuleListener(this, delegate, NULL); } void ModuleContext::RemoveModuleListener(const ModuleListener& delegate) { d->module->coreCtx->listeners.RemoveModuleListener(this, delegate, NULL); } void ModuleContext::AddServiceListener(const ServiceListener& delegate, void* data, const std::string &filter) { d->module->coreCtx->listeners.AddServiceListener(this, delegate, data, filter); } void ModuleContext::RemoveServiceListener(const ServiceListener& delegate, void* data) { d->module->coreCtx->listeners.RemoveServiceListener(this, delegate, data); } void ModuleContext::AddModuleListener(const ModuleListener& delegate, void* data) { d->module->coreCtx->listeners.AddModuleListener(this, delegate, data); } void ModuleContext::RemoveModuleListener(const ModuleListener& delegate, void* data) { d->module->coreCtx->listeners.RemoveModuleListener(this, delegate, data); } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/module/usModuleContext.h b/Core/CppMicroServices/src/module/usModuleContext.h index 0ec6aaaabb..04023703b0 100644 --- a/Core/CppMicroServices/src/module/usModuleContext.h +++ b/Core/CppMicroServices/src/module/usModuleContext.h @@ -1,831 +1,838 @@ /*============================================================================= 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 USMODULECONTEXT_H_ #define USMODULECONTEXT_H_ // TODO: Replace includes with forward directives! -#include "usUtils_p.h" +#include "usListenerFunctors_p.h" #include "usServiceInterface.h" #include "usServiceEvent.h" #include "usServiceRegistration.h" #include "usServiceException.h" #include "usModuleEvent.h" US_BEGIN_NAMESPACE typedef US_SERVICE_LISTENER_FUNCTOR ServiceListener; typedef US_MODULE_LISTENER_FUNCTOR ModuleListener; class ModuleContextPrivate; class ServiceFactory; template class ServiceObjects; /** * \ingroup MicroServices * * A module's execution context within the framework. The context is used to * grant access to other methods so that this module can interact with the * Micro Services Framework. * *

* ModuleContext methods allow a module to: *

    *
  • Subscribe to events published by the framework. *
  • Register service objects with the framework service registry. *
  • Retrieve ServiceReferences from the framework service * registry. *
  • Get and release service objects for a referenced service. *
  • Get the list of modules loaded in the framework. *
  • Get the {@link Module} object for a module. *
* *

* A ModuleContext object will be created and provided to the * module associated with this context when it is loaded using the * {@link ModuleActivator::Load} method. The same ModuleContext * object will be passed to the module associated with this context when it is * unloaded using the {@link ModuleActivator::Unload} method. A * ModuleContext object is generally for the private use of its * associated module and is not meant to be shared with other modules in the * module environment. * *

* The Module object associated with a ModuleContext * object is called the context module. * *

* The ModuleContext object is only valid during the execution of * its context module; that is, during the period when the context module * is loaded. If the ModuleContext * object is used subsequently, a std::logic_error is * thrown. The ModuleContext object is never reused after * its context module is unloaded. * *

* The framework is the only entity that can create ModuleContext * objects. * * @remarks This class is thread safe. */ class US_EXPORT ModuleContext { public: ~ModuleContext(); /** * Returns the Module object associated with this * ModuleContext. This module is called the context module. * * @return The Module object associated with this * ModuleContext. * @throws std::logic_error If this ModuleContext is no * longer valid. */ Module* GetModule() const; /** * Returns the module with the specified identifier. * * @param id The identifier of the module to retrieve. * @return A Module object or 0 if the * identifier does not match any previously loaded module. */ Module* GetModule(long id) const; + /** + * Get the module that with the specified module name. + * + * @param name The name of the module to get. + * @return The requested \c Module or \c NULL. + */ + Module* GetModule(const std::string& name); /** * Returns a list of all known modules. *

* This method returns a list of all modules loaded in the module * environment at the time of the call to this method. This list will * also contain modules which might already have been unloaded. * * @param modules A std::vector of Module objects which * will hold one object per known module. */ - void GetModules(std::vector& modules) const; + std::vector GetModules() const; /** * Registers the specified service object with the specified properties * under the specified class names into the framework. A * ServiceRegistration object is returned. The * ServiceRegistration object is for the private use of the * module registering the service and should not be shared with other * modules. The registering module is defined to be the context module. * Other modules can locate the service by using either the * {@link #GetServiceReferences} or {@link #GetServiceReference} method. * *

* A module can register a service object that implements the * ServiceFactory or PrototypeServiceFactory interface to have more * flexibility in providing service objects to other modules. * *

* The following steps are taken when registering a service: *

    *
  1. The framework adds the following service properties to the service * properties from the specified ServiceProperties (which may be * omitted):
    * A property named ServiceConstants#SERVICE_ID() identifying the * registration number of the service
    * A property named ServiceConstants#OBJECTCLASS() containing all the * specified classes.
    * A property named ServiceConstants#SERVICE_SCOPE() identifying the scope * of the service.
    * Properties with these names in the specified ServiceProperties will * be ignored. *
  2. The service is added to the framework service registry and may now be * used by other modules. *
  3. A service event of type ServiceEvent#REGISTERED is fired. *
  4. A ServiceRegistration object for this registration is * returned. *
* * @note This is a low-level method and should normally not be used directly. * Use one of the templated RegisterService methods instead. * * @param service The service object, which is a map of interface identifiers * to raw service pointers. * @param properties The properties for this service. The keys in the * properties object must all be std::string objects. See * {@link ServiceConstants} for a list of standard service property keys. * Changes should not be made to this object after calling this * method. To update the service's properties the * {@link ServiceRegistration::SetProperties} method must be called. * The set of properties may be omitted if the service has * no properties. * @return A ServiceRegistration object for use by the module * registering the service to update the service's properties or to * unregister the service. * * @throws std::invalid_argument If one of the following is true: *
    *
  • service is 0. *
  • properties contains case variants of the same key name. *
* @throws std::logic_error If this ModuleContext is no longer valid. * * @see ServiceRegistration * @see ServiceFactory * @see PrototypeServiceFactory */ ServiceRegistrationU RegisterService(const InterfaceMap& service, const ServiceProperties& properties = ServiceProperties()); /** * Registers the specified service object with the specified properties * using the specified template argument with the framework. * *

* This method is provided as a convenience when service will only be registered under * a single class name whose type is available to the caller. It is otherwise identical to * RegisterService(const InterfaceMap&, const ServiceProperties&) but should be preferred * since it avoids errors in the string literal identifying the class name or interface identifier. * * Example usage: * \snippet uServices-registration/main.cpp 1-1 * \snippet uServices-registration/main.cpp 1-2 * * @tparam S The type under which the service can be located. * @param service The service object or a ServiceFactory object. * @param properties The properties for this service. * @return A ServiceRegistration object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If the service type \c S is invalid or the * \c service object is NULL. * * @see RegisterService(const InterfaceMap&, const ServiceProperties&) */ template ServiceRegistration RegisterService(S* service, const ServiceProperties& properties = ServiceProperties()) { InterfaceMap servicePointers = MakeInterfaceMap(service); return RegisterService(servicePointers, properties); } /** * Registers the specified service object with the specified properties * using the specified template argument with the framework. * *

* This method is provided as a convenience when registering a service under * two interface classes whose type is available to the caller. It is otherwise identical to * RegisterService(const InterfaceMap&, const ServiceProperties&) but should be preferred * since it avoids errors in the string literal identifying the class name or interface identifier. * * Example usage: * \snippet uServices-registration/main.cpp 2-1 * \snippet uServices-registration/main.cpp 2-2 * * @tparam I1 The first interface type under which the service can be located. * @tparam I2 The second interface type under which the service can be located. * @param impl The service object or a ServiceFactory object. * @param properties The properties for this service. * @return A ServiceRegistration object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If the service type \c S is invalid or the * \c service object is NULL. * * @see RegisterService(const InterfaceMap&, const ServiceProperties&) */ template ServiceRegistration RegisterService(Impl* impl, const ServiceProperties& properties = ServiceProperties()) { InterfaceMap servicePointers = MakeInterfaceMap(impl); return RegisterService(servicePointers, properties); } /** * Registers the specified service object with the specified properties * using the specified template argument with the framework. * *

* This method is identical to the RegisterService(Impl*, const ServiceProperties&) * method except that it supports three service interface types. * * @tparam I1 The first interface type under which the service can be located. * @tparam I2 The second interface type under which the service can be located. * @tparam I3 The third interface type under which the service can be located. * @param impl The service object or a ServiceFactory object. * @param properties The properties for this service. * @return A ServiceRegistration object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If the service type \c S is invalid or the * \c service object is NULL. * * @see RegisterService(const InterfaceMap&, const ServiceProperties&) */ template ServiceRegistration RegisterService(Impl* impl, const ServiceProperties& properties = ServiceProperties()) { InterfaceMap servicePointers = MakeInterfaceMap(impl); return RegisterService(servicePointers, properties); } /** * Registers the specified service factory as a service with the specified properties * using the specified template argument as service interface type with the framework. * *

* This method is provided as a convenience when factory will only be registered under * a single class name whose type is available to the caller. It is otherwise identical to * RegisterService(const InterfaceMap&, const ServiceProperties&) but should be preferred * since it avoids errors in the string literal identifying the class name or interface identifier. * * Example usage: * \snippet uServices-registration/main.cpp 1-1 * \snippet uServices-registration/main.cpp f1 * * @tparam S The type under which the service can be located. * @param factory The ServiceFactory or PrototypeServiceFactory object. * @param properties The properties for this service. * @return A ServiceRegistration object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If the service type \c S is invalid or the * \c service factory object is NULL. * * @see RegisterService(const InterfaceMap&, const ServiceProperties&) */ template ServiceRegistration RegisterService(ServiceFactory* factory, const ServiceProperties& properties = ServiceProperties()) { InterfaceMap servicePointers = MakeInterfaceMap(factory); return RegisterService(servicePointers, properties); } /** * Registers the specified service factory as a service with the specified properties * using the specified template argument as service interface type with the framework. * *

* This method is identical to the RegisterService(ServiceFactory*, const ServiceProperties&) * method except that it supports two service interface types. * * Example usage: * \snippet uServices-registration/main.cpp 2-1 * \snippet uServices-registration/main.cpp f2 * * @tparam I1 The first interface type under which the service can be located. * @tparam I2 The second interface type under which the service can be located. * @param factory The ServiceFactory or PrototypeServiceFactory object. * @param properties The properties for this service. * @return A ServiceRegistration object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If the service type \c S is invalid or the * \c service factory object is NULL. * * @see RegisterService(const InterfaceMap&, const ServiceProperties&) */ template ServiceRegistration RegisterService(ServiceFactory* factory, const ServiceProperties& properties = ServiceProperties()) { InterfaceMap servicePointers = MakeInterfaceMap(factory); return RegisterService(servicePointers, properties); } /** * Registers the specified service factory as a service with the specified properties * using the specified template argument as service interface type with the framework. * *

* This method is identical to the RegisterService(ServiceFactory*, const ServiceProperties&) * method except that it supports three service interface types. * * @tparam I1 The first interface type under which the service can be located. * @tparam I2 The second interface type under which the service can be located. * @tparam I3 The third interface type under which the service can be located. * @param factory The ServiceFactory or PrototypeServiceFactory object. * @param properties The properties for this service. * @return A ServiceRegistration object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If the service type \c S is invalid or the * \c service factory object is NULL. * * @see RegisterService(const InterfaceMap&, const ServiceProperties&) */ template ServiceRegistration RegisterService(ServiceFactory* factory, const ServiceProperties& properties = ServiceProperties()) { InterfaceMap servicePointers = MakeInterfaceMap(factory); return RegisterService(servicePointers, properties); } /** * Returns a list of ServiceReference objects. The returned * list contains services that * were registered under the specified class and match the specified filter * expression. * *

* The list is valid at the time of the call to this method. However since * the Micro Services framework is a very dynamic environment, services can be modified or * unregistered at any time. * *

* The specified filter expression is used to select the * registered services whose service properties contain keys and values * which satisfy the filter expression. See LDAPFilter for a description * of the filter syntax. If the specified filter is * empty, all registered services are considered to match the * filter. If the specified filter expression cannot be parsed, * an std::invalid_argument will be thrown with a human readable * message where the filter became unparsable. * *

* The result is a list of ServiceReference objects for all * services that meet all of the following conditions: *

    *
  • If the specified class name, clazz, is not * empty, the service must have been registered with the * specified class name. The complete list of class names with which a * service was registered is available from the service's * {@link ServiceConstants#OBJECTCLASS() objectClass} property. *
  • If the specified filter is not empty, the * filter expression must match the service. *
* * @param clazz The class name with which the service was registered or * an empty string for all services. * @param filter The filter expression or empty for all * services. * @return A list of ServiceReference objects or * an empty list if no services are registered which satisfy the * search. * @throws std::invalid_argument If the specified filter * contains an invalid filter expression that cannot be parsed. * @throws std::logic_error If this ModuleContext is no longer valid. */ std::vector GetServiceReferences(const std::string& clazz, const std::string& filter = std::string()); /** * Returns a list of ServiceReference objects. The returned * list contains services that * were registered under the interface id of the template argument S * and match the specified filter expression. * *

* This method is identical to GetServiceReferences(const std::string&, const std::string&) except that * the class name for the service object is automatically deduced from the template argument. * * @tparam S The type under which the requested service objects must have been registered. * @param filter The filter expression or empty for all * services. * @return A list of ServiceReference objects or * an empty list if no services are registered which satisfy the * search. * @throws std::invalid_argument If the specified filter * contains an invalid filter expression that cannot be parsed. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If the service type \c S is invalid. * * @see GetServiceReferences(const std::string&, const std::string&) */ template std::vector > GetServiceReferences(const std::string& filter = std::string()) { const char* clazz = us_service_interface_iid(); if (clazz == 0) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); typedef std::vector BaseVectorT; BaseVectorT serviceRefs = GetServiceReferences(std::string(clazz), filter); std::vector > result; for(BaseVectorT::const_iterator i = serviceRefs.begin(); i != serviceRefs.end(); ++i) { result.push_back(ServiceReference(*i)); } return result; } /** * Returns a ServiceReference object for a service that * implements and was registered under the specified class. * *

* The returned ServiceReference object is valid at the time of * the call to this method. However as the Micro Services framework is a very dynamic * environment, services can be modified or unregistered at any time. * *

* This method is the same as calling * {@link ModuleContext::GetServiceReferences(const std::string&, const std::string&)} with an * empty filter expression. It is provided as a convenience for * when the caller is interested in any service that implements the * specified class. *

* If multiple such services exist, the service with the highest ranking (as * specified in its ServiceConstants::SERVICE_RANKING() property) is returned. *

* If there is a tie in ranking, the service with the lowest service ID (as * specified in its ServiceConstants::SERVICE_ID() property); that is, the * service that was registered first is returned. * * @param clazz The class name with which the service was registered. * @return A ServiceReference object, or an invalid ServiceReference if * no services are registered which implement the named class. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException If no service was registered under the given class name. * * @see #GetServiceReferences(const std::string&, const std::string&) */ ServiceReferenceU GetServiceReference(const std::string& clazz); /** * Returns a ServiceReference object for a service that * implements and was registered under the specified template class argument. * *

* This method is identical to GetServiceReference(const std::string&) except that * the class name for the service object is automatically deduced from the template argument. * * @tparam S The type under which the requested service must have been registered. * @return A ServiceReference object, or an invalid ServiceReference if * no services are registered which implement the type S. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws ServiceException It no service was registered under the given class name. * @see #GetServiceReference(const std::string&) * @see #GetServiceReferences(const std::string&) */ template ServiceReference GetServiceReference() { const char* clazz = us_service_interface_iid(); if (clazz == 0) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); return ServiceReference(GetServiceReference(std::string(clazz))); } /** * Returns the service object referenced by the specified * ServiceReferenceBase object. *

* A module's use of a service is tracked by the module's use count of that * service. Each time a service's service object is returned by * {@link #GetService(const ServiceReference&)} the context module's use count for * that service is incremented by one. Each time the service is released by * {@link #UngetService(const ServiceReferenceBase&)} the context module's use count * for that service is decremented by one. *

* When a module's use count for a service drops to zero, the module should * no longer use that service. * *

* This method will always return 0 when the service * associated with this reference has been unregistered. * *

* The following steps are taken to get the service object: *

    *
  1. If the service has been unregistered, 0 is returned. *
  2. The context module's use count for this service is incremented by * one. *
  3. If the context module's use count for the service is currently one * and the service was registered with an object implementing the * ServiceFactory interface, the * {@link ServiceFactory::GetService} method is * called to create a service object for the context module. This service * object is cached by the framework. While the context module's use count * for the service is greater than zero, subsequent calls to get the * services's service object for the context module will return the cached * service object.
    * If the ServiceFactory object throws an * exception, 0 is returned and a warning is logged. *
  4. The service object for the service is returned. *
* * @param reference A reference to the service. * @return A service object for the service associated with * reference or 0 if the service is not * registered or the ServiceFactory threw * an exception. * @throws std::logic_error If this ModuleContext is no * longer valid. * @throws std::invalid_argument If the specified * ServiceReferenceBase is invalid (default constructed). * @see #UngetService(const ServiceReferenceBase&) * @see ServiceFactory */ void* GetService(const ServiceReferenceBase& reference); InterfaceMap GetService(const ServiceReferenceU& reference); /** * Returns the service object referenced by the specified * ServiceReference object. *

* This is a convenience method which is identical to void* GetService(const ServiceReferenceBase&) * except that it casts the service object to the supplied template argument type * * @tparam S The type the service object will be cast to. * @return A service object for the service associated with * reference or 0 if the service is not * registered, the ServiceFactory threw * an exception or the service could not be casted to the desired type. * @throws std::logic_error If this ModuleContext is no * longer valid. * @throws std::invalid_argument If the specified * ServiceReference is invalid (default constructed). * @see #GetService(const ServiceReferenceBase&) * @see #UngetService(const ServiceReferenceBase&) * @see ServiceFactory */ template S* GetService(const ServiceReference& reference) { const ServiceReferenceBase& baseRef = reference; return reinterpret_cast(GetService(baseRef)); } /** * Returns the ServiceObjects object for the service referenced by the specified * ServiceReference object. The ServiceObjects object can be used to obtain * multiple service objects for services with prototype scope. For services with * singleton or module scope, the ServiceObjects::GetService() method behaves * the same as the GetService(const ServiceReference&) method and the * ServiceObjects::UngetService(const ServiceReferenceBase&) method behaves the * same as the UngetService(const ServiceReferenceBase&) method. That is, only one, * use-counted service object is available from the ServiceObjects object. * * @tparam S Type of Service. * @param reference A reference to the service. * @return A ServiceObjects object for the service associated with the specified * reference or an invalid instance if the service is not registered. * @throws std::logic_error If this ModuleContext is no longer valid. * @throws std::invalid_argument If the specified ServiceReference is invalid * (default constructed or the service has been unregistered) * * @see PrototypeServiceFactory */ template ServiceObjects GetServiceObjects(const ServiceReference& reference) { return ServiceObjects(this, reference); } /** * Releases the service object referenced by the specified * ServiceReference object. If the context module's use count * for the service is zero, this method returns false. * Otherwise, the context modules's use count for the service is decremented * by one. * *

* The service's service object should no longer be used and all references * to it should be destroyed when a module's use count for the service drops * to zero. * *

* The following steps are taken to unget the service object: *

    *
  1. If the context module's use count for the service is zero or the * service has been unregistered, false is returned. *
  2. The context module's use count for this service is decremented by * one. *
  3. If the context module's use count for the service is currently zero * and the service was registered with a ServiceFactory object, * the ServiceFactory#UngetService * method is called to release the service object for the context module. *
  4. true is returned. *
* * @param reference A reference to the service to be released. * @return false if the context module's use count for the * service is zero or if the service has been unregistered; * true otherwise. * @throws std::logic_error If this ModuleContext is no * longer valid. * @see #GetService * @see ServiceFactory */ bool UngetService(const ServiceReferenceBase& reference); void AddServiceListener(const ServiceListener& delegate, const std::string& filter = std::string()); void RemoveServiceListener(const ServiceListener& delegate); void AddModuleListener(const ModuleListener& delegate); void RemoveModuleListener(const ModuleListener& delegate); /** * Adds the specified callback with the * specified filter to the context modules's list of listeners. * See LDAPFilter for a description of the filter syntax. Listeners * are notified when a service has a lifecycle state change. * *

* You must take care to remove registered listeners befor the receiver * object is destroyed. However, the Micro Services framework takes care * of removing all listeners registered by this context module's classes * after the module is unloaded. * *

* If the context module's list of listeners already contains a pair (r,c) * of receiver and callback such that * (r == receiver && c == callback), then this * method replaces that callback's filter (which may be empty) * with the specified one (which may be empty). * *

* The callback is called if the filter criteria is met. To filter based * upon the class of the service, the filter should reference the * ServiceConstants#OBJECTCLASS() property. If filter is * empty, all services are considered to match the filter. * *

* When using a filter, it is possible that the * ServiceEvents for the complete lifecycle of a service * will not be delivered to the callback. For example, if the * filter only matches when the property x has * the value 1, the callback will not be called if the * service is registered with the property x not set to the * value 1. Subsequently, when the service is modified * setting property x to the value 1, the * filter will match and the callback will be called with a * ServiceEvent of type MODIFIED. Thus, the * callback will not be called with a ServiceEvent of type * REGISTERED. * * @tparam R The type of the receiver (containing the member function to be called) * @param receiver The object to connect to. * @param callback The member function pointer to call. * @param filter The filter criteria. * @throws std::invalid_argument If filter contains an * invalid filter string that cannot be parsed. * @throws std::logic_error If this ModuleContext is no * longer valid. * @see ServiceEvent * @see RemoveServiceListener() */ template void AddServiceListener(R* receiver, void(R::*callback)(const ServiceEvent), const std::string& filter = std::string()) { AddServiceListener(ServiceListenerMemberFunctor(receiver, callback), static_cast(receiver), filter); } /** * Removes the specified callback from the context module's * list of listeners. * *

* If the (receiver,callback) pair is not contained in this * context module's list of listeners, this method does nothing. * * @tparam R The type of the receiver (containing the member function to be removed) * @param receiver The object from which to disconnect. * @param callback The member function pointer to remove. * @throws std::logic_error If this ModuleContext is no * longer valid. * @see AddServiceListener() */ template void RemoveServiceListener(R* receiver, void(R::*callback)(const ServiceEvent)) { RemoveServiceListener(ServiceListenerMemberFunctor(receiver, callback), static_cast(receiver)); } /** * Adds the specified callback to the context modules's list * of listeners. Listeners are notified when a module has a lifecycle * state change. * *

* If the context module's list of listeners already contains a pair (r,c) * of receiver and callback such that * (r == receiver && c == callback), then this method does nothing. * * @tparam R The type of the receiver (containing the member function to be called) * @param receiver The object to connect to. * @param callback The member function pointer to call. * @throws std::logic_error If this ModuleContext is no * longer valid. * @see ModuleEvent */ template void AddModuleListener(R* receiver, void(R::*callback)(const ModuleEvent)) { AddModuleListener(ModuleListenerMemberFunctor(receiver, callback), static_cast(receiver)); } /** * Removes the specified callback from the context module's * list of listeners. * *

* If the (receiver,callback) pair is not contained in this * context module's list of listeners, this method does nothing. * * @tparam R The type of the receiver (containing the member function to be removed) * @param receiver The object from which to disconnect. * @param callback The member function pointer to remove. * @throws std::logic_error If this ModuleContext is no * longer valid. * @see AddModuleListener() */ template void RemoveModuleListener(R* receiver, void(R::*callback)(const ModuleEvent)) { RemoveModuleListener(ModuleListenerMemberFunctor(receiver, callback), static_cast(receiver)); } private: friend class Module; friend class ModulePrivate; ModuleContext(ModulePrivate* module); // purposely not implemented ModuleContext(const ModuleContext&); ModuleContext& operator=(const ModuleContext&); void AddServiceListener(const ServiceListener& delegate, void* data, const std::string& filter); void RemoveServiceListener(const ServiceListener& delegate, void* data); void AddModuleListener(const ModuleListener& delegate, void* data); void RemoveModuleListener(const ModuleListener& delegate, void* data); ModuleContextPrivate * const d; }; US_END_NAMESPACE #endif /* USMODULECONTEXT_H_ */ diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp b/Core/CppMicroServices/src/module/usModuleEventHook.cpp similarity index 75% copy from Core/CppMicroServices/src/module/usCoreModuleContext.cpp copy to Core/CppMicroServices/src/module/usModuleEventHook.cpp index b2d4d9896c..fdfbe5d70d 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp +++ b/Core/CppMicroServices/src/module/usModuleEventHook.cpp @@ -1,46 +1,30 @@ /*============================================================================= 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 "usCoreModuleContext_p.h" - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4355) -#endif +#include "usModuleEventHook.h" US_BEGIN_NAMESPACE -CoreModuleContext::CoreModuleContext() - : services(this) -{ -} - -CoreModuleContext::~CoreModuleContext() +ModuleEventHook::~ModuleEventHook() { } US_END_NAMESPACE - -#ifdef _MSC_VER -#pragma warning(pop) -#endif diff --git a/Core/CppMicroServices/src/module/usModuleEventHook.h b/Core/CppMicroServices/src/module/usModuleEventHook.h new file mode 100644 index 0000000000..9e8f33c755 --- /dev/null +++ b/Core/CppMicroServices/src/module/usModuleEventHook.h @@ -0,0 +1,70 @@ +/*============================================================================= + + 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 USMODULEEVENTHOOK_H +#define USMODULEEVENTHOOK_H + +#include "usServiceInterface.h" +#include "usShrinkableVector.h" + +US_BEGIN_NAMESPACE + +class ModuleContext; +class ModuleEvent; + +/** + * Module Event Hook Service. + * + *

+ * Modules registering this service will be called during module lifecycle + * (loading, loaded, unloading, and unloaded) operations. + * + * @remarks Implementations of this interface are required to be thread-safe. + */ +struct US_EXPORT ModuleEventHook +{ + + virtual ~ModuleEventHook(); + + /** + * Module event hook method. This method is called prior to module event + * delivery when a module is loading, loaded, unloading, or unloaded. + * This method can filter the modules which receive the event. + *

+ * This method is called one and only one time for + * each module event generated, this includes module events which are + * generated when there are no module listeners registered. + * + * @param event The module event to be delivered. + * @param contexts A list of Module Contexts for modules which have + * listeners to which the specified event will be delivered. The + * implementation of this method may remove module contexts from the + * list to prevent the event from being delivered to the + * associated modules. + */ + virtual void Event(const ModuleEvent& event, ShrinkableVector& contexts) = 0; +}; + +US_END_NAMESPACE + +US_DECLARE_SERVICE_INTERFACE(us::ModuleEventHook, "org.cppmicroservices.ModuleEventHook/2.0.0") + +#endif // USMODULEEVENTHOOK_H diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp b/Core/CppMicroServices/src/module/usModuleFindHook.cpp similarity index 75% copy from Core/CppMicroServices/src/module/usCoreModuleContext.cpp copy to Core/CppMicroServices/src/module/usModuleFindHook.cpp index b2d4d9896c..f146504bc6 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp +++ b/Core/CppMicroServices/src/module/usModuleFindHook.cpp @@ -1,46 +1,30 @@ /*============================================================================= 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 "usCoreModuleContext_p.h" - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4355) -#endif +#include "usModuleFindHook.h" US_BEGIN_NAMESPACE -CoreModuleContext::CoreModuleContext() - : services(this) -{ -} - -CoreModuleContext::~CoreModuleContext() +ModuleFindHook::~ModuleFindHook() { } US_END_NAMESPACE - -#ifdef _MSC_VER -#pragma warning(pop) -#endif diff --git a/Core/CppMicroServices/src/module/usModuleFindHook.h b/Core/CppMicroServices/src/module/usModuleFindHook.h new file mode 100644 index 0000000000..8b9d6c3c5b --- /dev/null +++ b/Core/CppMicroServices/src/module/usModuleFindHook.h @@ -0,0 +1,71 @@ +/*============================================================================= + + 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 USMODULEFINDHOOK_H +#define USMODULEFINDHOOK_H + +#include "usServiceInterface.h" +#include "usShrinkableVector.h" + +US_BEGIN_NAMESPACE + +class Module; +class ModuleContext; + +/** + * Module Context Hook Service. + * + *

+ * Modules registering this service will be called during module find + * (get modules) operations. + * + * @remarks Implementations of this interface are required to be thread-safe. + */ +struct US_EXPORT ModuleFindHook +{ + + virtual ~ModuleFindHook(); + + /** + * Find hook method. This method is called for module find operations + * using ModuleContext::GetBundle(long) + * and ModuleContext::GetModules() methods. The find method can + * filter the result of the find operation. + * + * \note A find operation using the ModuleContext::GetModule(const std::string&) + * method does not cause the find method to be called, neither does any + * call to the static methods of the ModuleRegistry class. + * + * @param context The module context of the module performing the find + * operation. + * @param modules A list of Modules to be returned as a result of the + * find operation. The implementation of this method may remove + * modules from the list to prevent the modules from being + * returned to the module performing the find operation. + */ + virtual void Find(const ModuleContext* context, ShrinkableVector& modules) = 0; +}; + +US_END_NAMESPACE + +US_DECLARE_SERVICE_INTERFACE(us::ModuleFindHook, "org.cppmicroservices.ModuleFindHook/2.0.0") + +#endif // USMODULEFINDHOOK_H diff --git a/Core/CppMicroServices/src/module/usModuleHooks.cpp b/Core/CppMicroServices/src/module/usModuleHooks.cpp new file mode 100644 index 0000000000..def2b12a59 --- /dev/null +++ b/Core/CppMicroServices/src/module/usModuleHooks.cpp @@ -0,0 +1,158 @@ +/*============================================================================= + + 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 "usModuleHooks_p.h" + +#include "usModuleEventHook.h" +#include "usModuleFindHook.h" +#include "usCoreModuleContext_p.h" +#include "usGetModuleContext.h" +#include "usModuleContext.h" +#include "usServiceReferenceBasePrivate.h" + +US_BEGIN_NAMESPACE + +ModuleHooks::ModuleHooks(CoreModuleContext* ctx) + : coreCtx(ctx) +{ +} + +Module* ModuleHooks::FilterModule(const ModuleContext* mc, Module* module) const +{ + if(module == NULL) + { + return NULL; + } + + std::vector srl; + coreCtx->services.Get(us_service_interface_iid(), srl); + if (srl.empty()) + { + return module; + } + else + { + std::vector ml; + ml.push_back(module); + this->FilterModules(mc, ml); + return ml.empty() ? NULL : module; + } +} + +void ModuleHooks::FilterModules(const ModuleContext* mc, std::vector& modules) const +{ + std::vector srl; + coreCtx->services.Get(us_service_interface_iid(), srl); + ShrinkableVector filtered(modules); + + for (std::vector::iterator srBaseIter = srl.begin(), srBaseEnd = srl.end(); + srBaseIter != srBaseEnd; ++srBaseIter) + { + ServiceReference sr = srBaseIter->GetReference(); + ModuleFindHook* const fh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); + if (fh != NULL) + { + try + { + fh->Find(mc, filtered); + } + catch (const std::exception& e) + { + US_WARN << "Failed to call Module FindHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": " << e.what(); + } + catch (...) + { + US_WARN << "Failed to call Module FindHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": unknown exception type"; + } + } + } +} + +void ModuleHooks::FilterModuleEventReceivers(const ModuleEvent& evt, + ServiceListeners::ModuleListenerMap& moduleListeners) +{ + std::vector eventHooks; + coreCtx->services.Get(us_service_interface_iid(), eventHooks); + + { + MutexLock lock(coreCtx->listeners.moduleListenerMapMutex); + moduleListeners = coreCtx->listeners.moduleListenerMap; + } + + if(!eventHooks.empty()) + { + std::vector moduleContexts; + for (ServiceListeners::ModuleListenerMap::iterator le = moduleListeners.begin(), + leEnd = moduleListeners.end(); le != leEnd; ++le) + { + moduleContexts.push_back(le->first); + } + std::sort(moduleContexts.begin(), moduleContexts.end()); + moduleContexts.erase(std::unique(moduleContexts.begin(), moduleContexts.end()), moduleContexts.end()); + + const std::size_t unfilteredSize = moduleContexts.size(); + ShrinkableVector filtered(moduleContexts); + + for (std::vector::iterator iter = eventHooks.begin(), + iterEnd = eventHooks.end(); iter != iterEnd; ++iter) + { + ServiceReference sr = iter->GetReference(); + ModuleEventHook* eh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); + if (eh != NULL) + { + try + { + eh->Event(evt, filtered); + } + catch (const std::exception& e) + { + US_WARN << "Failed to call Module EventHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": " << e.what(); + } + catch (...) + { + US_WARN << "Failed to call Module EventHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": unknown exception type"; + } + } + } + + if (unfilteredSize != moduleContexts.size()) + { + for (ServiceListeners::ModuleListenerMap::iterator le = moduleListeners.begin(); + le != moduleListeners.end();) + { + if(std::find(moduleContexts.begin(), moduleContexts.end(), le->first) == moduleContexts.end()) + { + moduleListeners.erase(le++); + } + else + { + ++le; + } + } + } + } +} + +US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext_p.h b/Core/CppMicroServices/src/module/usModuleHooks_p.h similarity index 60% copy from Core/CppMicroServices/src/module/usCoreModuleContext_p.h copy to Core/CppMicroServices/src/module/usModuleHooks_p.h index 7f230f9ee5..5d7da7bb93 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext_p.h +++ b/Core/CppMicroServices/src/module/usModuleHooks_p.h @@ -1,60 +1,59 @@ /*============================================================================= 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 USMODULEHOOKS_P_H +#define USMODULEHOOKS_P_H -#ifndef USCOREMODULECONTEXT_H -#define USCOREMODULECONTEXT_H - +#include "usConfig.h" #include "usServiceListeners_p.h" -#include "usServiceRegistry_p.h" + +#include US_BEGIN_NAMESPACE -/** - * This class is not part of the public API. - */ -class CoreModuleContext +class CoreModuleContext; +class Module; +class ModuleContext; +class ModuleEvent; + +class ModuleHooks { + +private: + + CoreModuleContext* const coreCtx; + public: - /** - * All listeners in this framework. - */ - ServiceListeners listeners; + ModuleHooks(CoreModuleContext* ctx); - /** - * All registered services in this framework. - */ - ServiceRegistry services; + Module* FilterModule(const ModuleContext* mc, Module* module) const; - /** - * Contruct a core context - * - */ - CoreModuleContext(); + void FilterModules(const ModuleContext* mc, std::vector& modules) const; - ~CoreModuleContext(); + void FilterModuleEventReceivers(const ModuleEvent& evt, + ServiceListeners::ModuleListenerMap& moduleListeners); }; US_END_NAMESPACE -#endif // USCOREMODULECONTEXT_H +#endif // USMODULEHOOKS_P_H diff --git a/Core/CppMicroServices/src/module/usModulePrivate.cpp b/Core/CppMicroServices/src/module/usModulePrivate.cpp index cee3afcd9a..deda741a3d 100644 --- a/Core/CppMicroServices/src/module/usModulePrivate.cpp +++ b/Core/CppMicroServices/src/module/usModulePrivate.cpp @@ -1,271 +1,272 @@ /*============================================================================= 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 "usModulePrivate.h" #include "usModule.h" +#include "usModuleContext.h" #include "usModuleActivator.h" #include "usModuleUtils_p.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistration.h" #include "usServiceReferenceBasePrivate.h" #include #include #include #include US_BEGIN_NAMESPACE AtomicInt ModulePrivate::idCounter; ModulePrivate::ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info) : coreCtx(coreCtx) , info(*info) , moduleContext(0) , moduleActivator(0) , q(qq) { // Parse the statically imported module library names typedef const char*(*GetImportedModulesFunc)(void); std::string getImportedModulesSymbol("_us_get_imported_modules_for_"); getImportedModulesSymbol += this->info.libName; std::string location = this->info.location; if (this->info.libName.empty()) { /* make sure we retrieve symbols from the executable, if "libName" is empty */ location.clear(); } GetImportedModulesFunc getImportedModulesFunc = NULL; void* getImportedModulesSym = ModuleUtils::GetSymbol(location, getImportedModulesSymbol.c_str()); std::memcpy(&getImportedModulesFunc, &getImportedModulesSym, sizeof(void*)); if (getImportedModulesFunc != NULL) { std::string importedStaticModuleLibNames = getImportedModulesFunc(); std::istringstream iss(importedStaticModuleLibNames); std::copy(std::istream_iterator(iss), std::istream_iterator(), std::back_inserter >(this->staticModuleLibNames)); } InitializeResources(location); // Check if the module provides a manifest.json file and if yes, parse it. ModuleResource manifestRes; std::map::iterator resourceTreeIter = mapLibNameToResourceTrees.find(this->info.libName); if (resourceTreeIter != mapLibNameToResourceTrees.end() && resourceTreeIter->second->IsValid()) { manifestRes = ModuleResource("/manifest.json", resourceTreeIter->second, resourceTreePtrs); if (manifestRes) { ModuleResourceStream manifestStream(manifestRes); try { moduleManifest.Parse(manifestStream); } catch (const std::exception& e) { US_ERROR << "Parsing of manifest.json for module " << info->location << " failed: " << e.what(); } } } // Check if we got version information and validate the version identifier if (moduleManifest.Contains(Module::PROP_VERSION())) { Any versionAny = moduleManifest.GetValue(Module::PROP_VERSION()); std::string errMsg; if (versionAny.Type() != typeid(std::string)) { errMsg = std::string("The version identifier must be a string"); } try { version = ModuleVersion(versionAny.ToString()); } catch (const std::exception& e) { errMsg = std::string("The version identifier is invalid: ") + e.what(); } if (!errMsg.empty()) { throw std::invalid_argument(std::string("The Json value for ") + Module::PROP_VERSION() + " for module " + info->location + " is not valid: " + errMsg); } } std::stringstream propId; propId << this->info.id; moduleManifest.SetValue(Module::PROP_ID(), propId.str()); moduleManifest.SetValue(Module::PROP_LOCATION(), this->info.location); moduleManifest.SetValue(Module::PROP_NAME(), this->info.name); if (moduleManifest.Contains(Module::PROP_AUTOLOAD_DIR())) { this->info.autoLoadDir = moduleManifest.GetValue(Module::PROP_AUTOLOAD_DIR()).ToString(); } else { // default to the library name or a special name for executables if (!this->info.libName.empty()) { this->info.autoLoadDir = this->info.libName; moduleManifest.SetValue(Module::PROP_AUTOLOAD_DIR(), Any(this->info.autoLoadDir)); } else { this->info.autoLoadDir = "main"; moduleManifest.SetValue(Module::PROP_AUTOLOAD_DIR(), Any(this->info.autoLoadDir)); } } } ModulePrivate::~ModulePrivate() { delete moduleContext; for (std::size_t i = 0; i < this->resourceTreePtrs.size(); ++i) { delete resourceTreePtrs[i]; } } void ModulePrivate::RemoveModuleResources() { coreCtx->listeners.RemoveAllListeners(moduleContext); std::vector srs; coreCtx->services.GetRegisteredByModule(this, srs); for (std::vector::iterator i = srs.begin(); i != srs.end(); ++i) { try { i->Unregister(); } catch (const std::logic_error& /*ignore*/) { // Someone has unregistered the service after stop completed. // This should not occur, but we don't want get stuck in // an illegal state so we catch it. } } srs.clear(); coreCtx->services.GetUsedByModule(q, srs); for (std::vector::const_iterator i = srs.begin(); i != srs.end(); ++i) { i->GetReference(std::string()).d->UngetService(q, false); } for (std::size_t i = 0; i < resourceTreePtrs.size(); ++i) { resourceTreePtrs[i]->Invalidate(); } } void ModulePrivate::StartStaticModules() { std::string location = this->info.location; if (this->info.libName.empty()) { /* make sure we retrieve symbols from the executable, if "libName" is empty */ location.clear(); } for (std::vector::iterator i = staticModuleLibNames.begin(); i != staticModuleLibNames.end(); ++i) { std::string staticActivatorSymbol = "_us_module_activator_instance_"; staticActivatorSymbol += *i; ModuleInfo::ModuleActivatorHook staticActivator = NULL; void* staticActivatorSym = ModuleUtils::GetSymbol(location, staticActivatorSymbol.c_str()); std::memcpy(&staticActivator, &staticActivatorSym, sizeof(void*)); if (staticActivator) { US_DEBUG << "Loading static activator " << *i; staticActivators.push_back(staticActivator); staticActivator()->Load(moduleContext); } else { US_DEBUG << "Could not find an activator for the static module " << (*i) << ". It propably does not provide an activator on purpose.\n Or you either " "forgot a US_IMPORT_MODULE macro call in " << info.libName << " or to link " << (*i) << " to " << info.libName << "."; } } } void ModulePrivate::StopStaticModules() { for (std::list::iterator i = staticActivators.begin(); i != staticActivators.end(); ++i) { (*i)()->Unload(moduleContext); } } void ModulePrivate::InitializeResources(const std::string& location) { // Get the resource data from static modules and this module std::vector moduleLibNames; moduleLibNames.push_back(this->info.libName); moduleLibNames.insert(moduleLibNames.end(), this->staticModuleLibNames.begin(), this->staticModuleLibNames.end()); std::string initResourcesSymbolPrefix = "_us_init_resources_"; for (std::size_t i = 0; i < moduleLibNames.size(); ++i) { std::string initResourcesSymbol = initResourcesSymbolPrefix + moduleLibNames[i]; ModuleInfo::InitResourcesHook initResourcesFunc = NULL; void* initResourcesSym = ModuleUtils::GetSymbol(location, initResourcesSymbol.c_str()); std::memcpy(&initResourcesFunc, &initResourcesSym, sizeof(void*)); if (initResourcesFunc) { initResourcesFunc(&this->info); } } // Initialize this modules resource trees assert(this->info.resourceData.size() == this->info.resourceNames.size()); assert(this->info.resourceNames.size() == this->info.resourceTree.size()); for (std::size_t i = 0; i < this->info.resourceData.size(); ++i) { resourceTreePtrs.push_back(new ModuleResourceTree(this->info.resourceTree[i], this->info.resourceNames[i], this->info.resourceData[i])); mapLibNameToResourceTrees[moduleLibNames[i]] = resourceTreePtrs.back(); } } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/module/usModuleRegistry.cpp b/Core/CppMicroServices/src/module/usModuleRegistry.cpp index 44060b559c..f1bdbfa865 100644 --- a/Core/CppMicroServices/src/module/usModuleRegistry.cpp +++ b/Core/CppMicroServices/src/module/usModuleRegistry.cpp @@ -1,224 +1,223 @@ /*============================================================================= 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 "usModuleRegistry.h" #include "usModule.h" #include "usModuleInfo.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usCoreModuleContext_p.h" #include "usGetModuleContext.h" #include "usStaticInit_p.h" #include #include US_BEGIN_NAMESPACE -typedef Mutex MutexType; -typedef MutexLock MutexLocker; - typedef US_UNORDERED_MAP_TYPE ModuleMap; US_GLOBAL_STATIC(CoreModuleContext, coreModuleContext) template struct ModuleDeleter { void operator()(GlobalStatic& globalStatic) const { ModuleMap* moduleMap = globalStatic.pointer; for (ModuleMap::const_iterator i = moduleMap->begin(); i != moduleMap->end(); ++i) { delete i->second; } DefaultGlobalStaticDeleter defaultDeleter; defaultDeleter(globalStatic); } }; /** * Table of all installed modules in this framework. * Key is the module id. */ US_GLOBAL_STATIC_WITH_DELETER(ModuleMap, modules, ModuleDeleter) /** * Lock for protecting the modules object */ -US_GLOBAL_STATIC(MutexType, modulesLock) +US_GLOBAL_STATIC(Mutex, modulesLock) /** * Lock for protecting the register count */ -US_GLOBAL_STATIC(MutexType, countLock) +US_GLOBAL_STATIC(Mutex, countLock) void ModuleRegistry::Register(ModuleInfo* info) { static long regCount = 0; if (info->id > 0) { // The module was already registered Module* module = 0; { - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); module = modules()->operator[](info->id); assert(module != 0); } module->Start(); } else { Module* module = 0; // check if the module is reloaded { - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); ModuleMap* map = modules(); for (ModuleMap::const_iterator i = map->begin(); i != map->end(); ++i) { if (i->second->GetLocation() == info->location) { module = i->second; info->id = module->GetModuleId(); } } } if (!module) { module = new Module(); countLock()->Lock(); info->id = ++regCount; countLock()->Unlock(); module->Init(coreModuleContext(), info); - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); ModuleMap* map = modules(); map->insert(std::make_pair(info->id, module)); } else { module->Init(coreModuleContext(), info); } module->Start(); } } void ModuleRegistry::UnRegister(const ModuleInfo* info) { // If we are unregistering the core module, we just call // the module activators Unload() method (if there is a // module activator). Since we cannot be sure that the // ModuleContext for the core library is still valid, we // just pass a null-pointer. Using the module context during // static deinitalization time of the core library makes // no sense anyway. if (info->id == 1) { // Remove listeners from static modules if they have forgotten to do so coreModuleContext()->listeners.RemoveAllListeners(GetModuleContext()); if (info->activatorHook) { info->activatorHook()->Unload(0); } return; } Module* curr = 0; { - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); curr = modules()->operator[](info->id); assert(curr != 0); } curr->Stop(); - - curr->Uninit(); } Module* ModuleRegistry::GetModule(long id) { - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); ModuleMap::const_iterator iter = modules()->find(id); if (iter != modules()->end()) { return iter->second; } return 0; } Module* ModuleRegistry::GetModule(const std::string& name) { - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); ModuleMap::const_iterator iter = modules()->begin(); ModuleMap::const_iterator iterEnd = modules()->end(); for (; iter != iterEnd; ++iter) { if (iter->second->GetName() == name) { return iter->second; } } return 0; } -void ModuleRegistry::GetModules(std::vector& m) +std::vector ModuleRegistry::GetModules() { - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); + std::vector result; ModuleMap* map = modules(); ModuleMap::const_iterator iter = map->begin(); ModuleMap::const_iterator iterEnd = map->end(); for (; iter != iterEnd; ++iter) { - m.push_back(iter->second); + result.push_back(iter->second); } + return result; } -void ModuleRegistry::GetLoadedModules(std::vector& m) +std::vector ModuleRegistry::GetLoadedModules() { - MutexLocker lock(*modulesLock()); + MutexLock lock(*modulesLock()); + std::vector result; ModuleMap::const_iterator iter = modules()->begin(); ModuleMap::const_iterator iterEnd = modules()->end(); for (; iter != iterEnd; ++iter) { if (iter->second->IsLoaded()) { - m.push_back(iter->second); + result.push_back(iter->second); } } + return result; } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/module/usModuleRegistry.h b/Core/CppMicroServices/src/module/usModuleRegistry.h index d9c8bd975b..b471bf9c63 100644 --- a/Core/CppMicroServices/src/module/usModuleRegistry.h +++ b/Core/CppMicroServices/src/module/usModuleRegistry.h @@ -1,92 +1,92 @@ /*============================================================================= 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 USMODULEREGISTRY_H #define USMODULEREGISTRY_H #include #include #include US_BEGIN_NAMESPACE class Module; struct ModuleInfo; struct ModuleActivator; /** * \ingroup MicroServices * * Here we handle all the modules that are loaded in the framework. */ class US_EXPORT ModuleRegistry { public: /** * Get the module that has the specified module identifier. * * @param id The identifier of the module to get. * @return Module or null * if the module was not found. */ static Module* GetModule(long id); /** * Get the module that has specified module name. * * @param name The name of the module to get. * @return Module or null. */ static Module* GetModule(const std::string& name); /** * Get all known modules. * * @param modules A list which is filled with all known modules. */ - static void GetModules(std::vector& modules); + static std::vector GetModules(); /** * Get all modules currently in module state LOADED. * * @param modules A list which is filled with all modules in * state LOADED */ - static void GetLoadedModules(std::vector& modules); + static std::vector GetLoadedModules(); private: friend class ModuleInitializer; // disabled ModuleRegistry(); static void Register(ModuleInfo* info); static void UnRegister(const ModuleInfo* info); }; US_END_NAMESPACE #endif // USMODULEREGISTRY_H diff --git a/Core/CppMicroServices/src/module/usModuleSettings.cpp b/Core/CppMicroServices/src/module/usModuleSettings.cpp index 5cd8a18e18..530d860861 100644 --- a/Core/CppMicroServices/src/module/usModuleSettings.cpp +++ b/Core/CppMicroServices/src/module/usModuleSettings.cpp @@ -1,162 +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 +struct ModuleSettingsPrivate : public MultiThreaded<> { 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::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/Core/CppMicroServices/src/module/usModuleUtils.cpp b/Core/CppMicroServices/src/module/usModuleUtils.cpp index 29c64d4c52..aa7c7c8db9 100644 --- a/Core/CppMicroServices/src/module/usModuleUtils.cpp +++ b/Core/CppMicroServices/src/module/usModuleUtils.cpp @@ -1,175 +1,176 @@ /*============================================================================= 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 "usModuleUtils_p.h" +#include #include US_BEGIN_NAMESPACE namespace { #ifdef US_BUILD_SHARED_LIBS const bool sharedLibMode = true; #else const bool sharedLibMode = false; #endif } #ifdef __GNUC__ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include std::string GetLibraryPath_impl(const std::string& /*libName*/, void* symbol) { Dl_info info; if (dladdr(symbol, &info)) { return info.dli_fname; } else { US_DEBUG << "GetLibraryPath_impl() dladdr() failed: " << dlerror(); } return ""; } void* GetSymbol_impl(const std::string& libName, const char* symbol) { // Clear the last error message dlerror(); void* selfHandle = 0; if (libName.empty() || !sharedLibMode) { // Get the handle of the executable selfHandle = dlopen(0, RTLD_LAZY); } else { selfHandle = dlopen(libName.c_str(), RTLD_LAZY); } if (selfHandle) { void* addr = dlsym(selfHandle, symbol); if (!addr) { const char* dlerrorMsg = dlerror(); if (dlerrorMsg) { US_DEBUG << "GetSymbol_impl() failed: " << dlerrorMsg; } } dlclose(selfHandle); return addr; } else { US_DEBUG << "GetSymbol_impl() dlopen() failed: " << dlerror(); } return 0; } #elif _WIN32 #include std::string GetLibraryPath_impl(const std::string& libName, void *symbol) { HMODULE handle = 0; if (libName.empty() || !sharedLibMode) { // get the handle for the executable handle = GetModuleHandle(NULL); } else { handle = GetModuleHandle(libName.c_str()); } if (!handle) { // Test US_DEBUG << "GetLibraryPath_impl():GetModuleHandle() " << GetLastErrorStr(); return ""; } char modulePath[512]; if (GetModuleFileName(handle, modulePath, 512)) { return modulePath; } US_DEBUG << "GetLibraryPath_impl():GetModuleFileName() " << GetLastErrorStr(); return ""; } void* GetSymbol_impl(const std::string& libName, const char* symbol) { HMODULE handle = NULL; if (libName.empty() || !sharedLibMode) { handle = GetModuleHandle(NULL); } else { handle = GetModuleHandle(libName.c_str()); } if (!handle) { US_DEBUG << "GetSymbol_impl():GetModuleHandle() " << GetLastErrorStr(); return 0; } void* addr = (void*)GetProcAddress(handle, symbol); if (!addr) { US_DEBUG << "GetSymbol_impl():GetProcAddress(handle," << symbol << ") " << GetLastErrorStr(); } return addr; } #else std::string GetLibraryPath_impl(const std::string& libName, void* symbol) { return ""; } void* GetSymbol_impl(const std::string& libName, const char* symbol) { return 0; } #endif std::string ModuleUtils::GetLibraryPath(const std::string& libName, void* symbol) { return GetLibraryPath_impl(libName, symbol); } void* ModuleUtils::GetSymbol(const std::string& libName, const char* symbol) { return GetSymbol_impl(libName, symbol); } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceEvent.h b/Core/CppMicroServices/src/service/usServiceEvent.h index f5e2d45b17..e1f5b91ae0 100644 --- a/Core/CppMicroServices/src/service/usServiceEvent.h +++ b/Core/CppMicroServices/src/service/usServiceEvent.h @@ -1,197 +1,197 @@ /*============================================================================= 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 USSERVICEEVENT_H #define USSERVICEEVENT_H #ifdef REGISTERED #ifdef _WIN32 #error The REGISTERED preprocessor define clashes with the ServiceEvent::REGISTERED\ enum type. Try to reorder your includes, compile with WIN32_LEAN_AND_MEAN, or undef\ the REGISTERED macro befor including this header. #else #error The REGISTERED preprocessor define clashes with the ServiceEvent::REGISTERED\ enum type. Try to reorder your includes or undef the REGISTERED macro befor including\ this header. #endif #endif #include "usSharedData.h" #include "usServiceReference.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4251) #endif US_BEGIN_NAMESPACE class ServiceEventData; /** * \ingroup MicroServices * * An event from the Micro Services framework describing a service lifecycle change. *

* ServiceEvent objects are delivered to * listeners connected via ModuleContext::AddServiceListener() when a * change occurs in this service's lifecycle. A type code is used to identify * the event type for future extendability. */ class US_EXPORT ServiceEvent { SharedDataPointer d; public: enum Type { /** * This service has been registered. *

* This event is delivered after the service * has been registered with the framework. * * @see ModuleContext#RegisterService() */ REGISTERED = 0x00000001, /** * The properties of a registered service have been modified. *

* This event is delivered after the service * properties have been modified. * * @see ServiceRegistration#SetProperties */ MODIFIED = 0x00000002, /** * This service is in the process of being unregistered. *

* This event is delivered before the service * has completed unregistering. * *

* If a module is using a service that is UNREGISTERING, the * module should release its use of the service when it receives this event. * If the module does not release its use of the service when it receives * this event, the framework will automatically release the module's use of * the service while completing the service unregistration operation. * * @see ServiceRegistration#Unregister * @see ModuleContext#UngetService */ UNREGISTERING = 0x00000004, /** * The properties of a registered service have been modified and the new * properties no longer match the listener's filter. *

* This event is delivered after the service * properties have been modified. This event is only delivered to listeners * which were added with a non-empty filter where the filter * matched the service properties prior to the modification but the filter * does not match the modified service properties. * * @see ServiceRegistration#SetProperties */ MODIFIED_ENDMATCH = 0x00000008 }; /** * Creates an invalid instance. */ ServiceEvent(); ~ServiceEvent(); /** * Can be used to check if this ServiceEvent instance is valid, * or if it has been constructed using the default constructor. * * @return true if this event object is valid, * false otherwise. */ bool IsNull() const; /** * Creates a new service event object. * * @param type The event type. * @param reference A ServiceReference object to the service * that had a lifecycle change. */ ServiceEvent(Type type, const ServiceReferenceBase& reference); ServiceEvent(const ServiceEvent& other); ServiceEvent& operator=(const ServiceEvent& other); /** * Returns a reference to the service that had a change occur in its * lifecycle. *

* This reference is the source of the event. * * @return Reference to the service that had a lifecycle change. */ ServiceReferenceU GetServiceReference() const; template - ServiceReference GetServiceReference(InterfaceT) const + ServiceReference GetServiceReference(InterfaceType) const { return GetServiceReference(); } /** * Returns the type of event. The event type values are: *

    *
  • {@link #REGISTERED}
  • *
  • {@link #MODIFIED}
  • *
  • {@link #MODIFIED_ENDMATCH}
  • *
  • {@link #UNREGISTERING}
  • *
* * @return Type of service lifecycle change. */ Type GetType() const; }; US_END_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif /** * \ingroup MicroServices * @{ */ US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceEvent::Type)& type); US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceEvent)& event); /** @}*/ #endif // USSERVICEEVENT_H diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp b/Core/CppMicroServices/src/service/usServiceEventListenerHook.cpp similarity index 75% copy from Core/CppMicroServices/src/module/usCoreModuleContext.cpp copy to Core/CppMicroServices/src/service/usServiceEventListenerHook.cpp index b2d4d9896c..3aae20bd36 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp +++ b/Core/CppMicroServices/src/service/usServiceEventListenerHook.cpp @@ -1,46 +1,30 @@ /*============================================================================= 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 "usCoreModuleContext_p.h" - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4355) -#endif +#include "usServiceEventListenerHook.h" US_BEGIN_NAMESPACE -CoreModuleContext::CoreModuleContext() - : services(this) -{ -} - -CoreModuleContext::~CoreModuleContext() +ServiceEventListenerHook::~ServiceEventListenerHook() { } US_END_NAMESPACE - -#ifdef _MSC_VER -#pragma warning(pop) -#endif diff --git a/Core/CppMicroServices/src/service/usServiceEventListenerHook.h b/Core/CppMicroServices/src/service/usServiceEventListenerHook.h new file mode 100644 index 0000000000..b972fbf25f --- /dev/null +++ b/Core/CppMicroServices/src/service/usServiceEventListenerHook.h @@ -0,0 +1,69 @@ +/*============================================================================= + + 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 USSERVICEEVENTLISTENERHOOK_H +#define USSERVICEEVENTLISTENERHOOK_H + +#include "usServiceInterface.h" +#include "usServiceListenerHook.h" +#include "usShrinkableVector.h" +#include "usShrinkableMap.h" + +US_BEGIN_NAMESPACE + +class ModuleContext; +class ServiceEvent; + +/** + * Service Event Listener Hook Service. + * + *

+ * Modules registering this service will be called during service + * (register, modify, and unregister service) operations. + * + * @remarks Implementations of this interface are required to be thread-safe. + */ +struct US_EXPORT ServiceEventListenerHook +{ + + virtual ~ServiceEventListenerHook(); + + /** + * Event listener hook method. This method is called prior to service event + * delivery when a publishing module registers, modifies or unregisters a + * service. This method can filter the listeners which receive the event. + * + * @param event The service event to be delivered. + * @param listeners A map of Module Contexts to a list of Listener + * Infos for the module's listeners to which the specified event will + * be delivered. The implementation of this method may remove module + * contexts from the map and listener infos from the list + * values to prevent the event from being delivered to the associated + * listeners. + */ + virtual void Event(const ServiceEvent& event, ShrinkableMap >& listeners) = 0; +}; + +US_END_NAMESPACE + +US_DECLARE_SERVICE_INTERFACE(us::ServiceEventListenerHook, "org.cppmicroservices.ServiceEventListenerHook/2.0.0") + +#endif // USSERVICEEVENTLISTENERHOOK_H diff --git a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp b/Core/CppMicroServices/src/service/usServiceFindHook.cpp similarity index 75% copy from Core/CppMicroServices/src/module/usCoreModuleContext.cpp copy to Core/CppMicroServices/src/service/usServiceFindHook.cpp index b2d4d9896c..5a95f23648 100644 --- a/Core/CppMicroServices/src/module/usCoreModuleContext.cpp +++ b/Core/CppMicroServices/src/service/usServiceFindHook.cpp @@ -1,46 +1,30 @@ /*============================================================================= 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 "usCoreModuleContext_p.h" - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4355) -#endif +#include "usServiceFindHook.h" US_BEGIN_NAMESPACE -CoreModuleContext::CoreModuleContext() - : services(this) -{ -} - -CoreModuleContext::~CoreModuleContext() +ServiceFindHook::~ServiceFindHook() { } US_END_NAMESPACE - -#ifdef _MSC_VER -#pragma warning(pop) -#endif diff --git a/Core/CppMicroServices/src/service/usServiceFindHook.h b/Core/CppMicroServices/src/service/usServiceFindHook.h new file mode 100644 index 0000000000..962726e770 --- /dev/null +++ b/Core/CppMicroServices/src/service/usServiceFindHook.h @@ -0,0 +1,74 @@ +/*============================================================================= + + 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 USSERVICEFINDHOOK_H +#define USSERVICEFINDHOOK_H + +#include "usServiceInterface.h" +#include "usShrinkableVector.h" + +#include + +US_BEGIN_NAMESPACE + +class Module; +class ModuleContext; +class ServiceReferenceBase; + +/** + * Service Find Hook Service. + * + *

+ * Modules registering this service will be called during service find + * (get service references) operations. + * + * @remarks Implementations of this interface are required to be thread-safe. + */ +struct US_EXPORT ServiceFindHook +{ + + virtual ~ServiceFindHook(); + + /** + * Find hook method. This method is called during the service find operation + * (for example, ModuleContext::GetServiceReferences()). This method can + * filter the result of the find operation. + * + * @param context The module context of the module performing the find + * operation. + * @param name The class name of the services to find or an empty string to + * find all services. + * @param filter The filter criteria of the services to find or an empty string + * for no filter criteria. + * @param references A list of Service References to be returned as a result of the + * find operation. The implementation of this method may remove + * service references from the list to prevent the references from being + * returned to the module performing the find operation. + */ + virtual void Find(const ModuleContext* context, const std::string& name, + const std::string& filter, ShrinkableVector& references) = 0; +}; + +US_END_NAMESPACE + +US_DECLARE_SERVICE_INTERFACE(us::ServiceFindHook, "org.cppmicroservices.ServiceFindHook/2.0.0") + +#endif // USSERVICEFINDHOOK_H diff --git a/Core/CppMicroServices/src/service/usServiceHooks.cpp b/Core/CppMicroServices/src/service/usServiceHooks.cpp new file mode 100644 index 0000000000..ed93e8f1cf --- /dev/null +++ b/Core/CppMicroServices/src/service/usServiceHooks.cpp @@ -0,0 +1,283 @@ +/*============================================================================= + + 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 "usServiceHooks_p.h" + +#include "usGetModuleContext.h" +#include "usCoreModuleContext_p.h" +#include "usServiceEventListenerHook.h" +#include "usServiceFindHook.h" +#include "usServiceListenerHook.h" +#include "usServiceReferenceBasePrivate.h" + +US_BEGIN_NAMESPACE + +ServiceHooks::ServiceHooks(CoreModuleContext* coreCtx) + : coreCtx(coreCtx) + , listenerHookTracker(NULL) + , bOpen(false) +{ +} + +ServiceHooks::~ServiceHooks() +{ + this->Close(); +} + +ServiceHooks::TrackedType ServiceHooks::AddingService(const ServiceReferenceType& reference) +{ + ServiceListenerHook* lh = GetModuleContext()->GetService(reference); + try + { + lh->Added(coreCtx->listeners.GetListenerInfoCollection()); + } + catch (const std::exception& e) + { + US_WARN << "Failed to call listener hook #" << reference.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": " << e.what(); + } + catch (...) + { + US_WARN << "Failed to call listener hook #" << reference.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": unknown exception type"; + } + return lh; +} + +void ServiceHooks::ModifiedService(const ServiceReferenceType& /*reference*/, TrackedType /*service*/) +{ + // noop +} + +void ServiceHooks::RemovedService(const ServiceReferenceType& reference, TrackedType /*service*/) +{ + GetModuleContext()->UngetService(reference); +} + +void ServiceHooks::Open() +{ + Lock(this); + + listenerHookTracker = new ServiceTracker(GetModuleContext(), this); + listenerHookTracker->Open(); + + bOpen = true; +} + +void ServiceHooks::Close() +{ + Lock(this); + listenerHookTracker->Close(); + delete listenerHookTracker; + listenerHookTracker = NULL; + + bOpen = false; +} + +bool ServiceHooks::IsOpen() const +{ + Lock(this); + return bOpen; +} + +void ServiceHooks::FilterServiceReferences(ModuleContext* mc, const std::string& service, + const std::string& filter, std::vector& refs) +{ + std::vector srl; + coreCtx->services.Get_unlocked(us_service_interface_iid(), srl); + if (!srl.empty()) + { + ShrinkableVector filtered(refs); + + std::sort(srl.begin(), srl.end()); + for (std::vector::reverse_iterator fhrIter = srl.rbegin(), fhrEnd = srl.rend(); + fhrIter != fhrEnd; ++fhrIter) + { + ServiceReference sr = fhrIter->GetReference(); + ServiceFindHook* const fh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); + if (fh != NULL) + { + try + { + fh->Find(mc, service, filter, filtered); + } + catch (const std::exception& e) + { + US_WARN << "Failed to call find hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": " << e.what(); + } + catch (...) + { + US_WARN << "Failed to call find hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": unknown exception type"; + } + } + } + } +} + +void ServiceHooks::FilterServiceEventReceivers(const ServiceEvent& evt, + ServiceListeners::ServiceListenerEntries& receivers) +{ + std::vector eventListenerHooks; + coreCtx->services.Get_unlocked(us_service_interface_iid(), eventListenerHooks); + if (!eventListenerHooks.empty()) + { + std::sort(eventListenerHooks.begin(), eventListenerHooks.end()); + std::map > listeners; + for (ServiceListeners::ServiceListenerEntries::iterator sleIter = receivers.begin(), + sleEnd = receivers.end(); sleIter != sleEnd; ++sleIter) + { + listeners[sleIter->GetModuleContext()].push_back(*sleIter); + } + + std::map > shrinkableListeners; + for (std::map >::iterator iter = listeners.begin(), + iterEnd = listeners.end(); iter != iterEnd; ++iter) + { + shrinkableListeners.insert(std::make_pair(iter->first, ShrinkableVector(iter->second))); + } + + ShrinkableMap > filtered(shrinkableListeners); + + for(std::vector::reverse_iterator sriIter = eventListenerHooks.rbegin(), + sriEnd = eventListenerHooks.rend(); sriIter != sriEnd; ++sriIter) + { + ServiceReference sr = sriIter->GetReference(); + ServiceEventListenerHook* elh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); + if(elh != NULL) + { + try + { + elh->Event(evt, filtered); + } + catch(const std::exception& e) + { + US_WARN << "Failed to call event hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": " << e.what(); + } + catch(...) + { + US_WARN << "Failed to call event hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": unknown exception type"; + } + } + } + receivers.clear(); + for(std::map >::iterator iter = listeners.begin(), + iterEnd = listeners.end(); iter != iterEnd; ++iter) + { + receivers.insert(iter->second.begin(), iter->second.end()); + } + } +} + +void ServiceHooks::HandleServiceListenerReg(const ServiceListenerEntry& sle) +{ + if(!IsOpen() || listenerHookTracker->Size() == 0) + { + return; + } + + std::vector > srl + = listenerHookTracker->GetServiceReferences(); + + if (!srl.empty()) + { + std::sort(srl.begin(), srl.end()); + + std::vector set; + set.push_back(sle); + for (std::vector >::reverse_iterator srIter = srl.rbegin(), + srEnd = srl.rend(); srIter != srEnd; ++srIter) + { + ServiceListenerHook* lh = listenerHookTracker->GetService(*srIter); + try + { + lh->Added(set); + } + catch (const std::exception& e) + { + US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": " << e.what(); + } + catch (...) + { + US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": unknown exception"; + } + } + } +} + +void ServiceHooks::HandleServiceListenerUnreg(const ServiceListenerEntry& sle) +{ + if(IsOpen()) + { + std::vector set; + set.push_back(sle); + HandleServiceListenerUnreg(set); + } +} + +void ServiceHooks::HandleServiceListenerUnreg(const std::vector& set) +{ + if(!IsOpen() || listenerHookTracker->Size() == 0) + { + return; + } + + std::vector > srl + = listenerHookTracker->GetServiceReferences(); + + if (!srl.empty()) + { + std::vector lis; + for (std::vector::const_iterator sleIter = set.begin(), + sleEnd = set.end(); sleIter != sleEnd; ++sleIter) + { + lis.push_back(*sleIter); + } + + std::sort(srl.begin(), srl.end()); + for (std::vector >::reverse_iterator srIter = srl.rbegin(), + srEnd = srl.rend(); srIter != srEnd; ++srIter) + { + ServiceListenerHook* const lh = listenerHookTracker->GetService(*srIter); + try + { + lh->Removed(lis); + } + catch (const std::exception& e) + { + US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": " << e.what(); + } + catch (...) + { + US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() + << ": unknown exception type"; + } + } + } +} + +US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceHooks_p.h b/Core/CppMicroServices/src/service/usServiceHooks_p.h new file mode 100644 index 0000000000..ea7e003c78 --- /dev/null +++ b/Core/CppMicroServices/src/service/usServiceHooks_p.h @@ -0,0 +1,73 @@ +/*============================================================================= + + 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 USSERVICEHOOKS_P_H +#define USSERVICEHOOKS_P_H + +#include "usServiceTracker.h" +#include "usServiceListeners_p.h" + +US_BEGIN_NAMESPACE + +struct ServiceListenerHook; + +class ServiceHooks : private MultiThreaded<>, private ServiceTrackerCustomizer +{ + +private: + + CoreModuleContext* coreCtx; + ServiceTracker* listenerHookTracker; + + bool bOpen; + + virtual TrackedType AddingService(const ServiceReferenceType& reference); + virtual void ModifiedService(const ServiceReferenceType& reference, TrackedType service); + virtual void RemovedService(const ServiceReferenceType& reference, TrackedType service); + +public: + + ServiceHooks(CoreModuleContext* coreCtx); + ~ServiceHooks(); + + void Open(); + + void Close(); + + bool IsOpen() const; + + void FilterServiceReferences(ModuleContext* mc, const std::string& service, + const std::string& filter, std::vector& refs); + + void FilterServiceEventReceivers(const ServiceEvent& evt, + ServiceListeners::ServiceListenerEntries& receivers); + + void HandleServiceListenerReg(const ServiceListenerEntry& sle); + + void HandleServiceListenerUnreg(const ServiceListenerEntry& sle); + + void HandleServiceListenerUnreg(const std::vector& set); + +}; + +US_END_NAMESPACE + +#endif // USSERVICEHOOKS_P_H diff --git a/Core/CppMicroServices/src/service/usServiceInterface.h b/Core/CppMicroServices/src/service/usServiceInterface.h index 91efe207ff..5e1ab39e5d 100644 --- a/Core/CppMicroServices/src/service/usServiceInterface.h +++ b/Core/CppMicroServices/src/service/usServiceInterface.h @@ -1,342 +1,342 @@ /*============================================================================= 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 USSERVICEINTERFACE_H #define USSERVICEINTERFACE_H #include #include #include #include #include /** * \ingroup MicroServices * * Returns a unique id for a given type. * * This template method is specialized in the macro * #US_DECLARE_SERVICE_INTERFACE to return a unique id * for each service interface. * * @tparam T The service interface type. * @return A unique id for the service interface type T. */ template inline const char* us_service_interface_iid(); /// \cond template<> inline const char* us_service_interface_iid() { return ""; } /// \endcond #if defined(QT_DEBUG) || defined(QT_NO_DEBUG) #include #define US_DECLARE_SERVICE_INTERFACE(_service_interface_type, _service_interface_id) \ template<> inline const char* qobject_interface_iid<_service_interface_type*>() \ { return _service_interface_id; } \ template<> inline const char* us_service_interface_iid<_service_interface_type>() \ { return _service_interface_id; } \ template<> inline _service_interface_type* qobject_cast<_service_interface_type*>(QObject* object) \ { return reinterpret_cast<_service_interface_type*>(object ? object->qt_metacast(_service_interface_id) : 0); } \ template<> inline _service_interface_type* qobject_cast<_service_interface_type*>(const QObject* object) \ { return reinterpret_cast<_service_interface_type*>(object ? const_cast(object)->qt_metacast(_service_interface_id) : 0); } #else /** * \ingroup MicroServices * * \brief Declare a CppMicroServices service interface. * * This macro associates the given identifier \e _service_interface_id (a string literal) to the * interface class called _service_interface_type. The Identifier must be unique. For example: * * \code * #include * * struct ISomeInterace { ... }; * * US_DECLARE_SERVICE_INTERFACE(ISomeInterface, "com.mycompany.service.ISomeInterface/1.0") * \endcode * * This macro is normally used right after the class definition for _service_interface_type, in a header file. * * If you want to use #US_DECLARE_SERVICE_INTERFACE with interface classes declared in a * namespace then you have to make sure the #US_DECLARE_SERVICE_INTERFACE macro call is not * inside a namespace though. For example: * * \code * #include * * namespace Foo * { * struct ISomeInterface { ... }; * } * * US_DECLARE_SERVICE_INTERFACE(Foo::ISomeInterface, "com.mycompany.service.ISomeInterface/1.0") * \endcode * * @param _service_interface_type The service interface type. * @param _service_interface_id A string literal representing a globally unique identifier. */ #define US_DECLARE_SERVICE_INTERFACE(_service_interface_type, _service_interface_id) \ template<> inline const char* us_service_interface_iid<_service_interface_type>() \ { return _service_interface_id; } \ #endif US_BEGIN_NAMESPACE class ServiceFactory; /** * @ingroup MicroServices * * A helper type used in several methods to get proper * method overload resolutions. */ template -struct InterfaceT {}; +struct InterfaceType {}; /** * @ingroup MicroServices * * A map containing interfaces ids and their corresponding service object * pointers. InterfaceMap instances represent a complete service object * which implementes one or more service interfaces. For each implemented * service interface, there is an entry in the map with the key being * the service interface id and the value a pointer to the service * interface implementation. * * To create InterfaceMap instances, use the MakeInterfaceMap helper class. * * @note This is a low-level type and should only rarely be used. * * @see MakeInterfaceMap */ typedef std::map InterfaceMap; template bool InsertInterfaceType(InterfaceMap& im, I* i) { if (us_service_interface_iid() == NULL) { throw ServiceException(std::string("The interface class ") + typeid(I).name() + " uses an invalid id in its US_DECLARE_SERVICE_INTERFACE macro call."); } im.insert(std::make_pair(std::string(us_service_interface_iid()), static_cast(static_cast(i)))); return true; } template<> inline bool InsertInterfaceType(InterfaceMap&, void*) { return false; } /** * @ingroup MicroServices * * Helper class for constructing InterfaceMap instances based * on service implementations or service factories. * * Example usage: * \code * MyService service; // implementes I1 and I2 * InterfaceMap im = MakeInterfaceMap(&service); * \endcode * * The MakeInterfaceMap supports service implementations with * up to three service interfaces. * * @see InterfaceMap */ template struct MakeInterfaceMap { ServiceFactory* m_factory; I1* m_interface1; I2* m_interface2; I3* m_interface3; /** * Constructor taking a service implementation pointer. * * @param impl A service implementation pointer, which must * be castable to a all specified service interfaces. */ template MakeInterfaceMap(Impl* impl) : m_factory(NULL) , m_interface1(static_cast(impl)) , m_interface2(static_cast(impl)) , m_interface3(static_cast(impl)) {} /** * Constructor taking a service factory. * * @param factory A service factory. */ MakeInterfaceMap(ServiceFactory* factory) : m_factory(factory) , m_interface1(NULL) , m_interface2(NULL) , m_interface3(NULL) { if (factory == NULL) { throw ServiceException("The service factory argument must not be NULL."); } } operator InterfaceMap () { InterfaceMap sim; InsertInterfaceType(sim, m_interface1); InsertInterfaceType(sim, m_interface2); InsertInterfaceType(sim, m_interface3); if (m_factory) { sim.insert(std::make_pair(std::string("org.cppmicroservices.factory"), static_cast(m_factory))); } return sim; } }; /// \cond template struct MakeInterfaceMap { ServiceFactory* m_factory; I1* m_interface1; I2* m_interface2; template MakeInterfaceMap(Impl* impl) : m_factory(NULL) , m_interface1(static_cast(impl)) , m_interface2(static_cast(impl)) {} MakeInterfaceMap(ServiceFactory* factory) : m_factory(factory) , m_interface1(NULL) , m_interface2(NULL) { if (factory == NULL) { throw ServiceException("The service factory argument must not be NULL."); } } operator InterfaceMap () { InterfaceMap sim; InsertInterfaceType(sim, m_interface1); InsertInterfaceType(sim, m_interface2); if (m_factory) { sim.insert(std::make_pair(std::string("org.cppmicroservices.factory"), static_cast(m_factory))); } return sim; } }; template struct MakeInterfaceMap { ServiceFactory* m_factory; I1* m_interface1; template MakeInterfaceMap(Impl* impl) : m_factory(NULL) , m_interface1(static_cast(impl)) {} MakeInterfaceMap(ServiceFactory* factory) : m_factory(factory) , m_interface1(NULL) { if (factory == NULL) { throw ServiceException("The service factory argument must not be NULL."); } } operator InterfaceMap () { InterfaceMap sim; InsertInterfaceType(sim, m_interface1); if (m_factory) { sim.insert(std::make_pair(std::string("org.cppmicroservices.factory"), static_cast(m_factory))); } return sim; } }; template<> struct MakeInterfaceMap; /// \endcond /** * @ingroup MicroServices * * Extract a service interface pointer from a given InterfaceMap instance. * * @param map a InterfaceMap instance. * @return The service interface pointer for the service interface id of the * \c I1 interface type or NULL if \c map does not contain an entry * for the given type. * * @see MakeInterfaceMap */ template I1* ExtractInterface(const InterfaceMap& map) { InterfaceMap::const_iterator iter = map.find(us_service_interface_iid()); if (iter != map.end()) { return reinterpret_cast(iter->second); } return NULL; } US_END_NAMESPACE #endif // USSERVICEINTERFACE_H diff --git a/Core/CppMicroServices/src/service/usServiceListenerEntry.cpp b/Core/CppMicroServices/src/service/usServiceListenerEntry.cpp index 6dcb178ba0..f23f65f4a9 100644 --- a/Core/CppMicroServices/src/service/usServiceListenerEntry.cpp +++ b/Core/CppMicroServices/src/service/usServiceListenerEntry.cpp @@ -1,150 +1,148 @@ /*============================================================================= 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 "usServiceListenerEntry_p.h" +#include "usServiceListenerHook_p.h" + +#include US_BEGIN_NAMESPACE -class ServiceListenerEntryData : public SharedData +class ServiceListenerEntryData : public ServiceListenerHook::ListenerInfoData { public: - ServiceListenerEntryData(Module* mc, const ServiceListenerEntry::ServiceListener& l, + ServiceListenerEntryData(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& l, void* data, const std::string& filter) - : mc(mc), listener(l), data(data), bRemoved(false), ldap() + : ServiceListenerHook::ListenerInfoData(mc, l, data, filter) + , ldap() + , hashValue(0) { if (!filter.empty()) { ldap = LDAPExpr(filter); } } ~ServiceListenerEntryData() { - } - Module* const mc; - ServiceListenerEntry::ServiceListener listener; - void* data; - bool bRemoved; LDAPExpr ldap; /** * The elements of "simple" filters are cached, for easy lookup. * * The grammar for simple filters is as follows: * *

    * Simple = '(' attr '=' value ')'
    *        | '(' '|' Simple+ ')'
    * 
* where attr is one of Constants#OBJECTCLASS, * Constants#SERVICE_ID or Constants#SERVICE_PID, and * value must not contain a wildcard character. *

* The index of the vector determines which key the cache is for * (see ServiceListenerState#hashedKeys). For each key, there is * a vector pointing out the values which are accepted by this * ServiceListenerEntry's filter. This cache is maintained to make * it easy to remove this service listener. */ LDAPExpr::LocalCache local_cache; + std::size_t hashValue; + private: // purposely not implemented ServiceListenerEntryData(const ServiceListenerEntryData&); ServiceListenerEntryData& operator=(const ServiceListenerEntryData&); }; ServiceListenerEntry::ServiceListenerEntry(const ServiceListenerEntry& other) - : d(other.d) + : ServiceListenerHook::ListenerInfo(other) { +} +ServiceListenerEntry::ServiceListenerEntry(const ServiceListenerHook::ListenerInfo& info) + : ServiceListenerHook::ListenerInfo(info) +{ + assert(info.d); } ServiceListenerEntry::~ServiceListenerEntry() { - } ServiceListenerEntry& ServiceListenerEntry::operator=(const ServiceListenerEntry& other) { d = other.d; return *this; } -bool ServiceListenerEntry::operator==(const ServiceListenerEntry& other) const -{ - return ((d->mc == 0 || other.d->mc == 0) || d->mc == other.d->mc) && - (d->data == other.d->data) && ServiceListenerCompare()(d->listener, other.d->listener); -} - -bool ServiceListenerEntry::operator<(const ServiceListenerEntry& other) const -{ - return (d->mc == other.d->mc) ? (d->data < other.d->data) : (d->mc < other.d->mc); -} - void ServiceListenerEntry::SetRemoved(bool removed) const { d->bRemoved = removed; } -bool ServiceListenerEntry::IsRemoved() const -{ - return d->bRemoved; -} - -ServiceListenerEntry::ServiceListenerEntry(Module* mc, const ServiceListener& l, +ServiceListenerEntry::ServiceListenerEntry(ModuleContext* mc, const ServiceListener& l, void* data, const std::string& filter) - : d(new ServiceListenerEntryData(mc, l, data, filter)) + : ServiceListenerHook::ListenerInfo(new ServiceListenerEntryData(mc, l, data, filter)) { - } -Module* ServiceListenerEntry::GetModule() const +const LDAPExpr& ServiceListenerEntry::GetLDAPExpr() const { - return d->mc; + return static_cast(d.Data())->ldap; } -std::string ServiceListenerEntry::GetFilter() const +LDAPExpr::LocalCache& ServiceListenerEntry::GetLocalCache() const { - return d->ldap.IsNull() ? std::string() : d->ldap.ToString(); + return static_cast(d.Data())->local_cache; } -const LDAPExpr& ServiceListenerEntry::GetLDAPExpr() const +void ServiceListenerEntry::CallDelegate(const ServiceEvent& event) const { - return d->ldap; + d->listener(event); } -LDAPExpr::LocalCache& ServiceListenerEntry::GetLocalCache() const +bool ServiceListenerEntry::operator==(const ServiceListenerEntry& other) const { - return d->local_cache; + return ((d->mc == NULL || other.d->mc == NULL) || d->mc == other.d->mc) && + (d->data == other.d->data) && ServiceListenerCompare()(d->listener, other.d->listener); } -void ServiceListenerEntry::CallDelegate(const ServiceEvent& event) const +std::size_t ServiceListenerEntry::Hash() const { - d->listener(event); + using namespace US_HASH_FUNCTION_NAMESPACE; + + if (static_cast(d.Data())->hashValue == 0) + { + static_cast(d.Data())->hashValue = + ((US_HASH_FUNCTION(ModuleContext*, d->mc) ^ (US_HASH_FUNCTION(void*, d->data) << 1)) >> 1) ^ + (US_HASH_FUNCTION(US_SERVICE_LISTENER_FUNCTOR, d->listener) << 1); + } + return static_cast(d.Data())->hashValue; } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceListenerEntry_p.h b/Core/CppMicroServices/src/service/usServiceListenerEntry_p.h index 8bedffe193..dea22828f6 100644 --- a/Core/CppMicroServices/src/service/usServiceListenerEntry_p.h +++ b/Core/CppMicroServices/src/service/usServiceListenerEntry_p.h @@ -1,97 +1,79 @@ /*============================================================================= 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 USSERVICELISTENERENTRY_H #define USSERVICELISTENERENTRY_H #include -#include +#include +#include #include "usLDAPExpr_p.h" -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4396) -#endif - US_BEGIN_NAMESPACE class Module; class ServiceListenerEntryData; /** * Data structure for saving service listener info. Contains * the optional service listener filter, in addition to the info * in ListenerEntry. */ -class ServiceListenerEntry +class ServiceListenerEntry : public ServiceListenerHook::ListenerInfo { public: typedef US_SERVICE_LISTENER_FUNCTOR ServiceListener; ServiceListenerEntry(const ServiceListenerEntry& other); + ServiceListenerEntry(const ServiceListenerHook::ListenerInfo& info); + ~ServiceListenerEntry(); ServiceListenerEntry& operator=(const ServiceListenerEntry& other); - bool operator==(const ServiceListenerEntry& other) const; - - bool operator<(const ServiceListenerEntry& other) const; - void SetRemoved(bool removed) const; - bool IsRemoved() const; - - ServiceListenerEntry(Module* mc, const ServiceListener& l, void* data, const std::string& filter = ""); - Module* GetModule() const; - - std::string GetFilter() const; + ServiceListenerEntry(ModuleContext* mc, const ServiceListener& l, void* data, const std::string& filter = ""); const LDAPExpr& GetLDAPExpr() const; LDAPExpr::LocalCache& GetLocalCache() const; void CallDelegate(const ServiceEvent& event) const; -private: + bool operator==(const ServiceListenerEntry& other) const; - US_HASH_FUNCTION_FRIEND(ServiceListenerEntry); + std::size_t Hash() const; - ExplicitlySharedDataPointer d; }; US_END_NAMESPACE -#ifdef _MSC_VER -#pragma warning(pop) -#endif - US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceListenerEntry)) - -return US_HASH_FUNCTION(const US_PREPEND_NAMESPACE(ServiceListenerEntryData)*, arg.d.ConstData()); - + return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USSERVICELISTENERENTRY_H diff --git a/Core/CppMicroServices/src/service/usServiceListenerHook.cpp b/Core/CppMicroServices/src/service/usServiceListenerHook.cpp new file mode 100644 index 0000000000..b9245ddde3 --- /dev/null +++ b/Core/CppMicroServices/src/service/usServiceListenerHook.cpp @@ -0,0 +1,92 @@ +/*============================================================================= + + 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 "usServiceListenerHook.h" +#include "usServiceListenerHook_p.h" + +US_BEGIN_NAMESPACE + +ServiceListenerHook::~ServiceListenerHook() +{ +} + +ServiceListenerHook::ListenerInfoData::ListenerInfoData( + ModuleContext* mc, const ServiceListenerEntry::ServiceListener& l, + void* data, const std::string& filter) + : mc(mc) + , listener(l) + , data(data) + , filter(filter) + , bRemoved(false) +{ +} + +ServiceListenerHook::ListenerInfo::ListenerInfo(ListenerInfoData* data) + : d(data) +{ +} + +ServiceListenerHook::ListenerInfo::ListenerInfo() + : d(NULL) +{ +} + +ServiceListenerHook::ListenerInfo::ListenerInfo(const ListenerInfo& other) + : d(other.d) +{ +} + +ServiceListenerHook::ListenerInfo::~ListenerInfo() +{ +} + +ServiceListenerHook::ListenerInfo& ServiceListenerHook::ListenerInfo::operator=(const ListenerInfo& other) +{ + d = other.d; + return *this; +} + +bool ServiceListenerHook::ListenerInfo::IsNull() const +{ + return !d; +} + +ModuleContext* ServiceListenerHook::ListenerInfo::GetModuleContext() const +{ + return d->mc; +} + +std::string ServiceListenerHook::ListenerInfo::GetFilter() const +{ + return d->filter; +} + +bool ServiceListenerHook::ListenerInfo::IsRemoved() const +{ + return d->bRemoved; +} + +bool ServiceListenerHook::ListenerInfo::operator==(const ListenerInfo& other) const +{ + return d == other.d; +} + +US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceListenerHook.h b/Core/CppMicroServices/src/service/usServiceListenerHook.h new file mode 100644 index 0000000000..3d46ddee79 --- /dev/null +++ b/Core/CppMicroServices/src/service/usServiceListenerHook.h @@ -0,0 +1,174 @@ +/*============================================================================= + + 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 USSERVICELISTENERHOOK_H +#define USSERVICELISTENERHOOK_H + +#include "usServiceInterface.h" +#include "usShrinkableVector.h" +#include "usSharedData.h" + +#include + +US_BEGIN_NAMESPACE + +class ModuleContext; +class ServiceListenerEntry; + +/** + * Service Listener Hook Service. + * + *

+ * Modules registering this service will be called during service listener + * addition and removal. + * + * @remarks Implementations of this interface are required to be thread-safe. + */ +struct US_EXPORT ServiceListenerHook +{ + + class ListenerInfoData; + + /** + * Information about a Service Listener. This class describes the module + * which added the Service Listener and the filter with which it was added. + * + * @remark This class is not intended to be implemented by clients. + */ + struct US_EXPORT ListenerInfo + { + ListenerInfo(); + + ListenerInfo(const ListenerInfo& other); + + ~ListenerInfo(); + + ListenerInfo& operator=(const ListenerInfo& other); + + /** + * Can be used to check if this ListenerInfo instance is valid, + * or if it has been constructed using the default constructor. + * + * @return true if this listener object is valid, + * false otherwise. + */ + bool IsNull() const; + + /** + * Return the context of the module which added the listener. + * + * @return The context of the module which added the listener. + */ + ModuleContext* GetModuleContext() const; + + /** + * Return the filter string with which the listener was added. + * + * @return The filter string with which the listener was added. This may + * be empty if the listener was added without a filter. + */ + std::string GetFilter() const; + + /** + * Return the state of the listener for this addition and removal life + * cycle. Initially this method will return \c false indicating the + * listener has been added but has not been removed. After the listener + * has been removed, this method must always returns \c true. + * + *

+ * There is an extremely rare case in which removed notification to + * {@link ServiceListenerHook}s can be made before added notification if two + * threads are racing to add and remove the same service listener. + * Because {@link ServiceListenerHook}s are called synchronously during service + * listener addition and removal, the CppMicroServices library cannot guarantee + * in-order delivery of added and removed notification for a given + * service listener. This method can be used to detect this rare + * occurrence. + * + * @return \c false if the listener has not been been removed, + * \c true otherwise. + */ + bool IsRemoved() const; + + /** + * Compares this \c ListenerInfo to another \c ListenerInfo. + * Two {@code ListenerInfo}s are equal if they refer to the same + * listener for a given addition and removal life cycle. If the same + * listener is added again, it will have a different + * \c ListenerInfo which is not equal to this \c ListenerInfo. + * + * @param other The object to compare against this \c ListenerInfo. + * @return \c true if the other object is a \c ListenerInfo + * object and both objects refer to the same listener for a + * given addition and removal life cycle. + */ + bool operator==(const ListenerInfo& other) const; + + private: + + friend class ServiceListenerEntry; + + US_HASH_FUNCTION_FRIEND(ServiceListenerHook::ListenerInfo); + + ListenerInfo(ListenerInfoData* data); + + ExplicitlySharedDataPointer d; + }; + + virtual ~ServiceListenerHook(); + + /** + * Added listeners hook method. This method is called to provide the hook + * implementation with information on newly added service listeners. This + * method will be called as service listeners are added while this hook is + * registered. Also, immediately after registration of this hook, this + * method will be called to provide the current collection of service + * listeners which had been added prior to the hook being registered. + * + * @param listeners A collection of \c ListenerInfo objects for newly added + * service listeners which are now listening to service events. + */ + virtual void Added(const std::vector& listeners) = 0; + + /** + * Removed listeners hook method. This method is called to provide the hook + * implementation with information on newly removed service listeners. This + * method will be called as service listeners are removed while this hook is + * registered. + * + * @param listeners A collection of \c ListenerInfo objects for newly removed + * service listeners which are no longer listening to service events. + */ + virtual void Removed(const std::vector& listeners) = 0; + +}; + +US_END_NAMESPACE + +US_HASH_FUNCTION_NAMESPACE_BEGIN +US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceListenerHook::ListenerInfo)) + return US_HASH_FUNCTION(const US_PREPEND_NAMESPACE(ServiceListenerHook::ListenerInfoData)*, arg.d.Data()); +US_HASH_FUNCTION_END +US_HASH_FUNCTION_NAMESPACE_END + +US_DECLARE_SERVICE_INTERFACE(us::ServiceListenerHook, "org.cppmicroservices.ServiceListenerHook/2.0.0") + +#endif // USSERVICELISTENERHOOK_H diff --git a/Core/CppMicroServices/src/service/usServiceListenerHook_p.h b/Core/CppMicroServices/src/service/usServiceListenerHook_p.h new file mode 100644 index 0000000000..704d5d9206 --- /dev/null +++ b/Core/CppMicroServices/src/service/usServiceListenerHook_p.h @@ -0,0 +1,43 @@ +/*=================================================================== + +BlueBerry Platform + +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. + +===================================================================*/ + +#ifndef USSERVICELISTENERHOOK_P_H +#define USSERVICELISTENERHOOK_P_H + +#include + +#include "usServiceListenerHook.h" +#include "usServiceListenerEntry_p.h" +#include "usSharedData.h" + +US_BEGIN_NAMESPACE + +class ServiceListenerHook::ListenerInfoData : public SharedData +{ +public: + ListenerInfoData(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& l, + void* data, const std::string& filter); + + ModuleContext* const mc; + ServiceListenerEntry::ServiceListener listener; + void* data; + std::string filter; + bool bRemoved; +}; + +US_END_NAMESPACE + +#endif // USSERVICELISTENERHOOK_P_H diff --git a/Core/CppMicroServices/src/service/usServiceListeners.cpp b/Core/CppMicroServices/src/service/usServiceListeners.cpp index 85df22931b..f364968f8c 100644 --- a/Core/CppMicroServices/src/service/usServiceListeners.cpp +++ b/Core/CppMicroServices/src/service/usServiceListeners.cpp @@ -1,290 +1,329 @@ /*============================================================================= 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 "usUtils_p.h" #include "usServiceListeners_p.h" #include "usServiceReferenceBasePrivate.h" +#include "usCoreModuleContext_p.h" #include "usModule.h" +#include "usModuleContext.h" -//#include US_BEGIN_NAMESPACE const int ServiceListeners::OBJECTCLASS_IX = 0; const int ServiceListeners::SERVICE_ID_IX = 1; -ServiceListeners::ServiceListeners() +ServiceListeners::ServiceListeners(CoreModuleContext* coreCtx) + : coreCtx(coreCtx) { hashedServiceKeys.push_back(ServiceConstants::OBJECTCLASS()); hashedServiceKeys.push_back(ServiceConstants::SERVICE_ID()); } void ServiceListeners::AddServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data, const std::string& filter) { - MutexLocker lock(mutex); + Lock(this); + + ServiceListenerEntry sle(mc, listener, data, filter); + RemoveServiceListener_unlocked(sle); - ServiceListenerEntry sle(mc->GetModule(), listener, data, filter); - if (serviceSet.find(sle) != serviceSet.end()) - { - RemoveServiceListener_unlocked(sle); - } serviceSet.insert(sle); + coreCtx->serviceHooks.HandleServiceListenerReg(sle); CheckSimple(sle); } void ServiceListeners::RemoveServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data) { - ServiceListenerEntry entryToRemove(mc->GetModule(), listener, data); + ServiceListenerEntry entryToRemove(mc, listener, data); - MutexLocker lock(mutex); + Lock(this); RemoveServiceListener_unlocked(entryToRemove); } void ServiceListeners::RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove) { - for (ServiceListenerEntries::iterator it = serviceSet.begin(); - it != serviceSet.end(); ++it) + ServiceListenerEntries::const_iterator it = serviceSet.find(entryToRemove); + if (it != serviceSet.end()) { - if (it->operator ==(entryToRemove)) - { - it->SetRemoved(true); - RemoveFromCache(*it); - serviceSet.erase(it); - break; - } + it->SetRemoved(true); + coreCtx->serviceHooks.HandleServiceListenerUnreg(*it); + RemoveFromCache(*it); + serviceSet.erase(it); } } void ServiceListeners::AddModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data) { - MutexLocker lock(moduleListenerMapMutex); + MutexLock lock(moduleListenerMapMutex); ModuleListenerMap::value_type::second_type& listeners = moduleListenerMap[mc]; if (std::find_if(listeners.begin(), listeners.end(), std::bind1st(ModuleListenerCompare(), std::make_pair(listener, data))) == listeners.end()) { listeners.push_back(std::make_pair(listener, data)); } } void ServiceListeners::RemoveModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data) { - MutexLocker lock(moduleListenerMapMutex); + MutexLock lock(moduleListenerMapMutex); moduleListenerMap[mc].remove_if(std::bind1st(ModuleListenerCompare(), std::make_pair(listener, data))); } void ServiceListeners::ModuleChanged(const ModuleEvent& evt) { - MutexLocker lock(moduleListenerMapMutex); - for(ModuleListenerMap::iterator i = moduleListenerMap.begin(); - i != moduleListenerMap.end(); ++i) + ModuleListenerMap filteredModuleListeners; + coreCtx->moduleHooks.FilterModuleEventReceivers(evt, filteredModuleListeners); + + for(ModuleListenerMap::iterator iter = filteredModuleListeners.begin(), end = filteredModuleListeners.end(); + iter != end; ++iter) { - for(std::list >::iterator j = i->second.begin(); - j != i->second.end(); ++j) + for (ModuleListenerMap::mapped_type::iterator iter2 = iter->second.begin(), end2 = iter->second.end(); + iter2 != end2; ++iter2) { - (j->first)(evt); + (iter2->first)(evt); } } } void ServiceListeners::RemoveAllListeners(ModuleContext* mc) { { - MutexLocker lock(mutex); + Lock(this); for (ServiceListenerEntries::iterator it = serviceSet.begin(); it != serviceSet.end(); ) { - if (it->GetModule() == mc->GetModule()) + if (it->GetModuleContext() == mc) { RemoveFromCache(*it); serviceSet.erase(it++); } else { ++it; } } } { - MutexLocker lock(moduleListenerMapMutex); + MutexLock lock(moduleListenerMapMutex); moduleListenerMap.erase(mc); } } -void ServiceListeners::ServiceChanged(const ServiceListenerEntries& receivers, +void ServiceListeners::HooksModuleStopped(ModuleContext* mc) +{ + Lock(this); + std::vector entries; + for (ServiceListenerEntries::iterator it = serviceSet.begin(); + it != serviceSet.end(); ) + { + if (it->GetModuleContext() == mc) + { + entries.push_back(*it); + } + } + coreCtx->serviceHooks.HandleServiceListenerUnreg(entries); +} + +void ServiceListeners::ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt) { ServiceListenerEntries matchBefore; ServiceChanged(receivers, evt, matchBefore); } -void ServiceListeners::ServiceChanged(const ServiceListenerEntries& receivers, +void ServiceListeners::ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt, ServiceListenerEntries& matchBefore) { int n = 0; - for (ServiceListenerEntries::const_iterator l = receivers.begin(); - l != receivers.end(); ++l) + if (!matchBefore.empty()) { - if (!matchBefore.empty()) + for (ServiceListenerEntries::const_iterator l = receivers.begin(); + l != receivers.end(); ++l) { matchBefore.erase(*l); } + } + for (ServiceListenerEntries::const_iterator l = receivers.begin(); + l != receivers.end(); ++l) + { if (!l->IsRemoved()) { try { ++n; l->CallDelegate(evt); } catch (...) { US_WARN << "Service listener" #ifdef US_MODULE_SUPPORT_ENABLED << " in " << l->GetModule()->GetName() #endif << " threw an exception!"; } } } //US_DEBUG << "Notified " << n << " listeners"; } -void ServiceListeners::GetMatchingServiceListeners(const ServiceReferenceBase& sr, ServiceListenerEntries& set, +void ServiceListeners::GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& set, bool lockProps) { - MutexLocker lock(mutex); + Lock(this); + + // Filter the original set of listeners + ServiceListenerEntries receivers = serviceSet; + coreCtx->serviceHooks.FilterServiceEventReceivers(evt, receivers); // Check complicated or empty listener filters - int n = 0; for (std::list::const_iterator sse = complicatedListeners.begin(); sse != complicatedListeners.end(); ++sse) { - ++n; + if (receivers.count(*sse) == 0) continue; const LDAPExpr& ldapExpr = sse->GetLDAPExpr(); if (ldapExpr.IsNull() || - ldapExpr.Evaluate(sr.d->GetProperties(), false)) + ldapExpr.Evaluate(evt.GetServiceReference().d->GetProperties(), false)) { set.insert(*sse); } } //US_DEBUG << "Added " << set.size() << " out of " << n // << " listeners with complicated filters"; // Check the cache const std::vector c(any_cast > - (sr.d->GetProperty(ServiceConstants::OBJECTCLASS(), lockProps))); + (evt.GetServiceReference().d->GetProperty(ServiceConstants::OBJECTCLASS(), lockProps))); for (std::vector::const_iterator objClass = c.begin(); objClass != c.end(); ++objClass) { - AddToSet(set, OBJECTCLASS_IX, *objClass); + AddToSet(set, receivers, OBJECTCLASS_IX, *objClass); } - long service_id = any_cast(sr.d->GetProperty(ServiceConstants::SERVICE_ID(), lockProps)); + long service_id = any_cast(evt.GetServiceReference().d->GetProperty(ServiceConstants::SERVICE_ID(), lockProps)); std::stringstream ss; ss << service_id; - AddToSet(set, SERVICE_ID_IX, ss.str()); + AddToSet(set, receivers, SERVICE_ID_IX, ss.str()); +} + +std::vector ServiceListeners::GetListenerInfoCollection() const +{ + Lock(this); + std::vector result; + result.reserve(serviceSet.size()); + for (ServiceListenerEntries::const_iterator iter = serviceSet.begin(), + iterEnd = serviceSet.end(); iter != iterEnd; ++iter) + { + result.push_back(*iter); + } + return result; } void ServiceListeners::RemoveFromCache(const ServiceListenerEntry& sle) { if (!sle.GetLocalCache().empty()) { for (std::size_t i = 0; i < hashedServiceKeys.size(); ++i) { CacheType& keymap = cache[i]; std::vector& l = sle.GetLocalCache()[i]; for (std::vector::const_iterator it = l.begin(); it != l.end(); ++it) { std::list& sles = keymap[*it]; sles.remove(sle); if (sles.empty()) { keymap.erase(*it); } } } } else { complicatedListeners.remove(sle); } } void ServiceListeners::CheckSimple(const ServiceListenerEntry& sle) { if (sle.GetLDAPExpr().IsNull()) { complicatedListeners.push_back(sle); } else { LDAPExpr::LocalCache local_cache; if (sle.GetLDAPExpr().IsSimple(hashedServiceKeys, local_cache, false)) { sle.GetLocalCache() = local_cache; for (std::size_t i = 0; i < hashedServiceKeys.size(); ++i) { for (std::vector::const_iterator it = local_cache[i].begin(); it != local_cache[i].end(); ++it) { std::list& sles = cache[i][*it]; sles.push_back(sle); } } } else { //US_DEBUG << "Too complicated filter: " << sle.GetFilter(); complicatedListeners.push_back(sle); } } } void ServiceListeners::AddToSet(ServiceListenerEntries& set, + const ServiceListenerEntries& receivers, int cache_ix, const std::string& val) { std::list& l = cache[cache_ix][val]; if (!l.empty()) { //US_DEBUG << hashedServiceKeys[cache_ix] << " matches " << l.size(); for (std::list::const_iterator entry = l.begin(); entry != l.end(); ++entry) { - set.insert(*entry); + if (receivers.count(*entry)) + { + set.insert(*entry); + } } } else { //US_DEBUG << hashedServiceKeys[cache_ix] << " matches none"; } } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceListeners_p.h b/Core/CppMicroServices/src/service/usServiceListeners_p.h index 0544b58ee3..51c2bf2ab3 100644 --- a/Core/CppMicroServices/src/service/usServiceListeners_p.h +++ b/Core/CppMicroServices/src/service/usServiceListeners_p.h @@ -1,176 +1,181 @@ /*============================================================================= 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 USSERVICELISTENERS_H #define USSERVICELISTENERS_H #include #include #include #include #include "usServiceListenerEntry_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModuleContext; /** * Here we handle all listeners that modules have registered. * */ -class ServiceListeners { - -private: - - typedef Mutex MutexType; - typedef MutexLock MutexLocker; +class ServiceListeners : private MultiThreaded<> +{ public: typedef US_MODULE_LISTENER_FUNCTOR ModuleListener; typedef US_UNORDERED_MAP_TYPE > > ModuleListenerMap; ModuleListenerMap moduleListenerMap; - MutexType moduleListenerMapMutex; + Mutex moduleListenerMapMutex; typedef US_UNORDERED_MAP_TYPE > CacheType; typedef US_UNORDERED_SET_TYPE ServiceListenerEntries; private: std::vector hashedServiceKeys; static const int OBJECTCLASS_IX; // = 0; static const int SERVICE_ID_IX; // = 1; /* Service listeners with complicated or empty filters */ std::list complicatedListeners; /* Service listeners with "simple" filters are cached. */ CacheType cache[2]; ServiceListenerEntries serviceSet; - MutexType mutex; + CoreModuleContext* coreCtx; public: - ServiceListeners(); + ServiceListeners(CoreModuleContext* coreCtx); /** * Add a new service listener. If an old one exists, and it has the * same owning module, the old listener is removed first. * * @param mc The module context adding this listener. * @param listener The service listener to add. * @param data Additional data to distinguish ServiceListener objects. * @param filter An LDAP filter string to check when a service is modified. * @exception org.osgi.framework.InvalidSyntaxException * If the filter is not a correct LDAP expression. */ void AddServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data, const std::string& filter); /** * Remove service listener from current framework. Silently ignore * if listener doesn't exist. If listener is registered more than * once remove all instances. * * @param mc The module context who wants to remove listener. * @param listener Object to remove. * @param data Additional data to distinguish ServiceListener objects. */ void RemoveServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data); /** * Add a new module listener. * * @param mc The module context adding this listener. * @param listener The module listener to add. * @param data Additional data to distinguish ModuleListener objects. */ void AddModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data); /** * Remove module listener from current framework. Silently ignore * if listener doesn't exist. * * @param mc The module context who wants to remove listener. * @param listener Object to remove. * @param data Additional data to distinguish ModuleListener objects. */ void RemoveModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data); void ModuleChanged(const ModuleEvent& evt); /** * Remove all listener registered by a module in the current framework. * * @param mc Module context which listeners we want to remove. */ void RemoveAllListeners(ModuleContext* mc); + /** + * Notify hooks that a module is about to be stopped + * + * @param mc Module context which listeners are about to be removed. + */ + void HooksModuleStopped(ModuleContext* mc); + /** * Receive notification that a service has had a change occur in its lifecycle. * * @see org.osgi.framework.ServiceListener#serviceChanged */ - void ServiceChanged(const ServiceListenerEntries& receivers, + void ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt, ServiceListenerEntries& matchBefore); - void ServiceChanged(const ServiceListenerEntries& receivers, + void ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt); /** * * */ - void GetMatchingServiceListeners(const ServiceReferenceBase& sr, ServiceListenerEntries& listeners, + void GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& listeners, bool lockProps = true); + std::vector GetListenerInfoCollection() const; + private: void RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove); /** * Remove all references to a service listener from the service listener * cache. */ void RemoveFromCache(const ServiceListenerEntry& sle); /** * Checks if the specified service listener's filter is simple enough * to cache. */ void CheckSimple(const ServiceListenerEntry& sle); - void AddToSet(ServiceListenerEntries& set, int cache_ix, const std::string& val); + void AddToSet(ServiceListenerEntries& set, const ServiceListenerEntries& receivers, int cache_ix, const std::string& val); }; US_END_NAMESPACE #endif // USSERVICELISTENERS_H diff --git a/Core/CppMicroServices/src/service/usServiceReference.h b/Core/CppMicroServices/src/service/usServiceReference.h index ff9bfc6cd0..8ad00e8a0c 100644 --- a/Core/CppMicroServices/src/service/usServiceReference.h +++ b/Core/CppMicroServices/src/service/usServiceReference.h @@ -1,146 +1,142 @@ /*============================================================================= 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 USSERVICEREFERENCE_H #define USSERVICEREFERENCE_H #include #include -//US_MSVC_PUSH_DISABLE_WARNING(4396) - US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * A reference to a service. * *

* The framework returns ServiceReference objects from the * ModuleContext::GetServiceReference and * ModuleContext::GetServiceReferences methods. *

* A ServiceReference object may be shared between modules and * can be used to examine the properties of the service and to get the service * object. *

* Every service registered in the framework has a unique * ServiceRegistration object and may have multiple, distinct * ServiceReference objects referring to it. * ServiceReference objects associated with a * ServiceRegistration are considered equal * (more specifically, their operator==() * method will return true when compared). *

* If the same service object is registered multiple times, * ServiceReference objects associated with different * ServiceRegistration objects are not equal. * * @tparam S The class type of the service interface * @see ModuleContext::GetServiceReference * @see ModuleContext::GetServiceReferences * @see ModuleContext::GetService * @remarks This class is thread safe. */ template class ServiceReference : public ServiceReferenceBase { public: - typedef S ServiceT; + typedef S ServiceType; /** * Creates an invalid ServiceReference object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceReference() : ServiceReferenceBase() { } ServiceReference(const ServiceReferenceBase& base) : ServiceReferenceBase(base) { const std::string interfaceId(us_service_interface_iid()); if (GetInterfaceId() != interfaceId) { if (this->IsConvertibleTo(interfaceId)) { this->SetInterfaceId(interfaceId); } else { this->operator =(0); } } } using ServiceReferenceBase::operator=; }; /** * \cond * * Specialization for void, representing a generic service * reference not bound to any interface identifier. * */ template<> class ServiceReference : public ServiceReferenceBase { public: /** * Creates an invalid ServiceReference object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceReference() : ServiceReferenceBase() { } ServiceReference(const ServiceReferenceBase& base) : ServiceReferenceBase(base) { } using ServiceReferenceBase::operator=; typedef void ServiceType; }; /// \endcond /** * \ingroup MicroServices * * A service reference of unknown type, which is not bound to any * interface identifier. */ typedef ServiceReference ServiceReferenceU; US_END_NAMESPACE -//US_MSVC_POP_WARNING - #endif // USSERVICEREFERENCE_H diff --git a/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp b/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp index 0c8e60d8f4..f785148c74 100644 --- a/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp +++ b/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp @@ -1,218 +1,215 @@ /*============================================================================= 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 "usServiceReferenceBase.h" #include "usServiceReferenceBasePrivate.h" #include "usServiceRegistrationBasePrivate.h" #include "usModule.h" #include "usModulePrivate.h" US_BEGIN_NAMESPACE -typedef ServiceRegistrationBasePrivate::MutexType MutexType; -typedef MutexLock MutexLocker; - ServiceReferenceBase::ServiceReferenceBase() : d(new ServiceReferenceBasePrivate(0)) { } ServiceReferenceBase::ServiceReferenceBase(const ServiceReferenceBase& ref) : d(ref.d) { d->ref.Ref(); } ServiceReferenceBase::ServiceReferenceBase(ServiceRegistrationBasePrivate* reg) : d(new ServiceReferenceBasePrivate(reg)) { } void ServiceReferenceBase::SetInterfaceId(const std::string& interfaceId) { if (d->ref > 1) { // detach d->ref.Deref(); d = new ServiceReferenceBasePrivate(d->registration); } d->interfaceId = interfaceId; } ServiceReferenceBase::operator bool_type() const { return GetModule() != 0 ? &ServiceReferenceBase::d : NULL; } ServiceReferenceBase& ServiceReferenceBase::operator=(int null) { if (null == 0) { if (!d->ref.Deref()) delete d; d = new ServiceReferenceBasePrivate(0); } return *this; } ServiceReferenceBase::~ServiceReferenceBase() { if (!d->ref.Deref()) delete d; } Any ServiceReferenceBase::GetProperty(const std::string& key) const { - MutexLocker lock(d->registration->propsLock); + MutexLock lock(d->registration->propsLock); return d->registration->properties.Value(key); } void ServiceReferenceBase::GetPropertyKeys(std::vector& keys) const { - MutexLocker lock(d->registration->propsLock); + MutexLock lock(d->registration->propsLock); const std::vector& ks = d->registration->properties.Keys(); keys.assign(ks.begin(), ks.end()); } Module* ServiceReferenceBase::GetModule() const { if (d->registration == 0 || d->registration->module == 0) { return 0; } return d->registration->module->q; } void ServiceReferenceBase::GetUsingModules(std::vector& modules) const { - MutexLocker lock(d->registration->propsLock); + MutexLock lock(d->registration->propsLock); ServiceRegistrationBasePrivate::ModuleToRefsMap::const_iterator end = d->registration->dependents.end(); for (ServiceRegistrationBasePrivate::ModuleToRefsMap::const_iterator iter = d->registration->dependents.begin(); iter != end; ++iter) { modules.push_back(iter->first); } } bool ServiceReferenceBase::operator<(const ServiceReferenceBase& reference) const { int r1 = 0; int r2 = 0; if (!(*this)) { return true; } if (!reference) { return false; } Any anyR1 = GetProperty(ServiceConstants::SERVICE_RANKING()); Any anyR2 = reference.GetProperty(ServiceConstants::SERVICE_RANKING()); if (anyR1.Type() == typeid(int)) r1 = any_cast(anyR1); if (anyR2.Type() == typeid(int)) r2 = any_cast(anyR2); if (r1 != r2) { // use ranking if ranking differs return r1 < r2; } else { long int id1 = any_cast(GetProperty(ServiceConstants::SERVICE_ID())); long int id2 = any_cast(reference.GetProperty(ServiceConstants::SERVICE_ID())); // otherwise compare using IDs, // is less than if it has a higher ID. return id2 < id1; } } bool ServiceReferenceBase::operator==(const ServiceReferenceBase& reference) const { return d->registration == reference.d->registration; } ServiceReferenceBase& ServiceReferenceBase::operator=(const ServiceReferenceBase& reference) { ServiceReferenceBasePrivate* curr_d = d; d = reference.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } bool ServiceReferenceBase::IsConvertibleTo(const std::string& interfaceId) const { return d->IsConvertibleTo(interfaceId); } std::string ServiceReferenceBase::GetInterfaceId() const { return d->interfaceId; } std::size_t ServiceReferenceBase::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; return US_HASH_FUNCTION(ServiceRegistrationBasePrivate*, this->d->registration); } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ServiceReferenceBase& serviceRef) { if (serviceRef) { os << "Reference for service object registered from " << serviceRef.GetModule()->GetName() << " " << serviceRef.GetModule()->GetVersion() << " ("; std::vector keys; serviceRef.GetPropertyKeys(keys); size_t keySize = keys.size(); for(size_t i = 0; i < keySize; ++i) { os << keys[i] << "=" << serviceRef.GetProperty(keys[i]).ToString(); if (i < keySize-1) os << ","; } os << ")"; } else { os << "Invalid service reference"; } return os; } diff --git a/Core/CppMicroServices/src/service/usServiceReferenceBase.h b/Core/CppMicroServices/src/service/usServiceReferenceBase.h index b707fc884d..8949cec859 100644 --- a/Core/CppMicroServices/src/service/usServiceReferenceBase.h +++ b/Core/CppMicroServices/src/service/usServiceReferenceBase.h @@ -1,232 +1,234 @@ /*============================================================================= 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 USSERVICEREFERENCEBASE_H #define USSERVICEREFERENCEBASE_H #include US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class Module; class ServiceRegistrationBasePrivate; class ServiceReferenceBasePrivate; /** * \ingroup MicroServices * * A reference to a service. * * \note This class is provided as public API for low-level service queries only. * In almost all cases you should use the template ServiceReference instead. */ class US_EXPORT ServiceReferenceBase { private: typedef ServiceReferenceBasePrivate* ServiceReferenceBase::*bool_type; public: ServiceReferenceBase(const ServiceReferenceBase& ref); /** * Converts this ServiceReferenceBase instance into a boolean * expression. If this instance was default constructed or * the service it references has been unregistered, the conversion * returns false, otherwise it returns true. */ operator bool_type() const; /** * Releases any resources held or locked by this * ServiceReferenceBase and renders it invalid. */ ServiceReferenceBase& operator=(int null); ~ServiceReferenceBase(); /** * Returns the property value to which the specified property key is mapped * in the properties ServiceProperties object of the service * referenced by this ServiceReferenceBase object. * *

* Property keys are case-insensitive. * *

* This method continues to return property values after the service has * been unregistered. This is so references to unregistered services can * still be interrogated. * * @param key The property key. * @return The property value to which the key is mapped; an invalid Any * if there is no property named after the key. */ Any GetProperty(const std::string& key) const; /** * Returns a list of the keys in the ServiceProperties * object of the service referenced by this ServiceReferenceBase * object. * *

* This method will continue to return the keys after the service has been * unregistered. This is so references to unregistered services can * still be interrogated. * * @param keys A vector being filled with the property keys. */ void GetPropertyKeys(std::vector& keys) const; /** * Returns the module that registered the service referenced by this * ServiceReferenceBase object. * *

* This method must return 0 when the service has been * unregistered. This can be used to determine if the service has been * unregistered. * * @return The module that registered the service referenced by this * ServiceReferenceBase object; 0 if that * service has already been unregistered. * @see ModuleContext::RegisterService(const InterfaceMap&, const ServiceProperties&) */ Module* GetModule() const; /** * Returns the modules that are using the service referenced by this * ServiceReferenceBase object. Specifically, this method returns * the modules whose usage count for that service is greater than zero. * * @param modules A list of modules whose usage count for the service referenced * by this ServiceReferenceBase object is greater than * zero. */ void GetUsingModules(std::vector& modules) const; /** * Returns the interface identifier this ServiceReferenceBase object * is bound to. * * A default constructed ServiceReferenceBase object is not bound to * any interface identifier and calling this method will return an * empty string. * * @return The interface identifier for this ServiceReferenceBase object. */ std::string GetInterfaceId() const; /** * Checks wether this ServiceReferenceBase object can be converted to * another ServiceReferenceBase object, which will be bound to the * given interface identifier. * * ServiceReferenceBase objects can be converted if the underlying service * implementation was registered under multiple service interfaces. * * @param interfaceid * @return \c true if this ServiceReferenceBase object can be converted, * \c false otherwise. */ bool IsConvertibleTo(const std::string& interfaceid) const; /** * Compares this ServiceReferenceBase with the specified * ServiceReferenceBase for order. * *

* If this ServiceReferenceBase and the specified * ServiceReferenceBase have the same \link ServiceConstants::SERVICE_ID() * service id\endlink they are equal. This ServiceReferenceBase is less * than the specified ServiceReferenceBase if it has a lower * {@link ServiceConstants::SERVICE_RANKING service ranking} and greater if it has a * higher service ranking. Otherwise, if this ServiceReferenceBase * and the specified ServiceReferenceBase have the same * {@link ServiceConstants::SERVICE_RANKING service ranking}, this * ServiceReferenceBase is less than the specified * ServiceReferenceBase if it has a higher * {@link ServiceConstants::SERVICE_ID service id} and greater if it has a lower * service id. * * @param reference The ServiceReferenceBase to be compared. * @return Returns a false or true if this * ServiceReferenceBase is less than or greater * than the specified ServiceReferenceBase. */ bool operator<(const ServiceReferenceBase& reference) const; bool operator==(const ServiceReferenceBase& reference) const; ServiceReferenceBase& operator=(const ServiceReferenceBase& reference); private: friend class ModulePrivate; friend class ModuleContext; + friend class ModuleHooks; + friend class ServiceHooks; friend class ServiceObjectsBase; friend class ServiceObjectsBasePrivate; friend class ServiceRegistrationBase; friend class ServiceRegistrationBasePrivate; friend class ServiceListeners; friend class ServiceRegistry; friend class LDAPFilter; template friend class ServiceReference; US_HASH_FUNCTION_FRIEND(ServiceReferenceBase); std::size_t Hash() const; /** * Creates an invalid ServiceReferenceBase object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceReferenceBase(); ServiceReferenceBase(ServiceRegistrationBasePrivate* reg); void SetInterfaceId(const std::string& interfaceId); ServiceReferenceBasePrivate* d; }; US_END_NAMESPACE US_MSVC_POP_WARNING /** * \ingroup MicroServices */ US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceReferenceBase)& serviceRef); US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceReferenceBase)) return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USSERVICEREFERENCEBASE_H diff --git a/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp b/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp index 505fdc4cc0..913c78f6cb 100644 --- a/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp +++ b/Core/CppMicroServices/src/service/usServiceReferenceBasePrivate.cpp @@ -1,324 +1,322 @@ /*============================================================================= 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); + MutexLock 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); + MutexLock 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); + MutexLock 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); + MutexLock 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); + MutexLock 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); + MutexLock lock(registration->propsLock); return registration->properties.Value(key); } else { return registration->properties.Value(key); } } bool ServiceReferenceBasePrivate::IsConvertibleTo(const std::string& interfaceId) const { return registration ? registration->service.find(interfaceId) != registration->service.end() : false; } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceRegistration.h b/Core/CppMicroServices/src/service/usServiceRegistration.h index d604ee8a41..d847321ce4 100644 --- a/Core/CppMicroServices/src/service/usServiceRegistration.h +++ b/Core/CppMicroServices/src/service/usServiceRegistration.h @@ -1,203 +1,203 @@ /*============================================================================= 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 USSERVICEREGISTRATION_H #define USSERVICEREGISTRATION_H #include "usServiceRegistrationBase.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * A registered service. * *

* The framework returns a ServiceRegistration object when a * ModuleContext#RegisterService() method invocation is successful. * The ServiceRegistration object is for the private use of the * registering module and should not be shared with other modules. *

* The ServiceRegistration object may be used to update the * properties of the service or to unregister the service. * * @tparam S Class tyoe of the service interface * @see ModuleContext#RegisterService() * @remarks This class is thread safe. */ template class ServiceRegistration : public ServiceRegistrationBase { public: /** * Creates an invalid ServiceRegistration object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceRegistration() : ServiceRegistrationBase() { } ///@{ /** * Returns a ServiceReference object for a service being * registered. *

* The ServiceReference object may be shared with other * modules. * * @throws std::logic_error If this * ServiceRegistration object has already been * unregistered or if it is invalid. * @return ServiceReference object. */ - ServiceReference GetReference(InterfaceT) const + ServiceReference GetReference(InterfaceType) const { return this->ServiceRegistrationBase::GetReference(us_service_interface_iid()); } - ServiceReference GetReference(InterfaceT) const + ServiceReference GetReference(InterfaceType) const { return this->ServiceRegistrationBase::GetReference(us_service_interface_iid()); } - ServiceReference GetReference(InterfaceT) const + ServiceReference GetReference(InterfaceType) const { return this->ServiceRegistrationBase::GetReference(us_service_interface_iid()); } ///@} using ServiceRegistrationBase::operator=; private: friend class ModuleContext; ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } }; /// \cond template class ServiceRegistration : public ServiceRegistrationBase { public: ServiceRegistration() : ServiceRegistrationBase() { } - ServiceReference GetReference(InterfaceT) const + ServiceReference GetReference(InterfaceType) const { return ServiceReference(this->ServiceRegistrationBase::GetReference(us_service_interface_iid())); } - ServiceReference GetReference(InterfaceT) const + ServiceReference GetReference(InterfaceType) const { return ServiceReference(this->ServiceRegistrationBase::GetReference(us_service_interface_iid())); } using ServiceRegistrationBase::operator=; private: friend class ModuleContext; ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } }; template class ServiceRegistration : public ServiceRegistrationBase { public: ServiceRegistration() : ServiceRegistrationBase() { } ServiceReference GetReference() const { - return this->GetReference(InterfaceT()); + return this->GetReference(InterfaceType()); } - ServiceReference GetReference(InterfaceT) const + ServiceReference GetReference(InterfaceType) const { return ServiceReference(this->ServiceRegistrationBase::GetReference(us_service_interface_iid())); } using ServiceRegistrationBase::operator=; private: friend class ModuleContext; ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } }; template<> class ServiceRegistration : public ServiceRegistrationBase { public: /** * Creates an invalid ServiceReference object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceRegistration() : ServiceRegistrationBase() { } ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } using ServiceRegistrationBase::operator=; }; /// \endcond /** * \ingroup MicroServices * * A service registration object of unknown type. */ typedef ServiceRegistration ServiceRegistrationU; US_END_NAMESPACE #endif // USSERVICEREGISTRATION_H diff --git a/Core/CppMicroServices/src/service/usServiceRegistrationBase.cpp b/Core/CppMicroServices/src/service/usServiceRegistrationBase.cpp index a84eb3db16..bbab8bad4b 100644 --- a/Core/CppMicroServices/src/service/usServiceRegistrationBase.cpp +++ b/Core/CppMicroServices/src/service/usServiceRegistrationBase.cpp @@ -1,272 +1,273 @@ /*============================================================================= 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 "usServiceRegistrationBase.h" #include "usServiceRegistrationBasePrivate.h" #include "usServiceListenerEntry_p.h" #include "usServiceRegistry_p.h" #include "usServiceFactory.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" #include US_BEGIN_NAMESPACE -typedef ServiceRegistrationBasePrivate::MutexLocker MutexLocker; - ServiceRegistrationBase::ServiceRegistrationBase() : d(0) { } ServiceRegistrationBase::ServiceRegistrationBase(const ServiceRegistrationBase& reg) : d(reg.d) { if (d) d->ref.Ref(); } ServiceRegistrationBase::ServiceRegistrationBase(ServiceRegistrationBasePrivate* registrationPrivate) : d(registrationPrivate) { if (d) d->ref.Ref(); } ServiceRegistrationBase::ServiceRegistrationBase(ModulePrivate* module, const InterfaceMap& service, const ServicePropertiesImpl& props) : d(new ServiceRegistrationBasePrivate(module, service, props)) { } ServiceRegistrationBase::operator bool_type() const { return d != NULL ? &ServiceRegistrationBase::d : NULL; } ServiceRegistrationBase& ServiceRegistrationBase::operator=(int null) { if (null == 0) { if (d && !d->ref.Deref()) { delete d; } d = 0; } return *this; } ServiceRegistrationBase::~ServiceRegistrationBase() { if (d && !d->ref.Deref()) delete d; } ServiceReferenceBase ServiceRegistrationBase::GetReference(const std::string& interfaceId) const { if (!d) throw std::logic_error("ServiceRegistrationBase object invalid"); if (!d->available) throw std::logic_error("Service is unregistered"); ServiceReferenceBase ref = d->reference; ref.SetInterfaceId(interfaceId); return ref; } void ServiceRegistrationBase::SetProperties(const ServiceProperties& props) { if (!d) throw std::logic_error("ServiceRegistrationBase object invalid"); - MutexLocker lock(d->eventLock); + MutexLock lock(d->eventLock); + ServiceEvent modifiedEndMatchEvent(ServiceEvent::MODIFIED_ENDMATCH, d->reference); ServiceListeners::ServiceListenerEntries before; // TBD, optimize the locking of services { - //MutexLocker lock2(d->module->coreCtx->globalFwLock); + //MutexLock lock2(d->module->coreCtx->globalFwLock); if (d->available) { // NYI! Optimize the MODIFIED_ENDMATCH code int old_rank = 0; int new_rank = 0; std::vector classes; { - MutexLocker lock3(d->propsLock); + MutexLock lock3(d->propsLock); { const Any& any = d->properties.Value(ServiceConstants::SERVICE_RANKING()); if (any.Type() == typeid(int)) old_rank = any_cast(any); } - d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, before, false); + d->module->coreCtx->listeners.GetMatchingServiceListeners(modifiedEndMatchEvent, before, false); classes = ref_any_cast >(d->properties.Value(ServiceConstants::OBJECTCLASS())); long int sid = any_cast(d->properties.Value(ServiceConstants::SERVICE_ID())); d->properties = ServiceRegistry::CreateServiceProperties(props, classes, false, false, sid); { const Any& any = d->properties.Value(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"); } } + ServiceEvent modifiedEvent(ServiceEvent::MODIFIED, d->reference); ServiceListeners::ServiceListenerEntries matchingListeners; - d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, matchingListeners); + d->module->coreCtx->listeners.GetMatchingServiceListeners(modifiedEvent, matchingListeners); d->module->coreCtx->listeners.ServiceChanged(matchingListeners, - ServiceEvent(ServiceEvent::MODIFIED, d->reference), + modifiedEvent, before); d->module->coreCtx->listeners.ServiceChanged(before, - ServiceEvent(ServiceEvent::MODIFIED_ENDMATCH, d->reference)); + modifiedEndMatchEvent); } void ServiceRegistrationBase::Unregister() { if (!d) throw std::logic_error("ServiceRegistrationBase object invalid"); if (d->unregistering) return; // Silently ignore redundant unregistration. { - MutexLocker lock(d->eventLock); + MutexLock 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)); + ServiceEvent unregisteringEvent(ServiceEvent::UNREGISTERING, d->reference); + d->module->coreCtx->listeners.GetMatchingServiceListeners(unregisteringEvent, listeners); + d->module->coreCtx->listeners.ServiceChanged( + listeners, + unregisteringEvent); } { - MutexLocker lock(d->eventLock); + MutexLock lock(d->eventLock); { - MutexLocker lock2(d->propsLock); + MutexLock lock2(d->propsLock); d->available = false; InterfaceMap::const_iterator factoryIter = d->service.find("org.cppmicroservices.factory"); if (d->module && factoryIter != d->service.end()) { ServiceFactory* serviceFactory = reinterpret_cast(factoryIter->second); ServiceRegistrationBasePrivate::ModuleToServicesMap::const_iterator end = d->prototypeServiceInstances.end(); // unget all prototype services for (ServiceRegistrationBasePrivate::ModuleToServicesMap::const_iterator i = d->prototypeServiceInstances.begin(); i != end; ++i) { for (std::list::const_iterator listIter = i->second.begin(); listIter != i->second.end(); ++listIter) { const InterfaceMap& service = *listIter; try { // NYI, don't call inside lock serviceFactory->UngetService(i->first, *this, service); } catch (const std::exception& /*ue*/) { US_WARN << "ServiceFactory UngetService implementation threw an exception"; } } } // unget module scope services ServiceRegistrationBasePrivate::ModuleToServiceMap::const_iterator moduleEnd = d->moduleServiceInstance.end(); for (ServiceRegistrationBasePrivate::ModuleToServiceMap::const_iterator i = d->moduleServiceInstance.begin(); i != moduleEnd; ++i) { try { // NYI, don't call inside lock serviceFactory->UngetService(i->first, *this, i->second); } catch (const std::exception& /*ue*/) { US_WARN << "ServiceFactory UngetService implementation threw an exception"; } } } d->module = 0; d->dependents.clear(); d->service.clear(); d->prototypeServiceInstances.clear(); d->moduleServiceInstance.clear(); // increment the reference count, since "d->reference" was used originally // to keep d alive. d->ref.Ref(); d->reference = 0; d->unregistering = false; } } } bool ServiceRegistrationBase::operator<(const ServiceRegistrationBase& o) const { if ((!d && !o.d) || !o.d) return false; if (!d) return true; return d->reference <(o.d->reference); } bool ServiceRegistrationBase::operator==(const ServiceRegistrationBase& registration) const { return d == registration.d; } ServiceRegistrationBase& ServiceRegistrationBase::operator=(const ServiceRegistrationBase& registration) { ServiceRegistrationBasePrivate* 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/CppMicroServices/src/service/usServiceRegistrationBase.h b/Core/CppMicroServices/src/service/usServiceRegistrationBase.h index 0dacb93622..5e02216946 100644 --- a/Core/CppMicroServices/src/service/usServiceRegistrationBase.h +++ b/Core/CppMicroServices/src/service/usServiceRegistrationBase.h @@ -1,228 +1,223 @@ /*============================================================================= 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 USSERVICEREGISTRATIONBASE_H #define USSERVICEREGISTRATIONBASE_H #include "usServiceProperties.h" #include "usServiceReference.h" -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4396) -#endif +US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class ModulePrivate; class ServiceRegistrationBasePrivate; class ServicePropertiesImpl; /** * \ingroup MicroServices * * A registered service. * *

* The framework returns a ServiceRegistrationBase object when a * ModuleContext#RegisterService() method invocation is successful. * The ServiceRegistrationBase object is for the private use of the * registering module and should not be shared with other modules. *

* The ServiceRegistrationBase object may be used to update the * properties of the service or to unregister the service. * * \note This class is provided as public API for low-level service management only. * In almost all cases you should use the template ServiceRegistration instead. * * @see ModuleContext#RegisterService() * @remarks This class is thread safe. */ class US_EXPORT ServiceRegistrationBase { private: typedef ServiceRegistrationBasePrivate* ServiceRegistrationBase::*bool_type; public: ServiceRegistrationBase(const ServiceRegistrationBase& reg); /** * A boolean conversion operator converting this ServiceRegistrationBase object * to \c true if it is valid and to \c false otherwise. A SeriveRegistration * object is invalid if it was default-constructed or was invalidated by * assigning 0 to it. * * \see operator=(int) * * \return \c true if this ServiceRegistrationBase object is valid, \c false * otherwise. */ operator bool_type() const; /** * Releases any resources held or locked by this * ServiceRegistrationBase and renders it invalid. * * \return This ServiceRegistrationBase object. */ ServiceRegistrationBase& operator=(int null); ~ServiceRegistrationBase(); /** * Returns a ServiceReference object for a service being * registered. *

* The ServiceReference object may be shared with other * modules. * * @throws std::logic_error If this * ServiceRegistrationBase object has already been * unregistered or if it is invalid. * @return ServiceReference object. */ ServiceReferenceBase GetReference(const std::string& interfaceId = std::string()) const; /** * Updates the properties associated with a service. * *

* The ServiceConstants#OBJECTCLASS and ServiceConstants#SERVICE_ID keys * cannot be modified by this method. These values are set by the framework * when the service is registered in the environment. * *

* The following steps are taken to modify service properties: *

    *
  1. The service's properties are replaced with the provided properties. *
  2. A service event of type ServiceEvent#MODIFIED is fired. *
* * @param properties The properties for this service. See {@link ServiceProperties} * for a list of standard service property keys. Changes should not * be made to this object after calling this method. To update the * service's properties this method should be called again. * * @throws std::logic_error If this ServiceRegistrationBase * object has already been unregistered or if it is invalid. * @throws std::invalid_argument If properties contains * case variants of the same key name. */ void SetProperties(const ServiceProperties& properties); /** * Unregisters a service. Remove a ServiceRegistrationBase object * from the framework service registry. All ServiceRegistrationBase * objects associated with this ServiceRegistrationBase object * can no longer be used to interact with the service once unregistration is * complete. * *

* The following steps are taken to unregister a service: *

    *
  1. The service is removed from the framework service registry so that * it can no longer be obtained. *
  2. A service event of type ServiceEvent#UNREGISTERING is fired * so that modules using this service can release their use of the service. * Once delivery of the service event is complete, the * ServiceRegistrationBase objects for the service may no longer be * used to get a service object for the service. *
  3. For each module whose use count for this service is greater than * zero:
    * The module's use count for this service is set to zero.
    * If the service was registered with a ServiceFactory object, the * ServiceFactory#UngetService method is called to release * the service object for the module. *
* * @throws std::logic_error If this * ServiceRegistrationBase object has already been * unregistered or if it is invalid. * @see ModuleContext#UngetService * @see ServiceFactory#UngetService */ void Unregister(); /** * Compare two ServiceRegistrationBase objects. * * If both ServiceRegistrationBase objects are valid, the comparison is done * using the underlying ServiceReference object. Otherwise, this ServiceRegistrationBase * object is less than the other object if and only if this object is invalid and * the other object is valid. * * @param o The ServiceRegistrationBase object to compare with. * @return \c true if this ServiceRegistrationBase object is less than the other object. */ bool operator<(const ServiceRegistrationBase& o) const; bool operator==(const ServiceRegistrationBase& registration) const; ServiceRegistrationBase& operator=(const ServiceRegistrationBase& registration); private: friend class ServiceRegistry; friend class ServiceReferenceBasePrivate; template friend class ServiceRegistration; US_HASH_FUNCTION_FRIEND(ServiceRegistrationBase); /** * Creates an invalid ServiceRegistrationBase object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceRegistrationBase(); ServiceRegistrationBase(ServiceRegistrationBasePrivate* registrationPrivate); ServiceRegistrationBase(ModulePrivate* module, const InterfaceMap& service, const ServicePropertiesImpl& props); ServiceRegistrationBasePrivate* d; }; US_END_NAMESPACE -#ifdef _MSC_VER -#pragma warning(pop) -#endif +US_MSVC_POP_WARNING US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceRegistrationBase)) return US_HASH_FUNCTION(US_PREPEND_NAMESPACE(ServiceRegistrationBasePrivate)*, arg.d); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END inline std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceRegistrationBase)& /*reg*/) { return os << "US_PREPEND_NAMESPACE(ServiceRegistrationBase) object"; } #endif // USSERVICEREGISTRATIONBASE_H diff --git a/Core/CppMicroServices/src/service/usServiceRegistrationBasePrivate.h b/Core/CppMicroServices/src/service/usServiceRegistrationBasePrivate.h index 504907f61f..5a70e504f4 100644 --- a/Core/CppMicroServices/src/service/usServiceRegistrationBasePrivate.h +++ b/Core/CppMicroServices/src/service/usServiceRegistrationBasePrivate.h @@ -1,152 +1,149 @@ /*============================================================================= 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 USSERVICEREGISTRATIONBASEPRIVATE_H #define USSERVICEREGISTRATIONBASEPRIVATE_H #include "usServiceInterface.h" #include "usServiceReference.h" #include "usServicePropertiesImpl_p.h" #include "usAtomicInt_p.h" US_BEGIN_NAMESPACE class ModulePrivate; class ServiceRegistrationBase; /** * \ingroup MicroServices */ class ServiceRegistrationBasePrivate { protected: friend class ServiceRegistrationBase; // The ServiceReferenceBasePrivate class holds a pointer to a // ServiceRegistrationBasePrivate instance and needs to manipulate // its reference count. This way it can keep the ServiceRegistrationBasePrivate // instance alive and keep returning service properties for // unregistered service instances. friend class ServiceReferenceBasePrivate; /** * Reference count for implicitly shared private implementation. */ AtomicInt ref; /** * Service or ServiceFactory object. */ InterfaceMap service; public: - typedef Mutex MutexType; - typedef MutexLock MutexLocker; - typedef US_UNORDERED_MAP_TYPE ModuleToRefsMap; typedef US_UNORDERED_MAP_TYPE ModuleToServiceMap; typedef US_UNORDERED_MAP_TYPE > ModuleToServicesMap; /** * Modules dependent on this service. Integer is used as * reference counter, counting number of unbalanced getService(). */ ModuleToRefsMap dependents; /** * Object instances that a prototype factory has produced. */ ModuleToServicesMap prototypeServiceInstances; /** * Object instance with module scope that a factory may have produced. */ ModuleToServiceMap moduleServiceInstance; /** * Module registering this service. */ ModulePrivate* module; /** * Reference object to this service registration. */ ServiceReferenceBase reference; /** * Service properties. */ ServicePropertiesImpl properties; /** * Is service available. I.e., if true then holders * of a ServiceReference for the service are allowed to get it. */ volatile bool available; /** * Avoid recursive unregistrations. I.e., if true then * unregistration of this service has started but is not yet * finished. */ volatile bool unregistering; /** * Lock object for synchronous event delivery. */ - MutexType eventLock; + Mutex eventLock; // needs to be recursive - MutexType propsLock; + Mutex propsLock; ServiceRegistrationBasePrivate(ModulePrivate* module, const InterfaceMap& service, const ServicePropertiesImpl& props); ~ServiceRegistrationBasePrivate(); /** * Check if a module uses this service * * @param p Module to check * @return true if module uses this service */ bool IsUsedByModule(Module* m) const; const InterfaceMap& GetInterfaces() const; void* GetService(const std::string& interfaceId) const; private: // purposely not implemented ServiceRegistrationBasePrivate(const ServiceRegistrationBasePrivate&); ServiceRegistrationBasePrivate& operator=(const ServiceRegistrationBasePrivate&); }; US_END_NAMESPACE #endif // USSERVICEREGISTRATIONBASEPRIVATE_H diff --git a/Core/CppMicroServices/src/service/usServiceRegistry.cpp b/Core/CppMicroServices/src/service/usServiceRegistry.cpp index 92222eba19..5841b382d8 100644 --- a/Core/CppMicroServices/src/service/usServiceRegistry.cpp +++ b/Core/CppMicroServices/src/service/usServiceRegistry.cpp @@ -1,322 +1,338 @@ /*============================================================================= 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 "usServiceRegistry_p.h" #include "usServiceFactory.h" #include "usPrototypeServiceFactory.h" #include "usServiceRegistry_p.h" #include "usServiceRegistrationBasePrivate.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE -typedef MutexLock MutexLocker; - - ServicePropertiesImpl ServiceRegistry::CreateServiceProperties(const ServiceProperties& in, const std::vector& classes, bool isFactory, bool isPrototypeFactory, long sid) { static long nextServiceID = 1; ServiceProperties props(in); if (!classes.empty()) { props.insert(std::make_pair(ServiceConstants::OBJECTCLASS(), classes)); } props.insert(std::make_pair(ServiceConstants::SERVICE_ID(), sid != -1 ? sid : nextServiceID++)); if (isPrototypeFactory) { props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_PROTOTYPE())); } else if (isFactory) { props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_MODULE())); } else { props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_SINGLETON())); } return ServicePropertiesImpl(props); } ServiceRegistry::ServiceRegistry(CoreModuleContext* coreCtx) : core(coreCtx) { } ServiceRegistry::~ServiceRegistry() { Clear(); } void ServiceRegistry::Clear() { services.clear(); serviceRegistrations.clear(); classServices.clear(); core = 0; } ServiceRegistrationBase ServiceRegistry::RegisterService(ModulePrivate* module, const InterfaceMap& service, const ServiceProperties& properties) { if (service.empty()) { throw std::invalid_argument("Can't register empty InterfaceMap as a service"); } // Check if we got a service factory bool isFactory = service.count("org.cppmicroservices.factory") > 0; bool isPrototypeFactory = (isFactory ? dynamic_cast(reinterpret_cast(service.find("org.cppmicroservices.factory")->second)) != NULL : false); std::vector classes; // Check if service implements claimed classes and that they exist. for (InterfaceMap::const_iterator i = service.begin(); i != service.end(); ++i) { if (i->first.empty() || (!isFactory && i->second == NULL)) { throw std::invalid_argument("Can't register as null class"); } classes.push_back(i->first); } ServiceRegistrationBase res(module, service, CreateServiceProperties(properties, classes, isFactory, isPrototypeFactory)); { - MutexLocker lock(mutex); + MutexLock lock(mutex); services.insert(std::make_pair(res, classes)); serviceRegistrations.push_back(res); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::vector& s = classServices[*i]; std::vector::iterator ip = std::lower_bound(s.begin(), s.end(), res); s.insert(ip, res); } } ServiceReferenceBase r = res.GetReference(std::string()); ServiceListeners::ServiceListenerEntries listeners; - module->coreCtx->listeners.GetMatchingServiceListeners(r, listeners); + ServiceEvent registeredEvent(ServiceEvent::REGISTERED, r); + module->coreCtx->listeners.GetMatchingServiceListeners(registeredEvent, listeners); module->coreCtx->listeners.ServiceChanged(listeners, - ServiceEvent(ServiceEvent::REGISTERED, r)); + registeredEvent); return res; } void ServiceRegistry::UpdateServiceRegistrationOrder(const ServiceRegistrationBase& sr, const std::vector& classes) { - MutexLocker lock(mutex); + MutexLock lock(mutex); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::vector& s = classServices[*i]; s.erase(std::remove(s.begin(), s.end(), sr), s.end()); s.insert(std::lower_bound(s.begin(), s.end(), sr), sr); } } void ServiceRegistry::Get(const std::string& clazz, std::vector& serviceRegs) const { - MutexLocker lock(mutex); + MutexLock lock(mutex); + Get_unlocked(clazz, serviceRegs); +} + +void ServiceRegistry::Get_unlocked(const std::string& clazz, + std::vector& serviceRegs) const +{ MapClassServices::const_iterator i = classServices.find(clazz); if (i != classServices.end()) { serviceRegs = i->second; } } ServiceReferenceBase ServiceRegistry::Get(ModulePrivate* module, const std::string& clazz) const { - MutexLocker lock(mutex); + MutexLock lock(mutex); try { std::vector srs; Get_unlocked(clazz, "", module, srs); US_DEBUG << "get service ref " << clazz << " for module " << module->info.name << " = " << srs.size() << " refs"; if (!srs.empty()) { return srs.back(); } } catch (const std::invalid_argument& ) { } return ServiceReferenceBase(); } void ServiceRegistry::Get(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::vector& res) const { - MutexLocker lock(mutex); + MutexLock lock(mutex); Get_unlocked(clazz, filter, module, res); } void ServiceRegistry::Get_unlocked(const std::string& clazz, const std::string& filter, - ModulePrivate* /*module*/, std::vector& res) const + ModulePrivate* module, std::vector& res) const { std::vector::const_iterator s; std::vector::const_iterator send; std::vector v; LDAPExpr ldap; if (clazz.empty()) { if (!filter.empty()) { ldap = LDAPExpr(filter); LDAPExpr::ObjectClassSet matched; if (ldap.GetMatchedObjectClasses(matched)) { v.clear(); for(LDAPExpr::ObjectClassSet::const_iterator className = matched.begin(); className != matched.end(); ++className) { MapClassServices::const_iterator i = classServices.find(*className); if (i != classServices.end()) { std::copy(i->second.begin(), i->second.end(), std::back_inserter(v)); } } if (!v.empty()) { s = v.begin(); send = v.end(); } else { return; } } else { s = serviceRegistrations.begin(); send = serviceRegistrations.end(); } } else { s = serviceRegistrations.begin(); send = serviceRegistrations.end(); } } else { MapClassServices::const_iterator it = classServices.find(clazz); if (it != classServices.end()) { s = it->second.begin(); send = it->second.end(); } else { return; } if (!filter.empty()) { ldap = LDAPExpr(filter); } } for (; s != send; ++s) { ServiceReferenceBase sri = s->GetReference(clazz); if (filter.empty() || ldap.Evaluate(s->d->properties, false)) { res.push_back(sri); } } + + if (!res.empty()) + { + if (module != NULL) + { + core->serviceHooks.FilterServiceReferences(module->moduleContext, clazz, filter, res); + } + else + { + core->serviceHooks.FilterServiceReferences(NULL, clazz, filter, res); + } + } } void ServiceRegistry::RemoveServiceRegistration(const ServiceRegistrationBase& sr) { - MutexLocker lock(mutex); + MutexLock lock(mutex); const std::vector& classes = ref_any_cast >( sr.d->properties.Value(ServiceConstants::OBJECTCLASS())); services.erase(sr); serviceRegistrations.erase(std::remove(serviceRegistrations.begin(), serviceRegistrations.end(), sr), serviceRegistrations.end()); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::vector& s = classServices[*i]; if (s.size() > 1) { s.erase(std::remove(s.begin(), s.end(), sr), s.end()); } else { classServices.erase(*i); } } } void ServiceRegistry::GetRegisteredByModule(ModulePrivate* p, std::vector& res) const { - MutexLocker lock(mutex); + MutexLock lock(mutex); for (std::vector::const_iterator i = serviceRegistrations.begin(); i != serviceRegistrations.end(); ++i) { if (i->d->module == p) { res.push_back(*i); } } } void ServiceRegistry::GetUsedByModule(Module* p, std::vector& res) const { - MutexLocker lock(mutex); + MutexLock lock(mutex); for (std::vector::const_iterator i = serviceRegistrations.begin(); i != serviceRegistrations.end(); ++i) { if (i->d->IsUsedByModule(p)) { res.push_back(*i); } } } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceRegistry_p.h b/Core/CppMicroServices/src/service/usServiceRegistry_p.h index 9d780ab707..cffec3eff4 100644 --- a/Core/CppMicroServices/src/service/usServiceRegistry_p.h +++ b/Core/CppMicroServices/src/service/usServiceRegistry_p.h @@ -1,185 +1,189 @@ /*============================================================================= 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 USSERVICEREGISTRY_H #define USSERVICEREGISTRY_H #include "usServiceInterface.h" #include "usServiceRegistration.h" #include "usThreads_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModulePrivate; class ServicePropertiesImpl; /** * Here we handle all the CppMicroServices services that are registered. */ class ServiceRegistry { public: typedef Mutex MutexType; mutable MutexType mutex; /** * Creates a new ServiceProperties object containing in * with the keys converted to lower case. * * @param classes A list of class names which will be added to the * created ServiceProperties object under the key * ModuleConstants::OBJECTCLASS. * @param sid A service id which will be used instead of a default one. */ static ServicePropertiesImpl CreateServiceProperties(const ServiceProperties& in, const std::vector& classes = std::vector(), bool isFactory = false, bool isPrototypeFactory = false, long sid = -1); typedef US_UNORDERED_MAP_TYPE > MapServiceClasses; typedef US_UNORDERED_MAP_TYPE > MapClassServices; /** * All registered services in the current framework. * Mapping of registered service to class names under which * the service is registerd. */ MapServiceClasses services; std::vector serviceRegistrations; /** * Mapping of classname to registered service. * The List of registered services are ordered with the highest * ranked service first. */ MapClassServices classServices; CoreModuleContext* core; ServiceRegistry(CoreModuleContext* coreCtx); ~ServiceRegistry(); void Clear(); /** * Register a service in the framework wide register. * * @param module The module registering the service. * @param classes The class names under which the service can be located. * @param service The service object. * @param properties The properties for this service. * @return A ServiceRegistration object. * @exception std::invalid_argument If one of the following is true: *
    *
  • The service object is 0.
  • *
  • The service parameter is not a ServiceFactory or an * instance of all the named classes in the classes parameter.
  • *
*/ ServiceRegistrationBase RegisterService(ModulePrivate* module, const InterfaceMap& service, const ServiceProperties& properties); /** * Service ranking changed, reorder registered services * according to ranking. * * @param serviceRegistration The ServiceRegistrationPrivate object. * @param rank New rank of object. */ void UpdateServiceRegistrationOrder(const ServiceRegistrationBase& sr, const std::vector& classes); /** * Get all services implementing a certain class. * Only used internally by the framework. * * @param clazz The class name of the requested service. * @return A sorted list of {@link ServiceRegistrationPrivate} objects. */ void Get(const std::string& clazz, std::vector& serviceRegs) const; /** * Get a service implementing a certain class. * * @param module The module requesting reference * @param clazz The class name of the requested service. * @return A {@link ServiceReference} object. */ ServiceReferenceBase Get(ModulePrivate* module, const std::string& clazz) const; /** * Get all services implementing a certain class and then * filter these with a property filter. * * @param clazz The class name of requested service. * @param filter The property filter. * @param module The module requesting reference. * @return A list of {@link ServiceReference} object. */ void Get(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::vector& serviceRefs) const; /** * Remove a registered service. * * @param sr The ServiceRegistration object that is registered. */ void RemoveServiceRegistration(const ServiceRegistrationBase& sr) ; /** * Get all services that a module has registered. * * @param p The module * @return A set of {@link ServiceRegistration} objects */ void GetRegisteredByModule(ModulePrivate* m, std::vector& serviceRegs) const; /** * Get all services that a module uses. * * @param p The module * @return A set of {@link ServiceRegistration} objects */ void GetUsedByModule(Module* m, std::vector& serviceRegs) const; private: + friend class ServiceHooks; + + void Get_unlocked(const std::string& clazz, std::vector& serviceRegs) const; + void Get_unlocked(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::vector& serviceRefs) const; // purposely not implemented ServiceRegistry(const ServiceRegistry&); ServiceRegistry& operator=(const ServiceRegistry&); }; US_END_NAMESPACE #endif // USSERVICEREGISTRY_H diff --git a/Core/CppMicroServices/src/service/usServiceTracker.h b/Core/CppMicroServices/src/service/usServiceTracker.h index b0835bec14..ab0f7e77f5 100644 --- a/Core/CppMicroServices/src/service/usServiceTracker.h +++ b/Core/CppMicroServices/src/service/usServiceTracker.h @@ -1,600 +1,600 @@ /*============================================================================= 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 USSERVICETRACKER_H #define USSERVICETRACKER_H #include #include "usServiceReference.h" #include "usServiceTrackerCustomizer.h" #include "usLDAPFilter.h" US_BEGIN_NAMESPACE template class TrackedService; template class ServiceTrackerPrivate; class ModuleContext; /** * \ingroup MicroServices * * A base class template for type traits for objects tracked by a * ServiceTracker instance. It provides the \c TrackedType typedef * and two dummy method definitions. * * Tracked type traits (TTT) classes must additionally provide the * following methods: * *
    *
  • static bool IsValid(const TrackedType& t) Returns \c true if \c t is a valid object, \c false otherwise.
  • *
  • static void Dispose(TrackedType& t) Clears any resources held by the tracked object \c t.
  • *
  • static TrackedType DefaultValue() Returns the default value for newly created tracked objects.
  • *
* * @tparam T The type of the tracked object. * @tparam TTT The tracked type traits class deriving from this class. * * @see ServiceTracker */ template struct TrackedTypeTraitsBase { typedef T TrackedType; // Needed for S == void static TrackedType ConvertToTrackedType(const InterfaceMap&) { throw std::runtime_error("A custom ServiceTrackerCustomizer instance is required for custom tracked objects."); return TTT::DefaultValue(); } // Needed for S != void static TrackedType ConvertToTrackedType(void*) { throw std::runtime_error("A custom ServiceTrackerCustomizer instance is required for custom tracked objects."); return TTT::DefaultValue(); } }; /// \cond template struct TrackedTypeTraits; /// \endcond /** * \ingroup MicroServices * * Default type traits for custom tracked objects of pointer type. * * Use this tracked type traits template for custom tracked objects of * pointer type with the ServiceTracker class. * * @tparam S The type of the service being tracked. * @tparam T The type of the tracked object. */ template struct TrackedTypeTraits : public TrackedTypeTraitsBase > { typedef T* TrackedType; static bool IsValid(const TrackedType& t) { return t != NULL; } static TrackedType DefaultValue() { return NULL; } static void Dispose(TrackedType& t) { t = 0; } }; /// \cond template struct TrackedTypeTraits { typedef S* TrackedType; static bool IsValid(const TrackedType& t) { return t != NULL; } static TrackedType DefaultValue() { return NULL; } static void Dispose(TrackedType& t) { t = 0; } static TrackedType ConvertToTrackedType(S* s) { return s; } }; /// \endcond /// \cond /* * This specialization is "special" because the tracked type is not * void* (as specified in the second template parameter) but InterfaceMap. * This is in line with the ModuleContext::GetService(...) overloads to * return either S* or InterfaceMap dependening on the template parameter. */ template<> struct TrackedTypeTraits { typedef InterfaceMap TrackedType; static bool IsValid(const TrackedType& t) { return !t.empty(); } static TrackedType DefaultValue() { return TrackedType(); } static void Dispose(TrackedType& t) { t.clear(); } static TrackedType ConvertToTrackedType(const InterfaceMap& im) { return im; } }; /// \endcond /** * \ingroup MicroServices * * The ServiceTracker class simplifies using services from the * framework's service registry. *

* A ServiceTracker object is constructed with search criteria and * a ServiceTrackerCustomizer object. A ServiceTracker * can use a ServiceTrackerCustomizer to customize the service * objects to be tracked. The ServiceTracker can then be opened to * begin tracking all services in the framework's service registry that match * the specified search criteria. The ServiceTracker correctly * handles all of the details of listening to ServiceEvents and * getting and ungetting services. *

* The GetServiceReferences method can be called to get references * to the services being tracked. The GetService and * GetServices methods can be called to get the service objects for * the tracked service. * * \note The ServiceTracker class is thread-safe. It does not call a * ServiceTrackerCustomizer while holding any locks. * ServiceTrackerCustomizer implementations must also be * thread-safe. * * Customization of the services to be tracked requires a custom tracked type traits * class if the custom tracked type is not a pointer type. To customize a tracked * service using a custom type with value-semantics like * \snippet uServices-servicetracker/main.cpp tt * the custom tracked type traits class should look like this: * \snippet uServices-servicetracker/main.cpp ttt * * For a custom tracked type, a ServiceTrackerCustomizer is required, which knows * how to associate the tracked service with the custom tracked type: * \snippet uServices-servicetracker/main.cpp customizer * The custom tracking type traits class and customizer can now be used to instantiate * a ServiceTracker: * \snippet uServices-servicetracker/main.cpp tracker * * If the custom tracked type is a pointer type, a suitable tracked type traits * template is provided by the framework and only a ServiceTrackerCustomizer needs * to be provided: * \snippet uServices-servicetracker/main.cpp tracker2 * * * @tparam S The type of the service being tracked. The type S* must be an * assignable datatype. Further, if the * ServiceTracker(ModuleContext*, ServiceTrackerCustomizer*) * constructor is used, the type must have an associated interface id via * #US_DECLARE_SERVICE_INTERFACE. * @tparam TTT Type traits of the tracked object. The type traits class provides * information about the customized service object, see TrackedTypeTraitsBase. * * @remarks This class is thread safe. */ template > class ServiceTracker : protected ServiceTrackerCustomizer { public: /// The type of the service being tracked - typedef S ServiceT; + typedef S ServiceType; /// The type of the tracked object typedef typename TTT::TrackedType T; - typedef ServiceReference ServiceReferenceT; + typedef ServiceReference ServiceReferenceType; typedef std::map,T> TrackingMap; ~ServiceTracker(); /** * Create a ServiceTracker on the specified * ServiceReference. * *

* The service referenced by the specified ServiceReference * will be tracked by this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param reference The ServiceReference for the service to be * tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this * ServiceTracker will be used as the * ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, - const ServiceReferenceT& reference, + const ServiceReferenceType& reference, ServiceTrackerCustomizer* customizer = 0); /** * Create a ServiceTracker on the specified class name. * *

* Services registered under the specified class name will be tracked by * this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param clazz The class name of the services to be tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this * ServiceTracker will be used as the * ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, const std::string& clazz, ServiceTrackerCustomizer* customizer = 0); /** * Create a ServiceTracker on the specified * LDAPFilter object. * *

* Services which match the specified LDAPFilter object will be * tracked by this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param filter The LDAPFilter to select the services to be * tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this ServiceTracker will be * used as the ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, const LDAPFilter& filter, ServiceTrackerCustomizer* customizer = 0); /** * Create a ServiceTracker on the class template * argument S. * *

* Services registered under the interface name of the class template * argument S will be tracked by this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this ServiceTracker will be * used as the ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, ServiceTrackerCustomizer* customizer = 0); /** * Open this ServiceTracker and begin tracking services. * *

* Services which match the search criteria specified when this * ServiceTracker was created are now tracked by this * ServiceTracker. * * @throws std::logic_error If the ModuleContext * with which this ServiceTracker was created is no * longer valid. */ virtual void Open(); /** * Close this ServiceTracker. * *

* This method should be called when this ServiceTracker should * end the tracking of services. * *

* This implementation calls GetServiceReferences() to get the list * of tracked services to remove. */ virtual void Close(); /** * Wait for at least one service to be tracked by this * ServiceTracker. This method will also return when this * ServiceTracker is closed. * *

* It is strongly recommended that WaitForService is not used * during the calling of the ModuleActivator methods. * ModuleActivator methods are expected to complete in a short * period of time. * *

* This implementation calls GetService() to determine if a service * is being tracked. * * @return Returns the result of GetService(). */ virtual T WaitForService(unsigned long timeoutMillis = 0); /** * Return a list of ServiceReferences for all services being * tracked by this ServiceTracker. * * @return List of ServiceReferences. */ - virtual std::vector GetServiceReferences() const; + virtual std::vector GetServiceReferences() const; /** * Returns a ServiceReference for one of the services being * tracked by this ServiceTracker. * *

* If multiple services are being tracked, the service with the highest * ranking (as specified in its service.ranking property) is * returned. If there is a tie in ranking, the service with the lowest * service ID (as specified in its service.id property); that * is, the service that was registered first is returned. This is the same * algorithm used by ModuleContext::GetServiceReference(). * *

* This implementation calls GetServiceReferences() to get the list * of references for the tracked services. * * @return A ServiceReference for a tracked service. * @throws ServiceException if no services are being tracked. */ - virtual ServiceReferenceT GetServiceReference() const; + virtual ServiceReferenceType GetServiceReference() const; /** * Returns the service object for the specified * ServiceReference if the specified referenced service is * being tracked by this ServiceTracker. * * @param reference The reference to the desired service. * @return A service object or null if the service referenced * by the specified ServiceReference is not being * tracked. */ - virtual T GetService(const ServiceReferenceT& reference) const; + virtual T GetService(const ServiceReferenceType& reference) const; /** * Return a list of service objects for all services being tracked by this * ServiceTracker. * *

* This implementation calls GetServiceReferences() to get the list * of references for the tracked services and then calls * GetService(const ServiceReference&) for each reference to get the * tracked service object. * * @return A list of service objects or an empty list if no services * are being tracked. */ virtual std::vector GetServices() const; /** * Returns a service object for one of the services being tracked by this * ServiceTracker. * *

* If any services are being tracked, this implementation returns the result * of calling %GetService(%GetServiceReference()). * * @return A service object or null if no services are being * tracked. */ virtual T GetService() const; /** * Remove a service from this ServiceTracker. * * The specified service will be removed from this * ServiceTracker. If the specified service was being tracked * then the ServiceTrackerCustomizer::RemovedService method will * be called for that service. * * @param reference The reference to the service to be removed. */ - virtual void Remove(const ServiceReferenceT& reference); + virtual void Remove(const ServiceReferenceType& reference); /** * Return the number of services being tracked by this * ServiceTracker. * * @return The number of services being tracked. */ virtual int Size() const; /** * Returns the tracking count for this ServiceTracker. * * The tracking count is initialized to 0 when this * ServiceTracker is opened. Every time a service is added, * modified or removed from this ServiceTracker, the tracking * count is incremented. * *

* The tracking count can be used to determine if this * ServiceTracker has added, modified or removed a service by * comparing a tracking count value previously collected with the current * tracking count value. If the value has not changed, then no service has * been added, modified or removed from this ServiceTracker * since the previous tracking count was collected. * * @return The tracking count for this ServiceTracker or -1 if * this ServiceTracker is not open. */ virtual int GetTrackingCount() const; /** * Return a sorted map of the ServiceReferences and * service objects for all services being tracked by this * ServiceTracker. The map is sorted in natural order * of ServiceReference. That is, the last entry is the service * with the highest ranking and the lowest service id. * * @param tracked A TrackingMap with the ServiceReferences * and service objects for all services being tracked by this * ServiceTracker. If no services are being tracked, * then the returned map is empty. */ virtual void GetTracked(TrackingMap& tracked) const; /** * Return if this ServiceTracker is empty. * * @return true if this ServiceTracker is not tracking any * services. */ virtual bool IsEmpty() const; protected: /** * Default implementation of the * ServiceTrackerCustomizer::AddingService method. * *

* This method is only called when this ServiceTracker has been * constructed with a null ServiceTrackerCustomizer argument. * *

* This implementation returns the result of calling GetService * on the ModuleContext with which this * ServiceTracker was created passing the specified * ServiceReference. *

* This method can be overridden in a subclass to customize the service * object to be tracked for the service being added. In that case, take care * not to rely on the default implementation of - * \link RemovedService(const ServiceReferenceT&, T service) removedService\endlink + * \link RemovedService(const ServiceReferenceType&, T service) removedService\endlink * to unget the service. * * @param reference The reference to the service being added to this * ServiceTracker. * @return The service object to be tracked for the service added to this * ServiceTracker. * @see ServiceTrackerCustomizer::AddingService(const ServiceReference&) */ - T AddingService(const ServiceReferenceT& reference); + T AddingService(const ServiceReferenceType& reference); /** * Default implementation of the * ServiceTrackerCustomizer::ModifiedService method. * *

* This method is only called when this ServiceTracker has been * constructed with a null ServiceTrackerCustomizer argument. * *

* This implementation does nothing. * * @param reference The reference to modified service. * @param service The service object for the modified service. * @see ServiceTrackerCustomizer::ModifiedService(const ServiceReference&, T) */ - void ModifiedService(const ServiceReferenceT& reference, T service); + void ModifiedService(const ServiceReferenceType& reference, T service); /** * Default implementation of the * ServiceTrackerCustomizer::RemovedService method. * *

* This method is only called when this ServiceTracker has been * constructed with a null ServiceTrackerCustomizer argument. * *

* This implementation calls UngetService, on the * ModuleContext with which this ServiceTracker * was created, passing the specified ServiceReference. *

* This method can be overridden in a subclass. If the default - * implementation of \link AddingService(const ServiceReferenceT&) AddingService\endlink + * implementation of \link AddingService(const ServiceReferenceType&) AddingService\endlink * method was used, this method must unget the service. * * @param reference The reference to removed service. * @param service The service object for the removed service. - * @see ServiceTrackerCustomizer::RemovedService(const ServiceReferenceT&, T) + * @see ServiceTrackerCustomizer::RemovedService(const ServiceReferenceType&, T) */ - void RemovedService(const ServiceReferenceT& reference, T service); + void RemovedService(const ServiceReferenceType& reference, T service); private: typedef ServiceTracker _ServiceTracker; typedef TrackedService _TrackedService; typedef ServiceTrackerPrivate _ServiceTrackerPrivate; typedef ServiceTrackerCustomizer _ServiceTrackerCustomizer; friend class TrackedService; friend class ServiceTrackerPrivate; _ServiceTrackerPrivate* const d; }; US_END_NAMESPACE #include "usServiceTracker.tpp" #endif // USSERVICETRACKER_H diff --git a/Core/CppMicroServices/src/service/usServiceTracker.tpp b/Core/CppMicroServices/src/service/usServiceTracker.tpp index 1e5e9467c8..2dbb9a5ad0 100644 --- a/Core/CppMicroServices/src/service/usServiceTracker.tpp +++ b/Core/CppMicroServices/src/service/usServiceTracker.tpp @@ -1,463 +1,463 @@ /*============================================================================= 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 "usServiceTrackerPrivate.h" #include "usTrackedService_p.h" #include "usServiceException.h" #include "usModuleContext.h" #include #include US_BEGIN_NAMESPACE template ServiceTracker::~ServiceTracker() { Close(); delete d; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4355) #endif template ServiceTracker::ServiceTracker(ModuleContext* context, - const ServiceReferenceT& reference, + const ServiceReferenceType& reference, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, reference, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const std::string& clazz, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, clazz, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const LDAPFilter& filter, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, filter, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext *context, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, us_service_interface_iid(), customizer)) { const char* clazz = us_service_interface_iid(); if (clazz == 0) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); } #ifdef _MSC_VER #pragma warning(pop) #endif template void ServiceTracker::Open() { _TrackedService* t; { typename _ServiceTrackerPrivate::Lock l(d); if (d->trackedService) { return; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::Open: " << d->filter; t = new _TrackedService(this, d->customizer); { typename _TrackedService::Lock l(*t); try { d->context->AddServiceListener(t, &_TrackedService::ServiceChanged, d->listenerFilter); - std::vector references; + std::vector references; if (!d->trackClass.empty()) { references = d->GetInitialReferences(d->trackClass, std::string()); } else { if (d->trackReference.GetModule() != 0) { references.push_back(d->trackReference); } else { /* user supplied filter */ references = d->GetInitialReferences(std::string(), (d->listenerFilter.empty()) ? d->filter.ToString() : d->listenerFilter); } } /* set tracked with the initial references */ t->SetInitial(references); } catch (const std::invalid_argument& e) { throw std::runtime_error(std::string("unexpected std::invalid_argument exception: ") + e.what()); } } d->trackedService = t; } /* Call tracked outside of synchronized region */ t->TrackInitial(); /* process the initial references */ } template void ServiceTracker::Close() { _TrackedService* outgoing; - std::vector references; + std::vector references; { typename _ServiceTrackerPrivate::Lock l(d); outgoing = d->trackedService; if (outgoing == 0) { return; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::close:" << d->filter; outgoing->Close(); references = GetServiceReferences(); d->trackedService = 0; try { d->context->RemoveServiceListener(outgoing, &_TrackedService::ServiceChanged); } catch (const std::logic_error& /*e*/) { /* In case the context was stopped. */ } } d->Modified(); /* clear the cache */ { typename _TrackedService::Lock l(outgoing); outgoing->NotifyAll(); /* wake up any waiters */ } - for(typename std::vector::const_iterator ref = references.begin(); + for(typename std::vector::const_iterator ref = references.begin(); ref != references.end(); ++ref) { outgoing->Untrack(*ref, ServiceEvent()); } if (d->DEBUG_OUTPUT) { typename _ServiceTrackerPrivate::Lock l(d); if ((d->cachedReference.GetModule() == 0) && !TTT::IsValid(d->cachedService)) { US_DEBUG(true) << "ServiceTracker::close[cached cleared]:" << d->filter; } } delete outgoing; d->trackedService = 0; } template typename ServiceTracker::T ServiceTracker::WaitForService(unsigned long timeoutMillis) { T object = GetService(); while (!TTT::IsValid(object)) { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return TTT::DefaultValue(); } { typename _TrackedService::Lock l(t); if (t->Size() == 0) { t->Wait(timeoutMillis); } } object = GetService(); } return object; } template -std::vector::ServiceReferenceT> +std::vector::ServiceReferenceType> ServiceTracker::GetServiceReferences() const { - std::vector refs; + std::vector refs; _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return refs; } { typename _TrackedService::Lock l(t); d->GetServiceReferences_unlocked(refs, t); } return refs; } template -typename ServiceTracker::ServiceReferenceT +typename ServiceTracker::ServiceReferenceType ServiceTracker::GetServiceReference() const { - ServiceReferenceT reference; + ServiceReferenceType reference; { typename _ServiceTrackerPrivate::Lock l(d); reference = d->cachedReference; } if (reference.GetModule() != 0) { US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getServiceReference[cached]:" << d->filter; return reference; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getServiceReference:" << d->filter; - std::vector references = GetServiceReferences(); + std::vector references = GetServiceReferences(); std::size_t length = references.size(); if (length == 0) { /* if no service is being tracked */ throw ServiceException("No service is being tracked"); } - typename std::vector::const_iterator selectedRef = references.begin(); + typename std::vector::const_iterator selectedRef = references.begin(); if (length > 1) { /* if more than one service, select highest ranking */ std::vector rankings(length); int count = 0; int maxRanking = std::numeric_limits::min(); - typename std::vector::const_iterator refIter = references.begin(); + typename std::vector::const_iterator refIter = references.begin(); for (std::size_t i = 0; i < length; i++) { Any rankingAny = refIter->GetProperty(ServiceConstants::SERVICE_RANKING()); int ranking = 0; if (rankingAny.Type() == typeid(int)) { ranking = any_cast(rankingAny); } rankings[i] = ranking; if (ranking > maxRanking) { selectedRef = refIter; maxRanking = ranking; count = 1; } else { if (ranking == maxRanking) { count++; } } ++refIter; } if (count > 1) { /* if still more than one service, select lowest id */ long int minId = std::numeric_limits::max(); refIter = references.begin(); for (std::size_t i = 0; i < length; i++) { if (rankings[i] == maxRanking) { Any idAny = refIter->GetProperty(ServiceConstants::SERVICE_ID()); long int id = 0; if (idAny.Type() == typeid(long int)) { id = any_cast(idAny); } if (id < minId) { selectedRef = refIter; minId = id; } } ++refIter; } } } { typename _ServiceTrackerPrivate::Lock l(d); d->cachedReference = *selectedRef; return d->cachedReference; } } template typename ServiceTracker::T -ServiceTracker::GetService(const ServiceReferenceT& reference) const +ServiceTracker::GetService(const ServiceReferenceType& reference) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return TTT::DefaultValue(); } { typename _TrackedService::Lock l(t); return t->GetCustomizedObject(reference); } } template std::vector::T> ServiceTracker::GetServices() const { std::vector services; _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return services; } { typename _TrackedService::Lock l(t); - std::vector references; + std::vector references; d->GetServiceReferences_unlocked(references, t); - for(typename std::vector::const_iterator ref = references.begin(); + for(typename std::vector::const_iterator ref = references.begin(); ref != references.end(); ++ref) { services.push_back(t->GetCustomizedObject(*ref)); } } return services; } template typename ServiceTracker::T ServiceTracker::GetService() const { { typename _ServiceTrackerPrivate::Lock l(d); const T& service = d->cachedService; if (TTT::IsValid(service)) { US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getService[cached]:" << d->filter; return service; } } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getService:" << d->filter; try { - ServiceReferenceT reference = GetServiceReference(); + ServiceReferenceType reference = GetServiceReference(); if (reference.GetModule() == 0) { return TTT::DefaultValue(); } { typename _ServiceTrackerPrivate::Lock l(d); return d->cachedService = GetService(reference); } } catch (const ServiceException&) { return TTT::DefaultValue(); } } template -void ServiceTracker::Remove(const ServiceReferenceT& reference) +void ServiceTracker::Remove(const ServiceReferenceType& reference) { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } t->Untrack(reference, ServiceEvent()); } template int ServiceTracker::Size() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return 0; } { typename _TrackedService::Lock l(t); return static_cast(t->Size()); } } template int ServiceTracker::GetTrackingCount() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return -1; } { typename _TrackedService::Lock l(t); return t->GetTrackingCount(); } } template void ServiceTracker::GetTracked(TrackingMap& map) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } { typename _TrackedService::Lock l(t); t->CopyEntries(map); } } template bool ServiceTracker::IsEmpty() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return true; } { typename _TrackedService::Lock l(t); return t->IsEmpty(); } } template typename ServiceTracker::T -ServiceTracker::AddingService(const ServiceReferenceT& reference) +ServiceTracker::AddingService(const ServiceReferenceType& reference) { return TTT::ConvertToTrackedType(d->context->GetService(reference)); } template -void ServiceTracker::ModifiedService(const ServiceReferenceT& /*reference*/, T /*service*/) +void ServiceTracker::ModifiedService(const ServiceReferenceType& /*reference*/, T /*service*/) { /* do nothing */ } template -void ServiceTracker::RemovedService(const ServiceReferenceT& reference, T /*service*/) +void ServiceTracker::RemovedService(const ServiceReferenceType& reference, T /*service*/) { d->context->UngetService(reference); } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usServiceTrackerCustomizer.h b/Core/CppMicroServices/src/service/usServiceTrackerCustomizer.h index f7aa7e0eb1..b6f067bdf4 100644 --- a/Core/CppMicroServices/src/service/usServiceTrackerCustomizer.h +++ b/Core/CppMicroServices/src/service/usServiceTrackerCustomizer.h @@ -1,117 +1,118 @@ /*============================================================================= 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 USSERVICETRACKERCUSTOMIZER_H #define USSERVICETRACKERCUSTOMIZER_H #include "usServiceReference.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * The ServiceTrackerCustomizer interface allows a * ServiceTracker to customize the service objects that are * tracked. A ServiceTrackerCustomizer is called when a service is * being added to a ServiceTracker. The * ServiceTrackerCustomizer can then return an object for the * tracked service. A ServiceTrackerCustomizer is also called when * a tracked service is modified or has been removed from a * ServiceTracker. * *

* The methods in this interface may be called as the result of a * ServiceEvent being received by a ServiceTracker. * Since ServiceEvents are synchronously delivered, * it is highly recommended that implementations of these methods do * not register (ModuleContext::RegisterService), modify ( * ServiceRegistration::SetProperties) or unregister ( * ServiceRegistration::Unregister) a service while being * synchronized on any object. * *

* The ServiceTracker class is thread-safe. It does not call a * ServiceTrackerCustomizer while holding any locks. * ServiceTrackerCustomizer implementations must also be * thread-safe. * * \tparam S The type of the service being tracked * \tparam T The type of the tracked object. * \remarks This class is thread safe. */ template struct ServiceTrackerCustomizer { - typedef S ServiceT; - typedef ServiceReference ServiceReferenceT; + typedef S ServiceType; + typedef T TrackedType; + typedef ServiceReference ServiceReferenceType; virtual ~ServiceTrackerCustomizer() {} /** * A service is being added to the ServiceTracker. * *

* This method is called before a service which matched the search * parameters of the ServiceTracker is added to the * ServiceTracker. This method should return the service object * to be tracked for the specified ServiceReference. The * returned service object is stored in the ServiceTracker and * is available from the GetService and * GetServices methods. * * @param reference The reference to the service being added to the * ServiceTracker. * @return The service object to be tracked for the specified referenced * service or 0 if the specified referenced service * should not be tracked. */ - virtual T AddingService(const ServiceReferenceT& reference) = 0; + virtual TrackedType AddingService(const ServiceReferenceType& reference) = 0; /** * A service tracked by the ServiceTracker has been modified. * *

* This method is called when a service being tracked by the * ServiceTracker has had it properties modified. * * @param reference The reference to the service that has been modified. * @param service The service object for the specified referenced service. */ - virtual void ModifiedService(const ServiceReferenceT& reference, T service) = 0; + virtual void ModifiedService(const ServiceReferenceType& reference, TrackedType service) = 0; /** * A service tracked by the ServiceTracker has been removed. * *

* This method is called after a service is no longer being tracked by the * ServiceTracker. * * @param reference The reference to the service that has been removed. * @param service The service object for the specified referenced service. */ - virtual void RemovedService(const ServiceReferenceT& reference, T service) = 0; + virtual void RemovedService(const ServiceReferenceType& reference, TrackedType service) = 0; }; US_END_NAMESPACE #endif // USSERVICETRACKERCUSTOMIZER_H diff --git a/Core/CppMicroServices/src/service/usServiceTrackerPrivate.h b/Core/CppMicroServices/src/service/usServiceTrackerPrivate.h index 0d0d4f3efa..1ec0ffb1d6 100644 --- a/Core/CppMicroServices/src/service/usServiceTrackerPrivate.h +++ b/Core/CppMicroServices/src/service/usServiceTrackerPrivate.h @@ -1,172 +1,172 @@ /*============================================================================= 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 USSERVICETRACKERPRIVATE_H #define USSERVICETRACKERPRIVATE_H #include "usServiceReference.h" #include "usLDAPFilter.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices */ template -class ServiceTrackerPrivate : US_DEFAULT_THREADING > +class ServiceTrackerPrivate : MultiThreaded<> { public: typedef typename TTT::TrackedType T; ServiceTrackerPrivate(ServiceTracker* st, ModuleContext* context, const ServiceReference& reference, ServiceTrackerCustomizer* customizer); ServiceTrackerPrivate(ServiceTracker* st, ModuleContext* context, const std::string& clazz, ServiceTrackerCustomizer* customizer); ServiceTrackerPrivate(ServiceTracker* st, ModuleContext* context, const LDAPFilter& filter, ServiceTrackerCustomizer* customizer); ~ServiceTrackerPrivate(); /** * Returns the list of initial ServiceReferences that will be * tracked by this ServiceTracker. * * @param className The class name with which the service was registered, or * null for all services. * @param filterString The filter criteria or null for all * services. * @return The list of initial ServiceReferences. * @throws std::invalid_argument If the specified filterString has an * invalid syntax. */ std::vector > GetInitialReferences(const std::string& className, const std::string& filterString); void GetServiceReferences_unlocked(std::vector >& refs, TrackedService* t) const; /* set this to true to compile in debug messages */ static const bool DEBUG_OUTPUT; // = false; /** * The Module Context used by this ServiceTracker. */ ModuleContext* const context; /** * The filter used by this ServiceTracker which specifies the * search criteria for the services to track. */ LDAPFilter filter; /** * The ServiceTrackerCustomizer for this tracker. */ ServiceTrackerCustomizer* customizer; /** * Filter string for use when adding the ServiceListener. If this field is * set, then certain optimizations can be taken since we don't have a user * supplied filter. */ std::string listenerFilter; /** * Class name to be tracked. If this field is set, then we are tracking by * class name. */ std::string trackClass; /** * Reference to be tracked. If this field is set, then we are tracking a * single ServiceReference. */ ServiceReference trackReference; /** * Tracked services: ServiceReference -> customized Object and * ServiceListenerEntry object */ TrackedService* trackedService; /** * Accessor method for the current TrackedService object. This method is only * intended to be used by the unsynchronized methods which do not modify the * trackedService field. * * @return The current Tracked object. */ TrackedService* Tracked() const; /** * Called by the TrackedService object whenever the set of tracked services is * modified. Clears the cache. */ /* * This method must not be synchronized since it is called by TrackedService while * TrackedService is synchronized. We don't want synchronization interactions * between the listener thread and the user thread. */ void Modified(); /** * Cached ServiceReference for getServiceReference. */ mutable ServiceReference cachedReference; /** * Cached service object for GetService. */ mutable T cachedService; private: inline ServiceTracker* q_func() { return static_cast *>(q_ptr); } inline const ServiceTracker* q_func() const { return static_cast *>(q_ptr); } friend class ServiceTracker; ServiceTracker * const q_ptr; }; US_END_NAMESPACE #include "usServiceTrackerPrivate.tpp" #endif // USSERVICETRACKERPRIVATE_H diff --git a/Core/CppMicroServices/src/service/usTrackedService.tpp b/Core/CppMicroServices/src/service/usTrackedService.tpp index 59765b8d6a..4de4228386 100644 --- a/Core/CppMicroServices/src/service/usTrackedService.tpp +++ b/Core/CppMicroServices/src/service/usTrackedService.tpp @@ -1,128 +1,128 @@ /*============================================================================= 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. =============================================================================*/ US_BEGIN_NAMESPACE template TrackedService::TrackedService(ServiceTracker* serviceTracker, ServiceTrackerCustomizer* customizer) : serviceTracker(serviceTracker), customizer(customizer) { } template void TrackedService::ServiceChanged(const ServiceEvent event) { /* * Check if we had a delayed call (which could happen when we * close). */ if (this->closed) { return; } - ServiceReference reference = event.GetServiceReference(InterfaceT()); + ServiceReference reference = event.GetServiceReference(InterfaceType()); US_DEBUG(serviceTracker->d->DEBUG_OUTPUT) << "TrackedService::ServiceChanged[" << event.GetType() << "]: " << reference; if (!reference) { return; } switch (event.GetType()) { case ServiceEvent::REGISTERED : case ServiceEvent::MODIFIED : { if (!serviceTracker->d->listenerFilter.empty()) { // service listener added with filter this->Track(reference, event); /* * If the customizer throws an unchecked exception, it * is safe to let it propagate */ } else { // service listener added without filter if (serviceTracker->d->filter.Match(reference)) { this->Track(reference, event); /* * If the customizer throws an unchecked exception, * it is safe to let it propagate */ } else { this->Untrack(reference, event); /* * If the customizer throws an unchecked exception, * it is safe to let it propagate */ } } break; } case ServiceEvent::MODIFIED_ENDMATCH : case ServiceEvent::UNREGISTERING : this->Untrack(reference, event); /* * If the customizer throws an unchecked exception, it is * safe to let it propagate */ break; } } template void TrackedService::Modified() { Superclass::Modified(); /* increment the modification count */ serviceTracker->d->Modified(); } template typename TrackedService::T TrackedService::CustomizerAdding(ServiceReference item, const ServiceEvent& /*related*/) { return customizer->AddingService(item); } template void TrackedService::CustomizerModified(ServiceReference item, const ServiceEvent& /*related*/, T object) { customizer->ModifiedService(item, object); } template void TrackedService::CustomizerRemoved(ServiceReference item, const ServiceEvent& /*related*/, T object) { customizer->RemovedService(item, object); } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/util/usAtomicInt_p.h b/Core/CppMicroServices/src/util/usAtomicInt_p.h index 4bc954ec02..99622bf0df 100644 --- a/Core/CppMicroServices/src/util/usAtomicInt_p.h +++ b/Core/CppMicroServices/src/util/usAtomicInt_p.h @@ -1,83 +1,79 @@ /*============================================================================= 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 USATOMICINT_H #define USATOMICINT_H #include #include "usThreads_p.h" US_BEGIN_NAMESPACE /** * This class acts as an atomic integer. * * The integer value represented by this class can be incremented * and decremented atomically. This is often useful in reference * counting scenarios to minimize locking overhead in multi-threaded * environments. */ -class AtomicInt : private US_DEFAULT_THREADING +class AtomicInt : private AtomicCounter { public: - AtomicInt(int value = 0) : m_ReferenceCount(value) {} + AtomicInt(int value = 0) : AtomicCounter(value) {} /** * Increase the reference count atomically by 1. * * \return true if the new value is unequal to zero, false * otherwise. */ inline bool Ref() const - { return AtomicIncrement(m_ReferenceCount) != 0; } + { return AtomicIncrement() != 0; } /** * Decrease the reference count atomically by 1. * * \return true if the new value is unequal to zero, false * otherwise. */ inline bool Deref() const - { return AtomicDecrement(m_ReferenceCount) != 0; } + { return AtomicDecrement() != 0; } /** * Returns the current value. * */ inline operator int() const { IntType curr(0); - AtomicAssign(curr, m_ReferenceCount); + AtomicAssign(curr); return curr; } -private: - - mutable IntType m_ReferenceCount; - }; US_END_NAMESPACE #endif // USATOMICINT_H diff --git a/Core/CppMicroServices/src/util/usFunctor_p.h b/Core/CppMicroServices/src/util/usFunctor_p.h index dfdd608d0f..ba4daeb92e 100644 --- a/Core/CppMicroServices/src/util/usFunctor_p.h +++ b/Core/CppMicroServices/src/util/usFunctor_p.h @@ -1,139 +1,144 @@ /*============================================================================= 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() {} 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); } 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); } 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); + } + private: typedef FunctorImpl Impl; Impl* m_Impl; }; US_END_NAMESPACE #endif // USFUNCTOR_H diff --git a/Core/CppMicroServices/src/util/usUtils_p.h b/Core/CppMicroServices/src/util/usListenerFunctors_p.h similarity index 64% copy from Core/CppMicroServices/src/util/usUtils_p.h copy to Core/CppMicroServices/src/util/usListenerFunctors_p.h index 32c88713e2..385ad8cf58 100644 --- a/Core/CppMicroServices/src/util/usUtils_p.h +++ b/Core/CppMicroServices/src/util/usListenerFunctors_p.h @@ -1,225 +1,136 @@ /*============================================================================= 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 USUTILS_H -#define USUTILS_H +#ifndef USLISTENERFUNCTORS_P_H +#define USLISTENERFUNCTORS_P_H #include - -#include -#include -#include - - -//------------------------------------------------------------------- -// Logging -//------------------------------------------------------------------- - -US_BEGIN_NAMESPACE - -US_EXPORT void message_output(MsgType, const char* buf); - -struct LogMsg { - - LogMsg(int t, const char* file, int ln, const char* func) - : type(static_cast(t)), enabled(true), buffer() - { buffer << "In " << func << " at " << file << ":" << ln << " : "; } - - ~LogMsg() { if(enabled) message_output(type, buffer.str().c_str()); } - - template - LogMsg& operator<<(T t) - { - if (enabled) buffer << t; - return *this; - } - - LogMsg& operator()(bool flag) - { - this->enabled = flag; - return *this; - } - -private: - - MsgType type; - bool enabled; - std::stringstream buffer; -}; - -struct NoLogMsg { - - template - NoLogMsg& operator<<(T) - { - return *this; - } - - NoLogMsg& operator()(bool) - { - return *this; - } - -}; - -US_END_NAMESPACE - -#if defined(US_ENABLE_DEBUG_OUTPUT) - #define US_DEBUG US_PREPEND_NAMESPACE(LogMsg)(0, __FILE__, __LINE__, __FUNCTION__) -#else - #define US_DEBUG true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() -#endif - -#if !defined(US_NO_INFO_OUTPUT) - #define US_INFO US_PREPEND_NAMESPACE(LogMsg)(1, __FILE__, __LINE__, __FUNCTION__) -#else - #define US_INFO true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() -#endif - -#if !defined(US_NO_WARNING_OUTPUT) - #define US_WARN US_PREPEND_NAMESPACE(LogMsg)(2, __FILE__, __LINE__, __FUNCTION__) -#else - #define US_WARN true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() -#endif - -#define US_ERROR US_PREPEND_NAMESPACE(LogMsg)(3, __FILE__, __LINE__, __FUNCTION__) - -//------------------------------------------------------------------- -// Module auto-loading -//------------------------------------------------------------------- - -US_BEGIN_NAMESPACE - -struct ModuleInfo; - -void AutoLoadModules(const ModuleInfo& moduleInfo); - -US_END_NAMESPACE - -//------------------------------------------------------------------- -// Error handling -//------------------------------------------------------------------- - -US_BEGIN_NAMESPACE - -US_EXPORT std::string GetLastErrorStr(); - -US_END_NAMESPACE - - -//------------------------------------------------------------------- -// Functors -//------------------------------------------------------------------- - #include #include +#include +#include + #if defined(US_USE_CXX11) || defined(__GNUC__) #ifdef US_USE_CXX11 #include #define US_MODULE_LISTENER_FUNCTOR std::function #define US_SERVICE_LISTENER_FUNCTOR std::function #else #include #define US_MODULE_LISTENER_FUNCTOR std::tr1::function #define US_SERVICE_LISTENER_FUNCTOR std::tr1::function #endif US_BEGIN_NAMESPACE template US_MODULE_LISTENER_FUNCTOR ModuleListenerMemberFunctor(X* x, void (X::*memFn)(const US_PREPEND_NAMESPACE(ModuleEvent))) { return std::bind1st(std::mem_fun(memFn), x); } US_END_NAMESPACE US_BEGIN_NAMESPACE struct ModuleListenerCompare : std::binary_function, std::pair, bool> { bool operator()(const std::pair& p1, const std::pair& p2) const { return p1.second == p2.second && p1.first.target() == p2.first.target(); } }; US_END_NAMESPACE US_BEGIN_NAMESPACE template US_SERVICE_LISTENER_FUNCTOR ServiceListenerMemberFunctor(X* x, void (X::*memFn)(const US_PREPEND_NAMESPACE(ServiceEvent))) { return std::bind1st(std::mem_fun(memFn), x); } US_END_NAMESPACE US_BEGIN_NAMESPACE struct ServiceListenerCompare : std::binary_function { bool operator()(const US_SERVICE_LISTENER_FUNCTOR& f1, const US_SERVICE_LISTENER_FUNCTOR& f2) const { return f1.target() == f2.target(); } }; US_END_NAMESPACE + US_HASH_FUNCTION_NAMESPACE_BEGIN + US_HASH_FUNCTION_BEGIN(US_SERVICE_LISTENER_FUNCTOR) + void(*targetFunc)(const US_PREPEND_NAMESPACE(ServiceEvent)&) = arg.target(); + void* targetPtr = NULL; + std::memcpy(&targetPtr, &targetFunc, sizeof(void*)); + return US_HASH_FUNCTION(void*, targetPtr); + US_HASH_FUNCTION_END + US_HASH_FUNCTION_NAMESPACE_END + #else #include #define US_MODULE_LISTENER_FUNCTOR US_PREPEND_NAMESPACE(Functor) US_BEGIN_NAMESPACE template US_MODULE_LISTENER_FUNCTOR ModuleListenerMemberFunctor(X* x, MemFn memFn) { return Functor(x, memFn); } US_END_NAMESPACE US_BEGIN_NAMESPACE struct ModuleListenerCompare : std::binary_function, std::pair, bool> { bool operator()(const std::pair& p1, const std::pair& p2) const { return p1.second == p2.second && p1.first == p2.first; } }; US_END_NAMESPACE #define US_SERVICE_LISTENER_FUNCTOR US_PREPEND_NAMESPACE(Functor) US_BEGIN_NAMESPACE template US_SERVICE_LISTENER_FUNCTOR ServiceListenerMemberFunctor(X* x, MemFn memFn) { return Functor(x, memFn); } US_END_NAMESPACE US_BEGIN_NAMESPACE struct ServiceListenerCompare : std::binary_function { bool operator()(const US_SERVICE_LISTENER_FUNCTOR& f1, const US_SERVICE_LISTENER_FUNCTOR& f2) const { return f1 == f2; } }; US_END_NAMESPACE + US_HASH_FUNCTION_NAMESPACE_BEGIN + US_HASH_FUNCTION_BEGIN(US_SERVICE_LISTENER_FUNCTOR) + return US_HASH_FUNCTION(void*, reinterpret_cast(arg.target())); + US_HASH_FUNCTION_END + US_HASH_FUNCTION_NAMESPACE_END + #endif -#endif // USUTILS_H +#endif // USLISTENERFUNCTORS_P_H diff --git a/Core/CppMicroServices/src/util/usLog_p.h b/Core/CppMicroServices/src/util/usLog_p.h new file mode 100644 index 0000000000..33cc97be5f --- /dev/null +++ b/Core/CppMicroServices/src/util/usLog_p.h @@ -0,0 +1,99 @@ +/*============================================================================= + + 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 USLOG_P_H +#define USLOG_P_H + +#include + +#include +#include + +US_BEGIN_NAMESPACE + +US_EXPORT void message_output(MsgType, const char* buf); + +struct LogMsg { + + LogMsg(int t, const char* file, int ln, const char* func) + : type(static_cast(t)), enabled(true), buffer() + { buffer << "In " << func << " at " << file << ":" << ln << " : "; } + + ~LogMsg() { if(enabled) message_output(type, buffer.str().c_str()); } + + template + LogMsg& operator<<(T t) + { + if (enabled) buffer << t; + return *this; + } + + LogMsg& operator()(bool flag) + { + this->enabled = flag; + return *this; + } + +private: + + MsgType type; + bool enabled; + std::stringstream buffer; +}; + +struct NoLogMsg { + + template + NoLogMsg& operator<<(T) + { + return *this; + } + + NoLogMsg& operator()(bool) + { + return *this; + } + +}; + +US_END_NAMESPACE + +#if defined(US_ENABLE_DEBUG_OUTPUT) + #define US_DEBUG US_PREPEND_NAMESPACE(LogMsg)(0, __FILE__, __LINE__, __FUNCTION__) +#else + #define US_DEBUG true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() +#endif + +#if !defined(US_NO_INFO_OUTPUT) + #define US_INFO US_PREPEND_NAMESPACE(LogMsg)(1, __FILE__, __LINE__, __FUNCTION__) +#else + #define US_INFO true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() +#endif + +#if !defined(US_NO_WARNING_OUTPUT) + #define US_WARN US_PREPEND_NAMESPACE(LogMsg)(2, __FILE__, __LINE__, __FUNCTION__) +#else + #define US_WARN true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() +#endif + +#define US_ERROR US_PREPEND_NAMESPACE(LogMsg)(3, __FILE__, __LINE__, __FUNCTION__) + +#endif // USLOG_P_H diff --git a/Core/CppMicroServices/src/util/usShrinkableMap.h b/Core/CppMicroServices/src/util/usShrinkableMap.h new file mode 100644 index 0000000000..fb5c68a407 --- /dev/null +++ b/Core/CppMicroServices/src/util/usShrinkableMap.h @@ -0,0 +1,175 @@ +/*============================================================================= + + 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 USSHRINKABLEMAP_H +#define USSHRINKABLEMAP_H + +#include "usConfig.h" + +#include + +US_BEGIN_NAMESPACE + +template +class ShrinkableMap +{ +private: + static std::map emptyContainer; + +public: + + typedef std::map container_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::size_type size_type; + typedef typename container_type::key_type key_type; + typedef typename container_type::mapped_type mapped_type; + typedef typename container_type::value_type value_type; + typedef typename container_type::reference reference; + typedef typename container_type::const_reference const_reference; + + ShrinkableMap() + : container(emptyContainer) + { + } + + iterator begin() + { + return container.begin(); + } + + const_iterator begin() const + { + return container.begin(); + } + + iterator end() + { + return container.end(); + } + + const_iterator end() const + { + return container.end(); + } + + void erase(iterator pos) + { + return container.erase(pos); + } + + void erase(iterator first, iterator last) + { + return container.erase(first, last); + } + + size_type erase(const Key& key) + { + return container.erase(key); + } + + bool empty() const + { + return container.empty(); + } + + void clear() + { + container.clear(); + } + + size_type size() const + { + return container.size(); + } + + size_type max_size() const + { + return container.max_size(); + } + + T& operator[](const Key& key) + { + return container[key]; + } + + size_type count(const Key& key) const + { + return container.count(key); + } + + iterator find(const Key& key) + { + return container.find(key); + } + + const_iterator find(const Key& key) const + { + return container.find(key); + } + + std::pair equal_range(const Key& key) + { + return container.equal_range(key); + } + + std::pair equal_range(const Key& key) const + { + return container.equal_range(key); + } + + iterator lower_bound(const Key& key) + { + return container.lower_bound(key); + } + + const_iterator lower_bound(const Key& key) const + { + return container.lower_bound(key); + } + + iterator upper_bound(const Key& key) + { + return container.upper_bound(key); + } + + const_iterator upper_bound(const Key& key) const + { + return container.upper_bound(key); + } + +private: + + friend class ServiceHooks; + + ShrinkableMap(container_type& container) + : container(container) + {} + + container_type& container; +}; + +template +typename ShrinkableMap::container_type ShrinkableMap::emptyContainer; + +US_END_NAMESPACE + +#endif // USSHRINKABLEMAP_H diff --git a/Core/CppMicroServices/src/util/usShrinkableVector.h b/Core/CppMicroServices/src/util/usShrinkableVector.h new file mode 100644 index 0000000000..4c1d10a2ba --- /dev/null +++ b/Core/CppMicroServices/src/util/usShrinkableVector.h @@ -0,0 +1,158 @@ +/*============================================================================= + + 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 USSHRINKABLEVECTOR_H +#define USSHRINKABLEVECTOR_H + +#include "usConfig.h" + +#include + +US_BEGIN_NAMESPACE + +template +class ShrinkableVector +{ +private: + static std::vector emptyVector; + +public: + + typedef std::vector container_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::size_type size_type; + typedef typename container_type::reference reference; + typedef typename container_type::const_reference const_reference; + + ShrinkableVector() + : container(emptyVector) + { + } + + iterator begin() + { + return container.begin(); + } + + const_iterator begin() const + { + return container.begin(); + } + + iterator end() + { + return container.end(); + } + + const_iterator end() const + { + return container.end(); + } + + reference front() + { + return container.front(); + } + + const_reference front() const + { + return container.front(); + } + + reference back() + { + return container.back(); + } + + const_reference back() const + { + return container.back(); + } + + iterator erase(iterator pos) + { + return container.erase(pos); + } + + iterator erase(iterator first, iterator last) + { + return container.erase(first, last); + } + + void pop_back() + { + container.pop_back(); + } + + bool empty() const + { + return container.empty(); + } + + void clear() + { + container.clear(); + } + + size_type size() const + { + return container.size(); + } + + reference at(size_type pos) + { + return container.at(pos); + } + + const_reference at(size_type pos) const + { + return container.at(pos); + } + + const_reference operator[](size_type i) const + { + return container[i]; + } + + reference operator[](size_type i) + { + return container[i]; + } + +private: + + friend class ModuleHooks; + friend class ServiceHooks; + + ShrinkableVector(container_type& container) + : container(container) + {} + + container_type& container; +}; + +template +std::vector ShrinkableVector::emptyVector; + +US_END_NAMESPACE + +#endif // USSHRINKABLEVECTOR_H diff --git a/Core/CppMicroServices/src/util/usStaticInit_p.h b/Core/CppMicroServices/src/util/usStaticInit_p.h index b69d45c61d..2431456654 100644 --- a/Core/CppMicroServices/src/util/usStaticInit_p.h +++ b/Core/CppMicroServices/src/util/usStaticInit_p.h @@ -1,166 +1,166 @@ /*============================================================================= 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. Extracted from qglobal.h from Qt 4.7.3 and adapted for CppMicroServices. Original copyright (c) Nokia Corporation. Usage covered by the GNU Lesser General Public License version 2.1 (http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and the Nokia Qt LGPL Exception version 1.1 (file LGPL_EXCEPTION.txt in Qt 4.7.3 package). =========================================================================*/ #ifndef US_STATIC_INIT_H #define US_STATIC_INIT_H #include #include "usThreads_p.h" US_BEGIN_NAMESPACE // POD for US_GLOBAL_STATIC template -class GlobalStatic : public US_DEFAULT_THREADING > +class GlobalStatic : public MultiThreaded<> { public: GlobalStatic(T* p = 0, bool destroyed = false) : pointer(p), destroyed(destroyed) {} T* pointer; bool destroyed; private: // purposely not implemented GlobalStatic(const GlobalStatic&); GlobalStatic& operator=(const GlobalStatic&); }; template struct DefaultGlobalStaticDeleter { void operator()(GlobalStatic& globalStatic) const { delete globalStatic.pointer; globalStatic.pointer = 0; globalStatic.destroyed = true; } }; // Created as a function-local static to delete a GlobalStatic template class Deleter = DefaultGlobalStaticDeleter> class GlobalStaticDeleter { public: GlobalStatic &globalStatic; GlobalStaticDeleter(GlobalStatic &_globalStatic) : globalStatic(_globalStatic) { } inline ~GlobalStaticDeleter() { Deleter deleter; deleter(globalStatic); } }; US_END_NAMESPACE #define US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static US_PREPEND_NAMESPACE(GlobalStatic)& this_##NAME() \ { \ static US_PREPEND_NAMESPACE(GlobalStatic) l; \ return l; \ } #define US_GLOBAL_STATIC(TYPE, NAME) \ US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE; \ bool ok = false; \ { \ US_PREPEND_NAMESPACE(GlobalStatic)::Lock lock(this_##NAME()); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ } \ if (!ok) \ delete x; \ else \ static US_PREPEND_NAMESPACE(GlobalStaticDeleter) cleanup(this_##NAME()); \ } \ return this_##NAME().pointer; \ } #define US_GLOBAL_STATIC_WITH_DELETER(TYPE, NAME, DELETER) \ US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE; \ bool ok = false; \ { \ US_PREPEND_NAMESPACE(GlobalStatic)::Lock lock(this_##NAME()); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ } \ if (!ok) \ delete x; \ else \ static US_PREPEND_NAMESPACE(GlobalStaticDeleter) cleanup(this_##NAME()); \ } \ return this_##NAME().pointer; \ } #define US_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE ARGS; \ bool ok = false; \ { \ US_PREPEND_NAMESPACE(GlobalStatic)::Lock lock(this_##NAME()); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ } \ if (!ok) \ delete x; \ else \ static US_PREPEND_NAMESPACE(GlobalStaticDeleter) cleanup(this_##NAME()); \ } \ return this_##NAME().pointer; \ } #endif // US_STATIC_INIT_H diff --git a/Core/CppMicroServices/src/util/usThreads_p.h b/Core/CppMicroServices/src/util/usThreads_p.h index 8c77a24781..ea7fc8aa67 100644 --- a/Core/CppMicroServices/src/util/usThreads_p.h +++ b/Core/CppMicroServices/src/util/usThreads_p.h @@ -1,430 +1,329 @@ /*============================================================================= 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 USTHREADINGMODEL_H #define USTHREADINGMODEL_H #include #ifdef US_ENABLE_THREADING_SUPPORT // Atomic compiler intrinsics #if defined(US_PLATFORM_APPLE) // OSAtomic.h optimizations only used in 10.5 and later #include #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 #include #define US_ATOMIC_OPTIMIZATION_APPLE #endif #elif defined(__GLIBCPP__) || defined(__GLIBCXX__) #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) # include #else # include #endif #define US_ATOMIC_OPTIMIZATION_GNUC #endif // Mutex support #ifdef US_PLATFORM_WINDOWS #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef NOMINMAX #define NOMINMAX #endif #include #define US_THREADS_MUTEX(x) HANDLE (x); #define US_THREADS_MUTEX_INIT(x) #define US_THREADS_MUTEX_CTOR(x) : x(::CreateMutex(NULL, FALSE, NULL)) #define US_THREADS_MUTEX_DELETE(x) ::CloseHandle (x) #define US_THREADS_MUTEX_LOCK(x) ::WaitForSingleObject (x, INFINITE) #define US_THREADS_MUTEX_UNLOCK(x) ::ReleaseMutex (x) #define US_THREADS_LONG LONG #define US_ATOMIC_OPTIMIZATION #define US_ATOMIC_INCREMENT(x) IntType n = InterlockedIncrement(x) #define US_ATOMIC_DECREMENT(x) IntType n = InterlockedDecrement(x) #define US_ATOMIC_ASSIGN(l, r) InterlockedExchange(l, r) #elif defined(US_PLATFORM_POSIX) #include #define US_THREADS_MUTEX(x) pthread_mutex_t (x); #define US_THREADS_MUTEX_INIT(x) ::pthread_mutex_init(&x, 0) #define US_THREADS_MUTEX_CTOR(x) : x() #define US_THREADS_MUTEX_DELETE(x) ::pthread_mutex_destroy (&x) #define US_THREADS_MUTEX_LOCK(x) ::pthread_mutex_lock (&x) #define US_THREADS_MUTEX_UNLOCK(x) ::pthread_mutex_unlock (&x) #define US_ATOMIC_OPTIMIZATION #if defined(US_ATOMIC_OPTIMIZATION_APPLE) #if defined (__LP64__) && __LP64__ #define US_THREADS_LONG volatile int64_t #define US_ATOMIC_INCREMENT(x) IntType n = OSAtomicIncrement64Barrier(x) #define US_ATOMIC_DECREMENT(x) IntType n = OSAtomicDecrement64Barrier(x) #define US_ATOMIC_ASSIGN(l, v) OSAtomicCompareAndSwap64Barrier(*l, v, l) #else #define US_THREADS_LONG volatile int32_t #define US_ATOMIC_INCREMENT(x) IntType n = OSAtomicIncrement32Barrier(x) #define US_ATOMIC_DECREMENT(x) IntType n = OSAtomicDecrement32Barrier(x) #define US_ATOMIC_ASSIGN(l, v) OSAtomicCompareAndSwap32Barrier(*l, v, l) #endif #elif defined(US_ATOMIC_OPTIMIZATION_GNUC) #define US_THREADS_LONG _Atomic_word #define US_ATOMIC_INCREMENT(x) IntType n = __sync_add_and_fetch(x, 1) #define US_ATOMIC_DECREMENT(x) IntType n = __sync_add_and_fetch(x, -1) #define US_ATOMIC_ASSIGN(l, v) __sync_val_compare_and_swap(l, *l, v) #else #define US_THREADS_LONG long #undef US_ATOMIC_OPTIMIZATION #define US_ATOMIC_INCREMENT(x) m_AtomicMtx.Lock(); \ IntType n = ++(*x); \ m_AtomicMtx.Unlock() #define US_ATOMIC_DECREMENT(x) m_AtomicMtx.Lock(); \ IntType n = --(*x); \ m_AtomicMtx.Unlock() #define US_ATOMIC_ASSIGN(l, v) m_AtomicMtx.Lock(); \ *l = v; \ m_AtomicMtx.Unlock() #endif #endif #else // single threaded #define US_THREADS_MUTEX(x) #define US_THREADS_MUTEX_INIT(x) #define US_THREADS_MUTEX_CTOR(x) #define US_THREADS_MUTEX_DELETE(x) #define US_THREADS_MUTEX_LOCK(x) #define US_THREADS_MUTEX_UNLOCK(x) - #define US_THREADS_LONG + #define US_THREADS_LONG int -#endif + #define US_ATOMIC_INCREMENT(x) IntType n = ++(*x); + #define US_ATOMIC_DECREMENT(x) IntType n = --(*x); + #define US_ATOMIC_ASSIGN(l, r) *l = r; -#ifndef US_DEFAULT_MUTEX - #define US_DEFAULT_MUTEX US_PREPEND_NAMESPACE(Mutex) #endif US_BEGIN_NAMESPACE class Mutex { public: Mutex() US_THREADS_MUTEX_CTOR(m_Mtx) { US_THREADS_MUTEX_INIT(m_Mtx); } ~Mutex() { US_THREADS_MUTEX_DELETE(m_Mtx); } void Lock() { US_THREADS_MUTEX_LOCK(m_Mtx); } void Unlock() { US_THREADS_MUTEX_UNLOCK(m_Mtx); } private: - friend class WaitCondition; + template friend class WaitCondition; // Copy-constructor not implemented. Mutex(const Mutex &); // Copy-assignement operator not implemented. Mutex & operator = (const Mutex &); US_THREADS_MUTEX(m_Mtx) }; -template class MutexLock { public: - typedef MutexPolicy MutexType; + typedef Mutex MutexType; MutexLock(MutexType& mtx) : m_Mtx(&mtx) { m_Mtx->Lock(); } ~MutexLock() { m_Mtx->Unlock(); } private: MutexType* m_Mtx; // purposely not implemented MutexLock(const MutexLock&); MutexLock& operator=(const MutexLock&); }; -typedef MutexLock<> DefaultMutexLock; - - -/** - * \brief A thread synchronization object used to suspend execution until some - * condition on shared data is met. - * - * A thread calls Wait() to suspend its execution until the condition is - * met. Each call to Notify() from an executing thread will then cause a single - * waiting thread to be released. A call to Notify() means, "signal - * that the condition is true." NotifyAll() releases all threads waiting on - * the condition variable. - * - * The WaitCondition implementation is consistent with the standard - * definition and use of condition variables in pthreads and other common - * thread libraries. - * - * IMPORTANT: A condition variable always requires an associated mutex - * object. The mutex object is used to avoid a dangerous race condition when - * Wait() and Notify() are called simultaneously from two different - * threads. - * - * On systems using pthreads, this implementation abstracts the - * standard calls to the pthread condition variable. On Win32 - * systems, there is no system provided condition variable. This - * class implements a condition variable using a critical section, a - * semphore, an event and a number of counters. The implementation is - * almost an extract translation of the implementation presented by - * Douglas C Schmidt and Irfan Pyarali in "Strategies for Implementing - * POSIX Condition Variables on Win32". This article can be found at - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - * - */ -class US_EXPORT WaitCondition +class AtomicCounter { public: - typedef US_DEFAULT_MUTEX MutexType; + typedef US_THREADS_LONG IntType; - WaitCondition(); - ~WaitCondition(); + AtomicCounter(int value = 0) + : m_Counter(value) + {} - /** Suspend execution of this thread until the condition is signaled. The - * argument is a SimpleMutex object that must be locked prior to calling - * this method. */ - bool Wait(MutexType& mutex, unsigned long time = 0); + IntType AtomicIncrement() const + { + US_ATOMIC_INCREMENT(&m_Counter); + return n; + } - bool Wait(MutexType* mutex, unsigned long time = 0); + IntType AtomicIncrement(volatile IntType& lval) const + { + US_ATOMIC_INCREMENT(&lval); + return n; + } - /** Notify that the condition is true and release one waiting thread */ - void Notify(); + IntType AtomicDecrement() const + { + US_ATOMIC_DECREMENT(&m_Counter); + return n; + } - /** Notify that the condition is true and release all waiting threads */ - void NotifyAll(); + IntType AtomicDecrement(volatile IntType& lval) const + { + US_ATOMIC_DECREMENT(&lval); + return n; + } -private: + void AtomicAssign(volatile IntType& lval) const + { + US_ATOMIC_ASSIGN(&lval, m_Counter); + } - // purposely not implemented - WaitCondition(const WaitCondition& other); - const WaitCondition& operator=(const WaitCondition&); + void AtomicAssign(volatile IntType& lval, const IntType val) const + { + US_ATOMIC_ASSIGN(&lval, val); + } -#ifdef US_ENABLE_THREADING_SUPPORT - #ifdef US_PLATFORM_POSIX - pthread_cond_t m_WaitCondition; - #else - - int m_NumberOfWaiters; // number of waiting threads - CRITICAL_SECTION m_NumberOfWaitersLock; // Serialize access to - // m_NumberOfWaiters - - HANDLE m_Semaphore; // Semaphore to queue threads - HANDLE m_WaitersAreDone; // Auto-reset event used by the - // broadcast/signal thread to - // wait for all the waiting - // threads to wake up and - // release the semaphore - - std::size_t m_WasNotifyAll; // Keeps track of whether we - // were broadcasting or signaling - #endif + mutable IntType m_Counter; +private: + +#if !defined(US_ATOMIC_OPTIMIZATION) + mutable Mutex m_AtomicMtx; #endif }; -US_END_NAMESPACE - -#ifdef US_ENABLE_THREADING_SUPPORT - -US_BEGIN_NAMESPACE - -template -class MultiThreaded +class MutexLockingStrategy { - mutable MutexPolicy m_Mtx; - WaitCondition m_Cond; - - #if !defined(US_ATOMIC_OPTIMIZATION) - mutable MutexPolicy m_AtomicMtx; - #endif - public: - MultiThreaded() : m_Mtx(), m_Cond() {} - MultiThreaded(const MultiThreaded&) : m_Mtx(), m_Cond() {} - virtual ~MultiThreaded() {} + MutexLockingStrategy() +#ifdef US_ENABLE_THREADING_SUPPORT + : m_Mtx() +#endif + {} + + MutexLockingStrategy(const MutexLockingStrategy&) +#ifdef US_ENABLE_THREADING_SUPPORT + : m_Mtx() +#endif + {} class Lock; friend class Lock; class Lock { public: +#ifdef US_ENABLE_THREADING_SUPPORT // Lock object - explicit Lock(const MultiThreaded& host) : m_Host(host) + explicit Lock(const MutexLockingStrategy& host) : m_Host(host) { m_Host.m_Mtx.Lock(); } // Lock object - explicit Lock(const MultiThreaded* host) : m_Host(*host) + explicit Lock(const MutexLockingStrategy* host) : m_Host(*host) { m_Host.m_Mtx.Lock(); } // Unlock object ~Lock() { m_Host.m_Mtx.Unlock(); } +#else + explicit Lock(const MutexLockingStrategy&) {} + explicit Lock(const MutexLockingStrategy*) {} +#endif private: // private by design Lock(); Lock(const Lock&); Lock& operator=(const Lock&); - const MultiThreaded& m_Host; - +#ifdef US_ENABLE_THREADING_SUPPORT + const MutexLockingStrategy& m_Host; +#endif }; - typedef volatile Host VolatileType; - typedef US_THREADS_LONG IntType; - - bool Wait(unsigned long timeoutMillis = 0) - { - return m_Cond.Wait(m_Mtx, timeoutMillis); - } - - void Notify() - { - m_Cond.Notify(); - } +protected: - void NotifyAll() - { - m_Cond.NotifyAll(); - } - - IntType AtomicIncrement(volatile IntType& lval) const - { - US_ATOMIC_INCREMENT(&lval); - return n; - } - - IntType AtomicDecrement(volatile IntType& lval) const - { - US_ATOMIC_DECREMENT(&lval); - return n; - } - - void AtomicAssign(volatile IntType& lval, const IntType val) const - { - US_ATOMIC_ASSIGN(&lval, val); - } +#ifdef US_ENABLE_THREADING_SUPPORT + mutable Mutex m_Mtx; +#endif +}; +class NoLockingStrategy +{ }; US_END_NAMESPACE -#endif - +#include US_BEGIN_NAMESPACE -template -class SingleThreaded +template class WaitConditionStrategy = NoWaitCondition + > +class MultiThreaded : public LockingStrategy, + public WaitConditionStrategy > { -public: - - virtual ~SingleThreaded() {} - - // Dummy Lock class - struct Lock - { - Lock() {} - explicit Lock(const SingleThreaded&) {} - explicit Lock(const SingleThreaded*) {} - }; - - typedef Host VolatileType; - typedef int IntType; - - bool Wait(unsigned long = 0) - { return false; } - - void Notify() {} - - void NotifyAll() {} - - static IntType AtomicAdd(volatile IntType& lval, const IntType val) - { return lval += val; } - - static IntType AtomicSubtract(volatile IntType& lval, const IntType val) - { return lval -= val; } - - static IntType AtomicMultiply(volatile IntType& lval, const IntType val) - { return lval *= val; } - - static IntType AtomicDivide(volatile IntType& lval, const IntType val) - { return lval /= val; } - - static IntType AtomicIncrement(volatile IntType& lval) - { return ++lval; } - - static IntType AtomicDecrement(volatile IntType& lval) - { return --lval; } - - static void AtomicAssign(volatile IntType & lval, const IntType val) - { lval = val; } - - static void AtomicAssign(IntType & lval, volatile IntType & val) - { lval = val; } - + friend class WaitConditionStrategy >; }; US_END_NAMESPACE #endif // USTHREADINGMODEL_H diff --git a/Core/CppMicroServices/src/util/usUncompressResourceData.cpp b/Core/CppMicroServices/src/util/usUncompressResourceData.cpp index dbc383145d..c7f9332ebf 100644 --- a/Core/CppMicroServices/src/util/usUncompressResourceData.cpp +++ b/Core/CppMicroServices/src/util/usUncompressResourceData.cpp @@ -1,86 +1,86 @@ /*============================================================================= 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 "usUncompressResourceData.h" #ifdef US_ENABLE_RESOURCE_COMPRESSION -#include "usUtils_p.h" +#include "usLog_p.h" extern "C" { const char* us_uncompress_resource_error(); void us_uncompress_resource_data(const unsigned char*, size_t, unsigned char*, size_t); } US_BEGIN_NAMESPACE unsigned char* UncompressResourceData(const unsigned char* data, std::size_t size, std::size_t* uncompressedSize) { if (size <= 4) { if (size < 4 || (data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 0)) { US_WARN << "UncompressResourceData: Input data is corrupted"; return NULL; } } std::size_t expectedSize = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; try { unsigned char* uncompressedData = new unsigned char[expectedSize]; us_uncompress_resource_data(data+4, size-4, uncompressedData, expectedSize); if (us_uncompress_resource_error()[0] != 0) { US_WARN << us_uncompress_resource_error(); delete[] uncompressedData; return NULL; } if (uncompressedSize != NULL) { *uncompressedSize = expectedSize; } return uncompressedData; } catch (const std::bad_alloc&) { US_WARN << "UncompressResourceData: Could not allocate enough memory for uncompressing resource data"; return NULL; } return NULL; } US_END_NAMESPACE #else US_BEGIN_NAMESPACE unsigned char* UncompressResourceData(const unsigned char*, std::size_t, std::size_t*) { return 0; } US_END_NAMESPACE #endif // US_ENABLE_RESOURCE_COMPRESSION diff --git a/Core/CppMicroServices/src/util/usUtils.cpp b/Core/CppMicroServices/src/util/usUtils.cpp index 9149a8c4a9..811ee9f460 100644 --- a/Core/CppMicroServices/src/util/usUtils.cpp +++ b/Core/CppMicroServices/src/util/usUtils.cpp @@ -1,278 +1,282 @@ /*============================================================================= 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 "usUtils_p.h" +#include "usLog_p.h" #include "usModuleInfo.h" #include "usModuleSettings.h" #include #include +#include #ifdef US_PLATFORM_POSIX #include #include #include #include #else #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include "dirent_win32_p.h" #endif //------------------------------------------------------------------- // Module auto-loading //------------------------------------------------------------------- namespace { + #if !defined(US_PLATFORM_LINUX) std::string library_suffix() { #ifdef US_PLATFORM_WINDOWS return ".dll"; #elif defined(US_PLATFORM_APPLE) return ".dylib"; #else return ".so"; #endif } #endif #ifdef US_PLATFORM_POSIX const char DIR_SEP = '/'; bool load_impl(const std::string& modulePath) { void* handle = dlopen(modulePath.c_str(), RTLD_NOW | RTLD_LOCAL); return (handle != NULL); } #elif defined(US_PLATFORM_WINDOWS) const char DIR_SEP = '\\'; bool load_impl(const std::string& modulePath) { void* handle = LoadLibrary(modulePath.c_str()); return (handle != NULL); } #else #ifdef US_ENABLE_AUTOLOADING_SUPPORT #error "Missing load_impl implementation for this platform." #else bool load_impl(const std::string&) { return false; } #endif #endif + } US_BEGIN_NAMESPACE void AutoLoadModulesFromPath(const std::string& absoluteBasePath, const std::string& subDir) { std::string loadPath = absoluteBasePath + DIR_SEP + subDir; DIR* dir = opendir(loadPath.c_str()); #ifdef CMAKE_INTDIR // Try intermediate output directories if (dir == NULL) { std::size_t indexOfLastSeparator = absoluteBasePath.find_last_of(DIR_SEP); if (indexOfLastSeparator != -1) { std::string intermediateDir = absoluteBasePath.substr(indexOfLastSeparator+1); bool equalSubDir = intermediateDir.size() == std::strlen(CMAKE_INTDIR); for (std::size_t i = 0; equalSubDir && i < intermediateDir.size(); ++i) { if (std::tolower(intermediateDir[i]) != std::tolower(CMAKE_INTDIR[i])) { equalSubDir = false; } } if (equalSubDir) { loadPath = absoluteBasePath.substr(0, indexOfLastSeparator+1) + subDir + DIR_SEP + CMAKE_INTDIR; dir = opendir(loadPath.c_str()); } } } #endif if (dir != NULL) { struct dirent *ent = NULL; while ((ent = readdir(dir)) != NULL) { bool loadFile = true; #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type != DT_UNKNOWN && ent->d_type != DT_REG) { loadFile = false; } #endif std::string entryFileName(ent->d_name); // On Linux, library file names can have version numbers appended. On other platforms, we // check the file ending. This could be refined for Linux in the future. #if !defined(US_PLATFORM_LINUX) if (entryFileName.rfind(library_suffix()) != (entryFileName.size() - library_suffix().size())) { loadFile = false; } #endif if (!loadFile) continue; std::string libPath = loadPath; if (!libPath.empty() && libPath.find_last_of(DIR_SEP) != libPath.size() -1) { libPath += DIR_SEP; } libPath += entryFileName; US_INFO << "Auto-loading module " << libPath; if (!load_impl(libPath)) { US_WARN << "Auto-loading of module " << libPath << " failed: " << GetLastErrorStr(); } } closedir(dir); } } void AutoLoadModules(const ModuleInfo& moduleInfo) { if (moduleInfo.autoLoadDir.empty()) { return; } ModuleSettings::PathList autoLoadPaths = ModuleSettings::GetAutoLoadPaths(); std::size_t indexOfLastSeparator = moduleInfo.location.find_last_of(DIR_SEP); std::string moduleBasePath = moduleInfo.location.substr(0, indexOfLastSeparator); for (ModuleSettings::PathList::iterator i = autoLoadPaths.begin(); i != autoLoadPaths.end(); ++i) { if (*i == ModuleSettings::CURRENT_MODULE_PATH()) { // Load all modules from a directory located relative to this modules location // and named after this modules library name. *i = moduleBasePath; } } // We could have introduced a duplicate above, so remove it. std::sort(autoLoadPaths.begin(), autoLoadPaths.end()); autoLoadPaths.erase(std::unique(autoLoadPaths.begin(), autoLoadPaths.end()), autoLoadPaths.end()); for (ModuleSettings::PathList::iterator i = autoLoadPaths.begin(); i != autoLoadPaths.end(); ++i) { if (i->empty()) continue; AutoLoadModulesFromPath(*i, moduleInfo.autoLoadDir); } } US_END_NAMESPACE //------------------------------------------------------------------- // Error handling //------------------------------------------------------------------- US_BEGIN_NAMESPACE std::string GetLastErrorStr() { #ifdef US_PLATFORM_POSIX return std::string(strerror(errno)); #else // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); std::string errMsg((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return errMsg; #endif } static MsgHandler handler = 0; MsgHandler installMsgHandler(MsgHandler h) { MsgHandler old = handler; handler = h; return old; } void message_output(MsgType msgType, const char *buf) { if (handler) { (*handler)(msgType, buf); } else { fprintf(stderr, "%s\n", buf); fflush(stderr); } if (msgType == ErrorMsg) { #if defined(_MSC_VER) && !defined(NDEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) // get the current report mode int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW); _CrtSetReportMode(_CRT_ERROR, reportMode); int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, CppMicroServices_VERSION_STR, buf); if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW) return; // ignore else if (ret == 1) _CrtDbgBreak(); #endif #ifdef US_PLATFORM_POSIX abort(); // trap; generates core dump #else exit(1); // goodbye cruel world #endif } } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/util/usUtils_p.h b/Core/CppMicroServices/src/util/usUtils_p.h index 32c88713e2..9ad7ba1542 100644 --- a/Core/CppMicroServices/src/util/usUtils_p.h +++ b/Core/CppMicroServices/src/util/usUtils_p.h @@ -1,225 +1,52 @@ /*============================================================================= 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 USUTILS_H #define USUTILS_H #include -#include -#include -#include - - -//------------------------------------------------------------------- -// Logging -//------------------------------------------------------------------- - -US_BEGIN_NAMESPACE - -US_EXPORT void message_output(MsgType, const char* buf); - -struct LogMsg { - - LogMsg(int t, const char* file, int ln, const char* func) - : type(static_cast(t)), enabled(true), buffer() - { buffer << "In " << func << " at " << file << ":" << ln << " : "; } - - ~LogMsg() { if(enabled) message_output(type, buffer.str().c_str()); } - - template - LogMsg& operator<<(T t) - { - if (enabled) buffer << t; - return *this; - } - - LogMsg& operator()(bool flag) - { - this->enabled = flag; - return *this; - } - -private: - - MsgType type; - bool enabled; - std::stringstream buffer; -}; - -struct NoLogMsg { - - template - NoLogMsg& operator<<(T) - { - return *this; - } - - NoLogMsg& operator()(bool) - { - return *this; - } - -}; - -US_END_NAMESPACE - -#if defined(US_ENABLE_DEBUG_OUTPUT) - #define US_DEBUG US_PREPEND_NAMESPACE(LogMsg)(0, __FILE__, __LINE__, __FUNCTION__) -#else - #define US_DEBUG true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() -#endif - -#if !defined(US_NO_INFO_OUTPUT) - #define US_INFO US_PREPEND_NAMESPACE(LogMsg)(1, __FILE__, __LINE__, __FUNCTION__) -#else - #define US_INFO true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() -#endif - -#if !defined(US_NO_WARNING_OUTPUT) - #define US_WARN US_PREPEND_NAMESPACE(LogMsg)(2, __FILE__, __LINE__, __FUNCTION__) -#else - #define US_WARN true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() -#endif - -#define US_ERROR US_PREPEND_NAMESPACE(LogMsg)(3, __FILE__, __LINE__, __FUNCTION__) +#include //------------------------------------------------------------------- // Module auto-loading //------------------------------------------------------------------- US_BEGIN_NAMESPACE struct ModuleInfo; void AutoLoadModules(const ModuleInfo& moduleInfo); US_END_NAMESPACE //------------------------------------------------------------------- // Error handling //------------------------------------------------------------------- US_BEGIN_NAMESPACE US_EXPORT std::string GetLastErrorStr(); US_END_NAMESPACE - -//------------------------------------------------------------------- -// Functors -//------------------------------------------------------------------- - -#include -#include - -#if defined(US_USE_CXX11) || defined(__GNUC__) - - #ifdef US_USE_CXX11 - #include - #define US_MODULE_LISTENER_FUNCTOR std::function - #define US_SERVICE_LISTENER_FUNCTOR std::function - #else - #include - #define US_MODULE_LISTENER_FUNCTOR std::tr1::function - #define US_SERVICE_LISTENER_FUNCTOR std::tr1::function - #endif - - US_BEGIN_NAMESPACE - template - US_MODULE_LISTENER_FUNCTOR ModuleListenerMemberFunctor(X* x, void (X::*memFn)(const US_PREPEND_NAMESPACE(ModuleEvent))) - { return std::bind1st(std::mem_fun(memFn), x); } - US_END_NAMESPACE - - US_BEGIN_NAMESPACE - struct ModuleListenerCompare : std::binary_function, - std::pair, bool> - { - bool operator()(const std::pair& p1, - const std::pair& p2) const - { - return p1.second == p2.second && - p1.first.target() == p2.first.target(); - } - }; - US_END_NAMESPACE - - US_BEGIN_NAMESPACE - template - US_SERVICE_LISTENER_FUNCTOR ServiceListenerMemberFunctor(X* x, void (X::*memFn)(const US_PREPEND_NAMESPACE(ServiceEvent))) - { return std::bind1st(std::mem_fun(memFn), x); } - US_END_NAMESPACE - - US_BEGIN_NAMESPACE - struct ServiceListenerCompare : std::binary_function - { - bool operator()(const US_SERVICE_LISTENER_FUNCTOR& f1, - const US_SERVICE_LISTENER_FUNCTOR& f2) const - { - return f1.target() == f2.target(); - } - }; - US_END_NAMESPACE - -#else - - #include - - #define US_MODULE_LISTENER_FUNCTOR US_PREPEND_NAMESPACE(Functor) - - US_BEGIN_NAMESPACE - template - US_MODULE_LISTENER_FUNCTOR ModuleListenerMemberFunctor(X* x, MemFn memFn) - { return Functor(x, memFn); } - US_END_NAMESPACE - - US_BEGIN_NAMESPACE - struct ModuleListenerCompare : std::binary_function, - std::pair, bool> - { - bool operator()(const std::pair& p1, - const std::pair& p2) const - { return p1.second == p2.second && p1.first == p2.first; } - }; - US_END_NAMESPACE - - #define US_SERVICE_LISTENER_FUNCTOR US_PREPEND_NAMESPACE(Functor) - - US_BEGIN_NAMESPACE - template - US_SERVICE_LISTENER_FUNCTOR ServiceListenerMemberFunctor(X* x, MemFn memFn) - { return Functor(x, memFn); } - US_END_NAMESPACE - - US_BEGIN_NAMESPACE - struct ServiceListenerCompare : std::binary_function - { - bool operator()(const US_SERVICE_LISTENER_FUNCTOR& f1, - const US_SERVICE_LISTENER_FUNCTOR& f2) const - { return f1 == f2; } - }; - US_END_NAMESPACE - -#endif - #endif // USUTILS_H diff --git a/Core/CppMicroServices/src/util/usThreads.cpp b/Core/CppMicroServices/src/util/usWaitCondition_p.h similarity index 58% rename from Core/CppMicroServices/src/util/usThreads.cpp rename to Core/CppMicroServices/src/util/usWaitCondition_p.h index 4464c9038e..70e1107b65 100644 --- a/Core/CppMicroServices/src/util/usThreads.cpp +++ b/Core/CppMicroServices/src/util/usWaitCondition_p.h @@ -1,254 +1,378 @@ /*============================================================================= 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 "usThreads_p.h" +#ifndef USWAITCONDITION_P_H +#define USWAITCONDITION_P_H +#include "usConfig.h" +#include "usLog_p.h" #include "usUtils_p.h" +#include "usThreads_p.h" #ifdef US_PLATFORM_POSIX #include #include #endif US_BEGIN_NAMESPACE -WaitCondition::WaitCondition() +/** + * \brief A thread synchronization object used to suspend execution until some + * condition on shared data is met. + * + * A thread calls Wait() to suspend its execution until the condition is + * met. Each call to Notify() from an executing thread will then cause a single + * waiting thread to be released. A call to Notify() means, "signal + * that the condition is true." NotifyAll() releases all threads waiting on + * the condition variable. + * + * The WaitCondition implementation is consistent with the standard + * definition and use of condition variables in pthreads and other common + * thread libraries. + * + * IMPORTANT: A condition variable always requires an associated mutex + * object. The mutex object is used to avoid a dangerous race condition when + * Wait() and Notify() are called simultaneously from two different + * threads. + * + * On systems using pthreads, this implementation abstracts the + * standard calls to the pthread condition variable. On Win32 + * systems, there is no system provided condition variable. This + * class implements a condition variable using a critical section, a + * semphore, an event and a number of counters. The implementation is + * almost an extract translation of the implementation presented by + * Douglas C Schmidt and Irfan Pyarali in "Strategies for Implementing + * POSIX Condition Variables on Win32". This article can be found at + * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * + */ +template +class WaitCondition { +public: + + WaitCondition(); + ~WaitCondition(); + + bool Wait(unsigned long time = 0); + + /** Notify that the condition is true and release one waiting thread */ + void Notify(); + + /** Notify that the condition is true and release all waiting threads */ + void NotifyAll(); + +private: + + // purposely not implemented + WaitCondition(const WaitCondition& other); + const WaitCondition& operator=(const WaitCondition&); + #ifdef US_ENABLE_THREADING_SUPPORT + + /** Suspend execution of this thread until the condition is signaled. The + * argument is a SimpleMutex object that must be locked prior to calling + * this method. */ + bool Wait(Mutex& mutex, unsigned long time = 0); + + bool Wait(Mutex* mutex, unsigned long time = 0); + + #ifdef US_PLATFORM_POSIX + pthread_cond_t m_WaitCondition; + #else + + int m_NumberOfWaiters; // number of waiting threads + CRITICAL_SECTION m_NumberOfWaitersLock; // Serialize access to + // m_NumberOfWaiters + + HANDLE m_Semaphore; // Semaphore to queue threads + HANDLE m_WaitersAreDone; // Auto-reset event used by the + // broadcast/signal thread to + // wait for all the waiting + // threads to wake up and + // release the semaphore + + std::size_t m_WasNotifyAll; // Keeps track of whether we + // were broadcasting or signaling + #endif + +#endif // US_ENABLE_THREADING_SUPPORT +}; + +template +class NoWaitCondition +{ +public: + NoWaitCondition() {} +private: + // purposely not implemented + NoWaitCondition(const NoWaitCondition& other); + const NoWaitCondition& operator=(const NoWaitCondition&); +}; + +// ------------------------------------------------------------------------ +// WaitCondition implementation +// ------------------------------------------------------------------------ + +#ifdef US_ENABLE_THREADING_SUPPORT +template +WaitCondition::WaitCondition() +{ #ifdef US_PLATFORM_POSIX pthread_cond_init(&m_WaitCondition, 0); #else m_NumberOfWaiters = 0; m_WasNotifyAll = 0; m_Semaphore = CreateSemaphore(0, // no security 0, // initial value 0x7fffffff, // max count 0); // unnamed InitializeCriticalSection(&m_NumberOfWaitersLock); m_WaitersAreDone = CreateEvent(0, // no security FALSE, // auto-reset FALSE, // non-signaled initially 0 ); // unnamed #endif -#endif } -WaitCondition::~WaitCondition() +template +WaitCondition::~WaitCondition() { -#ifdef US_ENABLE_THREADING_SUPPORT #ifdef US_PLATFORM_POSIX pthread_cond_destroy(&m_WaitCondition); #else CloseHandle(m_Semaphore); CloseHandle(m_WaitersAreDone); DeleteCriticalSection(&m_NumberOfWaitersLock); #endif -#endif } -void WaitCondition::Notify() +template +bool WaitCondition::Wait(unsigned long time) +{ + return this->Wait(static_cast(this)->m_Mtx, time); +} + +template +void WaitCondition::Notify() { -#ifdef US_ENABLE_THREADING_SUPPORT #ifdef US_PLATFORM_POSIX pthread_cond_signal(&m_WaitCondition); #else EnterCriticalSection(&m_NumberOfWaitersLock); int haveWaiters = m_NumberOfWaiters > 0; LeaveCriticalSection(&m_NumberOfWaitersLock); // if there were not any waiters, then this is a no-op if (haveWaiters) { ReleaseSemaphore(m_Semaphore, 1, 0); } #endif -#endif } -void WaitCondition::NotifyAll() +template +void WaitCondition::NotifyAll() { -#ifdef US_ENABLE_THREADING_SUPPORT #ifdef US_PLATFORM_POSIX pthread_cond_broadcast(&m_WaitCondition); #else // This is needed to ensure that m_NumberOfWaiters and m_WasNotifyAll are // consistent EnterCriticalSection(&m_NumberOfWaitersLock); int haveWaiters = 0; if (m_NumberOfWaiters > 0) { // We are broadcasting, even if there is just one waiter... // Record that we are broadcasting, which helps optimize Notify() // for the non-broadcast case m_WasNotifyAll = 1; haveWaiters = 1; } if (haveWaiters) { // Wake up all waiters atomically ReleaseSemaphore(m_Semaphore, m_NumberOfWaiters, 0); LeaveCriticalSection(&m_NumberOfWaitersLock); // Wait for all the awakened threads to acquire the counting // semaphore WaitForSingleObject(m_WaitersAreDone, INFINITE); // This assignment is ok, even without the m_NumberOfWaitersLock held // because no other waiter threads can wake up to access it. m_WasNotifyAll = 0; } else { LeaveCriticalSection(&m_NumberOfWaitersLock); } #endif -#endif } -bool WaitCondition::Wait(MutexType* mutex, unsigned long timeoutMillis) +template +bool WaitCondition::Wait(Mutex* mutex, unsigned long timeoutMillis) { return Wait(*mutex, timeoutMillis); } -#ifdef US_ENABLE_THREADING_SUPPORT -bool WaitCondition::Wait(MutexType& mutex, unsigned long timeoutMillis) +template +bool WaitCondition::Wait(Mutex& mutex, unsigned long timeoutMillis) { #ifdef US_PLATFORM_POSIX struct timespec ts, * pts = 0; if (timeoutMillis) { pts = &ts; struct timeval tv; int error = gettimeofday(&tv, NULL); if (error) { US_ERROR << "gettimeofday error: " << GetLastErrorStr(); return false; } ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; ts.tv_sec += timeoutMillis / 1000; ts.tv_nsec += (timeoutMillis % 1000) * 1000000; ts.tv_sec += ts.tv_nsec / 1000000000; ts.tv_nsec = ts.tv_nsec % 1000000000; } if (pts) { int error = pthread_cond_timedwait(&m_WaitCondition, &mutex.m_Mtx, pts); if (error == 0) { return true; } else { if (error != ETIMEDOUT) { US_ERROR << "pthread_cond_timedwait error: " << GetLastErrorStr(); } return false; } } else { int error = pthread_cond_wait(&m_WaitCondition, &mutex.m_Mtx); if (error) { US_ERROR << "pthread_cond_wait error: " << GetLastErrorStr(); return false; } return true; } #else // Avoid race conditions EnterCriticalSection(&m_NumberOfWaitersLock); m_NumberOfWaiters++; LeaveCriticalSection(&m_NumberOfWaitersLock); DWORD dw; bool result = true; // This call atomically releases the mutex and waits on the // semaphore until signaled dw = SignalObjectAndWait(mutex.m_Mtx, m_Semaphore, timeoutMillis ? timeoutMillis : INFINITE, FALSE); if (dw == WAIT_TIMEOUT) { result = false; } else if (dw == WAIT_FAILED) { result = false; US_ERROR << "SignalObjectAndWait failed: " << GetLastErrorStr(); } // Reacquire lock to avoid race conditions EnterCriticalSection(&m_NumberOfWaitersLock); // We're no longer waiting.... m_NumberOfWaiters--; // Check to see if we're the last waiter after the broadcast int lastWaiter = m_WasNotifyAll && m_NumberOfWaiters == 0; LeaveCriticalSection(&m_NumberOfWaitersLock); // If we're the last waiter thread during this particular broadcast // then let the other threads proceed if (lastWaiter) { // This call atomically signals the m_WaitersAreDone event and waits // until it can acquire the external mutex. This is required to // ensure fairness dw = SignalObjectAndWait(m_WaitersAreDone, mutex.m_Mtx, INFINITE, FALSE); if (result && dw == WAIT_FAILED) { result = false; US_ERROR << "SignalObjectAndWait failed: " << GetLastErrorStr(); } } else { // Always regain the external mutex since that's the guarentee we // give to our callers dw = WaitForSingleObject(mutex.m_Mtx, INFINITE); if (result && dw == WAIT_FAILED) { result = false; US_ERROR << "SignalObjectAndWait failed: " << GetLastErrorStr(); } } return result; #endif } + #else -bool WaitCondition::Wait(MutexType&, unsigned long) + +template +WaitCondition::WaitCondition() {} + +template +WaitCondition::~WaitCondition() {} + +template +bool WaitCondition::Wait(unsigned long) { return true; } + +template +void WaitCondition::Notify() {} + +template +void WaitCondition::NotifyAll() {} + #endif US_END_NAMESPACE + +#endif // USWAITCONDITION_P_H diff --git a/Core/CppMicroServices/test/CMakeLists.txt b/Core/CppMicroServices/test/CMakeLists.txt index c4bb27b578..a0e8c9d981 100644 --- a/Core/CppMicroServices/test/CMakeLists.txt +++ b/Core/CppMicroServices/test/CMakeLists.txt @@ -1,87 +1,93 @@ #----------------------------------------------------------------------------- # Configure files, include dirs, etc. #----------------------------------------------------------------------------- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/usTestingConfig.h.in" "${PROJECT_BINARY_DIR}/include/usTestingConfig.h") include_directories(${US_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}) #----------------------------------------------------------------------------- # Create test modules #----------------------------------------------------------------------------- include(usFunctionCreateTestModule) set(_us_test_module_libs "" CACHE INTERNAL "" FORCE) add_subdirectory(modules) #----------------------------------------------------------------------------- # Add unit tests #----------------------------------------------------------------------------- set(_tests usDebugOutputTest usLDAPFilterTest usModuleTest usModuleResourceTest usServiceFactoryTest + usServiceHooksTest usServiceRegistryPerformanceTest usServiceRegistryTest usServiceTemplateTest usServiceTrackerTest usStaticModuleResourceTest usStaticModuleTest ) if(US_BUILD_SHARED_LIBS) - list(APPEND _tests usServiceListenerTest usModuleManifestTest usSharedLibraryTest) + list(APPEND _tests + usModuleHooksTest + usModuleManifestTest + usServiceListenerTest + usSharedLibraryTest + ) if(US_ENABLE_AUTOLOADING_SUPPORT) list(APPEND _tests usModuleAutoLoadTest) endif() endif() set(_additional_srcs usTestManager.cpp usTestUtilModuleListener.cpp ) set(_test_driver ${PROJECT_NAME}TestDriver) set(_test_sourcelist_extra_args ) create_test_sourcelist(_srcs ${_test_driver}.cpp ${_tests} ${_test_sourcelist_extra_args}) usFunctionEmbedResources(_srcs EXECUTABLE_NAME ${_test_driver} FILES usTestResource.txt manifest.json) # Generate a custom "module init" file for the test driver executable if(US_BUILD_SHARED_LIBS) usFunctionGenerateExecutableInit(_srcs IDENTIFIER ${_test_driver}) endif() add_executable(${_test_driver} ${_srcs} ${_additional_srcs}) if(NOT US_BUILD_SHARED_LIBS) target_link_libraries(${_test_driver} ${_us_test_module_libs}) endif() target_link_libraries(${_test_driver} ${US_LIBRARY_TARGET}) if(UNIX AND NOT APPLE) target_link_libraries(${_test_driver} rt) endif() # Register tests foreach(_test ${_tests}) add_test(NAME ${_test} COMMAND ${_test_driver} ${_test}) endforeach() if(US_TEST_LABELS) set_tests_properties(${_tests} PROPERTIES LABELS "${US_TEST_LABELS}") endif() #----------------------------------------------------------------------------- # Add dependencies for shared libraries #----------------------------------------------------------------------------- if(US_BUILD_SHARED_LIBS) foreach(_test_module ${_us_test_module_libs}) add_dependencies(${_test_driver} ${_test_module}) endforeach() endif() diff --git a/Core/CppMicroServices/test/modules/libSL1/usActivatorSL1.cpp b/Core/CppMicroServices/test/modules/libSL1/usActivatorSL1.cpp index f7070ce255..55dcc4dd46 100644 --- a/Core/CppMicroServices/test/modules/libSL1/usActivatorSL1.cpp +++ b/Core/CppMicroServices/test/modules/libSL1/usActivatorSL1.cpp @@ -1,106 +1,106 @@ /*============================================================================= 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 "usFooService.h" US_BEGIN_NAMESPACE class ActivatorSL1 : public ModuleActivator, public ModulePropsInterface, public ServiceTrackerCustomizer { public: ActivatorSL1() : tracker(0), context(0) { } ~ActivatorSL1() { delete tracker; } void Load(ModuleContext* context) { this->context = context; InterfaceMap im = MakeInterfaceMap(this); im.insert(std::make_pair(std::string("ActivatorSL1"), this)); sr = context->RegisterService(im); delete tracker; tracker = new FooTracker(context, this); tracker->Open(); } void Unload(ModuleContext* /*context*/) { tracker->Close(); } const Properties& GetProperties() const { return props; } - FooService* AddingService(const ServiceReferenceT& reference) + FooService* AddingService(const ServiceReferenceType& reference) { props["serviceAdded"] = true; FooService* fooService = context->GetService(reference); fooService->foo(); return fooService; } - void ModifiedService(const ServiceReferenceT& /*reference*/, FooService* /*service*/) + void ModifiedService(const ServiceReferenceType& /*reference*/, FooService* /*service*/) {} - void RemovedService(const ServiceReferenceT& /*reference*/, FooService* /*service*/) + void RemovedService(const ServiceReferenceType& /*reference*/, FooService* /*service*/) { props["serviceRemoved"] = true; } private: ModulePropsInterface::Properties props; ServiceRegistrationU sr; typedef ServiceTracker FooTracker; FooTracker* tracker; ModuleContext* context; }; // ActivatorSL1 US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(TestModuleSL1, US_PREPEND_NAMESPACE(ActivatorSL1)) diff --git a/Core/CppMicroServices/test/modules/libSL3/usActivatorSL3.cpp b/Core/CppMicroServices/test/modules/libSL3/usActivatorSL3.cpp index ea5e9a8706..ed636fc3da 100644 --- a/Core/CppMicroServices/test/modules/libSL3/usActivatorSL3.cpp +++ b/Core/CppMicroServices/test/modules/libSL3/usActivatorSL3.cpp @@ -1,100 +1,100 @@ /*============================================================================= 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 US_BEGIN_NAMESPACE class ActivatorSL3 : public ModuleActivator, public ModulePropsInterface, public ServiceTrackerCustomizer { public: ActivatorSL3() : tracker(0), context(0) {} ~ActivatorSL3() { delete tracker; } void Load(ModuleContext* context) { this->context = context; InterfaceMap im = MakeInterfaceMap(this); im.insert(std::make_pair(std::string("ActivatorSL3"), this)); sr = context->RegisterService(im); delete tracker; tracker = new FooTracker(context, this); tracker->Open(); } void Unload(ModuleContext* /*context*/) { tracker->Close(); } const ModulePropsInterface::Properties& GetProperties() const { return props; } - FooService* AddingService(const ServiceReferenceT& reference) + FooService* AddingService(const ServiceReferenceType& reference) { props["serviceAdded"] = true; US_INFO << "SL3: Adding reference =" << reference; FooService* fooService = context->GetService(reference); fooService->foo(); return fooService; } - void ModifiedService(const ServiceReferenceT& /*reference*/, FooService* /*service*/) + void ModifiedService(const ServiceReferenceType& /*reference*/, FooService* /*service*/) { } - void RemovedService(const ServiceReferenceT& reference, FooService* /*service*/) + void RemovedService(const ServiceReferenceType& reference, FooService* /*service*/) { props["serviceRemoved"] = true; US_INFO << "SL3: Removing reference =" << reference; } private: typedef ServiceTracker FooTracker; FooTracker* tracker; ModuleContext* context; ServiceRegistrationU sr; ModulePropsInterface::Properties props; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(TestModuleSL3, US_PREPEND_NAMESPACE(ActivatorSL3)) diff --git a/Core/CppMicroServices/test/usDebugOutputTest.cpp b/Core/CppMicroServices/test/usDebugOutputTest.cpp index 3fcc643854..ae87a6eb32 100644 --- a/Core/CppMicroServices/test/usDebugOutputTest.cpp +++ b/Core/CppMicroServices/test/usDebugOutputTest.cpp @@ -1,99 +1,99 @@ /*============================================================================= 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 "usTestingMacros.h" US_USE_NAMESPACE static int lastMsgType = -1; static std::string lastMsg; void handleMessages(MsgType type, const char* msg) { lastMsgType = type; lastMsg.assign(msg); } void resetLastMsg() { lastMsgType = -1; lastMsg.clear(); } int usDebugOutputTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("DebugOutputTest"); // Use the default message handler { US_DEBUG << "Msg"; US_DEBUG(false) << "Msg"; US_INFO << "Msg"; US_INFO(false) << "Msg"; US_WARN << "Msg"; US_WARN(false) << "Msg"; } US_TEST_CONDITION(lastMsg.empty(), "Testing default message handler"); resetLastMsg(); installMsgHandler(handleMessages); { US_DEBUG << "Msg"; } #if !defined(US_ENABLE_DEBUG_OUTPUT) US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing suppressed debug message") #else US_TEST_CONDITION(lastMsgType == 0 && lastMsg.find("Msg") != std::string::npos, "Testing debug message") #endif resetLastMsg(); { US_DEBUG(false) << "No msg"; } US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing disabled debug message") resetLastMsg(); { US_INFO << "Info msg"; } US_TEST_CONDITION(lastMsgType == 1 && lastMsg.find("Info msg") != std::string::npos, "Testing informational message") resetLastMsg(); { US_WARN << "Warn msg"; } US_TEST_CONDITION(lastMsgType == 2 && lastMsg.find("Warn msg") != std::string::npos, "Testing warning message") resetLastMsg(); // We cannot test US_ERROR since it will call abort(). installMsgHandler(0); { US_INFO << "Info msg"; } US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing message handler reset") US_TEST_END() } diff --git a/Core/CppMicroServices/test/usModuleHooksTest.cpp b/Core/CppMicroServices/test/usModuleHooksTest.cpp new file mode 100644 index 0000000000..b1dea8ccdc --- /dev/null +++ b/Core/CppMicroServices/test/usModuleHooksTest.cpp @@ -0,0 +1,187 @@ +/*============================================================================= + + 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 +#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 + +class TestModuleListener +{ +public: + + void ModuleChanged(const ModuleEvent moduleEvent) + { + this->events.push_back(moduleEvent); + } + + std::vector events; +}; + +class TestModuleFindHook : public ModuleFindHook +{ +public: + + void Find(const ModuleContext* /*context*/, ShrinkableVector& modules) + { + for (ShrinkableVector::iterator i = modules.begin(); + i != modules.end();) + { + if ((*i)->GetName() == "TestModuleA Module") + { + i = modules.erase(i); + } + else + { + ++i; + } + } + } +}; + +class TestModuleEventHook : public ModuleEventHook +{ +public: + + void Event(const ModuleEvent& event, ShrinkableVector& contexts) + { + if (event.GetType() == ModuleEvent::LOADING || event.GetType() == ModuleEvent::UNLOADING) + { + contexts.erase(std::remove(contexts.begin(), contexts.end(), GetModuleContext()), contexts.end()); + } + } +}; + +void TestFindHook() +{ + SharedLibrary libA(LIB_PATH, "TestModuleA"); + try + { + libA.Load(); + } + catch (const std::exception& e) + { + US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) + } + + Module* moduleA = GetModuleContext()->GetModule("TestModuleA Module"); + US_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for existing module TestModuleA") + + US_TEST_CONDITION(moduleA->GetName() == "TestModuleA Module", "Test module name") + + US_TEST_CONDITION(moduleA->IsLoaded() == true, "Test if loaded correctly"); + + long moduleAId = moduleA->GetModuleId(); + US_TEST_CONDITION_REQUIRED(moduleAId > 0, "Test for valid module id") + + US_TEST_CONDITION_REQUIRED(GetModuleContext()->GetModule(moduleAId) != NULL, "Test for non-filtered GetModule(long) result") + + TestModuleFindHook findHook; + ServiceRegistration findHookReg = GetModuleContext()->RegisterService(&findHook); + + US_TEST_CONDITION_REQUIRED(GetModuleContext()->GetModule(moduleAId) == NULL, "Test for filtered GetModule(long) result") + + std::vector modules = GetModuleContext()->GetModules(); + for (std::vector::iterator i = modules.begin(); + i != modules.end(); ++i) + { + if((*i)->GetName() == "TestModuleA Module") + { + US_TEST_FAILED_MSG(<< "TestModuleA not filtered from GetModules()") + } + } + + findHookReg.Unregister(); + + libA.Unload(); +} + +void TestEventHook() +{ + TestModuleListener moduleListener; + GetModuleContext()->AddModuleListener(&moduleListener, &TestModuleListener::ModuleChanged); + + SharedLibrary libA(LIB_PATH, "TestModuleA"); + try + { + libA.Load(); + } + catch (const std::exception& e) + { + US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) + } + US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 2, "Test for received load module events") + + libA.Unload(); + US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 4, "Test for received unload module events") + + TestModuleEventHook eventHook; + ServiceRegistration eventHookReg = GetModuleContext()->RegisterService(&eventHook); + + moduleListener.events.clear(); + try + { + libA.Load(); + } + catch (const std::exception& e) + { + US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) + } + + US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 1, "Test for filtered load module events") + US_TEST_CONDITION_REQUIRED(moduleListener.events[0].GetType() == ModuleEvent::LOADED, "Test for LOADED event") + + libA.Unload(); + US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 2, "Test for filtered unload module events") + US_TEST_CONDITION_REQUIRED(moduleListener.events[1].GetType() == ModuleEvent::UNLOADED, "Test for UNLOADED event") + + eventHookReg.Unregister(); + GetModuleContext()->RemoveModuleListener(&moduleListener, &TestModuleListener::ModuleChanged); +} + +} // end unnamed namespace + +int usModuleHooksTest(int /*argc*/, char* /*argv*/[]) +{ + US_TEST_BEGIN("ModuleHooksTest"); + + TestFindHook(); + TestEventHook(); + + US_TEST_END() +} diff --git a/Core/CppMicroServices/test/usServiceHooksTest.cpp b/Core/CppMicroServices/test/usServiceHooksTest.cpp new file mode 100644 index 0000000000..a9821498bc --- /dev/null +++ b/Core/CppMicroServices/test/usServiceHooksTest.cpp @@ -0,0 +1,414 @@ +/*============================================================================= + + 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 +#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 + +class TestServiceListener +{ +public: + + void ServiceChanged(const ServiceEvent serviceEvent) + { + this->events.push_back(serviceEvent); + } + + std::vector events; +}; + +class TestServiceEventListenerHook : public ServiceEventListenerHook +{ +private: + + int id; + +public: + + TestServiceEventListenerHook(int id) + : id(id) + { + } + + typedef ShrinkableMap > MapType; + + void Event(const ServiceEvent& /*event*/, MapType& listeners) + { + US_TEST_CONDITION_REQUIRED(listeners.size() > 0 && listeners.find(GetModuleContext()) != listeners.end(), "Check listener content"); + ShrinkableVector& listenerInfos = listeners[GetModuleContext()]; + + // listener count should be 2 because the event listener hooks are called with + // the list of listeners before filtering them according to ther LDAP filter + if (id == 1) + { +#ifdef US_BUILD_SHARED_LIBS + US_TEST_CONDITION(listenerInfos.size() == 2, "2 service listeners expected"); +#else + US_TEST_CONDITION(listenerInfos.size() >= 2, "2 service listeners expected"); +#endif + US_TEST_CONDITION(listenerInfos[0].IsRemoved() == false, "Listener is not removed"); + US_TEST_CONDITION(listenerInfos[1].IsRemoved() == false, "Listener is not removed"); + US_TEST_CONDITION(!(listenerInfos[0] == listenerInfos[1]), "listener info inequality"); + } + else + { + // there is already one listener filtered out +#ifdef US_BUILD_SHARED_LIBS + US_TEST_CONDITION(listenerInfos.size() == 1, "1 service listener expected"); +#else + US_TEST_CONDITION(listenerInfos.size() >= 1, "1 service listener expected"); +#endif + US_TEST_CONDITION(listenerInfos[0].IsRemoved() == false, "Listener is not removed"); + } + if (listenerInfo.IsNull()) + { + listenerInfo = listenerInfos[0]; + } + else + { + US_TEST_CONDITION(listenerInfo == listenerInfos[0], "Equal listener info objects"); + } + + // Remove the listener without a filter from the list + for(ShrinkableVector::iterator infoIter = listenerInfos.begin(); + infoIter != listenerInfos.end();) + { + if (infoIter->GetFilter().empty()) + { + infoIter = listenerInfos.erase(infoIter); + } + else + { + ++infoIter; + } + } +#ifdef US_BUILD_SHARED_LIBS + US_TEST_CONDITION(listenerInfos.size() == 1, "One listener with LDAP filter should remain"); +#else + US_TEST_CONDITION(listenerInfos.size() >= 1, "One listener with LDAP filter should remain"); +#endif + + ordering.push_back(id); + } + + ServiceListenerHook::ListenerInfo listenerInfo; + + static std::vector ordering; +}; + +std::vector TestServiceEventListenerHook::ordering; + + +class TestServiceFindHook : public ServiceFindHook +{ +private: + int id; + +public: + + TestServiceFindHook(int id) + : id(id) + { + } + + void Find(const ModuleContext* context, const std::string& /*name*/, + const std::string& /*filter*/, ShrinkableVector& references) + { + US_TEST_CONDITION(context == GetModuleContext(), "Module context"); + + references.clear(); + ordering.push_back(id); + } + + static std::vector ordering; +}; + +std::vector TestServiceFindHook::ordering; + +class TestServiceListenerHook : public ServiceListenerHook +{ +private: + int id; + +public: + + TestServiceListenerHook(int id) + : id(id) + { + } + + void Added(const std::vector& listeners) + { + for (std::vector::const_iterator iter = listeners.begin(); + iter != listeners.end(); ++iter) + { + if (iter->IsRemoved() || iter->GetModuleContext() != GetModuleContext()) continue; + listenerInfos.insert(*iter); + lastAdded = listeners.back(); + ordering.push_back(id); + } + } + + void Removed(const std::vector& listeners) + { + for (std::vector::const_iterator iter = listeners.begin(); + iter != listeners.end(); ++iter) + { + listenerInfos.erase(*iter); + ordering.push_back(id*10); + } + lastRemoved = listeners.back(); + } + + static std::vector ordering; + + US_UNORDERED_SET_TYPE listenerInfos; + ListenerInfo lastAdded; + ListenerInfo lastRemoved; +}; + +std::vector TestServiceListenerHook::ordering; + + +void TestEventListenerHook() +{ + ModuleContext* context = GetModuleContext(); + + TestServiceListener serviceListener1; + TestServiceListener serviceListener2; + context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); + context->AddServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged, LDAPProp(ServiceConstants::OBJECTCLASS()) == "bla"); + + TestServiceEventListenerHook serviceEventListenerHook1(1); + ServiceProperties hookProps1; + hookProps1[ServiceConstants::SERVICE_RANKING()] = 10; + ServiceRegistration eventListenerHookReg1 = + context->RegisterService(&serviceEventListenerHook1, hookProps1); + + TestServiceEventListenerHook serviceEventListenerHook2(2); + ServiceProperties hookProps2; + hookProps2[ServiceConstants::SERVICE_RANKING()] = 0; + ServiceRegistration eventListenerHookReg2 = + context->RegisterService(&serviceEventListenerHook2, hookProps2); + + std::vector expectedOrdering; + expectedOrdering.push_back(1); + expectedOrdering.push_back(1); + expectedOrdering.push_back(2); + US_TEST_CONDITION(serviceEventListenerHook1.ordering == expectedOrdering, "Event listener hook call order"); + + US_TEST_CONDITION(serviceListener1.events.empty(), "service event of service event listener hook"); + US_TEST_CONDITION(serviceListener2.events.empty(), "no service event for filtered listener"); + +#ifdef US_BUILD_SHARED_LIBS + SharedLibrary libA(LIB_PATH, "TestModuleA"); + try + { + libA.Load(); + } + catch (const std::exception& e) + { + US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) + } + + expectedOrdering.push_back(1); + expectedOrdering.push_back(2); + US_TEST_CONDITION(serviceEventListenerHook1.ordering == expectedOrdering, "Event listener hook call order"); + + libA.Unload(); +#endif + + US_TEST_CONDITION(serviceListener1.events.empty(), "no service event due to service event listener hook"); + US_TEST_CONDITION(serviceListener2.events.empty(), "no service event for filtered listener due to service event listener hook"); + + eventListenerHookReg2.Unregister(); + eventListenerHookReg1.Unregister(); + + context->RemoveServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); + context->RemoveServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged); +} + +void TestListenerHook() +{ + ModuleContext* context = GetModuleContext(); + + TestServiceListener serviceListener1; + TestServiceListener serviceListener2; + context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); + context->AddServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged, LDAPProp(ServiceConstants::OBJECTCLASS()) == "bla"); + + TestServiceListenerHook serviceListenerHook1(1); + ServiceProperties hookProps1; + hookProps1[ServiceConstants::SERVICE_RANKING()] = 0; + ServiceRegistration listenerHookReg1 = + context->RegisterService(&serviceListenerHook1, hookProps1); + + TestServiceListenerHook serviceListenerHook2(2); + ServiceProperties hookProps2; + hookProps2[ServiceConstants::SERVICE_RANKING()] = 10; + ServiceRegistration listenerHookReg2 = + context->RegisterService(&serviceListenerHook2, hookProps2); + +#ifdef US_BUILD_SHARED_LIBS + // check if hooks got notified about the existing listeners + US_TEST_CONDITION_REQUIRED(serviceListenerHook1.listenerInfos.size() == 2, "Notification about existing listeners") +#endif + const std::size_t listenerInfoSizeOld = serviceListenerHook1.listenerInfos.size() - 2; + + context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); + ServiceListenerHook::ListenerInfo lastAdded = serviceListenerHook1.lastAdded; + +#ifdef US_BUILD_SHARED_LIBS + std::vector expectedOrdering; + expectedOrdering.push_back(1); + expectedOrdering.push_back(1); + expectedOrdering.push_back(2); + expectedOrdering.push_back(2); + expectedOrdering.push_back(20); + expectedOrdering.push_back(10); + expectedOrdering.push_back(2); + expectedOrdering.push_back(1); + US_TEST_CONDITION(serviceListenerHook1.ordering == expectedOrdering, "Listener hook call order"); +#endif + + context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged, LDAPProp(ServiceConstants::OBJECTCLASS()) == "blub"); + US_TEST_CONDITION(lastAdded == serviceListenerHook1.lastRemoved, "Same ListenerInfo object)"); + US_TEST_CONDITION(!(lastAdded == serviceListenerHook1.lastAdded), "New ListenerInfo object)"); + +#ifdef US_BUILD_SHARED_LIBS + expectedOrdering.push_back(20); + expectedOrdering.push_back(10); + expectedOrdering.push_back(2); + expectedOrdering.push_back(1); + US_TEST_CONDITION(serviceListenerHook1.ordering == expectedOrdering, "Listener hook call order"); +#endif + + context->RemoveServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); + context->RemoveServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged); + +#ifdef US_BUILD_SHARED_LIBS + expectedOrdering.push_back(20); + expectedOrdering.push_back(10); + expectedOrdering.push_back(20); + expectedOrdering.push_back(10); + US_TEST_CONDITION(serviceListenerHook1.ordering == expectedOrdering, "Listener hook call order"); +#endif + + US_TEST_CONDITION_REQUIRED(serviceListenerHook1.listenerInfos.size() == listenerInfoSizeOld, "Removed listener infos") + + listenerHookReg2.Unregister(); + listenerHookReg1.Unregister(); +} + +void TestFindHook() +{ + ModuleContext* context = GetModuleContext(); + + TestServiceFindHook serviceFindHook1(1); + ServiceProperties hookProps1; + hookProps1[ServiceConstants::SERVICE_RANKING()] = 0; + ServiceRegistration findHookReg1 = + context->RegisterService(&serviceFindHook1, hookProps1); + + TestServiceFindHook serviceFindHook2(2); + ServiceProperties hookProps2; + hookProps2[ServiceConstants::SERVICE_RANKING()] = 10; + ServiceRegistration findHookReg2 = + context->RegisterService(&serviceFindHook2, hookProps2); + + std::vector expectedOrdering; + US_TEST_CONDITION(serviceFindHook1.ordering == expectedOrdering, "Find hook call order"); + + TestServiceListener serviceListener; + context->AddServiceListener(&serviceListener, &TestServiceListener::ServiceChanged); + +#ifdef US_BUILD_SHARED_LIBS + SharedLibrary libA(LIB_PATH, "TestModuleA"); + try + { + libA.Load(); + } + catch (const std::exception& e) + { + US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) + } + + US_TEST_CONDITION(serviceListener.events.size() == 1, "Service registered"); +#endif + + std::vector refs = context->GetServiceReferences("org.cppmicroservices.TestModuleAService"); + US_TEST_CONDITION(refs.empty(), "Empty references"); + ServiceReferenceU ref = context->GetServiceReference("org.cppmicroservices.TestModuleAService"); + US_TEST_CONDITION(!ref, "Invalid reference (filtered out)"); + + expectedOrdering.push_back(2); + expectedOrdering.push_back(1); + expectedOrdering.push_back(2); + expectedOrdering.push_back(1); + + US_TEST_CONDITION(serviceFindHook1.ordering == expectedOrdering, "Find hook call order"); + + findHookReg2.Unregister(); + findHookReg1.Unregister(); + + refs = context->GetServiceReferences("org.cppmicroservices.TestModuleAService"); + US_TEST_CONDITION(!refs.empty(), "Non-empty references"); + ref = context->GetServiceReference("org.cppmicroservices.TestModuleAService"); + US_TEST_CONDITION(ref, "Valid reference"); + +#ifdef US_BUILD_SHARED_LIBS + libA.Unload(); +#endif + + context->RemoveServiceListener(&serviceListener, &TestServiceListener::ServiceChanged); +} + +} // end unnamed namespace + +int usServiceHooksTest(int /*argc*/, char* /*argv*/[]) +{ + US_TEST_BEGIN("ServiceHooksTest"); + + TestListenerHook(); + TestFindHook(); + TestEventListenerHook(); + + US_TEST_END() +} diff --git a/Core/CppMicroServices/test/usServiceTemplateTest.cpp b/Core/CppMicroServices/test/usServiceTemplateTest.cpp index 783ebfa8d5..ef7ab792bb 100644 --- a/Core/CppMicroServices/test/usServiceTemplateTest.cpp +++ b/Core/CppMicroServices/test/usServiceTemplateTest.cpp @@ -1,211 +1,211 @@ /*============================================================================= 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 "usTestingMacros.h" struct Interface1 {}; US_DECLARE_SERVICE_INTERFACE(Interface1, "org.cppmicroservices.test.Interface1") struct Interface2 {}; US_DECLARE_SERVICE_INTERFACE(Interface2, "org.cppmicroservices.test.Interface2") struct Interface3 {}; US_DECLARE_SERVICE_INTERFACE(Interface3, "org.cppmicroservices.test.Interface3") struct MyService1 : public Interface1 {}; struct MyService2 : public Interface1, public Interface2 {}; struct MyService3 : public Interface1, public Interface2, public Interface3 {}; struct MyFactory1 : public us::ServiceFactory { std::map m_idToServiceMap; virtual us::InterfaceMap GetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/) { MyService1* s = new MyService1; m_idToServiceMap.insert(std::make_pair(module->GetModuleId(), s)); return us::MakeInterfaceMap(s); } virtual void UngetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) { std::map::iterator iter = m_idToServiceMap.find(module->GetModuleId()); if (iter != m_idToServiceMap.end()) { US_TEST_CONDITION(static_cast(iter->second) == us::ExtractInterface(service), "Compare service pointer") delete iter->second; m_idToServiceMap.erase(iter); } } }; struct MyFactory2 : public us::ServiceFactory { std::map m_idToServiceMap; virtual us::InterfaceMap GetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/) { MyService2* s = new MyService2; m_idToServiceMap.insert(std::make_pair(module->GetModuleId(), s)); return us::MakeInterfaceMap(s); } virtual void UngetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) { std::map::iterator iter = m_idToServiceMap.find(module->GetModuleId()); if (iter != m_idToServiceMap.end()) { US_TEST_CONDITION(static_cast(iter->second) == us::ExtractInterface(service), "Compare service pointer") delete iter->second; m_idToServiceMap.erase(iter); } } }; struct MyFactory3 : public us::ServiceFactory { std::map m_idToServiceMap; virtual us::InterfaceMap GetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/) { MyService3* s = new MyService3; m_idToServiceMap.insert(std::make_pair(module->GetModuleId(), s)); return us::MakeInterfaceMap(s); } virtual void UngetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) { std::map::iterator iter = m_idToServiceMap.find(module->GetModuleId()); if (iter != m_idToServiceMap.end()) { US_TEST_CONDITION(static_cast(iter->second) == us::ExtractInterface(service), "Compare service pointer") delete iter->second; m_idToServiceMap.erase(iter); } } }; US_USE_NAMESPACE int usServiceTemplateTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceTemplateTest"); ModuleContext* mc = GetModuleContext(); // Register compile tests MyService1 s1; MyService2 s2; MyService3 s3; us::ServiceRegistration sr1 = mc->RegisterService(&s1); us::ServiceRegistration sr2 = mc->RegisterService(&s2); us::ServiceRegistration sr3 = mc->RegisterService(&s3); MyFactory1 f1; us::ServiceRegistration sfr1 = mc->RegisterService(&f1); MyFactory2 f2; us::ServiceRegistration sfr2 = mc->RegisterService(static_cast(&f2)); MyFactory3 f3; us::ServiceRegistration sfr3 = mc->RegisterService(static_cast(&f3)); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(mc->GetModule()->GetRegisteredServices().size() == 6, "# of reg services") #endif std::vector > s1refs = mc->GetServiceReferences(); US_TEST_CONDITION(s1refs.size() == 6, "# of interface1 regs") std::vector > s2refs = mc->GetServiceReferences(); US_TEST_CONDITION(s2refs.size() == 4, "# of interface2 regs") std::vector > s3refs = mc->GetServiceReferences(); US_TEST_CONDITION(s3refs.size() == 2, "# of interface3 regs") Interface1* i1 = mc->GetService(sr1.GetReference()); US_TEST_CONDITION(i1 == static_cast(&s1), "interface1 ptr") i1 = NULL; US_TEST_CONDITION(mc->UngetService(sr1.GetReference()), "unget interface1 ptr") i1 = mc->GetService(sfr1.GetReference()); US_TEST_CONDITION(i1 == static_cast(f1.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface1 factory ptr") i1 = NULL; US_TEST_CONDITION(mc->UngetService(sfr1.GetReference()), "unget interface1 factory ptr") - i1 = mc->GetService(sr2.GetReference(InterfaceT())); + i1 = mc->GetService(sr2.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(&s2), "interface1 ptr") i1 = NULL; - US_TEST_CONDITION(mc->UngetService(sr2.GetReference(InterfaceT())), "unget interface1 ptr") - i1 = mc->GetService(sfr2.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sr2.GetReference(InterfaceType())), "unget interface1 ptr") + i1 = mc->GetService(sfr2.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(f2.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface1 factory ptr") i1 = NULL; - US_TEST_CONDITION(mc->UngetService(sfr2.GetReference(InterfaceT())), "unget interface1 factory ptr") - Interface2* i2 = mc->GetService(sr2.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sfr2.GetReference(InterfaceType())), "unget interface1 factory ptr") + Interface2* i2 = mc->GetService(sr2.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(&s2), "interface2 ptr") i2 = NULL; - US_TEST_CONDITION(mc->UngetService(sr2.GetReference(InterfaceT())), "unget interface2 ptr") - i2 = mc->GetService(sfr2.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sr2.GetReference(InterfaceType())), "unget interface2 ptr") + i2 = mc->GetService(sfr2.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(f2.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface2 factory ptr") i2 = NULL; - US_TEST_CONDITION(mc->UngetService(sfr2.GetReference(InterfaceT())), "unget interface2 factory ptr") + US_TEST_CONDITION(mc->UngetService(sfr2.GetReference(InterfaceType())), "unget interface2 factory ptr") - i1 = mc->GetService(sr3.GetReference(InterfaceT())); + i1 = mc->GetService(sr3.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(&s3), "interface1 ptr") i1 = NULL; - US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceT())), "unget interface1 ptr") - i1 = mc->GetService(sfr3.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceType())), "unget interface1 ptr") + i1 = mc->GetService(sfr3.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(f3.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface1 factory ptr") i1 = NULL; - US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceT())), "unget interface1 factory ptr") - i2 = mc->GetService(sr3.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceType())), "unget interface1 factory ptr") + i2 = mc->GetService(sr3.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(&s3), "interface2 ptr") i2 = NULL; - US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceT())), "unget interface2 ptr") - i2 = mc->GetService(sfr3.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceType())), "unget interface2 ptr") + i2 = mc->GetService(sfr3.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(f3.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface2 factory ptr") i2 = NULL; - US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceT())), "unget interface2 factory ptr") - Interface3* i3 = mc->GetService(sr3.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceType())), "unget interface2 factory ptr") + Interface3* i3 = mc->GetService(sr3.GetReference(InterfaceType())); US_TEST_CONDITION(i3 == static_cast(&s3), "interface3 ptr") i3 = NULL; - US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceT())), "unget interface3 ptr") - i3 = mc->GetService(sfr3.GetReference(InterfaceT())); + US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceType())), "unget interface3 ptr") + i3 = mc->GetService(sfr3.GetReference(InterfaceType())); US_TEST_CONDITION(i3 == static_cast(f3.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface3 factory ptr") i3 = NULL; - US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceT())), "unget interface3 factory ptr") + US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceType())), "unget interface3 factory ptr") sr1.Unregister(); sr2.Unregister(); sr3.Unregister(); US_TEST_END() } diff --git a/Core/CppMicroServices/test/usServiceTrackerTest.cpp b/Core/CppMicroServices/test/usServiceTrackerTest.cpp index 0ea92e94bc..bcf834347d 100644 --- a/Core/CppMicroServices/test/usServiceTrackerTest.cpp +++ b/Core/CppMicroServices/test/usServiceTrackerTest.cpp @@ -1,283 +1,283 @@ /*=================================================================== 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 ServiceReferenceT& reference) + virtual MyInterfaceOne* AddingService(const ServiceReferenceType& reference) { US_TEST_CONDITION_REQUIRED(reference, "AddingService() valid reference") return m_context->GetService(reference); } - virtual void ModifiedService(const ServiceReferenceT& reference, MyInterfaceOne* service) + 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 ServiceReferenceT& reference, MyInterfaceOne* 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); US_TEST_CONDITION(tracker.GetServiceReferences().size() == 1, "tracking count") } 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() } diff --git a/Core/CppMicroServices/test/usTestManager.cpp b/Core/CppMicroServices/test/usTestManager.cpp index 100d5b5997..def9cee003 100644 --- a/Core/CppMicroServices/test/usTestManager.cpp +++ b/Core/CppMicroServices/test/usTestManager.cpp @@ -1,82 +1,83 @@ /*============================================================================= 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 "usTestManager.h" #include "usModuleImport.h" US_BEGIN_NAMESPACE TestManager& TestManager::GetInstance() { static TestManager instance; return instance; } void TestManager::Initialize() { m_FailedTests = 0; m_PassedTests = 0; } int TestManager::NumberOfFailedTests() { return m_FailedTests; } int TestManager::NumberOfPassedTests() { return m_PassedTests; } void TestManager::TestFailed() { m_FailedTests++; } void TestManager::TestPassed() { m_PassedTests++; } US_END_NAMESPACE #ifndef US_BUILD_SHARED_LIBS +US_IMPORT_MODULE(CppMicroServices) US_IMPORT_MODULE_RESOURCES(CppMicroServices) US_IMPORT_MODULE(TestModuleA) US_IMPORT_MODULE(TestModuleA2) US_IMPORT_MODULE(TestModuleB) US_IMPORT_MODULE_RESOURCES(TestModuleB) US_IMPORT_MODULE(TestModuleH) US_IMPORT_MODULE(TestModuleM) US_IMPORT_MODULE_RESOURCES(TestModuleM) US_IMPORT_MODULE(TestModuleR) US_IMPORT_MODULE_RESOURCES(TestModuleR) US_IMPORT_MODULE(TestModuleS) US_IMPORT_MODULE(TestModuleSL1) US_IMPORT_MODULE(TestModuleSL3) US_IMPORT_MODULE(TestModuleSL4) US_LOAD_IMPORTED_MODULES_INTO_MAIN( TestModuleA TestModuleA2 TestModuleB TestModuleImportedByB TestModuleH TestModuleM TestModuleR TestModuleS TestModuleSL1 TestModuleSL3 TestModuleSL4 ) #endif diff --git a/Core/CppMicroServices/test/usTestingMacros.h b/Core/CppMicroServices/test/usTestingMacros.h index 0b85d3769d..44ec95e0d5 100644 --- a/Core/CppMicroServices/test/usTestingMacros.h +++ b/Core/CppMicroServices/test/usTestingMacros.h @@ -1,132 +1,133 @@ /*============================================================================= 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 "usTestManager.h" US_BEGIN_NAMESPACE /** \brief Indicate a failed test. */ class TestFailedException : public std::exception { public: TestFailedException() {} }; US_END_NAMESPACE /** * * \brief Output some text without generating a terminating newline. * * */ #define US_TEST_OUTPUT_NO_ENDL(x) \ std::cout x << std::flush; /** \brief Output some text. */ #define US_TEST_OUTPUT(x) \ US_TEST_OUTPUT_NO_ENDL(x << "\n") /** \brief Do some general test preparations. Must be called first in the main test function. */ #define US_TEST_BEGIN(testName) \ std::string usTestName(#testName); \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().Initialize(); \ try { /** \brief Fail and finish test with message MSG */ #define US_TEST_FAILED_MSG(MSG) \ US_TEST_OUTPUT(MSG) \ throw US_PREPEND_NAMESPACE(TestFailedException)(); /** \brief Must be called last in the main test function. */ #define US_TEST_END() \ } catch (const US_PREPEND_NAMESPACE(TestFailedException)&) { \ US_TEST_OUTPUT(<< "Further test execution skipped.") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ } catch (const std::exception& ex) { \ US_TEST_OUTPUT(<< "Exception occured " << ex.what()) \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ } \ if (US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfFailedTests() > 0) { \ US_TEST_OUTPUT(<< usTestName << ": [DONE FAILED] , subtests passed: " << \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfPassedTests() << " failed: " << \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfFailedTests() ) \ return EXIT_FAILURE; \ } else { \ US_TEST_OUTPUT(<< usTestName << ": " \ << US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfPassedTests() \ << " tests [DONE PASSED]") \ return EXIT_SUCCESS; \ } #define US_TEST_CONDITION(COND,MSG) \ US_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ US_TEST_OUTPUT(<< " [FAILED]\n" << "In " << __FILE__ \ << ", line " << __LINE__ \ << ": " #COND " : [FAILED]") \ } else { \ US_TEST_OUTPUT(<< " [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } #define US_TEST_CONDITION_REQUIRED(COND,MSG) \ US_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ US_TEST_FAILED_MSG(<< " [FAILED]\n" << " +--> in " << __FILE__ \ << ", line " << __LINE__ \ << ", expression is false: \"" #COND "\"") \ } else { \ US_TEST_OUTPUT(<< " [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } /** * \brief Begin block which should be checked for exceptions * * This macro, together with US_TEST_FOR_EXCEPTION_END, can be used * to test whether a code block throws an expected exception. The test FAILS if the * exception is NOT thrown. */ #define US_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ try { #define US_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ US_TEST_OUTPUT( << "Expected an '" << #EXCEPTIONCLASS << "' exception. [FAILED]") \ } \ catch (EXCEPTIONCLASS) { \ US_TEST_OUTPUT(<< "Caught an expected '" << #EXCEPTIONCLASS \ << "' exception. [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } /** * \brief Simplified version of US_TEST_FOR_EXCEPTION_BEGIN / END for * a single statement */ #define US_TEST_FOR_EXCEPTION(EXCEPTIONCLASS, STATEMENT) \ US_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ STATEMENT ; \ US_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) diff --git a/Core/CppMicroServices/usConfig.h.in b/Core/CppMicroServices/usConfig.h.in index 17e0eb7b12..637a47f70d 100644 --- a/Core/CppMicroServices/usConfig.h.in +++ b/Core/CppMicroServices/usConfig.h.in @@ -1,236 +1,226 @@ /* 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_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 + #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 + class hash : std::unary_function { \ + public: std::size_t operator()(const type& arg) const { - #define US_HASH_FUNCTION_NAMESPACE ::stdext - #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace stdext { - #define US_HASH_FUNCTION_NAMESPACE_END } + #define US_HASH_FUNCTION_END } }; -#endif + #define US_HASH_FUNCTION(type, arg) hash()(arg) + #define US_HASH_FUNCTION_FRIEND(type) friend class ::std::tr1::hash + #define US_UNORDERED_MAP_TYPE ::std::tr1::unordered_map + #define US_UNORDERED_SET_TYPE ::std::tr1::unordered_set -//------------------------------------------------------------------- -// Threading Configuration -//------------------------------------------------------------------- + #define US_HASH_FUNCTION_NAMESPACE ::std::tr1 + #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { namespace tr1 { + #define US_HASH_FUNCTION_NAMESPACE_END }} -#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