diff --git a/.travis.yml b/.travis.yml index 528cc50dcc..77d8094713 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,58 +1,24 @@ language: cpp compiler: - gcc - clang env: - global: - - # -- BEGIN Coverity Scan ENV - - # Pre-configuration steps that should not be analyzed - - COVERITY_SCAN_BUILD_COMMAND_PREPEND="cmake -DUS_BUILD_EXAMPLES:BOOL=ON -DUS_BUILD_TESTING:BOOL=ON -DUS_ENABLE_AUTOLOADING_SUPPORT:BOOL=ON -DUS_ENABLE_THREADING_SUPPORT:BOOL=ON ." - - # The build command with all of the arguments that you would apply to a manual `cov-build` - # Usually this is the same as STANDARD_BUILD_COMMAND, exluding the automated test arguments - - COVERITY_SCAN_BUILD_COMMAND="make -j4" - - - COVERITY_SCAN_PROJECT_NAME="saschazelzer/CppMicroServices" - - # Email address for notifications related to this build - - COVERITY_SCAN_NOTIFICATION_EMAIL="s.zelzer@dkfz-heidelberg.de" - - # Regular expression selects on which branches to run analysis - # Be aware of quotas. Do not run on every branch/commit - - COVERITY_SCAN_BRANCH_PATTERN="development" - - # COVERITY_SCAN_TOKEN via "travis encrypt" using the repo's public key - - secure: "byqeazsk6vCHFoWrZJvLFy/m1KI8sDIEhW7b1yvlGpcCrXQBoDk+dtr3kLCgiYl1+gC39av++0uOJnoM7xn/qiURW65CVDWxa9Giie079M63tqDRbOoeGezhBa8DEXJjhxZ77Iijt0tTOcp/VWg87uSiHSqI+B9HwrWDKwEtSzM=" - - - COVERITY_SCAN_BUILD_URL="https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh" - - # -- END Coverity Scan ENV - matrix: - BUILD_CONFIGURATION=0 - BUILD_CONFIGURATION=1 - BUILD_CONFIGURATION=2 - BUILD_CONFIGURATION=3 - BUILD_CONFIGURATION=4 - BUILD_CONFIGURATION=5 - BUILD_CONFIGURATION=6 - BUILD_CONFIGURATION=7 -matrix: - include: - - language: cpp - compiler: gcc - env: - script: curl -s $COVERITY_SCAN_BUILD_URL | bash - branches: only: - master - development - /^release-.*$/ script: - ctest -VV -S ./cmake/usCTestScript_travis.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 716b498c66..9ca7b769a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,434 +1,439 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 2) 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(US_CMAKE_DIR ${PROJECT_SOURCE_DIR}/cmake) + set(CMAKE_MODULE_PATH - ${PROJECT_SOURCE_DIR}/cmake + ${US_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CMakeParseArguments) include(CMakePackageConfigHelpers) include(CheckCXXSourceCompiles) +include(usFunctionAddResources) include(usFunctionCheckCompilerFlags) -include(usFunctionEmbedResources) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) -include(usFunctionGenerateExecutableInit) +include(usMacroCreateModule) + +if(US_BUILD_TESTING) + include(usFunctionCompileSnippets) +endif() #----------------------------------------------------------------------------- # 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) 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") us_cache_var(US_BUILD_EXAMPLES OFF BOOL "Build example projects") if(US_BUILD_TESTING) enable_testing() endif() 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) set(AUXILIARY_CMAKE_INSTALL_DIR ${AUXILIARY_INSTALL_DIR}/cmake) us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ Micro Services symbols") set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) -set(US_MODULE_INIT_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/usModuleInit.cpp" CACHE INTERNAL "The module initialization template code") -set(US_EXECUTABLE_INIT_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/usExecutableInit.cpp" CACHE INTERNAL "The executable initialization template code") +set(US_MODULE_INIT_TEMPLATE "${US_CMAKE_DIR}/usModuleInit.cpp" CACHE INTERNAL "The module initialization template code") +set(US_CMAKE_RESOURCE_DEPENDENCIES_CPP "${US_CMAKE_DIR}/usCMakeResourceDependencies.cpp" CACHE INTERNAL "The dummy resource dependencies code") #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- if(US_IS_EMBEDDED) set(CMAKE_C_FLAGS) set(CMAKE_C_FLAGS_RELEASE) set(CMAKE_C_FLAGS_DEBUG) set(CMAKE_CXX_FLAGS) set(CMAKE_CXX_FLAGS_RELEASE) set(CMAKE_CXX_FLAGS_DEBUG) set(CMAKE_LINK_FLAGS) set(CMAKE_LINK_FLAGS_RELEASE) set(CMAKE_LINK_FLAGS_DEBUG) endif() # 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() endif() set(US_HAVE_VISIBILITY_ATTRIBUTE 0) usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" _have_visibility) if(_have_visibility) set(US_HAVE_VISIBILITY_ATTRIBUTE 1) 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 (only for gcc >= 4.5) # We only support hidden visibility with gcc for now. # # Clang has troubles with correctly marking template declarations and explicit template # instantiations as exported across shared library boundaries. Specifically, comparing # type_info objects from STL types does not work (used in us::Any::Type() == typeid(std::string)) # which could be related to the default visibility of STL types declared in libstdc++ and/or libc++ # but also to using RTLD_LOCAL or RTLD_GLOBAL when loading shared libraries via dlopen(). # # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 # and http://llvm.org/bugs/show_bug.cgi?id=10113 # if(_have_visibility AND NOT ${GCC_VERSION} VERSION_LESS "4.5") set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") 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() endif() if(MSVC) set(US_CXX_FLAGS "/MP /WX /wd4996 /wd4251 /wd4503 ${US_CXX_FLAGS}") endif() 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}") #----------------------------------------------------------------------------- # 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(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) +CHECK_INCLUDE_FILE_CXX(cxxabi.h US_HAVE_CXXABI_H) CHECK_INCLUDE_FILE_CXX(stdint.h US_HAVE_STDINT_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_map US_HAVE_TR1_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_set US_HAVE_TR1_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(tr1/functional US_HAVE_TR1_FUNCTIONAL_H) CHECK_INCLUDE_FILE_CXX(unordered_map US_HAVE_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(unordered_set US_HAVE_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(functional US_HAVE_FUNCTIONAL_H) if(US_HAVE_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() elseif(US_HAVE_TR1_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() else() message(SEND_ERROR "The header file \"unordered_map\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_MAP OR US_HAVE_STD_UNORDERED_MAP)) message(SEND_ERROR "The \"unordered_map\" type is not available.") endif() if(US_HAVE_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) elseif(US_HAVE_TR1_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) else() message(SEND_ERROR "The header file \"unordered_set\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_SET OR US_HAVE_STD_UNORDERED_SET)) message(SEND_ERROR "The \"unordered_set\" type is not available.") endif() if(NOT (US_HAVE_FUNCTIONAL_H OR US_HAVE_TR1_FUNCTIONAL_H)) message(SEND_ERROR "The header file \"functional\" is not available.") endif() if(US_HAVE_FUNCTIONAL_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if((NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) AND US_HAVE_TR1_FUNCTIONAL_H) unset(US_HAVE_TR1_FUNCTION CACHE) unset(US_HAVE_STD_FUNCTION CACHE) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if(NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) message(SEND_ERROR "The \"function\" type is not available.") endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- -set(US_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include) +set(US_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/third_party ${PROJECT_BINARY_DIR}/include) # Configure CppMicroServicesConfig.cmake for the build tree. # The file is used in sub-directories. 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) +set(PACKAGE_CONFIG_CMAKE_DIR ${US_CMAKE_DIR}) set(US_RCC_EXECUTABLE_NAME usResourceCompiler CACHE INTERNAL "The target name of the usResourceCompiler executable.") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) set(us_global_config_h_file "${PROJECT_BINARY_DIR}/include/usGlobalConfig.h") -configure_file(${PROJECT_SOURCE_DIR}/cmake/usGlobalConfig.h.in ${us_global_config_h_file}) +configure_file(${US_CMAKE_DIR}/usGlobalConfig.h.in ${us_global_config_h_file}) include_directories(${US_INCLUDE_DIRS}) add_subdirectory(tools) add_subdirectory(core) #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(doc) #----------------------------------------------------------------------------- # Last configuration and install steps #----------------------------------------------------------------------------- export(TARGETS ${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_CMAKE_INSTALL_DIR}) set(_install_cmake_scripts ${US_MODULE_INIT_TEMPLATE} - ${US_EXECUTABLE_INIT_TEMPLATE} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeParseArguments.cmake - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPackageHandleStandardArgs.cmake - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPackageMessage.cmake - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/usFunctionGenerateModuleInit.cmake - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/usFunctionGenerateExecutableInit.cmake - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/usFunctionEmbedResources.cmake + ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} + ${US_CMAKE_DIR}/CMakeParseArguments.cmake + ${US_CMAKE_DIR}/FindPackageHandleStandardArgs.cmake + ${US_CMAKE_DIR}/FindPackageMessage.cmake + ${US_CMAKE_DIR}/usFunctionGenerateModuleInit.cmake + ${US_CMAKE_DIR}/usFunctionAddResources.cmake ) install(FILES ${_install_cmake_scripts} DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) install(FILES ${us_global_config_h_file} DESTINATION ${HEADER_INSTALL_DIR}) # 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_CMAKE_INSTALL_DIR}) 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_CMAKE_INSTALL_DIR} 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_CMAKE_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} ) diff --git a/CppMicroServicesConfig.cmake.in b/CppMicroServicesConfig.cmake.in index a69bde8f39..d770025474 100644 --- a/CppMicroServicesConfig.cmake.in +++ b/CppMicroServicesConfig.cmake.in @@ -1,192 +1,199 @@ # A package config for @PROJECT_NAME@. # This file loads component specific configuration files and # sets the following variables which can be used in other # CMake projects to build and link against @PROJECT_NAME@: # # US_INCLUDE_DIRS # US_LIBRARIES # US_RUNTIME_LIBRARY_DIRS # # The following variables are aliases for the ones above: # # CppMicroServices_INCLUDE_DIRS # CppMicroServices_LIBRARIES # CppMicroServices_RUNTIME_LIBRARY_DIRS # # To specify a compatible version for a specific component, # set the following variable before calling find_package: # # US__FIND_VERSION # # After find_package returns successfully, the following additional # variables will be set: # # US_FOUND # CPPMICROSERVICES_FOUND # # US_RCC_EXECUTABLE # # US_CXX_FLAGS # US_CXX_FLAGS_RELEASE # US_CXX_FLAGS_DEBUG # US_C_FLAGS # US_C_FLAGS_RELEASE # US_C_FLAGS_DEBUG # US_LINK_FLAGS # US_LINK_FLAGS_RELEASE # US_LINK_FLAGS_DEBUG # US_COMPILE_DEFINITIONS # US_COMPILE_DEFINITIONS_RELEASE # US_COMPILE_DEFINITIONS_DEBUG # # US_VERSION # US_VERSION_MAJOR # US_VERSION_MINOR # US_VERSION_PATCH # US_VERSION_TWEAK # US_VERSION_COUNT # # Additional component specific variables: # # US__FOUND # # US__VERSION # US__VERSION_MAJOR # US__VERSION_MINOR # US__VERSION_PATCH # US__VERSION_TWEAK # US__VERSION_COUNT # # US__CXX_FLAGS # US__CXX_FLAGS_RELEASE # US__CXX_FLAGS_DEBUG # US__C_FLAGS # US__C_FLAGS_RELEASE # US__C_FLAGS_DEBUG # US__LINK_FLAGS # US__LINK_FLAGS_RELEASE # US__LINK_FLAGS_DEBUG # US__COMPILE_DEFINITIONS # US__COMPILE_DEFINITIONS_RELEASE # US__COMPILE_DEFINITIONS_DEBUG # @PACKAGE_INIT@ list(APPEND CMAKE_MODULE_PATH "@PACKAGE_CONFIG_CMAKE_DIR@") set(US_RCC_EXECUTABLE_NAME @US_RCC_EXECUTABLE_NAME@) set(US_MODULE_INIT_TEMPLATE "@PACKAGE_CONFIG_CMAKE_DIR@/usModuleInit.cpp") -set(US_EXECUTABLE_INIT_TEMPLATE "@PACKAGE_CONFIG_CMAKE_DIR@/usExecutableInit.cpp") +set(US_CMAKE_RESOURCE_DEPENDENCIES_CPP "@PACKAGE_CONFIG_CMAKE_DIR@/usCMakeResourceDependencies.cpp") # The CppMicroServices resource compiler find_program(US_RCC_EXECUTABLE ${US_RCC_EXECUTABLE_NAME} PATHS "@PACKAGE_CONFIG_RUNTIME_DIR@" PATH_SUFFIXES Release Debug RelWithDebInfo MinSizeRel) mark_as_advanced(US_RCC_EXECUTABLE) # Include helper macros include(CMakeParseArguments) if(CMAKE_VERSION VERSION_LESS "2.8.8") # We need the HANDLE_COMPONENTS argument include("@PACKAGE_CONFIG_CMAKE_DIR@/FindPackageHandleStandardArgs.cmake") elseif(NOT COMMAND find_package_handle_standard_args) include(FindPackageHandleStandardArgs) endif() include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionGenerateModuleInit.cmake") -include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionGenerateExecutableInit.cmake") -include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionEmbedResources.cmake") +include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionAddResources.cmake") # Global include directory set(US_INCLUDE_DIRS "@PACKAGE_CONFIG_INCLUDE_DIR@") # Clear variables set(US_LIBRARIES ) set(US_RUNTIME_LIBRARY_DIRS ) set(US_CXX_FLAGS ) set(US_CXX_FLAGS_RELEASE ) set(US_CXX_FLAGS_DEBUG ) set(US_C_FLAGS ) set(US_C_FLAGS_RELEASE ) set(US_C_FLAGS_DEBUG ) set(US_LINK_FLAGS ) set(US_LINK_FLAGS_RELEASE ) set(US_LINK_FLAGS_DEBUG ) set(US_COMPILE_DEFINITIONS ) set(US_COMPILE_DEFINITIONS_RELEASE ) set(US_COMPILE_DEFINITIONS_DEBUG ) # Components support set(US_MODULES Core) # ConfigAdmin EventAdmin ... +set(US_Core_MODULE_DEPS ) + if(NOT @PROJECT_NAME@_FIND_COMPONENTS) set(@PROJECT_NAME@_FIND_COMPONENTS Core) endif() -set(@PROJECT_NAME@_FOUND TRUE) +set(US_MODULES_NEEDED ) foreach(component ${@PROJECT_NAME@_FIND_COMPONENTS}) + list(APPEND US_MODULES_NEEDED ${US_${component}_MODULE_DEPS} ${component}) +endforeach() +list(REMOVE_DUPLICATES US_MODULES_NEEDED) + +set(@PROJECT_NAME@_FOUND TRUE) +foreach(component ${US_MODULES_NEEDED}) if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/us${component}Config.cmake") set(US_${component}_FOUND 0) set(CppMicroServices_${component}_FOUND 0) else() find_package(us${component} ${US_${component}_FIND_VERSION} QUIET REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR} NO_DEFAULT_PATH ) mark_as_advanced(us${component}_DIR) set(US_${component}_FOUND ${us${component}_FOUND}) set(CppMicroServices_${component}_FOUND ${US_${component}_FOUND}) endif() if(US_${component}_FOUND) list(APPEND US_INCLUDE_DIRS ${US_${component}_INCLUDE_DIRS}) list(APPEND US_LIBRARIES ${US_${component}_LIBRARIES}) list(APPEND US_RUNTIME_LIBRARY_DIRS ${US_${component}_RUNTIME_LIBRARY_DIRS}) set(US_CXX_FLAGS "${US_CXX_FLAGS} ${US_${component}_CXX_FLAGS}") set(US_CXX_FLAGS_RELEASE "${US_CXX_FLAGS_RELEASE} ${US_${component}_CXX_FLAGS_RELEASE}") set(US_CXX_FLAGS_DEBUG "${US_CXX_FLAGS_DEBUG} ${US_${component}_CXX_FLAGS_DEBUG}") set(US_C_FLAGS "${US_C_FLAGS} ${US_${component}_C_FLAGS}") set(US_C_FLAGS_RELEASE "${US_C_FLAGS_RELEASE} ${US_${component}_C_FLAGS_RELEASE}") set(US_C_FLAGS_DEBUG "${US_C_FLAGS_DEBUG} ${US_${component}_C_FLAGS_DEBUG}") set(US_LINK_FLAGS "${US_LINK_FLAGS} ${US_${component}_LINK_FLAGS}") set(US_LINK_FLAGS_RELEASE "${US_LINK_FLAGS_RELEASE} ${US_${component}_LINK_FLAGS_RELEASE}") set(US_LINK_FLAGS_DEBUG "${US_LINK_FLAGS_DEBUG} ${US_${component}_LINK_FLAGS_DEBUG}") set(US_COMPILE_DEFINITIONS "${US_COMPILE_DEFINITIONS} ${US_${component}_COMPILE_DEFINITIONS}") set(US_COMPILE_DEFINITIONS_RELEASE "${US_COMPILE_DEFINITIONS_RELEASE} ${US_${component}_COMPILE_DEFINITIONS_RELEASE}") set(US_COMPILE_DEFINITIONS_DEBUG "${US_COMPILE_DEFINITIONS_DEBUG} ${US_${component}_COMPILE_DEFINITIONS_DEBUG}") set(US_${component}_VERSION ${${component}_VERSION}) set(US_${component}_VERSION_MAJOR ${${component}_VERSION_MAJOR}) set(US_${component}_VERSION_MINOR ${${component}_VERSION_MINOR}) set(US_${component}_VERSION_PATCH ${${component}_VERSION_PATCH}) set(US_${component}_VERSION_TWEAK ${${component}_VERSION_TWEAK}) set(US_${component}_VERSION_COUNT ${${component}_VERSION_COUNT}) else() if(@PROJECT_NAME@_FIND_REQUIRED_${component}) set(@PROJECT_NAME@_FOUND FALSE) endif() endif() endforeach() if(US_INCLUDE_DIRS) list(REMOVE_DUPLICATES US_INCLUDE_DIRS) endif() if(US_LIBRARIES) list(REMOVE_DUPLICATES US_LIBRARIES) endif() if(US_RUNTIME_LIBRARY_DIRS) list(REMOVE_DUPLICATES US_RUNTIME_LIBRARY_DIRS) endif() set(CppMicroServices_INCLUDE_DIRS ${US_INCLUDE_DIRS}) set(CppMicroServices_LIBRARIES ${US_LIBRARIES}) set(CppMicroServices_RUNTIME_LIBRARY_DIRS ${US_RUNTIME_LIBRARY_DIRS}) set(@PROJECT_NAME@_CONFIG ${CMAKE_CURRENT_LIST_FILE}) find_package_handle_standard_args(@PROJECT_NAME@ HANDLE_COMPONENTS CONFIG_MODE ) string(TOUPPER "@PROJECT_NAME@" @PROJECT_NAME@_UPPER) set(US_FOUND ${${@PROJECT_NAME@_UPPER}_FOUND}) diff --git a/cmake/usExecutableInit.cpp b/cmake/usCMakeResourceDependencies.cpp similarity index 79% rename from cmake/usExecutableInit.cpp rename to cmake/usCMakeResourceDependencies.cpp index 6e43c3d884..c1aa3719ea 100644 --- a/cmake/usExecutableInit.cpp +++ b/cmake/usCMakeResourceDependencies.cpp @@ -1,24 +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 -US_INITIALIZE_EXECUTABLE("@US_EXECUTABLE_IDENTIFIER@") +namespace { + +// This is dummy code to silence some linkers warning about +// empty object files. +struct CMakeResourceDependencies { CMakeResourceDependencies() { std::cout << std::flush; } }; + +} diff --git a/cmake/usCTestScript.cmake b/cmake/usCTestScript.cmake index 29a4b57aeb..eddc8c2b01 100644 --- a/cmake/usCTestScript.cmake +++ b/cmake/usCTestScript.cmake @@ -1,102 +1,109 @@ macro(build_and_test) set(CTEST_SOURCE_DIRECTORY ${US_SOURCE_DIR}) set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/${CTEST_PROJECT_NAME}_${CTEST_DASHBOARD_NAME}") #if(NOT CTEST_BUILD_NAME) # set(CTEST_BUILD_NAME "${CMAKE_SYSTEM}_${CTEST_COMPILER}_${CTEST_DASHBOARD_NAME}") #endif() ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY}) ctest_start("Experimental") if(NOT EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt") file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "${CTEST_INITIAL_CACHE}") endif() ctest_configure(RETURN_VALUE res) if (res) message(FATAL_ERROR "CMake configure error") endif() ctest_build(RETURN_VALUE res) if (res) message(FATAL_ERROR "CMake build error") endif() ctest_test(RETURN_VALUE res PARALLEL_LEVEL ${CTEST_PARALLEL_LEVEL}) if (res) message(FATAL_ERROR "CMake test error") endif() if(WITH_MEMCHECK AND CTEST_MEMORYCHECK_COMMAND) ctest_memcheck() endif() if(WITH_COVERAGE AND CTEST_COVERAGE_COMMAND) ctest_coverage() endif() #ctest_submit() endmacro() function(create_initial_cache var _shared _threading _autoload) set(_initial_cache " US_BUILD_TESTING:BOOL=ON US_BUILD_SHARED_LIBS:BOOL=${_shared} US_ENABLE_THREADING_SUPPORT:BOOL=${_threading} US_ENABLE_AUTOLOADING_SUPPORT:BOOL=${_autoload} ") if(_shared) set(_initial_cache "${_initial_cache} US_BUILD_EXAMPLES:BOOL=ON ") endif() set(${var} ${_initial_cache} PARENT_SCOPE) if(_shared) set(CTEST_DASHBOARD_NAME "shared") else() set(CTEST_DASHBOARD_NAME "static") endif() if(_threading) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-threading") endif() if(_autoload) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-autoloading") endif() - set(CTEST_DASHBOARD_NAME ${CTEST_DASHBOARD_NAME} PARENT_SCOPE) + set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME} (${_generator})" PARENT_SCOPE) endfunction() #========================================================= set(CTEST_PROJECT_NAME CppMicroServices) if(NOT CTEST_PARALLEL_LEVEL) set(CTEST_PARALLEL_LEVEL 1) endif() # SHARED THREADING AUTOLOAD set(config0 0 0 0 ) set(config1 0 0 1 ) set(config2 0 1 0 ) set(config3 0 1 1 ) set(config4 1 0 0 ) set(config5 1 0 1 ) set(config6 1 1 0 ) set(config7 1 1 1 ) -foreach(i ${US_BUILD_CONFIGURATION}) - create_initial_cache(CTEST_INITIAL_CACHE ${config${i}}) - message("Testing build configuration: ${CTEST_DASHBOARD_NAME}") - build_and_test() +if(NOT US_CMAKE_GENERATOR) + set(US_CMAKE_GENERATOR "Unix Makefiles") +endif() + +foreach (_generator ${US_CMAKE_GENERATOR}) + set(CTEST_CMAKE_GENERATOR ${_generator}) + foreach(i ${US_BUILD_CONFIGURATION}) + create_initial_cache(CTEST_INITIAL_CACHE ${config${i}}) + message("Testing build configuration: ${CTEST_DASHBOARD_NAME}") + build_and_test() + endforeach() endforeach() diff --git a/cmake/usCTestScript_custom.cmake b/cmake/usCTestScript_custom.cmake index ee9908c8bd..9b95df48b6 100644 --- a/cmake/usCTestScript_custom.cmake +++ b/cmake/usCTestScript_custom.cmake @@ -1,24 +1,38 @@ find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) find_program(CTEST_GIT_COMMAND NAMES git) set(CTEST_SITE "bigeye") -set(CTEST_DASHBOARD_ROOT "/tmp/us builds") -#set(CTEST_COMPILER "gcc-4.5") -set(CTEST_CMAKE_GENERATOR "Unix Makefiles") -set(CTEST_BUILD_FLAGS "-j") -set(CTEST_BUILD_CONFIGURATION Debug) +if(WIN32) + set(CTEST_DASHBOARD_ROOT "C:/tmp/us") +else() + set(CTEST_DASHBOARD_ROOT "/tmp/us") + set(CTEST_BUILD_FLAGS "-j") + #set(CTEST_COMPILER "gcc-4.5") +endif() + +set(CTEST_CONFIGURATION_TYPE Release) +set(CTEST_BUILD_CONFIGURATION Release) + set(CTEST_PARALLEL_LEVEL 4) set(US_TEST_SHARED 1) set(US_TEST_STATIC 1) set(US_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../") set(US_BUILD_CONFIGURATION ) foreach(i RANGE 7) list(APPEND US_BUILD_CONFIGURATION ${i}) endforeach() +if(WIN32 AND NOT MINGW) + set(US_CMAKE_GENERATOR + "Visual Studio 9 2008" + "Visual Studio 10" + "Visual Studio 11" + ) +endif() + include(${US_SOURCE_DIR}/cmake/usCTestScript.cmake) diff --git a/cmake/usFunctionAddResources.cmake b/cmake/usFunctionAddResources.cmake new file mode 100644 index 0000000000..b2c7b46784 --- /dev/null +++ b/cmake/usFunctionAddResources.cmake @@ -0,0 +1,136 @@ +#! \ingroup MicroServicesCMake +#! \brief Add resources to a library or executable. +#! +#! This CMake function uses an external command line program to generate a ZIP archive +#! containing data from external resources such as text files or images or other ZIP +#! archives. The created archive file is appended as a binary blob to the target file. +#! +#! Each module can call this function to add resources and make them available at +#! runtime through the Module class. Multiple calls to this function append the +#! input files to the target file. +#! +#! \note To set-up correct file dependencies from your module target to your resource +#! files, you have to add a file named \e $_resources.cpp +#! to the source list of the target. This ensures that changed resource files +#! will automatically be re-added to the module. +#! +#! In the case of linking static modules which contain resources to the target module, +#! adding the static module target name to the ZIP_ARCHIVES list will merge its +#! resources into the target module. +#! +#! Example usage: +#! \code{.cmake} +#! set(module_srcs ) +#! usFunctionAddResources(TARGET mylib +#! MODULE_NAME org_me_mylib +#! FILES config.properties logo.png +#! ) +#! \endcode +#! +#! \param TARGET (required) The target to which the resource files are added. +#! \param MODULE_NAME (required/optional) The module name of the target, as specified in +#! the \c US_MODULE_NAME pre-processor definition of that target. This parameter +#! is optional if a target property with the name US_MODULE_NAME exists, containing +#! the required module name. +#! \param COMPRESSION_LEVEL (optional) The zip compression level (0-9). Defaults to the default zip +#! level. Level 0 disables compression. +#! \param WORKING_DIRECTORY (optional) The root path for all resource files listed after the +#! FILES argument. If no or a relative path is given, it is considered relativ to the +#! current CMake source directory. +#! \param FILES (optional) A list of resource files (paths to external files in the file system) +#! relative to the current working directory. +#! \param ZIP_ARCHIVES (optional) A list of zip archives (relative to the current working directory +#! or absolute file paths) whose contents is merged into the target module. If a list entry +#! is a valid target name and that target is a static library, its absolute file path is +#! used instead. +#! +function(usFunctionAddResources) + + cmake_parse_arguments(US_RESOURCE "" "TARGET;MODULE_NAME;WORKING_DIRECTORY;COMPRESSION_LEVEL" "FILES;ZIP_ARCHIVES" ${ARGN}) + + if(NOT US_RESOURCE_TARGET) + message(SEND_ERROR "TARGET argument not specified.") + endif() + + if(NOT US_RESOURCE_MODULE_NAME) + get_target_property(US_RESOURCE_MODULE_NAME ${US_RESOURCE_TARGET} US_MODULE_NAME) + if(NOT US_RESOURCE_MODULE_NAME) + message(SEND_ERROR "Either the MODULE_NAME argument or the US_MODULE_NAME target property is required.") + endif() + endif() + + if(NOT US_RESOURCE_FILES AND NOT US_RESOURCE_ZIP_ARCHIVES) + message(WARNING "No resources specified. Skipping resource processing.") + return() + endif() + + if(NOT US_RESOURCE_WORKING_DIRECTORY) + set(US_RESOURCE_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + if(NOT IS_ABSOLUTE ${US_RESOURCE_WORKING_DIRECTORY}) + set(US_RESOURCE_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${US_RESOURCE_WORKING_DIRECTORY}") + endif() + + if(US_RESOURCE_COMPRESSION_LEVEL) + set(cmd_line_args -${US_RESOURCE_COMPRESSION_LEVEL}) + endif() + + set(resource_compiler ${US_RCC_EXECUTABLE}) + if(TARGET ${US_RCC_EXECUTABLE_NAME}) + set(resource_compiler ${US_RCC_EXECUTABLE_NAME}) + elseif(NOT resource_compiler) + message(FATAL_ERROR "The CppMicroServices resource compiler was not found. Check the US_RCC_EXECUTABLE CMake variable.") + endif() + + set(_cmd_deps ) + foreach(_file ${US_RESOURCE_FILES}) + if(IS_ABSOLUTE ${_file}) + list(APPEND _cmd_deps ${_file}) + else() + list(APPEND _cmd_deps ${US_RESOURCE_WORKING_DIRECTORY}/${_file}) + endif() + endforeach() + + set(_zip_args ) + if(US_RESOURCE_ZIP_ARCHIVES) + foreach(_zip_archive ${US_RESOURCE_ZIP_ARCHIVES}) + if(TARGET ${_zip_archive}) + get_target_property(_is_static_lib ${_zip_archive} TYPE) + if(_is_static_lib STREQUAL "STATIC_LIBRARY") + list(APPEND _cmd_deps ${_zip_archive}) + list(APPEND _zip_args $) + endif() + else() + if(IS_ABSOLUTE ${_zip_archive}) + list(APPEND _cmd_deps ${_zip_archive}) + else() + list(APPEND _cmd_deps ${US_RESOURCE_WORKING_DIRECTORY}/${_zip_archive}) + endif() + list(APPEND _zip_args ${_zip_archive}) + endif() + endforeach() + endif() + + # This command depends on the given resource files and creates a source + # file which must be added to the source list of the related target. + # This way, the following command is executed if the resources change + # and it just touches the created source file to force a (actually unnecessary) + # re-linking and hence the execution of POST_BUILD commands. + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_TARGET}_resources.cpp + COMMAND ${CMAKE_COMMAND} -E copy ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} ${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_TARGET}_resources.cpp + DEPENDS ${_cmd_deps} ${resource_compiler} + COMMENT "Checking resource dependencies for ${US_RESOURCE_TARGET}" + VERBATIM + ) + + add_custom_command( + TARGET ${US_RESOURCE_TARGET} + POST_BUILD + COMMAND ${resource_compiler} ${cmd_line_args} $ ${US_RESOURCE_MODULE_NAME} -a ${US_RESOURCE_FILES} -m ${_zip_args} + WORKING_DIRECTORY ${US_RESOURCE_WORKING_DIRECTORY} + COMMENT "Adding resources to ${US_RESOURCE_TARGET}" + VERBATIM + ) + +endfunction() diff --git a/cmake/usFunctionCompileSnippets.cmake b/cmake/usFunctionCompileSnippets.cmake index 6a3dcb92fd..e183c40837 100644 --- a/cmake/usFunctionCompileSnippets.cmake +++ b/cmake/usFunctionCompileSnippets.cmake @@ -1,48 +1,50 @@ function(usFunctionCompileSnippets snippet_path) # get all files called "main.cpp" file(GLOB_RECURSE main_cpp_list "${snippet_path}/main.cpp") foreach(main_cpp_file ${main_cpp_list}) # get the directory containing the main.cpp file get_filename_component(main_cpp_dir "${main_cpp_file}" PATH) set(snippet_src_files ) # If there exists a "files.cmake" file in the snippet directory, # include it and assume it sets the variable "snippet_src_files" # to a list of source files for the snippet. if(EXISTS "${main_cpp_dir}/files.cmake") include("${main_cpp_dir}/files.cmake") set(_tmp_src_files ${snippet_src_files}) set(snippet_src_files ) foreach(_src_file ${_tmp_src_files}) if(IS_ABSOLUTE ${_src_file}) list(APPEND snippet_src_files ${_src_file}) else() list(APPEND snippet_src_files ${main_cpp_dir}/${_src_file}) endif() endforeach() else() # glob all files in the directory and add them to the snippet src list file(GLOB_RECURSE snippet_src_files "${main_cpp_dir}/*") endif() # Uset the top-level directory name as the executable name string(REPLACE "/" ";" main_cpp_dir_tokens "${main_cpp_dir}") list(GET main_cpp_dir_tokens -1 snippet_exec_name) set(snippet_target_name "Snippet-${snippet_exec_name}") add_executable(${snippet_target_name} ${snippet_src_files}) target_link_libraries(${snippet_target_name} ${PROJECT_TARGET} ${snippet_link_libraries}) + set_property(TARGET ${snippet_target_name} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=main) + set_property(TARGET ${snippet_target_name} PROPERTY US_MODULE_NAME main) set_target_properties(${snippet_target_name} PROPERTIES LABELS Documentation RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/snippets" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/snippets" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/snippets" OUTPUT_NAME ${snippet_exec_name} ) endforeach() endfunction() diff --git a/cmake/usFunctionCreateTestModule.cmake b/cmake/usFunctionCreateTestModule.cmake index 11f31dfbe0..b97e3ac50d 100644 --- a/cmake/usFunctionCreateTestModule.cmake +++ b/cmake/usFunctionCreateTestModule.cmake @@ -1,42 +1,48 @@ macro(_us_create_test_module_helper) - if(_res_files) - usFunctionEmbedResources(_srcs LIBRARY_NAME ${name} ROOT_DIR ${_res_root} FILES ${_res_files}) - endif() - add_library(${name} ${_srcs}) - if(NOT US_BUILD_SHARED_LIBS) + set_property(TARGET ${name} + APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${name}) + set_property(TARGET ${name} PROPERTY US_MODULE_NAME ${name}) + if(NOT US_BUILD_SHARED_LIBS OR NOT BUILD_SHARED_LIBS) set_property(TARGET ${name} APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) endif() - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") get_property(_compile_flags TARGET ${name} PROPERTY COMPILE_FLAGS) set_property(TARGET ${name} PROPERTY COMPILE_FLAGS "${_compile_flags} -fPIC") endif() - target_link_libraries(${name} ${${PROJECT_NAME}_TARGET} ${US_LINK_LIBRARIES}) + target_link_libraries(${name} ${${PROJECT_NAME}_TARGET} ${US_TEST_LINK_LIBRARIES} ${US_LINK_LIBRARIES}) - set(_us_test_module_libs "${_us_test_module_libs};${name}" CACHE INTERNAL "" FORCE) + if(_res_files OR US_TEST_LINK_LIBRARIES) + usFunctionAddResources(TARGET ${name} WORKING_DIRECTORY ${_res_root} + FILES ${_res_files} + ZIP_ARCHIVES ${US_TEST_LINK_LIBRARIES}) + endif() + + if(NOT US_TEST_SKIP_MODULE_LIST) + set(_us_test_module_libs "${_us_test_module_libs};${name}" CACHE INTERNAL "" FORCE) + endif() endmacro() function(usFunctionCreateTestModule name) set(_srcs ${ARGN}) set(_res_files ) - usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name}) + usFunctionGenerateModuleInit(_srcs) _us_create_test_module_helper() endfunction() function(usFunctionCreateTestModuleWithResources name) - cmake_parse_arguments(US_TEST "" "RESOURCES_ROOT" "SOURCES;RESOURCES" "" ${ARGN}) - set(_srcs ${US_TEST_SOURCES}) + cmake_parse_arguments(US_TEST "SKIP_MODULE_LIST" "RESOURCES_ROOT" "SOURCES;RESOURCES;LINK_LIBRARIES" "" ${ARGN}) + set(_srcs ${US_TEST_SOURCES} ${name}_resources.cpp) set(_res_files ${US_TEST_RESOURCES}) if(US_TEST_RESOURCES_ROOT) set(_res_root ${US_TEST_RESOURCES_ROOT}) else() - set(_res_root resources) + set(_res_root ${CMAKE_CURRENT_SOURCE_DIR}/resources) endif() - usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name}) + usFunctionGenerateModuleInit(_srcs) _us_create_test_module_helper() endfunction() diff --git a/cmake/usFunctionEmbedResources.cmake b/cmake/usFunctionEmbedResources.cmake deleted file mode 100644 index ab81fc293e..0000000000 --- a/cmake/usFunctionEmbedResources.cmake +++ /dev/null @@ -1,155 +0,0 @@ -#! \ingroup MicroServicesCMake -#! \brief Embed resources into a shared library or executable. -#! -#! This CMake function uses an external command line program to generate a source -#! file containing data from external resources such as text files or images. The path -#! to the generated source file is appended to the \c src_var variable. -#! -#! Each module can call this function (at most once) to embed resources and make them -#! available at runtime through the Module class. Resources can also be embedded into -#! executables, using the EXECUTABLE_NAME argument instead of LIBRARY_NAME. -#! -#! Example usage: -#! \code{.cmake} -#! set(module_srcs ) -#! usFunctionEmbedResources(module_srcs -#! LIBRARY_NAME "mylib" -#! ROOT_DIR resources -#! FILES config.properties logo.png -#! ) -#! \endcode -#! -#! \param LIBRARY_NAME (required if EXECUTABLE_NAME is empty) The library name of the module -#! which will include the generated source file, without extension. -#! \param EXECUTABLE_NAME (required if LIBRARY_NAME is empty) The name of the executable -#! which will include the generated source file. -#! \param COMPRESSION_LEVEL (optional) The zip compression level. Defaults to the default zip -#! level. Level 0 disables compression. -#! \param COMPRESSION_THRESHOLD (optional) The compression threshold ranging from 0 to 100 for -#! actually compressing the resource data. The default threshold is 30, meaning a size -#! reduction of 30 percent or better results in the resource data being compressed. -#! \param ROOT_DIR (optional) The root path for all resources listed after the FILES argument. -#! If no or a relative path is given, it is considered relativ to the current CMake source directory. -#! \param FILES (optional) A list of resources (paths to external files in the file system) relative -#! to the ROOT_DIR argument or the current CMake source directory if ROOT_DIR is empty. -#! -#! The ROOT_DIR and FILES arguments may be repeated any number of times to merge files from -#! different root directories into the embedded resource tree (hence the relative file paths -#! after the FILES argument must be unique). -#! -function(usFunctionEmbedResources src_var) - - set(prefix US_RESOURCE) - set(arg_names LIBRARY_NAME EXECUTABLE_NAME COMPRESSION_LEVEL COMPRESSION_THRESHOLD ROOT_DIR FILES) - foreach(arg_name ${arg_names}) - set(${prefix}_${arg_name}) - endforeach(arg_name) - - set(cmd_line_args ) - set(absolute_res_files ) - set(current_arg_name DEFAULT_ARGS) - set(current_arg_list) - set(current_root_dir ${CMAKE_CURRENT_SOURCE_DIR}) - foreach(arg ${ARGN}) - - list(FIND arg_names "${arg}" is_arg_name) - - if(is_arg_name GREATER -1) - set(${prefix}_${current_arg_name} ${current_arg_list}) - set(current_arg_name "${arg}") - set(current_arg_list) - else() - set(current_arg_list ${current_arg_list} "${arg}") - if(current_arg_name STREQUAL "ROOT_DIR") - set(current_root_dir "${arg}") - if(NOT IS_ABSOLUTE ${current_root_dir}) - set(current_root_dir "${CMAKE_CURRENT_SOURCE_DIR}/${current_root_dir}") - endif() - if(NOT IS_DIRECTORY ${current_root_dir}) - message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${current_root_dir}") - endif() - get_filename_component(current_root_dir "${current_root_dir}" REALPATH) - if(WIN32) - string(REPLACE "/" "\\" current_root_dir "${current_root_dir}") - endif() - list(APPEND cmd_line_args -d "${current_root_dir}") - elseif(current_arg_name STREQUAL "FILES") - set(res_file "${current_root_dir}/${arg}") - if(WIN32) - string(REPLACE "/" "\\" res_file_native "${res_file}") - else() - set(res_file_native "${res_file}") - endif() - if(IS_DIRECTORY ${res_file}) - message(SEND_ERROR "A resource cannot be a directory: ${res_file_native}") - endif() - if(NOT EXISTS ${res_file}) - message(SEND_ERROR "Resource does not exists: ${res_file_native}") - endif() - list(APPEND absolute_res_files ${res_file}) - file(TO_NATIVE_PATH "${arg}" res_filename_native) - list(APPEND cmd_line_args "${res_filename_native}") - endif() - endif(is_arg_name GREATER -1) - - endforeach(arg ${ARGN}) - - set(${prefix}_${current_arg_name} ${current_arg_list}) - - if(NOT src_var) - message(SEND_ERROR "Output variable name not specified.") - endif() - - if(US_RESOURCE_EXECUTABLE_NAME AND US_RESOURCE_LIBRARY_NAME) - message(SEND_ERROR "Only one of LIBRARY_NAME or EXECUTABLE_NAME can be specified.") - endif() - - if(NOT US_RESOURCE_LIBRARY_NAME AND NOT US_RESOURCE_EXECUTABLE_NAME) - message(SEND_ERROR "LIBRARY_NAME or EXECUTABLE_NAME argument not specified.") - endif() - - if(NOT US_RESOURCE_FILES) - message(WARNING "No FILES argument given. Skipping resource processing.") - return() - endif() - - list(GET cmd_line_args 0 first_arg) - if(NOT first_arg STREQUAL "-d") - set(cmd_line_args -d "${CMAKE_CURRENT_SOURCE_DIR}" ${cmd_line_args}) - endif() - - if(US_RESOURCE_COMPRESSION_LEVEL) - set(cmd_line_args -c ${US_RESOURCE_COMPRESSION_LEVEL} ${cmd_line_args}) - endif() - - if(US_RESOURCE_COMPRESSION_THRESHOLD) - set(cmd_line_args -t ${US_RESOURCE_COMPRESSION_THRESHOLD} ${cmd_line_args}) - endif() - - if(US_RESOURCE_LIBRARY_NAME) - set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") - set(us_lib_name ${US_RESOURCE_LIBRARY_NAME}) - else() - set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_EXECUTABLE_NAME}_resources.cpp") - set(us_lib_name "") - endif() - - set(resource_compiler ${US_RCC_EXECUTABLE}) - if(TARGET ${US_RCC_EXECUTABLE_NAME}) - set(resource_compiler ${US_RCC_EXECUTABLE_NAME}) - elseif(NOT resource_compiler) - message(FATAL_ERROR "The CppMicroServices resource compiler was not found. Check the US_RCC_EXECUTABLE CMake variable.") - endif() - - add_custom_command( - OUTPUT ${us_cpp_resource_file} - COMMAND ${resource_compiler} "${us_lib_name}" ${us_cpp_resource_file} ${cmd_line_args} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${absolute_res_files} ${resource_compiler} - COMMENT "Generating embedded resource file ${us_cpp_resource_name}" - VERBATIM - ) - - set(${src_var} "${${src_var}};${us_cpp_resource_file}" PARENT_SCOPE) - -endfunction() diff --git a/cmake/usFunctionGenerateExecutableInit.cmake b/cmake/usFunctionGenerateExecutableInit.cmake deleted file mode 100644 index 6fb6ad80dc..0000000000 --- a/cmake/usFunctionGenerateExecutableInit.cmake +++ /dev/null @@ -1,43 +0,0 @@ -#! \ingroup MicroServicesCMake -#! \brief Generate a source file which handles proper initialization of an executable. -#! -#! This CMake function will store the path to a generated source file in the -#! src_var variable, which should be compiled into an executable. Example usage: -#! -#! \code{.cmake} -#! set(executable_srcs ) -#! usFunctionGenerateExecutableInit(executable_srcs -#! IDENTIFIER "MyExecutable" -#! ) -#! add_executable(MyExecutable ${executable_srcs}) -#! \endcode -#! -#! \param src_var (required) The name of a list variable to which the path of the generated -#! source file will be appended. -#! \param IDENTIFIER (required) A valid C identifier for the executable. -#! -#! \see #usFunctionGenerateModuleInit -#! \see \ref MicroServices_AutoLoading -#! -function(usFunctionGenerateExecutableInit src_var) - - cmake_parse_arguments(US_EXECUTABLE "" "IDENTIFIER" "" ${ARGN}) - - # sanity checks - if(NOT US_EXECUTABLE_IDENTIFIER) - message(SEND_ERROR "IDENTIFIER argument is mandatory") - endif() - - set(_regex_validation "[a-zA-Z_-][a-zA-Z_0-9-]*") - string(REGEX MATCH ${_regex_validation} _valid_chars ${US_EXECUTABLE_IDENTIFIER}) - if(NOT _valid_chars STREQUAL US_EXECUTABLE_IDENTIFIER) - message(FATAL_ERROR "IDENTIFIER contains illegal characters.") - endif() - - set(exec_init_src_file "${CMAKE_CURRENT_BINARY_DIR}/${US_EXECUTABLE_IDENTIFIER}_init.cpp") - configure_file(${US_EXECUTABLE_INIT_TEMPLATE} ${exec_init_src_file} @ONLY) - - set(_src ${exec_init_src_file} ${${src_var}}) - set(${src_var} ${_src} PARENT_SCOPE) - -endfunction() diff --git a/cmake/usFunctionGenerateModuleInit.cmake b/cmake/usFunctionGenerateModuleInit.cmake index 6986d228b8..b8d38faf7b 100644 --- a/cmake/usFunctionGenerateModuleInit.cmake +++ b/cmake/usFunctionGenerateModuleInit.cmake @@ -1,54 +1,29 @@ #! \ingroup MicroServicesCMake #! \brief Generate a source file which handles proper initialization of a module. #! #! This CMake function will store the path to a generated source file in the -#! src_var variable, which should be compiled into a module. Example usage: +#! src_var variable, which should be compiled into a module. The modules source +#! code must be compiled with the US_MODULE_NAME pre-processor definition. +#! Example usage: #! #! \code{.cmake} #! set(module_srcs ) -#! usFunctionGenerateModuleInit(module_srcs -#! NAME "My Module" -#! LIBRARY_NAME "mylib" -#! ) +#! usFunctionGenerateModuleInit(module_srcs) #! add_library(mylib ${module_srcs}) +#! set_property(TARGET ${mylib} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=MyModule) #! \endcode #! #! \param src_var (required) The name of a list variable to which the path of the generated #! source file will be appended. -#! \param NAME (required) A human-readable name for the module. -#! \param LIBRARY_NAME (optional) The name of the module, without extension. If empty, the -#! NAME argument will be used. #! -#! \see #usFunctionGenerateExecutableInit #! \see \ref MicroServices_AutoLoading #! function(usFunctionGenerateModuleInit src_var) - cmake_parse_arguments(US_MODULE "EXECUTABLE" "NAME;LIBRARY_NAME" "" ${ARGN}) - - if(US_MODULE_EXECUTABLE) - message(SEND_ERROR "EXECUTABLE option no longer supported. Use usFunctionGenerateExecutableInit instead.") - endif() - - # sanity checks - if(NOT US_MODULE_NAME) - message(SEND_ERROR "NAME argument is mandatory") - endif() - - if(NOT US_MODULE_LIBRARY_NAME) - set(US_MODULE_LIBRARY_NAME ${US_MODULE_NAME}) - endif() - - set(_regex_validation "[a-zA-Z_-][a-zA-Z_0-9-]*") - string(REGEX MATCH ${_regex_validation} _valid_chars ${US_MODULE_LIBRARY_NAME}) - if(NOT _valid_chars STREQUAL US_MODULE_LIBRARY_NAME) - message(FATAL_ERROR "[Module: ${US_MODULE_NAME}] LIBRARY_NAME \"${US_MODULE_LIBRARY_NAME}\" contains illegal characters.") - endif() - - set(module_init_src_file "${CMAKE_CURRENT_BINARY_DIR}/${US_MODULE_LIBRARY_NAME}_init.cpp") + set(module_init_src_file "${CMAKE_CURRENT_BINARY_DIR}/us_init.cpp") configure_file(${US_MODULE_INIT_TEMPLATE} ${module_init_src_file} @ONLY) set(_src ${module_init_src_file} ${${src_var}}) set(${src_var} ${_src} PARENT_SCOPE) endfunction() diff --git a/cmake/usGlobalConfig.h.in b/cmake/usGlobalConfig.h.in index 1ee63faa75..441e3eae5b 100644 --- a/cmake/usGlobalConfig.h.in +++ b/cmake/usGlobalConfig.h.in @@ -1,206 +1,206 @@ /* USCONFIG.h this file is generated. Do not change! */ #ifndef USGLOBALCONFIG_H #define USGLOBALCONFIG_H #cmakedefine US_BUILD_SHARED_LIBS #cmakedefine US_ENABLE_THREADING_SUPPORT -#cmakedefine US_ENABLE_RESOURCE_COMPRESSION #cmakedefine US_GCC_RTTI_WORKAROUND_NEEDED #cmakedefine US_HAVE_VISIBILITY_ATTRIBUTE //------------------------------------------------------------------- // Header Availability //------------------------------------------------------------------- +#cmakedefine US_HAVE_CXXABI_H #cmakedefine US_HAVE_STDINT_H #cmakedefine US_HAVE_TR1_UNORDERED_MAP_H #cmakedefine US_HAVE_TR1_UNORDERED_SET_H #cmakedefine US_HAVE_TR1_FUNCTIONAL_H #cmakedefine US_HAVE_UNORDERED_MAP_H #cmakedefine US_HAVE_UNORDERED_SET_H #cmakedefine US_HAVE_FUNCTIONAL_H #cmakedefine US_HAVE_TR1_UNORDERED_MAP #cmakedefine US_HAVE_TR1_UNORDERED_SET #cmakedefine US_HAVE_TR1_FUNCTION #cmakedefine US_HAVE_STD_UNORDERED_MAP #cmakedefine US_HAVE_STD_UNORDERED_SET #cmakedefine US_HAVE_STD_FUNCTION #cmakedefine US_HAVE_TR1_HASH #cmakedefine US_HAVE_TR1_HASH_STRUCT #cmakedefine US_HAVE_TR1_HASH_CLASS #cmakedefine US_HAVE_STD_HASH #cmakedefine US_HAVE_STD_HASH_STRUCT #cmakedefine US_HAVE_STD_HASH_CLASS ///------------------------------------------------------------------- // Version information //------------------------------------------------------------------- #define CppMicroServices_MAJOR_VERSION @CppMicroServices_MAJOR_VERSION@ #define CppMicroServices_MINOR_VERSION @CppMicroServices_MINOR_VERSION@ #define CppMicroServices_PATCH_VERSION @CppMicroServices_PATCH_VERSION@ #define CppMicroServices_VERSION @CppMicroServices_VERSION@ #define CppMicroServices_VERSION_STR "@CppMicroServices_VERSION@" #define US_MAJOR_VERSION @CppMicroServices_MAJOR_VERSION@ #define US_MINOR_VERSION @CppMicroServices_MINOR_VERSION@ #define US_PATCH_VERSION @CppMicroServices_PATCH_VERSION@ #define US_VERSION @CppMicroServices_VERSION@ #define US_VERSION_STR "@CppMicroServices_VERSION@" //------------------------------------------------------------------- // 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 import/export declarations //------------------------------------------------------------------- #if defined(US_PLATFORM_WINDOWS) #define US_ABI_EXPORT __declspec(dllexport) #define US_ABI_IMPORT __declspec(dllimport) #define US_ABI_LOCAL #elif defined(US_HAVE_VISIBILITY_ATTRIBUTE) #define US_ABI_EXPORT __attribute__ ((visibility ("default"))) #define US_ABI_IMPORT __attribute__ ((visibility ("default"))) #define US_ABI_LOCAL __attribute__ ((visibility ("hidden"))) #else #define US_ABI_EXPORT #define US_ABI_IMPORT #define US_ABI_LOCAL #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) // Mark a variable or expression result as unused #define US_UNUSED(x) (void)(x) //------------------------------------------------------------------- // Hash Container //------------------------------------------------------------------- #ifdef US_HAVE_UNORDERED_MAP_H #include #elif defined(US_HAVE_TR1_UNORDERED_MAP_H) #include #endif #ifdef US_HAVE_UNORDERED_SET_H #include #elif defined(US_HAVE_TR1_UNORDERED_SET_H) #include #endif #ifdef US_HAVE_STD_UNORDERED_MAP #define US_UNORDERED_MAP_TYPE ::std::unordered_map #elif defined(US_HAVE_TR1_UNORDERED_MAP) #define US_UNORDERED_MAP_TYPE ::std::tr1::unordered_map #endif #ifdef US_HAVE_STD_UNORDERED_SET #define US_UNORDERED_SET_TYPE ::std::unordered_set #elif defined(US_HAVE_TR1_UNORDERED_SET) #define US_UNORDERED_SET_TYPE ::std::tr1::unordered_set #endif #ifdef US_HAVE_STD_HASH #define US_HASH_FUNCTION_NAMESPACE ::std #ifdef US_HAVE_STD_HASH_STRUCT #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::hash #elif defined(US_HAVE_STD_HASH_CLASS) #define US_HASH_FUNCTION_FRIEND(type) friend class ::std::hash #endif #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { #define US_HASH_FUNCTION_NAMESPACE_END } #elif defined(US_HAVE_TR1_HASH) #define US_HASH_FUNCTION_NAMESPACE ::std::tr1 #ifdef US_HAVE_TR1_HASH_STRUCT #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::tr1::hash #elif defined(US_HAVE_TR1_HASH_CLASS) #define US_HASH_FUNCTION_FRIEND(type) friend class ::std::tr1::hash #endif #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { namespace tr1 { #define US_HASH_FUNCTION_NAMESPACE_END }} #endif #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) #endif // USGLOBALCONFIG_H diff --git a/cmake/usMacroCreateModule.cmake b/cmake/usMacroCreateModule.cmake new file mode 100644 index 0000000000..6f7a451773 --- /dev/null +++ b/cmake/usMacroCreateModule.cmake @@ -0,0 +1,220 @@ +# For internal use only + +macro(usMacroCreateModule _project_name) + +project(${_project_name}) + +cmake_parse_arguments(${PROJECT_NAME} + "SKIP_EXAMPLES;SKIP_INIT" + "VERSION;TARGET" + "DEPENDS;INTERNAL_INCLUDE_DIRS;LINK_LIBRARIES;SOURCES;PRIVATE_HEADERS;PUBLIC_HEADERS;RESOURCES;BINARY_RESOURCES" + ${ARGN} +) + +if(NOT ${PROJECT_NAME}_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+$") + message(SEND_ERROR "VERSION argument invalid: ${${PROJECT_NAME}_VERSION}") +endif() + +string(REPLACE "." ";" _version_numbers ${${PROJECT_NAME}_VERSION}) +list(GET _version_numbers 0 ${PROJECT_NAME}_MAJOR_VERSION) +list(GET _version_numbers 1 ${PROJECT_NAME}_MINOR_VERSION) +list(GET _version_numbers 2 ${PROJECT_NAME}_PATCH_VERSION) + +if(NOT ${PROJECT_NAME}_TARGET) + set(${PROJECT_NAME}_TARGET us${PROJECT_NAME}) +endif() +set(PROJECT_TARGET ${${PROJECT_NAME}_TARGET}) + +if(${PROJECT_NAME}_DEPENDS) + find_package(CppMicroServices REQUIRED ${${PROJECT_NAME}_DEPENDS} QUIET + HINTS ${CppMicroServices_BINARY_DIR} + NO_DEFAULT_PATH + ) +endif() + +#----------------------------------------------------------------------------- +# Include dirs and libraries +#----------------------------------------------------------------------------- + +set(${PROJECT_NAME}_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include +) + +configure_file(${CppMicroServices_SOURCE_DIR}/cmake/usExport.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Export.h) +list(APPEND ${PROJECT_NAME}_PUBLIC_HEADERS + ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Export.h) + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/include/us${PROJECT_NAME}Config.h.in) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/us${PROJECT_NAME}Config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Config.h) + list(APPEND ${PROJECT_NAME}_PUBLIC_HEADERS + ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Config.h) +endif() + +include_directories( + ${US_INCLUDE_DIRS} + ${${PROJECT_NAME}_INCLUDE_DIRS} +) + +set(_internal_include_dirs ${${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS}) +set(${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS ) +if(_internal_include_dirs) + foreach(_internal_include_dir ${_internal_include_dirs}) + if(IS_ABSOLUTE "${_internal_include_dir}") + list(APPEND ${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS ${_internal_include_dir}) + else() + list(APPEND ${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/${_internal_include_dir}) + endif() + endforeach() + include_directories(${${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS}) +endif() + +#----------------------------------------------------------------------------- +# Create library +#----------------------------------------------------------------------------- + +# Generate the module init file +if(NOT ${PROJECT_NAME}_SKIP_INIT) + usFunctionGenerateModuleInit(${PROJECT_NAME}_SOURCES) +endif() + +if(${PROJECT_NAME}_RESOURCES OR ${PROJECT_NAME}_BINARY_RESOURCES) + list(APPEND ${PROJECT_NAME}_SOURCES ${${PROJECT_NAME}_TARGET}_resources.cpp) +endif() + +# Create the module library +add_library(${${PROJECT_NAME}_TARGET} ${${PROJECT_NAME}_SOURCES} + ${${PROJECT_NAME}_PRIVATE_HEADERS} ${${PROJECT_NAME}_PUBLIC_HEADERS}) + +# Compile definitions +set_property(TARGET ${${PROJECT_NAME}_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${${PROJECT_NAME}_TARGET}) +set_property(TARGET ${${PROJECT_NAME}_TARGET} PROPERTY US_MODULE_NAME ${${PROJECT_NAME}_TARGET}) +if(NOT US_BUILD_SHARED_LIBS) + set_property(TARGET ${${PROJECT_NAME}_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) +endif() + +# Link flags +if(${PROJECT_NAME}_LINK_FLAGS OR US_LINK_FLAGS) + set_target_properties(${${PROJECT_NAME}_TARGET} PROPERTIES + LINK_FLAGS "${US_LINK_FLAGS} ${${PROJECT_NAME}_LINK_FLAGS}" + ) +endif() + +set_target_properties(${${PROJECT_NAME}_TARGET} PROPERTIES + SOVERSION ${${PROJECT_NAME}_VERSION} + PUBLIC_HEADER "${${PROJECT_NAME}_PUBLIC_HEADERS}" + PRIVATE_HEADER "${${PROJECT_NAME}_PRIVATE_HEADERS}" +) + +# Link additional libraries +if(${PROJECT_NAME}_LINK_LIBRARIES OR US_LIBRARIES) + target_link_libraries(${${PROJECT_NAME}_TARGET} ${US_LIBRARIES} ${${PROJECT_NAME}_LINK_LIBRARIES}) +endif() + +# Embed module resources + +if(${PROJECT_NAME}_RESOURCES OR US_LIBRARIES) + usFunctionAddResources(TARGET ${${PROJECT_NAME}_TARGET} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources + FILES ${${PROJECT_NAME}_RESOURCES} + ZIP_ARCHIVES ${US_LIBRARIES} + ) +endif() +if(${PROJECT_NAME}_BINARY_RESOURCES) + usFunctionAddResources(TARGET ${${PROJECT_NAME}_TARGET} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/resources + FILES ${${PROJECT_NAME}_BINARY_RESOURCES} + ) +endif() + +#----------------------------------------------------------------------------- +# Install support +#----------------------------------------------------------------------------- + +install(TARGETS ${${PROJECT_NAME}_TARGET} + EXPORT us${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}) + +#----------------------------------------------------------------------------- +# US testing +#----------------------------------------------------------------------------- + +if(US_BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + add_subdirectory(test) +endif() + +#----------------------------------------------------------------------------- +# Documentation +#----------------------------------------------------------------------------- + +if(US_BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doc/snippets/CMakeLists.txt") + # Compile source code snippets + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/doc/snippets) +endif() + +#----------------------------------------------------------------------------- +# Last configuration and install steps +#----------------------------------------------------------------------------- + +export(TARGETS ${${PROJECT_NAME}_TARGET} ${US_LIBRARIES} + FILE ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}Targets.cmake) +install(EXPORT us${PROJECT_NAME}Targets + FILE us${PROJECT_NAME}Targets.cmake + DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) + +# Configure config file for the build tree + +set(PACKAGE_CONFIG_INCLUDE_DIR + ${${PROJECT_NAME}_INCLUDE_DIRS} + ${${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS}) +set(PACKAGE_CONFIG_RUNTIME_LIBRARY_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + +configure_file( + ${US_CMAKE_DIR}/usModuleConfig.cmake.in + ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}Config.cmake + @ONLY + ) + +# Configure config file for the install tree + +set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) +set(CONFIG_RUNTIME_LIBRARY_DIR ${RUNTIME_INSTALL_DIR}) + +configure_package_config_file( + ${US_CMAKE_DIR}/usModuleConfig.cmake.in + ${CppMicroServices_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/us${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} + PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_LIBRARY_DIR + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO + ) + +# Version information +configure_file( + ${US_CMAKE_DIR}/usModuleConfigVersion.cmake.in + ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}ConfigVersion.cmake + @ONLY + ) + +install(FILES ${CppMicroServices_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/us${PROJECT_NAME}Config.cmake + ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} + ${US_SDK_INSTALL_COMPONENT}) + +#----------------------------------------------------------------------------- +# Build the examples +#----------------------------------------------------------------------------- + +if(US_BUILD_EXAMPLES AND NOT ${PROJECT_NAME}_SKIP_EXAMPLES AND + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt) + set(CppMicroServices_DIR ${CppMicroServices_BINARY_DIR}) + add_subdirectory(examples) +endif() + +endmacro() diff --git a/core/usCoreConfig.cmake.in b/cmake/usModuleConfig.cmake.in similarity index 100% rename from core/usCoreConfig.cmake.in rename to cmake/usModuleConfig.cmake.in diff --git a/core/usCoreConfigVersion.cmake.in b/cmake/usModuleConfigVersion.cmake.in similarity index 100% rename from core/usCoreConfigVersion.cmake.in rename to cmake/usModuleConfigVersion.cmake.in diff --git a/cmake/usModuleInit.cpp b/cmake/usModuleInit.cpp index 05678e8649..13cc7500d0 100644 --- a/cmake/usModuleInit.cpp +++ b/cmake/usModuleInit.cpp @@ -1,24 +1,24 @@ /*============================================================================= 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 -US_INITIALIZE_MODULE("@US_MODULE_NAME@", "@US_MODULE_LIBRARY_NAME@") +US_INITIALIZE_MODULE diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 466d699cfd..244fa9a635 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,202 +1,45 @@ -project(Core) - -set(${PROJECT_NAME}_MAJOR_VERSION 2) -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}) - -set(${PROJECT_NAME}_TARGET CppMicroServices) -set(PROJECT_TARGET ${${PROJECT_NAME}_TARGET}) - -cmake_minimum_required(VERSION 2.8) -cmake_policy(VERSION 2.8) -cmake_policy(SET CMP0017 NEW) - -#----------------------------------------------------------------------------- -# US include dirs and libraries -#----------------------------------------------------------------------------- - -set(${PROJECT_NAME}_INCLUDE_DIRS - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_BINARY_DIR}/include -) - -set(${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS - ${CMAKE_CURRENT_SOURCE_DIR}/src/util - ${CMAKE_CURRENT_SOURCE_DIR}/src/service - ${CMAKE_CURRENT_SOURCE_DIR}/src/module -) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/us${PROJECT_NAME}Config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Config.h -) - -configure_file(${CppMicroServices_SOURCE_DIR}/cmake/usExport.h.in - ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Export.h -) - -include_directories( - ${${PROJECT_NAME}_INCLUDE_DIRS} - ${${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS} -) - -# link libraries for the CppMicroServices lib -set(${PROJECT_NAME}_LINK_LIBRARIES ) -if(UNIX) - list(APPEND ${PROJECT_NAME}_LINK_LIBRARIES dl) -endif() - -#----------------------------------------------------------------------------- -# Create library -#----------------------------------------------------------------------------- - +# sources and headers include(${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt) include(${CMAKE_CURRENT_SOURCE_DIR}/include/CMakeLists.txt) -set(${PROJECT_NAME}_SOURCES ) +set(_core_srcs ) foreach(_src ${_srcs}) - list(APPEND ${PROJECT_NAME}_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/${_src}) + list(APPEND _core_srcs ${CMAKE_CURRENT_SOURCE_DIR}/src/${_src}) endforeach() -set(${PROJECT_NAME}_PRIVATE_HEADERS ) +set(_core_private_headers) foreach(_header ${_private_headers}) - list(APPEND ${PROJECT_NAME}_PRIVATE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/${_header}) + list(APPEND _core_private_headers ${CMAKE_CURRENT_SOURCE_DIR}/src/${_header}) endforeach() -set(${PROJECT_NAME}_PUBLIC_HEADERS ) +set(_core_public_headers ) foreach(_header ${_public_headers}) - list(APPEND ${PROJECT_NAME}_PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/${_header}) + list(APPEND _core_public_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/${_header}) endforeach() -list(APPEND ${PROJECT_NAME}_PUBLIC_HEADERS - ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Config.h - ${CMAKE_CURRENT_BINARY_DIR}/include/us${PROJECT_NAME}Export.h -) -# Generate the module init file -usFunctionGenerateModuleInit(${PROJECT_NAME}_SOURCES NAME ${${PROJECT_NAME}_TARGET}) +# link libraries for the CppMicroServices lib +set(_link_libraries ) +if(UNIX) + list(APPEND _link_libraries dl) +endif() # Configure the modules manifest.json file configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/resources/manifest.json) -# Embed module resources -usFunctionEmbedResources(${PROJECT_NAME}_SOURCES LIBRARY_NAME ${${PROJECT_NAME}_TARGET} - ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/resources - FILES manifest.json) - -# Create the module library -add_library(${${PROJECT_NAME}_TARGET} ${${PROJECT_NAME}_SOURCES} - ${${PROJECT_NAME}_PRIVATE_HEADERS} ${${PROJECT_NAME}_PUBLIC_HEADERS} ${us_config_h_file}) - -# Link flags -if(${PROJECT_NAME}_LINK_FLAGS OR US_LINK_FLAGS) - set_target_properties(${${PROJECT_NAME}_TARGET} PROPERTIES - LINK_FLAGS "${US_LINK_FLAGS} ${${PROJECT_NAME}_LINK_FLAGS}" - ) -endif() - -# Compile definitions -set_property(TARGET ${${PROJECT_NAME}_TARGET} - APPEND PROPERTY COMPILE_DEFINITIONS US_FORCE_MODULE_INIT -) - -set_target_properties(${${PROJECT_NAME}_TARGET} PROPERTIES - SOVERSION ${${PROJECT_NAME}_VERSION} - PUBLIC_HEADER "${${PROJECT_NAME}_PUBLIC_HEADERS}" - PRIVATE_HEADER "${${PROJECT_NAME}_PRIVATE_HEADERS}" -) - -# Link additional libraries -if(${PROJECT_NAME}_LINK_LIBRARIES) - target_link_libraries(${${PROJECT_NAME}_TARGET} ${${PROJECT_NAME}_LINK_LIBRARIES}) -endif() - - -#----------------------------------------------------------------------------- -# Install support -#----------------------------------------------------------------------------- - -install(TARGETS ${${PROJECT_NAME}_TARGET} - EXPORT us${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}) - -#----------------------------------------------------------------------------- -# US testing -#----------------------------------------------------------------------------- - -if(US_BUILD_TESTING) - add_subdirectory(test) -endif() - -#----------------------------------------------------------------------------- -# Documentation -#----------------------------------------------------------------------------- - -add_subdirectory(doc) - -#----------------------------------------------------------------------------- -# Last configuration and install steps -#----------------------------------------------------------------------------- - -export(TARGETS ${${PROJECT_NAME}_TARGET} - FILE ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}Targets.cmake) -install(EXPORT us${PROJECT_NAME}Targets - FILE us${PROJECT_NAME}Targets.cmake - DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) - -# Configure CoreConfig.cmake for the build tree - -set(PACKAGE_CONFIG_INCLUDE_DIR - ${${PROJECT_NAME}_INCLUDE_DIRS} - ${${PROJECT_NAME}_INTERNAL_INCLUDE_DIRS}) -set(PACKAGE_CONFIG_RUNTIME_LIBRARY_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/us${PROJECT_NAME}Config.cmake.in - ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}Config.cmake - @ONLY - ) - -# Configure CoreConfig.cmake for the install tree - -set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) -set(CONFIG_RUNTIME_LIBRARY_DIR ${RUNTIME_INSTALL_DIR}) - -configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/us${PROJECT_NAME}Config.cmake.in - ${CppMicroServices_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/us${PROJECT_NAME}Config.cmake - INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} - PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_LIBRARY_DIR - NO_SET_AND_CHECK_MACRO - NO_CHECK_REQUIRED_COMPONENTS_MACRO +usMacroCreateModule(Core + SKIP_INIT # we initialize the module in usModuleRegistry.cpp ourselves + VERSION "2.99.0" + TARGET CppMicroServices + INTERNAL_INCLUDE_DIRS src/util src/service src/module + LINK_LIBRARIES ${_link_libraries} + SOURCES ${_core_srcs} + PUBLIC_HEADERS ${_core_public_headers} + PRIVATE_HEADERS ${_core_private_headers} + BINARY_RESOURCES manifest.json +) + +set_property( + TARGET CppMicroServices APPEND PROPERTY + COMPILE_DEFINITIONS "MINIZ_NO_ARCHIVE_WRITING_API;MINIZ_NO_ZLIB_COMPATIBLE_NAMES" ) - -# Version information -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/us${PROJECT_NAME}ConfigVersion.cmake.in - ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}ConfigVersion.cmake - @ONLY - ) - -install(FILES ${CppMicroServices_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/us${PROJECT_NAME}Config.cmake - ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}ConfigVersion.cmake - DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} - ${US_SDK_INSTALL_COMPONENT} - ) - -#----------------------------------------------------------------------------- -# Build the examples -#----------------------------------------------------------------------------- - -if(US_BUILD_EXAMPLES) - if(NOT US_BUILD_SHARED_LIBS) - message(WARNING "Core examples are not available if US_BUILD_SHARED_LIBS is OFF") - else() - set(CppMicroServices_DIR ${CppMicroServices_BINARY_DIR}) - add_subdirectory(examples) - endif() -endif() diff --git a/core/doc/doxygen/MicroServices_EmulateSingleton.dox b/core/doc/doxygen/MicroServices_EmulateSingleton.dox index 55e51753e9..190535a9cb 100644 --- a/core/doc/doxygen/MicroServices_EmulateSingleton.dox +++ b/core/doc/doxygen/MicroServices_EmulateSingleton.dox @@ -1,89 +1,87 @@ /** \page MicroServices_EmulateSingleton Emulating singletons with micro services \section MicroServices_EmulateSingleton_1 Meyers Singleton Singletons are a well known pattern to ensure that only one instance of a class exists during the whole life-time of the application. A self-deleting variant is the "Meyers Singleton": \snippet uServices-singleton/SingletonOne.h s1 where the GetInstance() method is implemented as \snippet uServices-singleton/SingletonOne.cpp s1 If such a singleton is accessed during static deinitialization (which happens during unloading of shared libraries or application termination), your program might crash or even worse, exhibit undefined behavior, depending on your compiler and/or weekday. Such an access might happen in destructors of other objects with static life-time. For example, suppose that SingletonOne needs to call a second Meyers singleton during destruction: \snippet uServices-singleton/SingletonOne.cpp s1d If SingletonTwo was destroyed before SingletonOne, this leads to the mentioned problems. Note that this problem only occurs for static objects defined in the same shared library. Since you cannot reliably control the destruction order of global static objects, you must not introduce dependencies between them during static deinitialization. This is one reason why one should consider an alternative approach to singletons (unless you can absolutely make sure that nothing in your shared library will introduce such dependencies. Never.) Of course you could use something like a "Phoenix singleton" but that will have other drawbacks in certain scenarios. Returning pointers instead of references in GetInstance() would open up the possibility to return NULL, but than again this would not help if you require a non-NULL instance in your destructor. Another reason for an alternative approach is that singletons are usually not meant to be singletons for eternity. If your design evolves, you might hit a point where you suddenly need multiple instances of your singleton. \section MicroServices_EmulateSingleton_2 Singletons as a service The C++ Micro Services can be used to emulate the singleton pattern using a non-singleton class. This leaves room for future extensions without the need for heavy refactoring. Additionally, it gives you full control about the construction and destruction order of your "singletons" inside your shared library or executable, making it possible to have dependencies between them during destruction. \subsection MicroServices_EmulateSingleton_2_1 Converting a classic singleton We modify the previous SingletonOne class such that it internally uses the micro services API. The changes are discussed in detail below. \snippet uServices-singleton/SingletonOne.h ss1 - In the implementation above, the class SingletonOneService provides the implementation as well as the interface. - Friend activator: We move the responsibility of constructing instances of SingletonOneService from the GetInstance() method to the module activator. - - Service interface declaration: Because the SingletonOneService class introduces a new service interface, it must - be registered under a unique name using the helper macro US_DECLARE_SERVICE_INTERFACE. Let's have a look at the modified GetInstance() and ~SingletonOneService() methods. \snippet uServices-singleton/SingletonOne.cpp ss1gi The inline comments should explain the details. Note that we now had to change the return type to a pointer, instead of a reference as in the classic singleton. This is necessary since we can no longer guarantee that an instance always exists. Clients of the GetInstance() method must check for null pointers and react appropriately. \warning Newly created "singletons" should not expose a GetInstance() method. They should be handled as proper services and hence should be retrieved by clients using the ModuleContext or ServiceTracker API. The GetInstance() method is for migration purposes only. \snippet uServices-singleton/SingletonOne.cpp ss1d The SingletonTwoService::GetInstance() method is implemented exactly as in SingletonOneService. Because we know that the module activator guarantees that a SingletonTwoService instance will always be available during the life-time of a SingletonOneService instance (see below), we can assert a non-null pointer. Otherwise, we would have to handle the null-pointer case. The order of construction/registration and destruction/unregistration of our singletons (or any other services) is defined in the Load() and Unload() methods of the module activator. \snippet uServices-singleton/main.cpp 0 The Unload() method is defined as: \snippet uServices-singleton/main.cpp 1 */ diff --git a/core/doc/doxygen/MicroServices_Resources.md b/core/doc/doxygen/MicroServices_Resources.md index 101044d143..32e49f86f3 100644 --- a/core/doc/doxygen/MicroServices_Resources.md +++ b/core/doc/doxygen/MicroServices_Resources.md @@ -1,56 +1,67 @@ The Resources System {#MicroServices_Resources} ==================== The C++ Micro Services library provides a generic resources system to embed arbitrary files into a -module's shared library (the current size limitation is based on the largest source code file size -your compiler can handle). +module's shared library (the size limitation per resource is 2GB, due to the used ZIP format). The following features are supported: * Embed arbitrary data into shared or static modules or executables. - * Data is embedded in a compressed format if the size reduction exceeds a - configurable threshold. + * Data is embedded in a compressed format (zip) with a configurable compression level. * Resources are accessed via a Module instance, providing individual resource lookup and access for each module. * Resources are managed in a tree hierarchy, modeling the original child - parent relationship on the file-system. * The ModuleResource class provides a high-level API for accessing resource information and traversing the resource tree. * The ModuleResourceStream class provides an STL input stream derived class for the seamless usage of embedded resource data in third-party libraries. +The following conventions and limitations apply: + + * Resource entries are stored with case-insensitive names. On case-sensitive file systemes, + adding resources with the same name but different capitalization will lead to an error. + * Looking up resources by name at runtime *is* case sensitive. Embedding Resources in a %Module -------------------------------- -Resources are embedded by compiling a source file generated by the `usResourceCompiler` executable -into a module's shared or static library (or into an executable). +Resources are embedded into a module's shared or static library (or into an executable) +by using the `usResourceCompiler` executable. It will create a ZIP archive of all input +files and append it to the module file. -If you are using CMake, consider using the provided `#usFunctionEmbedResources` CMake macro which +If you are using CMake, consider using the provided `#usFunctionAddResources` CMake macro which handles the invocation of the `usResourceCompiler` executable and sets up the correct file -dependencies. +dependencies. Otherwise, you also need to make sure that the set of static modules linked +into a shared module or executable is also in the input file list of your `usResourceCompiler` +call for that shared module or executable. Accessing Resources at Runtime ------------------------------ Each module provides access to its embedded resources via the Module class which provides methods returning ModuleResource objects. The ModuleResourceStream class provides a std::istream compatible object to access the resource contents. The following example shows how to retrieve a resource from each currently loaded module whose path is specified by a module property: \snippet uServices-resources/main.cpp 2 This example could be enhanced to dynamically react to modules being loaded and unloaded, making use of the popular "extender pattern" from OSGi. -Limitations ------------ +Runtime overhead +---------------- + +The resources system has the following runtime characteristics: -Currently, the system has the following limitations: + * During static initialization of a module, it's ZIP archive header data (if available) + is parsed and stored in memory. + * Querying `Module` or `ModuleResource` objects for resource information will not + extract the embedded resource data and hence only has minimal runtime and memory + overhead. + * Creating a `ModuleResourceStream` object will allocate memory for the uncompressed + resource data and inflate it. The memory will be free'ed after the `ModuleResourceStream` + object is destroyed. - * At most one file generated by the `usResourceCompiler` executable can be compiled into a module's - shared library (you can work around this limitation by creating static modules and importing them). - * The size of embedded resources is limited by the file size your compiler can handle. However, the file - size is the sum of the size of all resources embedded into a module plus a small overhead. diff --git a/core/doc/doxygen/MicroServices_StaticModules.md b/core/doc/doxygen/MicroServices_StaticModules.md index 344cfb5146..c9ab730185 100644 --- a/core/doc/doxygen/MicroServices_StaticModules.md +++ b/core/doc/doxygen/MicroServices_StaticModules.md @@ -1,90 +1,66 @@ Static Modules {#MicroServices_StaticModules} ============== The normal and most flexible way to include a CppMicroServices module in an application is to compile it into a shared library that is either linked by another library (or executable) or \ref MicroServices_AutoLoading "auto-loaded" during runtime. However, modules can be linked statically to your application or shared library. This makes the deployment of your application less error-prone and in the case of a complete static build also minimizes its binary size and start-up time. The disadvantage is that no functionality can be added without a rebuild and redistribution of the application. # Creating Static Modules Static modules are written just like shared modules - there are no differences in the usage of the CppMicroServices API or the provided preprocessor macros. The only thing you need to make sure is that the `US_STATIC_MODULE` preprocessor macro is defined when building a module statically. # Using Static Modules Static modules can be used (imported) in shared or other static libraries or in the executable itself. -Assuming that a static module makes use of the CppMicroServices API (e.g. by registering some services -using a ModuleContext), the importing library or executable needs to put a call to the `#US_INITIALIZE_MODULE` -or the `#US_INITIALIZE_EXECUTABLE` macro somewhere in its source code. This ensures the availability of -a module context which is shared with all imported static libraries (see also \ref MicroServices_StaticModules_Context). - -\note Note that if your static module does not export a module activator by using the macro -`#US_EXPORT_MODULE_ACTIVATOR` or does not contain embedded resources (see \ref MicroServices_Resources) you -do not need to put the special import macros explained below into -your code. You can use and link the static module just like any other static library. - -For every static module you would like to import, you need to put a call to `#US_IMPORT_MODULE` into the -source code of the importing library. To make the static module's resources available to the importing module, -you must also call `#US_IMPORT_MODULE_RESOURCES`. Addidtionally, you need a call to `#US_LOAD_IMPORTED_MODULES` -which contains a space-deliminated list of module names in the importing libaries source code. This ensures -that the module activators of the imported static modules (if they exist) are called appropriately and that -the embedded resources are registered with the importing module. - -\note When importing a static module into another static module, the call to `#US_LOAD_IMPORTED_MODULES` in -the importing static module will have no effect. This macro can only be used in shared modules or executables. +For every static module you would like to import, you need to put a call to `#US_IMPORT_MODULE` or +to `#US_INITIALIZE_STATIC_MODULE` (if the module does not provide an activator) into the +source code of the importing library. + +\note While you can link static modules to other static modules, you will still need to +import *all* of the static modules into the final executable to ensure proper initialization. There are two main usage scenarios which are explained below together with some example code. ## Using a Shared CppMicroServices Library Building the CppMicroServices library as a shared library allows you to import static modules into other -shared or static modules or into the executable. As noted above, the importing shared module or executable -needs to provide a module context by calling the `#US_INITIALIZE_MODULE` or `#US_INITIALIZE_EXECUTABLE` macro. -Additionally, you must ensure to use the `#US_LOAD_IMPORTED_MODULES_INTO_MAIN` macro instead of -`#US_LOAD_IMPORTED_MODULES` when importing static modules into an executable. +shared or static modules or into the executable. -Example code for importing the two static modules `MyStaticModule1` and `MyStaticModule2` into an executable: +Example code for importing the static module `MyStaticModule1` into another library +or executable: \snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoMain -Importing the static module `MyStaticModule` into a shared or static module looks like this: - -\snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoLib - -Having a shared CppMicroServices library, the executable also needs some initialization code: - -\snippet uServices-staticmodules/main.cpp InitializeExecutable - -Note that shared (but not static) modules also need the `#US_INITIALIZE_MODULE` call when importing static modules. - ## Using a Static CppMicroServices Library -The CppMicroServices library can be build as a static library. In that case, creating shared modules is not supported. -If you create shared modules which link a static version of the CppMicroServices library, the runtime behavior is -undefined. - -In this usage scenario, every module will be statically build and linked to an executable. The executable needs to -import all the static modules, just like above: - -\snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoMain +The CppMicroServices library can be build as a static library. In that case, creating shared +modules is not supported. If you create shared modules which link a static version of the +CppMicroServices library, the runtime behavior is undefined. -However, it can omit the `#US_INITIALIZE_MODULE` macro call (the module context from the CppMicroServices library -will be shared across all modules and the executable). +In this usage scenario, every module will be statically build and linked to an executable: -# A Note About The Module Context {#MicroServices_StaticModules_Context} +\snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoMain2 -Modules using the CppMicroServices API frequently need a `ModuleContext` object to query, retrieve, and register services. -Static modules will never get their own module context but will share the context with their importing module or -executable. Therefore, the importing module or executable needs to ensure the availability of such a context (by using -the `#US_INITIALIZE_MODULE` or `#US_INITIALIZE_EXECUTABLE` macro). +Note that the first `#US_IMPORT_MODULE` call imports the static CppMicroServices library. +Then the `MyStaticModule2` module is imported and finally, the +executable itself is initialized (this is necessary if the executable itself is +a C++ Micro Services module). -\note The CppMicroServices library will *always* provide a module context, independent of its library build mode. +# A Note About Import Ordering {#MicroServices_StaticModules_Order} -So in a completely statically build application, the CppMicroServices library provides a global module context for all -imported modules and the executable. +Although static linking reduces the number of shared libraries, the statically +linked modules are still represented internally by distinct Module and ModuleContext +objects. In a shared module scenario, the linker dependencies define the load order +of modules and hence the order of their initialization and ModuleActivator::Load() +invocations. In the static case, the order of the `#US_IMPORT_MODULE` macro calls +defines the initialization and activation order. In case of a statically built +CppMicroServices library, it is therefore important to always import the static +CppMicroServices library into the executable first, and the executable itself +(if it needs to be initialized) last. diff --git a/core/doc/doxygen/MicroServices_TheModuleContext.md b/core/doc/doxygen/MicroServices_TheModuleContext.md index f35054b556..d3dd740cc0 100644 --- a/core/doc/doxygen/MicroServices_TheModuleContext.md +++ b/core/doc/doxygen/MicroServices_TheModuleContext.md @@ -1,37 +1,38 @@ The Module Context {#MicroServices_TheModuleContext} =================== In the context of the C++ Micro Services library, we will call all supported "shared library" types (DLL, DSO, DyLib, etc.) uniformly a *module*. A module accesses the C++ Micro Services API via a -ModuleContext object. While multiple modules could use the same ModuleContext, it is highly recommended -that each module gets its own (this will enable module specific service usage tracking and also allows -the C++ Micro Services framework to properly cleanup resources after a module has been unloaded). +ModuleContext object, which is specific to each module. ### Creating a ModuleContext To create a ModuleContext object for a specific library, you have two options. If your project uses CMake as the build system, use the supplied `#usFunctionGenerateModuleInit` CMake function to automatically create a source file and add it to your module's sources: ~~~{.cpp} set(module_srcs ) -usFunctionGenerateModuleInit(module_srcs - NAME "My Module" - LIBRARY_NAME "mylibname" - ) +usFunctionGenerateModuleInit(module_srcs) add_library(mylib ${module_srcs}) +set_property(TARGET ${mylib} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=mylib) ~~~ +You also need to specify a unique module name by using the `US_MODULE_NAME` compile definition as +shown in the last line. The module name must be a valid C identifier and in the case of +executables is required to be defined to `main`. + If you do not use CMake, you have to add a call to the macro `#US_INITIALIZE_MODULE` in one of the source files of your module: \snippet uServices-modulecontext/main.cpp InitializeModule ### Getting a ModuleContext To retrieve the module specific ModuleContext object from anywhere in your module, use the `#GetModuleContext` function: \snippet uServices-modulecontext/main.cpp GetModuleContext -Please note that the call to `#GetModuleContext` will fail if you did not create a module specific context. +Please note that trying to use `#GetModuleContext` without proper initialization code +in the using shared library while either lead to compile or rumtime errors. diff --git a/core/doc/doxygen/standalone/BuildInstructions.md b/core/doc/doxygen/standalone/BuildInstructions.md index 0a5f6fb275..201410319c 100644 --- a/core/doc/doxygen/standalone/BuildInstructions.md +++ b/core/doc/doxygen/standalone/BuildInstructions.md @@ -1,58 +1,55 @@ 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.6 (Ubuntu 12.04) - GCC 4.8 (Ubuntu 13.10) - Clang 3.2 (Ubuntu 13.10) - Clang (MacOS X 10.8 and 10.9) - Visual Studio 2008 SP1, 2010, 2012, 2013 (Windows 7) 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 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 your application is not multi-threaded, turn this option OFF to get maximum performance. -- **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/doc/doxygen/standalone/MicroServices_GettingStarted.md b/core/doc/doxygen/standalone/MicroServices_GettingStarted.md index fec5a1105c..7530637dd4 100644 --- a/core/doc/doxygen/standalone/MicroServices_GettingStarted.md +++ b/core/doc/doxygen/standalone/MicroServices_GettingStarted.md @@ -1,49 +1,52 @@ Getting Started {#MicroServices_GettingStarted} =============== Projects which want to make use of the capabilities provided by the C++ Micro Services library need to set-up the correct include paths and link dependencies. Further, each executable or shared library which needs a ModuleContext instance must contain specific -initialization code. +initialization code and must be compiled with a unique `US_MODULE_NAME` pre-processor +definition. In case of executables, the value is required to be `main`, e.g. compile +the executable with `-DUS_MODULE_NAME=main`. The C++ Micro Services library provides \ref MicroServicesCMake "CMake utility functions" for CMake based projects but there are no restrictions on the type of build system used for a project. CMake based projects -------------------- To easily set-up include paths and linker dependencies, use the common `find_package` mechanism provided by CMake: \dontinclude examples/CMakeLists.txt \skip project \until include_directories The CMake code above sets up a basic project (called CppMicroServicesExamples) and tries to find the CppMicroServices package and subsequently to set the necessary include directories. Building a shared library might then look like this: \dontinclude examples/dictionaryservice/CMakeLists.txt \until target_link The call to `#usFunctionGenerateModuleInit` generates the proper module initialization -code and provides access to the module specific ModuleContext instance. +code and provides access to the module specific ModuleContext instance. Further, the +`set_property`command sets the `US_MODULE_NAME` definition. Makefile based projects ----------------------- The following Makefile is located at examples/makefile/Makefile and demonstrates a minimal build script: \include makefile/Makefile The variable `CppMicroServices_ROOT` is an environment variable and must be set to the CppMicroServices installation directory prior to invoking `make`. The module initialization code for the `libmodule.so` shared library is generated by using the `#US_INITIALIZE_MODULE` pre-processor macro at the end of the `module.cpp` source file (any source file compiled into the module would do): \dontinclude makefile/module.cpp \skip usModuleInitialization \until US_INITIALIZE_MODULE diff --git a/core/doc/snippets/uServices-activator/main.cpp b/core/doc/snippets/uServices-activator/main.cpp index c4ba6c25e7..8b9feebd56 100644 --- a/core/doc/snippets/uServices-activator/main.cpp +++ b/core/doc/snippets/uServices-activator/main.cpp @@ -1,27 +1,27 @@ #include US_USE_NAMESPACE //! [0] class MyActivator : public ModuleActivator { public: void Load(ModuleContext* /*context*/) { /* register stuff */ } void Unload(ModuleContext* /*context*/) { /* cleanup */ } }; -US_EXPORT_MODULE_ACTIVATOR(mylibname, MyActivator) +US_EXPORT_MODULE_ACTIVATOR(MyActivator) //![0] int main(int /*argc*/, char* /*argv*/[]) { MyActivator ma; return 0; } diff --git a/core/doc/snippets/uServices-modulecontext/main.cpp b/core/doc/snippets/uServices-modulecontext/main.cpp index a793f3b343..a7b8bfd7d7 100644 --- a/core/doc/snippets/uServices-modulecontext/main.cpp +++ b/core/doc/snippets/uServices-modulecontext/main.cpp @@ -1,28 +1,28 @@ #include //! [GetModuleContext] #include #include #include US_USE_NAMESPACE void RetrieveModuleContext() { ModuleContext* context = GetModuleContext(); Module* module = context->GetModule(); std::cout << "Module name: " << module->GetName() << " [id: " << module->GetModuleId() << "]\n"; } //! [GetModuleContext] //! [InitializeModule] #include -US_INITIALIZE_MODULE("My Module", "mylibname") +US_INITIALIZE_MODULE //! [InitializeModule] int main(int /*argc*/, char* /*argv*/[]) { RetrieveModuleContext(); return 0; } diff --git a/core/doc/snippets/uServices-registration/main.cpp b/core/doc/snippets/uServices-registration/main.cpp index be9666e635..511791e1ac 100644 --- a/core/doc/snippets/uServices-registration/main.cpp +++ b/core/doc/snippets/uServices-registration/main.cpp @@ -1,119 +1,115 @@ #include #include #include #include US_USE_NAMESPACE struct InterfaceA { virtual ~InterfaceA() {} }; struct InterfaceB { virtual ~InterfaceB() {} }; struct InterfaceC { virtual ~InterfaceC() {} }; -US_DECLARE_SERVICE_INTERFACE(InterfaceA, "org.cppmicroservices.snippet.InterfaceA") -US_DECLARE_SERVICE_INTERFACE(InterfaceB, "org.cppmicroservices.snippet.InterfaceB") -US_DECLARE_SERVICE_INTERFACE(InterfaceC, "org.cppmicroservices.snippet.InterfaceC") - //! [1-1] class MyService : public InterfaceA {}; //! [1-1] //! [2-1] class MyService2 : public InterfaceA, public InterfaceB {}; //! [2-1] class MyActivator : public ModuleActivator { public: void Load(ModuleContext* context) { Register1(context); Register2(context); RegisterFactory1(context); RegisterFactory2(context); } void Register1(ModuleContext* context) { //! [1-2] MyService* myService = new MyService; context->RegisterService(myService); //! [1-2] } void Register2(ModuleContext* context) { //! [2-2] MyService2* myService = new MyService2; context->RegisterService(myService); //! [2-2] } void RegisterFactory1(ModuleContext* context) { //! [f1] class MyServiceFactory : public ServiceFactory { virtual InterfaceMap GetService(Module* /*module*/, const ServiceRegistrationBase& /*registration*/) { MyService* myService = new MyService; return MakeInterfaceMap(myService); } virtual void UngetService(Module* /*module*/, const ServiceRegistrationBase& /*registration*/, const InterfaceMap& service) { delete ExtractInterface(service); } }; MyServiceFactory* myServiceFactory = new MyServiceFactory; context->RegisterService(myServiceFactory); //! [f1] } void RegisterFactory2(ModuleContext* context) { //! [f2] class MyServiceFactory : public ServiceFactory { virtual InterfaceMap GetService(Module* /*module*/, const ServiceRegistrationBase& /*registration*/) { MyService2* myService = new MyService2; return MakeInterfaceMap(myService); } virtual void UngetService(Module* /*module*/, const ServiceRegistrationBase& /*registration*/, const InterfaceMap& service) { delete ExtractInterface(service); } }; MyServiceFactory* myServiceFactory = new MyServiceFactory; context->RegisterService(static_cast(myServiceFactory)); //! [f2] // In the RegisterService call above, we could remove the static_cast because local types // are not considered in template argument type deduction and hence the compiler choose // the correct RegisterService(ServiceFactory*) overload. However, local types are // usually the exception and using a non-local type for the service factory would make the // compiler choose RegisterService(Impl*) instead, unless we use the static_cast. } void Unload(ModuleContext* /*context*/) { /* cleanup */ } }; -US_EXPORT_MODULE_ACTIVATOR(mylibname, MyActivator) +US_EXPORT_MODULE_ACTIVATOR(MyActivator) int main(int /*argc*/, char* /*argv*/[]) { MyActivator ma; return 0; } diff --git a/core/doc/snippets/uServices-resources/main.cpp b/core/doc/snippets/uServices-resources/main.cpp index 45eaa61658..577ac85242 100644 --- a/core/doc/snippets/uServices-resources/main.cpp +++ b/core/doc/snippets/uServices-resources/main.cpp @@ -1,85 +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(); // 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") +US_INITIALIZE_MODULE diff --git a/core/doc/snippets/uServices-servicetracker/main.cpp b/core/doc/snippets/uServices-servicetracker/main.cpp index 5961f956da..4cbf68249b 100644 --- a/core/doc/snippets/uServices-servicetracker/main.cpp +++ b/core/doc/snippets/uServices-servicetracker/main.cpp @@ -1,110 +1,113 @@ #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 ServiceReferenceType&) { return MyTrackedClass(); } virtual void ModifiedService(const ServiceReferenceType&, MyTrackedClass) { } virtual void RemovedService(const ServiceReferenceType&, MyTrackedClass) { } }; //! [customizer] struct MyTrackingPointerCustomizer : public ServiceTrackerCustomizer { virtual MyTrackedClass* AddingService(const ServiceReferenceType&) { return new MyTrackedClass(); } virtual void ModifiedService(const ServiceReferenceType&, MyTrackedClass*) { } virtual void RemovedService(const ServiceReferenceType&, MyTrackedClass*) { } }; // For compilation test purposes only struct MyTrackingCustomizerVoid : public ServiceTrackerCustomizer { virtual MyTrackedClass AddingService(const ServiceReferenceType&) { return MyTrackedClass(); } virtual void ModifiedService(const ServiceReferenceType&, 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()); + try + { + ServiceTracker tracker2(GetModuleContext(), &myCustomizer2); + ServiceTracker > tracker3(GetModuleContext()); + } + catch (const us::ServiceException&) + {} return 0; } #include -US_INITIALIZE_EXECUTABLE("uServices-modulecontext") +US_INITIALIZE_MODULE diff --git a/core/doc/snippets/uServices-singleton/SingletonOne.h b/core/doc/snippets/uServices-singleton/SingletonOne.h index 8f993b075c..bcd0726e97 100644 --- a/core/doc/snippets/uServices-singleton/SingletonOne.h +++ b/core/doc/snippets/uServices-singleton/SingletonOne.h @@ -1,63 +1,61 @@ #ifndef SINGLETONONE_H #define SINGLETONONE_H #include #include #include //![s1] class SingletonOne { public: static SingletonOne& GetInstance(); // Just some member int a; private: SingletonOne(); ~SingletonOne(); // Disable copy constructor and assignment operator. SingletonOne(const SingletonOne&); SingletonOne& operator=(const SingletonOne&); }; //![s1] class SingletonTwoService; //![ss1] class SingletonOneService { public: // This will return a SingletonOneService instance with the // lowest service id at the time this method was called the first // time and returned a non-null value (which is usually the instance // which was registered first). A null-pointer is returned if no // instance was registered yet. static SingletonOneService* GetInstance(); int a; private: // Only our module activator class should be able to instantiate // a SingletonOneService object. friend class MyActivator; SingletonOneService(); ~SingletonOneService(); // Disable copy constructor and assignment operator. SingletonOneService(const SingletonOneService&); SingletonOneService& operator=(const SingletonOneService&); }; - -US_DECLARE_SERVICE_INTERFACE(SingletonOneService, "org.cppmicroservices.snippet.SingletonOneService") //![ss1] #endif // SINGLETONONE_H diff --git a/core/doc/snippets/uServices-singleton/SingletonTwo.h b/core/doc/snippets/uServices-singleton/SingletonTwo.h index 8185e509e0..03429d51a9 100644 --- a/core/doc/snippets/uServices-singleton/SingletonTwo.h +++ b/core/doc/snippets/uServices-singleton/SingletonTwo.h @@ -1,48 +1,46 @@ #ifndef SINGLETONTWO_H #define SINGLETONTWO_H #include #include class SingletonTwo { public: static SingletonTwo& GetInstance(); int b; private: SingletonTwo(); ~SingletonTwo(); // Disable copy constructor and assignment operator. SingletonTwo(const SingletonTwo&); SingletonTwo& operator=(const SingletonTwo&); }; class SingletonTwoService { public: static SingletonTwoService* GetInstance(); int b; private: friend class MyActivator; SingletonTwoService(); ~SingletonTwoService(); // Disable copy constructor and assignment operator. SingletonTwoService(const SingletonTwoService&); SingletonTwoService& operator=(const SingletonTwoService&); }; -US_DECLARE_SERVICE_INTERFACE(SingletonTwoService, "org.cppmicroservices.snippet.SingletonTwoService") - #endif // SINGLETONTWO_H diff --git a/core/doc/snippets/uServices-singleton/files.cmake b/core/doc/snippets/uServices-singleton/files.cmake index 7de7f5c5ad..d203a5547f 100644 --- a/core/doc/snippets/uServices-singleton/files.cmake +++ b/core/doc/snippets/uServices-singleton/files.cmake @@ -1,10 +1,8 @@ set(snippet_src_files main.cpp SingletonOne.cpp SingletonTwo.cpp ) -usFunctionGenerateExecutableInit(snippet_src_files - IDENTIFIER "uServices_singleton" - ) +usFunctionGenerateModuleInit(snippet_src_files) diff --git a/core/doc/snippets/uServices-singleton/main.cpp b/core/doc/snippets/uServices-singleton/main.cpp index 76883c7e98..63ec571af4 100644 --- a/core/doc/snippets/uServices-singleton/main.cpp +++ b/core/doc/snippets/uServices-singleton/main.cpp @@ -1,68 +1,73 @@ #include #include #include "SingletonOne.h" #include "SingletonTwo.h" US_USE_NAMESPACE class MyActivator : public ModuleActivator { public: + MyActivator() + : m_SingletonOne(NULL) + , m_SingletonTwo(NULL) + {} + //![0] void Load(ModuleContext* context) { // The Load() method of the module activator is called during static // initialization time of the shared library. // First create and register a SingletonTwoService instance. m_SingletonTwo = new SingletonTwoService; m_SingletonTwoReg = context->RegisterService(m_SingletonTwo); // Now the SingletonOneService constructor will get a valid // SingletonTwoService instance. m_SingletonOne = new SingletonOneService; m_SingletonOneReg = context->RegisterService(m_SingletonOne); } //![0] //![1] void Unload(ModuleContext* /*context*/) { // Services are automatically unregistered during unloading of // the shared library after the call to Unload(ModuleContext*) // has returned. // Since SingletonOneService needs a non-null SingletonTwoService // instance in its destructor, we explicitly unregister and delete the // SingletonOneService instance here. This way, the SingletonOneService // destructor will still get a valid SingletonTwoService instance. m_SingletonOneReg.Unregister(); delete m_SingletonOne; // For singletonTwoService, we could rely on the automatic unregistering // by the service registry and on automatic deletion if you used // smart pointer reference counting. You must not delete service instances // in this method without unregistering them first. m_SingletonTwoReg.Unregister(); delete m_SingletonTwo; } //![1] private: SingletonOneService* m_SingletonOne; SingletonTwoService* m_SingletonTwo; ServiceRegistration m_SingletonOneReg; ServiceRegistration m_SingletonTwoReg; }; -US_EXPORT_MODULE_ACTIVATOR(uServices_singleton, MyActivator) +US_EXPORT_MODULE_ACTIVATOR(MyActivator) int main() { } diff --git a/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp b/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp index 2984c93702..f61e009f6e 100644 --- a/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp +++ b/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp @@ -1,39 +1,39 @@ /*============================================================================= 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_USE_NAMESPACE struct MyStaticModuleActivator : public ModuleActivator { void Load(ModuleContext* /*context*/) { std::cout << "Hello from a static module." << std::endl; } void Unload(ModuleContext* /*context*/) {} }; -US_EXPORT_MODULE_ACTIVATOR(MyStaticModule, MyStaticModuleActivator) +US_EXPORT_MODULE_ACTIVATOR(MyStaticModuleActivator) -US_INITIALIZE_MODULE("My Static Module", "MyStaticModule") +US_INITIALIZE_MODULE diff --git a/core/doc/snippets/uServices-staticmodules/files.cmake b/core/doc/snippets/uServices-staticmodules/files.cmake index 2bf4c05a4b..989242adaa 100644 --- a/core/doc/snippets/uServices-staticmodules/files.cmake +++ b/core/doc/snippets/uServices-staticmodules/files.cmake @@ -1,11 +1,12 @@ set(snippet_src_files main.cpp ) set(base_dir uServices-staticmodules) add_library(MyStaticModule STATIC ${base_dir}/MyStaticModule.cpp) -set_property(TARGET MyStaticModule APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) +set_property(TARGET MyStaticModule APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE US_MODULE_NAME=MyStaticModule) +set_property(TARGET MyStaticModule PROPERTY US_MODULE_NAME MyStaticModule) set(snippet_link_libraries MyStaticModule ) diff --git a/core/doc/snippets/uServices-staticmodules/main.cpp b/core/doc/snippets/uServices-staticmodules/main.cpp index 404775b061..4a2a0c141f 100644 --- a/core/doc/snippets/uServices-staticmodules/main.cpp +++ b/core/doc/snippets/uServices-staticmodules/main.cpp @@ -1,34 +1,39 @@ #include -US_USE_NAMESPACE - -//! [ImportStaticModuleIntoLib] -#include +US_BEGIN_NAMESPACE +struct ModuleActivator; +US_END_NAMESPACE -US_IMPORT_MODULE(MyStaticModule) -US_LOAD_IMPORTED_MODULES(HostingModule, MyStaticModule) -//! [ImportStaticModuleIntoLib] +US_USE_NAMESPACE // This is just for illustration purposes in code snippets -extern "C" ModuleActivator* _us_module_activator_instance_MyStaticModule1() { return NULL; } -extern "C" ModuleActivator* _us_module_activator_instance_MyStaticModule2() { return NULL; } -extern "C" ModuleActivator* _us_init_resources_MyStaticModule2() { return NULL; } +extern "C" ModuleActivator* _us_module_activator_instance_MyStaticModule1() { return 0; } +extern "C" ModuleActivator* _us_module_activator_instance_MyStaticModule2() { return 0; } +extern "C" void _us_import_module_initializer_MyStaticModule1() {} +extern "C" void _us_import_module_initializer_MyStaticModule2() {} //! [ImportStaticModuleIntoMain] #include US_IMPORT_MODULE(MyStaticModule1) -US_IMPORT_MODULE(MyStaticModule2) -US_IMPORT_MODULE_RESOURCES(MyStaticModule2) -US_LOAD_IMPORTED_MODULES_INTO_MAIN(MyStaticModule1 MyStaticModule2) //! [ImportStaticModuleIntoMain] +//! [ImportStaticModuleIntoMain2] +#include + +#ifndef US_BUILD_SHARED_LIBS +US_IMPORT_MODULE(CppMicroServices) +US_IMPORT_MODULE(MyStaticModule2) +US_INITIALIZE_STATIC_MODULE(main) +#endif +//! [ImportStaticModuleIntoMain2] + int main(int /*argc*/, char* /*argv*/[]) { return 0; } //! [InitializeExecutable] #include -US_INITIALIZE_EXECUTABLE("MyExecutable") +US_INITIALIZE_MODULE //! [InitializeExecutable] diff --git a/core/examples/CMakeLists.txt b/core/examples/CMakeLists.txt index cdeac59465..1144b939be 100644 --- a/core/examples/CMakeLists.txt +++ b/core/examples/CMakeLists.txt @@ -1,169 +1,176 @@ project(CoreExamples) 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(CoreExamples_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(CoreExamples_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(CoreExamples_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${CoreExamples_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() function(CreateExample _name) - add_library(Example-${_name} SHARED ${ARGN}) + add_library(Example-${_name} ${ARGN}) + set_property(TARGET Example-${_name} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${_name}) + if(NOT US_BUILD_SHARED_LIBS) + set_property(TARGET Example-${_name} APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) + endif() + if(${_name}_DEPENDS) foreach(_dep ${${_name}_DEPENDS}) include_directories(${PROJECT_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 ) if(WIN32) string(REGEX REPLACE "^.:" "" _install_prefix ${CMAKE_INSTALL_PREFIX}) else() set(_install_prefix ${CMAKE_INSTALL_PREFIX}) endif() set(_install_dir "${CppMicroServices_BINARY_DIR}/install_test/${_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) + COMMAND ${CMAKE_COMMAND} --build ${CppMicroServices_BINARY_DIR} --config $ --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) list(APPEND _example_tests usInstallCleanTest usInstallTest usExamplesCleanTest 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} + -D BUILD_SHARED_LIBS:BOOL=${US_BUILD_SHARED_LIBS} -G ${CMAKE_GENERATOR} "-DCppMicroServices_DIR:PATH=${_install_dir}/${AUXILIARY_CMAKE_INSTALL_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} + -D BUILD_SHARED_LIBS:BOOL=${US_BUILD_SHARED_LIBS} -G ${CMAKE_GENERATOR} "-DCppMicroServices_DIR:PATH=${_install_dir}/${AUXILIARY_CMAKE_INSTALL_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) + if(UNIX AND NOT APPLE AND US_BUILD_SHARED_LIBS) 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 ${PROJECT_SOURCE_DIR}/makefile COMMAND ${MAKE_COMMAND} clean) add_test(NAME usMakefileExampleTest WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/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=${US_CXX_FLAGS}") + ENVIRONMENT "CppMicroServices_ROOT=${CppMicroServices_BINARY_DIR}/install_test${CMAKE_INSTALL_PREFIX};US_CXX_FLAGS=${US_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/examples/dictionaryclient/Activator.cpp b/core/examples/dictionaryclient/Activator.cpp index fc3d47f37d..0da637fc4b 100644 --- a/core/examples/dictionaryclient/Activator.cpp +++ b/core/examples/dictionaryclient/Activator.cpp @@ -1,117 +1,121 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a module activator that uses a dictionary service to check for * the proper spelling of a word by check for its existence in the dictionary. * This modules uses the first service that it finds and does not monitor the * dynamic availability of the service (i.e., it does not listen for the arrival * or departure of dictionary services). When loading this module, the thread * calling the Load() method is used to read words from standard input. You can * stop checking words by entering an empty line, but to start checking words * again you must unload and then load the module again. */ class US_ABI_LOCAL Activator : public ModuleActivator { public: /** * Implements ModuleActivator::Load(). Queries for all available dictionary * services. If none are found it simply prints a message and returns, * otherwise it reads words from standard input and checks for their * existence from the first dictionary that it finds. * * \note It is very bad practice to use the calling thread to perform a lengthy * process like this; this is only done for the purpose of the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { // Query for all service references matching any language. std::vector > refs = context->GetServiceReferences("(Language=*)"); if (!refs.empty()) { std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a word. std::cout << "Enter word: "; std::string word; std::getline(std::cin, word); // If the user entered a blank line, then // exit the loop. if (word.empty()) { break; } // First, get a dictionary service and then check // if the word is correct. IDictionaryService* dictionary = context->GetService(refs.front()); if ( dictionary->CheckWord( word ) ) { std::cout << "Correct." << std::endl; } else { std::cout << "Incorrect." << std::endl; } // Unget the dictionary service. context->UngetService(refs.front()); } } else { std::cout << "Couldn't find any dictionary service..." << std::endl; } } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically released. } }; -US_EXPORT_MODULE_ACTIVATOR(dictionaryclient, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/core/examples/dictionaryclient/CMakeLists.txt b/core/examples/dictionaryclient/CMakeLists.txt index bd610a3686..ed36e4caee 100644 --- a/core/examples/dictionaryclient/CMakeLists.txt +++ b/core/examples/dictionaryclient/CMakeLists.txt @@ -1,8 +1,6 @@ set(_srcs Activator.cpp) -usFunctionGenerateModuleInit(_srcs - NAME "Dictionary Client" - LIBRARY_NAME "dictionaryclient") +usFunctionGenerateModuleInit(_srcs) set(dictionaryclient_DEPENDS dictionaryservice) CreateExample(dictionaryclient ${_srcs}) diff --git a/core/examples/dictionaryclient2/Activator.cpp b/core/examples/dictionaryclient2/Activator.cpp index 28d2e14276..5c221098c7 100644 --- a/core/examples/dictionaryclient2/Activator.cpp +++ b/core/examples/dictionaryclient2/Activator.cpp @@ -1,214 +1,218 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a module activator that uses a dictionary service to check for * the proper spelling of a word by checking for its existence in the * dictionary. This module is more complex than the module in Example 3 because * it monitors the dynamic availability of the dictionary services. In other * words, if the service it is using departs, then it stops using it gracefully, * or if it needs a service and one arrives, then it starts using it * automatically. As before, the module uses the first service that it finds and * uses the calling thread of the Load() method to read words from standard * input. You can stop checking words by entering an empty line, but to start * checking words again you must unload and then load the module again. */ class US_ABI_LOCAL Activator : public ModuleActivator { public: Activator() : m_context(NULL) , m_dictionary(NULL) {} /** * Implements ModuleActivator::Load(). Adds itself as a listener for service * events, then queries for available dictionary services. If any * dictionaries are found it gets a reference to the first one available and * then starts its "word checking loop". If no dictionaries are found, then * it just goes directly into its "word checking loop", but it will not be * able to check any words until a dictionary service arrives; any arriving * dictionary service will be automatically used by the client if a * dictionary is not already in use. Once it has dictionary, it reads words * from standard input and checks for their existence in the dictionary that * it is using. * * \note It is very bad practice to use the calling thread to perform a * lengthy process like this; this is only done for the purpose of * the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { m_context = context; { // Use your favorite thread library to synchronize member // variable access within this scope while registering // the service listener and performing our initial // dictionary service lookup since we // don't want to receive service events when looking up the // dictionary service, if one exists. // MutexLocker lock(&m_mutex); // Listen for events pertaining to dictionary services. m_context->AddServiceListener(this, &Activator::ServiceChanged, std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")" + "(Language=*))"); // Query for any service references matching any language. std::vector > refs = context->GetServiceReferences("(Language=*)"); // If we found any dictionary services, then just get // a reference to the first one so we can use it. if (!refs.empty()) { m_ref = refs.front(); m_dictionary = m_context->GetService(m_ref); } } std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a word. std::cout << "Enter word: "; std::string word; std::getline(std::cin, word); // If the user entered a blank line, then // exit the loop. if (word.empty()) { break; } // If there is no dictionary, then say so. else if (m_dictionary == NULL) { std::cout << "No dictionary available." << std::endl; } // Otherwise print whether the word is correct or not. else if (m_dictionary->CheckWord( word )) { std::cout << "Correct." << std::endl; } else { std::cout << "Incorrect." << std::endl; } } } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically released. } /** * Implements ServiceListener.serviceChanged(). Checks to see if the service * we are using is leaving or tries to get a service if we need one. * * @param event the fired service event. */ void ServiceChanged(const ServiceEvent event) { // Use your favorite thread library to synchronize this // method with the Load() method. // MutexLocker lock(&m_mutex); // If a dictionary service was registered, see if we // need one. If so, get a reference to it. if (event.GetType() == ServiceEvent::REGISTERED) { if (!m_ref) { // Get a reference to the service object. m_ref = event.GetServiceReference(); m_dictionary = m_context->GetService(m_ref); } } // If a dictionary service was unregistered, see if it // was the one we were using. If so, unget the service // and try to query to get another one. else if (event.GetType() == ServiceEvent::UNREGISTERING) { if (event.GetServiceReference() == m_ref) { // Unget service object and null references. m_context->UngetService(m_ref); m_ref = 0; m_dictionary = NULL; // Query to see if we can get another service. std::vector > refs; try { refs = m_context->GetServiceReferences("(Language=*)"); } catch (const std::invalid_argument& e) { std::cout << e.what() << std::endl; } if (!refs.empty()) { // Get a reference to the first service object. m_ref = refs.front(); m_dictionary = m_context->GetService(m_ref); } } } } private: // Module context ModuleContext* m_context; // The service reference being used ServiceReference m_ref; // The service object being used IDictionaryService* m_dictionary; }; -US_EXPORT_MODULE_ACTIVATOR(dictionaryclient2, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/core/examples/dictionaryclient2/CMakeLists.txt b/core/examples/dictionaryclient2/CMakeLists.txt index 7e7524a088..acd00f2a3c 100644 --- a/core/examples/dictionaryclient2/CMakeLists.txt +++ b/core/examples/dictionaryclient2/CMakeLists.txt @@ -1,8 +1,6 @@ set(_srcs Activator.cpp) -usFunctionGenerateModuleInit(_srcs - NAME "Dictionary Client 2" - LIBRARY_NAME "dictionaryclient2") +usFunctionGenerateModuleInit(_srcs) set(dictionaryclient2_DEPENDS dictionaryservice) CreateExample(dictionaryclient2 ${_srcs}) diff --git a/core/examples/dictionaryclient3/Activator.cpp b/core/examples/dictionaryclient3/Activator.cpp index a97524435b..0c709e38fc 100644 --- a/core/examples/dictionaryclient3/Activator.cpp +++ b/core/examples/dictionaryclient3/Activator.cpp @@ -1,142 +1,146 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a module activator that uses a dictionary * service to check for the proper spelling of a word by * checking for its existence in the dictionary. This module * uses a service tracker to dynamically monitor the availability * of a dictionary service, instead of providing a custom service * listener as in Example 4. The module uses the service returned * by the service tracker, which is selected based on a ranking * algorithm defined by the C++ Micro Services library. * Again, the calling thread of the Load() method is used to read * words from standard input, checking its existence in the dictionary. * You can stop checking words by entering an empty line, but * to start checking words again you must unload and then load * the module again. */ class US_ABI_LOCAL Activator : public ModuleActivator { public: Activator() : m_context(NULL) , m_tracker(NULL) {} /** * Implements ModuleActivator::Load(). Creates a service * tracker to monitor dictionary services and starts its "word * checking loop". It will not be able to check any words until * the service tracker finds a dictionary service; any discovered * dictionary service will be automatically used by the client. * It reads words from standard input and checks for their * existence in the discovered dictionary. * * \note It is very bad practice to use the calling thread to perform a * lengthy process like this; this is only done for the purpose of * the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { m_context = context; // Create a service tracker to monitor dictionary services. m_tracker = new ServiceTracker( m_context, LDAPFilter(std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")" + "(Language=*))") ); m_tracker->Open(); std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a word. std::cout << "Enter word: "; std::string word; std::getline(std::cin, word); // Get the selected dictionary, if available. IDictionaryService* dictionary = m_tracker->GetService(); // If the user entered a blank line, then // exit the loop. if (word.empty()) { break; } // If there is no dictionary, then say so. else if (dictionary == NULL) { std::cout << "No dictionary available." << std::endl; } // Otherwise print whether the word is correct or not. else if (dictionary->CheckWord(word)) { std::cout << "Correct." << std::endl; } else { std::cout << "Incorrect." << std::endl; } } // This automatically closes the tracker delete m_tracker; } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { } private: // Module context ModuleContext* m_context; // The service tracker ServiceTracker* m_tracker; }; -US_EXPORT_MODULE_ACTIVATOR(dictionaryclient3, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/core/examples/dictionaryclient3/CMakeLists.txt b/core/examples/dictionaryclient3/CMakeLists.txt index 44984fbd6e..bdf08eaa5e 100644 --- a/core/examples/dictionaryclient3/CMakeLists.txt +++ b/core/examples/dictionaryclient3/CMakeLists.txt @@ -1,8 +1,6 @@ set(_srcs Activator.cpp) -usFunctionGenerateModuleInit(_srcs - NAME "Dictionary Client 3" - LIBRARY_NAME "dictionaryclient3") +usFunctionGenerateModuleInit(_srcs) set(dictionaryclient3_DEPENDS dictionaryservice) CreateExample(dictionaryclient3 ${_srcs}) diff --git a/core/examples/dictionaryservice/Activator.cpp b/core/examples/dictionaryservice/Activator.cpp index a7289f7a42..fb3ec2da27 100644 --- a/core/examples/dictionaryservice/Activator.cpp +++ b/core/examples/dictionaryservice/Activator.cpp @@ -1,116 +1,120 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include #include #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a module activator that uses the module * context to register an English language dictionary service * with the C++ Micro Services registry during static initialization * of the module. The dictionary service interface is * defined in a separate file and is implemented by a nested class. */ class US_ABI_LOCAL Activator : public ModuleActivator { private: /** * A private inner class that implements a dictionary service; * see IDictionaryService for details of the service. */ class DictionaryImpl : public IDictionaryService { // The set of words contained in the dictionary. std::set m_dictionary; public: DictionaryImpl() { m_dictionary.insert("welcome"); m_dictionary.insert("to"); m_dictionary.insert("the"); m_dictionary.insert("micro"); m_dictionary.insert("services"); m_dictionary.insert("tutorial"); } /** * Implements IDictionaryService::CheckWord(). Determines * if the passed in word is contained in the dictionary. * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ bool CheckWord(const std::string& word) { std::string lword(word); std::transform(lword.begin(), lword.end(), lword.begin(), ::tolower); return m_dictionary.find(lword) != m_dictionary.end(); } }; std::auto_ptr m_dictionaryService; public: /** * Implements ModuleActivator::Load(). Registers an * instance of a dictionary service using the module context; * attaches properties to the service that can be queried * when performing a service look-up. * @param context the context for the module. */ void Load(ModuleContext* context) { m_dictionaryService.reset(new DictionaryImpl); ServiceProperties props; props["Language"] = std::string("English"); context->RegisterService(m_dictionaryService.get(), props); } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unregister any registered services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically unregistered } }; -US_EXPORT_MODULE_ACTIVATOR(dictionaryservice, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/core/examples/dictionaryservice/CMakeLists.txt b/core/examples/dictionaryservice/CMakeLists.txt index ae21e3b14c..c904b4e9ac 100644 --- a/core/examples/dictionaryservice/CMakeLists.txt +++ b/core/examples/dictionaryservice/CMakeLists.txt @@ -1,26 +1,31 @@ # The library name for the module set(_lib_name dictionaryservice) # A list of source code files set(_srcs Activator.cpp IDictionaryService.cpp ) # Generate module initialization code -usFunctionGenerateModuleInit(_srcs - NAME "Dictionary Service" - LIBRARY_NAME ${_lib_name}) +usFunctionGenerateModuleInit(_srcs) # Create the library -add_library(Example-${_lib_name} SHARED ${_srcs}) +add_library(Example-${_lib_name} ${_srcs}) + +# Add the required compile definitions +set_property(TARGET Example-${_lib_name} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${_lib_name}) +if(NOT US_BUILD_SHARED_LIBS) + set_property(TARGET Example-${_lib_name} APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) +endif() + # Link the CppMicroServices library target_link_libraries(Example-${_lib_name} ${CppMicroServices_LIBRARIES}) set_target_properties(Example-${_lib_name} PROPERTIES LABELS Examples OUTPUT_NAME ${_lib_name} ) #CreateExample(dictionaryservice ${_srcs}) diff --git a/core/examples/dictionaryservice/IDictionaryService.h b/core/examples/dictionaryservice/IDictionaryService.h index df806d843f..df085b5d71 100644 --- a/core/examples/dictionaryservice/IDictionaryService.h +++ b/core/examples/dictionaryservice/IDictionaryService.h @@ -1,58 +1,60 @@ /*============================================================================= 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 IDICTIONARYSERVICE_H #define IDICTIONARYSERVICE_H //! [service] #include #include +#ifdef US_BUILD_SHARED_LIBS #ifdef Example_dictionaryservice_EXPORTS - #define DICTIONAYSERVICE_EXPORT US_ABI_EXPORT + #define DICTIONARYSERVICE_EXPORT US_ABI_EXPORT #else - #define DICTIONAYSERVICE_EXPORT US_ABI_IMPORT + #define DICTIONARYSERVICE_EXPORT US_ABI_IMPORT +#endif +#else +#define DICTIONARYSERVICE_EXPORT US_ABI_EXPORT #endif /** * A simple service interface that defines a dictionary service. * A dictionary service simply verifies the existence of a word. **/ -struct DICTIONAYSERVICE_EXPORT IDictionaryService +struct DICTIONARYSERVICE_EXPORT IDictionaryService { // Out-of-line virtual desctructor for proper dynamic cast // support with older versions of gcc. virtual ~IDictionaryService(); /** * Check for the existence of a word. * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ virtual bool CheckWord(const std::string& word) = 0; }; - -US_DECLARE_SERVICE_INTERFACE(IDictionaryService, "IDictionaryService/1.0") //! [service] #endif // DICTIONARYSERVICE_H diff --git a/core/examples/driver/CMakeLists.txt b/core/examples/driver/CMakeLists.txt index fe0c928f9a..e88c04d5df 100644 --- a/core/examples/driver/CMakeLists.txt +++ b/core/examples/driver/CMakeLists.txt @@ -1,16 +1,19 @@ if(WIN32) string(REPLACE "/" "\\\\" CMAKE_LIBRARY_OUTPUT_DIRECTORY_NATIVE ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) string(REPLACE "/" "\\\\" CMAKE_RUNTIME_OUTPUT_DIRECTORY_NATIVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) else() set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_NATIVE ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_NATIVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/us${PROJECT_NAME}DriverConfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/us${PROJECT_NAME}DriverConfig.h) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_executable(us${PROJECT_NAME}Driver main.cpp) +if(NOT US_BUILD_SHARED_LIBS) + target_link_libraries(us${PROJECT_NAME}Driver Example-eventlistener Example-dictionaryservice Example-dictionaryclient) +endif() target_link_libraries(us${PROJECT_NAME}Driver ${CppMicroServices_LIBRARIES}) diff --git a/core/examples/driver/main.cpp b/core/examples/driver/main.cpp index 89ee1c7ce9..3c87a5768a 100644 --- a/core/examples/driver/main.cpp +++ b/core/examples/driver/main.cpp @@ -1,298 +1,309 @@ /*============================================================================= 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 "usCoreExamplesDriverConfig.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::vector 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")); + std::vector names; +#ifdef US_BUILD_SHARED_LIBS + names.push_back("eventlistener"); + names.push_back("dictionaryservice"); + names.push_back("frenchdictionary"); + names.push_back("dictionaryclient"); + names.push_back("dictionaryclient2"); + names.push_back("dictionaryclient3"); + names.push_back("spellcheckservice"); + names.push_back("spellcheckclient"); +#endif return names; } int main(int /*argc*/, char** /*argv*/) { char cmd[256]; - std::map availableModules = GetExampleModules(); + std::vector 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(); + for (std::vector::const_iterator availableModuleIter = availableModules.begin(); availableModuleIter != availableModules.end(); ++availableModuleIter) { - if (availableModuleIter->second == idOrName) + if (*availableModuleIter == 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(); for (std::vector::const_iterator moduleIter = modules.begin(); moduleIter != modules.end(); ++moduleIter) { - availableModules.erase((*moduleIter)->GetName()); + availableModules.erase(std::remove(availableModules.begin(), availableModules.end(), (*moduleIter)->GetName()), + availableModules.end()); } } 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(); 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(); + for (std::vector::const_iterator nameIter = availableModules.begin(); nameIter != availableModules.end(); ++nameIter) { - std::cout << " - | " << std::setw(20) << nameIter->second << " | " << std::setw(9) << "-" << std::endl; + std::cout << " - | " << std::setw(20) << *nameIter << " | " << 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; } + +#ifndef US_BUILD_SHARED_LIBS +US_IMPORT_MODULE(CppMicroServices) +US_IMPORT_MODULE(eventlistener) +US_IMPORT_MODULE(dictionaryservice) +US_IMPORT_MODULE(dictionaryclient) +#endif diff --git a/core/examples/eventlistener/Activator.cpp b/core/examples/eventlistener/Activator.cpp index d7b9ae245f..af97ea85de 100644 --- a/core/examples/eventlistener/Activator.cpp +++ b/core/examples/eventlistener/Activator.cpp @@ -1,90 +1,94 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a simple module that utilizes the CppMicroServices's * event mechanism to listen for service events. Upon receiving a service event, * it prints out the event's details. */ class Activator : public ModuleActivator { private: /** * Implements ModuleActivator::Load(). Prints a message and adds a member * function to the module context as a service listener. * * @param context the framework context for the module. */ void Load(ModuleContext* context) { std::cout << "Starting to listen for service events." << std::endl; context->AddServiceListener(this, &Activator::ServiceChanged); } /** * Implements ModuleActivator::Unload(). Prints a message and removes the * member function from the module context as a service listener. * * @param context the framework context for the module. */ void Unload(ModuleContext* context) { context->RemoveServiceListener(this, &Activator::ServiceChanged); std::cout << "Stopped listening for service events." << std::endl; // Note: It is not required that we remove the listener here, // since the framework will do it automatically anyway. } /** * Prints the details of any service event from the framework. * * @param event the fired service event. */ void ServiceChanged(const ServiceEvent event) { - std::string objectClass = ref_any_cast >(event.GetServiceReference().GetProperty(ServiceConstants::OBJECTCLASS())).front(); + std::string objectClass = ref_any_cast >(event.GetServiceReference().GetProperty(ServiceConstants::OBJECTCLASS())).front(); if (event.GetType() == ServiceEvent::REGISTERED) { std::cout << "Ex1: Service of type " << objectClass << " registered." << std::endl; } else if (event.GetType() == ServiceEvent::UNREGISTERING) { std::cout << "Ex1: Service of type " << objectClass << " unregistered." << std::endl; } else if (event.GetType() == ServiceEvent::MODIFIED) { std::cout << "Ex1: Service of type " << objectClass << " modified." << std::endl; } } }; -US_EXPORT_MODULE_ACTIVATOR(eventlistener, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //! [Activator] diff --git a/core/examples/eventlistener/CMakeLists.txt b/core/examples/eventlistener/CMakeLists.txt index 2c6dce49be..b5103996bf 100644 --- a/core/examples/eventlistener/CMakeLists.txt +++ b/core/examples/eventlistener/CMakeLists.txt @@ -1,7 +1,5 @@ set(_srcs Activator.cpp) -usFunctionGenerateModuleInit(_srcs - NAME "Event Listener" - LIBRARY_NAME "eventlistener") +usFunctionGenerateModuleInit(_srcs) CreateExample(eventlistener ${_srcs}) diff --git a/core/examples/frenchdictionary/Activator.cpp b/core/examples/frenchdictionary/Activator.cpp index cb70512826..5943c14187 100644 --- a/core/examples/frenchdictionary/Activator.cpp +++ b/core/examples/frenchdictionary/Activator.cpp @@ -1,119 +1,122 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include -#include #include #include #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a module activator that uses the module * context to register a French language dictionary service * with the C++ Micro Services registry during static initialization * of the module. The dictionary service interface is * defined in Example 2 (dictionaryservice) and is implemented by a * nested class. This class is identical to the class in Example 2, * except that the dictionary contains French words. */ class US_ABI_LOCAL Activator : public ModuleActivator { private: /** * A private inner class that implements a dictionary service; * see DictionaryService for details of the service. */ class DictionaryImpl : public IDictionaryService { // The set of words contained in the dictionary. std::set m_dictionary; public: DictionaryImpl() { m_dictionary.insert("bienvenue"); m_dictionary.insert("au"); m_dictionary.insert("tutoriel"); m_dictionary.insert("micro"); m_dictionary.insert("services"); } /** * Implements DictionaryService.checkWord(). Determines * if the passed in word is contained in the dictionary. * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ bool CheckWord(const std::string& word) { std::string lword(word); std::transform(lword.begin(), lword.end(), lword.begin(), ::tolower); return m_dictionary.find(lword) != m_dictionary.end(); } }; std::auto_ptr m_dictionaryService; public: /** * Implements ModuleActivator::Load(). Registers an * instance of a dictionary service using the module context; * attaches properties to the service that can be queried * when performing a service look-up. * @param context the context for the module. */ void Load(ModuleContext* context) { m_dictionaryService.reset(new DictionaryImpl); ServiceProperties props; props["Language"] = std::string("French"); context->RegisterService(m_dictionaryService.get(), props); } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unregister any registered services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically unregistered } }; -US_EXPORT_MODULE_ACTIVATOR(frenchdictionary, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/core/examples/frenchdictionary/CMakeLists.txt b/core/examples/frenchdictionary/CMakeLists.txt index d5c0a649dd..79c3031d56 100644 --- a/core/examples/frenchdictionary/CMakeLists.txt +++ b/core/examples/frenchdictionary/CMakeLists.txt @@ -1,8 +1,6 @@ set(_srcs Activator.cpp) -usFunctionGenerateModuleInit(_srcs - NAME "French Dictionary" - LIBRARY_NAME "frenchdictionary") +usFunctionGenerateModuleInit(_srcs) set(frenchdictionary_DEPENDS dictionaryservice) CreateExample(frenchdictionary ${_srcs}) diff --git a/core/examples/makefile/IDictionaryService.h b/core/examples/makefile/IDictionaryService.h index 1f003f955d..9ffce159fc 100644 --- a/core/examples/makefile/IDictionaryService.h +++ b/core/examples/makefile/IDictionaryService.h @@ -1,33 +1,30 @@ #ifndef IDICTIONARYSERVICE_H #define IDICTIONARYSERVICE_H #include #include #ifdef MODULE_EXPORTS #define MODULE_EXPORT US_ABI_EXPORT #else #define MODULE_EXPORT US_ABI_IMPORT #endif /** * A simple service interface that defines a dictionary service. * A dictionary service simply verifies the existence of a word. **/ struct MODULE_EXPORT IDictionaryService { virtual ~IDictionaryService(); /** * Check for the existence of a word. * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ virtual bool CheckWord(const std::string& word) = 0; }; - -US_DECLARE_SERVICE_INTERFACE(IDictionaryService, "IDictionaryService/1.0") - #endif // DICTIONARYSERVICE_H diff --git a/core/examples/makefile/Makefile b/core/examples/makefile/Makefile index 860712a72a..c88e6e62ce 100644 --- a/core/examples/makefile/Makefile +++ b/core/examples/makefile/Makefile @@ -1,26 +1,26 @@ CXX = g++ CXXFLAGS = -g -Wall -Wno-unused -pedantic -fPIC $(US_CXX_FLAGS) LDFLAGS = -Wl,-rpath="$(CppMicroServices_ROOT)/lib" -Wl,-rpath=. LDLIBS = -lCppMicroServices INCLUDEDIRS = -I"$(CppMicroServices_ROOT)/include/CppMicroServices" LIBDIRS = -L"$(CppMicroServices_ROOT)/lib/CppMicroServices" -L. all : main libmodule.so main: libmodule.so main.o $(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS) $(INCLUDEDIRS) $(LIBDIRS) $(LDLIBS) -lmodule libmodule.so: module.o IDictionaryService.o $(CXX) -shared -o $@ $^ $(CXXFLAGS) $(LDFLAGS) $(INCLUDEDIRS) $(LIBDIRS) $(LDLIBS) main.o: main.cpp - $(CXX) $(CXXFLAGS) $(INCLUDEDIRS) -c $< -o $@ + $(CXX) $(CXXFLAGS) -DUS_MODULE_NAME=main $(INCLUDEDIRS) -c $< -o $@ %.o: %.cpp - $(CXX) $(CXXFLAGS) -DMODULE_EXPORTS $(INCLUDEDIRS) -c $< -o $@ + $(CXX) $(CXXFLAGS) -DMODULE_EXPORTS -DUS_MODULE_NAME=module $(INCLUDEDIRS) -c $< -o $@ .PHONY : clean clean: rm -f *.o diff --git a/core/examples/makefile/main.cpp b/core/examples/makefile/main.cpp index fe66aa18b3..fb1193b1a2 100644 --- a/core/examples/makefile/main.cpp +++ b/core/examples/makefile/main.cpp @@ -1,25 +1,25 @@ #include #include #include #include "IDictionaryService.h" US_USE_NAMESPACE int main(int /*argc*/, char* /*argv*/[]) { ServiceReference dictionaryServiceRef = GetModuleContext()->GetServiceReference(); if (dictionaryServiceRef) { IDictionaryService* dictionaryService = GetModuleContext()->GetService(dictionaryServiceRef); if (dictionaryService) { std::cout << "Dictionary contains 'Tutorial': " << dictionaryService->CheckWord("Tutorial") << std::endl; } } } #include -US_INITIALIZE_EXECUTABLE("main") +US_INITIALIZE_MODULE diff --git a/core/examples/makefile/module.cpp b/core/examples/makefile/module.cpp index e5260d7720..81342b9a47 100644 --- a/core/examples/makefile/module.cpp +++ b/core/examples/makefile/module.cpp @@ -1,102 +1,102 @@ #include #include #include #include #include "IDictionaryService.h" #include #include #include US_USE_NAMESPACE /** * This class implements a module activator that uses the module * context to register an English language dictionary service * with the C++ Micro Services registry during static initialization * of the module. The dictionary service interface is * defined in a separate file and is implemented by a nested class. */ class US_ABI_LOCAL MyActivator : public ModuleActivator { private: /** * A private inner class that implements a dictionary service; * see DictionaryService for details of the service. */ class DictionaryImpl : public IDictionaryService { // The set of words contained in the dictionary. std::set m_Dictionary; public: DictionaryImpl() { m_Dictionary.insert("welcome"); m_Dictionary.insert("to"); m_Dictionary.insert("the"); m_Dictionary.insert("micro"); m_Dictionary.insert("services"); m_Dictionary.insert("tutorial"); } /** * Implements IDictionaryService::CheckWord(). Determines * if the passed in word is contained in the dictionary. * * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ bool CheckWord(const std::string& word) { std::string lword(word); std::transform(lword.begin(), lword.end(), lword.begin(), ::tolower); return m_Dictionary.find(lword) != m_Dictionary.end(); } }; std::auto_ptr m_DictionaryService; public: /** * Implements ModuleActivator::Load(). Registers an * instance of a dictionary service using the module context; * attaches properties to the service that can be queried * when performing a service look-up. * * @param context the context for the module. */ void Load(ModuleContext* context) { m_DictionaryService.reset(new DictionaryImpl); ServiceProperties props; props["Language"] = std::string("English"); context->RegisterService(m_DictionaryService.get(), props); } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unregister any registered services. * * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically unregistered } }; -US_EXPORT_MODULE_ACTIVATOR(module, MyActivator) +US_EXPORT_MODULE_ACTIVATOR(MyActivator) #include -US_INITIALIZE_MODULE("My Module", "module") +US_INITIALIZE_MODULE diff --git a/core/examples/spellcheckclient/Activator.cpp b/core/examples/spellcheckclient/Activator.cpp index 7014fe46fa..ff4b09ec8b 100644 --- a/core/examples/spellcheckclient/Activator.cpp +++ b/core/examples/spellcheckclient/Activator.cpp @@ -1,143 +1,147 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include "ISpellCheckService.h" #include #include #include #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a module that uses a spell checker * service to check the spelling of a passage. This module * is essentially identical to Example 5, in that it uses the * Service Tracker to monitor the dynamic availability of the * spell checker service. When loading this module, the thread * calling the Load() method is used to read passages from * standard input. You can stop spell checking passages by * entering an empty line, but to start spell checking again * you must un-load and then load the module again. **/ class US_ABI_LOCAL Activator : public ModuleActivator { public: Activator() : m_context(NULL) , m_tracker(NULL) {} /** * Implements ModuleActivator::Load(). Creates a service * tracker object to monitor spell checker services. Enters * a spell check loop where it reads passages from standard * input and checks their spelling using the spell checker service. * * \note It is very bad practice to use the calling thread to perform a * lengthy process like this; this is only done for the purpose of * the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { m_context = context; // Create a service tracker to monitor spell check services. m_tracker = new ServiceTracker(m_context); m_tracker->Open(); std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a passage. std::cout << "Enter passage: "; std::string passage; std::getline(std::cin, passage); // Get the selected spell check service, if available. ISpellCheckService* checker = m_tracker->GetService(); // If the user entered a blank line, then // exit the loop. if (passage.empty()) { break; } // If there is no spell checker, then say so. else if (checker == NULL) { std::cout << "No spell checker available." << std::endl; } // Otherwise check passage and print misspelled words. else { std::vector errors = checker->Check(passage); if (errors.empty()) { std::cout << "Passage is correct." << std::endl; } else { std::cout << "Incorrect word(s):" << std::endl; for (std::size_t i = 0; i < errors.size(); ++i) { std::cout << " " << errors[i] << std::endl; } } } } // This automatically closes the tracker delete m_tracker; } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { } private: // Module context ModuleContext* m_context; // The service tracker ServiceTracker* m_tracker; }; -US_EXPORT_MODULE_ACTIVATOR(spellcheckclient, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/core/examples/spellcheckclient/CMakeLists.txt b/core/examples/spellcheckclient/CMakeLists.txt index 7e28ef4b12..4600cc22ac 100644 --- a/core/examples/spellcheckclient/CMakeLists.txt +++ b/core/examples/spellcheckclient/CMakeLists.txt @@ -1,8 +1,6 @@ set(_srcs Activator.cpp) -usFunctionGenerateModuleInit(_srcs - NAME "Spell Check Client" - LIBRARY_NAME "spellcheckclient") +usFunctionGenerateModuleInit(_srcs) set(spellcheckclient_DEPENDS spellcheckservice) CreateExample(spellcheckclient ${_srcs}) diff --git a/core/examples/spellcheckservice/Activator.cpp b/core/examples/spellcheckservice/Activator.cpp index 1470d00a4f..816c20cf9e 100644 --- a/core/examples/spellcheckservice/Activator.cpp +++ b/core/examples/spellcheckservice/Activator.cpp @@ -1,225 +1,229 @@ /*============================================================================= 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. =============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include "ISpellCheckService.h" #include #include #include #include #include #include #include #include US_USE_NAMESPACE +namespace { + /** * This class implements a module that implements a spell * checker service. The spell checker service uses all available * dictionary services to check for the existence of words in * a given sentence. This module uses a ServiceTracker to * monitors the dynamic availability of dictionary services, * and to aggregate all available dictionary services as they * arrive and depart. The spell checker service is only registered * if there are dictionary services available, thus the spell * checker service will appear and disappear as dictionary * services appear and disappear, respectively. **/ class US_ABI_LOCAL Activator : public ModuleActivator, public ServiceTrackerCustomizer { private: /** * A private inner class that implements a spell check service; see * ISpellCheckService for details of the service. */ class SpellCheckImpl : public ISpellCheckService { private: typedef std::map, IDictionaryService*> RefToServiceType; RefToServiceType m_refToSvcMap; public: /** * Implements ISpellCheckService::Check(). Checks the given passage for * misspelled words. * * @param passage the passage to spell check. * @return A list of misspelled words. */ std::vector Check(const std::string& passage) { std::vector errorList; // No misspelled words for an empty string. if (passage.empty()) { return errorList; } // Tokenize the passage using spaces and punctuation. const char* delimiters = " ,.!?;:"; char* passageCopy = new char[passage.size()+1]; std::memcpy(passageCopy, passage.c_str(), passage.size()+1); char* pch = std::strtok(passageCopy, delimiters); { // Lock the m_refToSvcMap member using your favorite thread library here... // MutexLocker lock(&m_refToSvcMapMutex) // Loop through each word in the passage. while (pch) { std::string word(pch); bool correct = false; // Check each available dictionary for the current word. for (RefToServiceType::const_iterator i = m_refToSvcMap.begin(); (!correct) && (i != m_refToSvcMap.end()); ++i) { IDictionaryService* dictionary = i->second; if (dictionary->CheckWord(word)) { correct = true; } } // If the word is not correct, then add it // to the incorrect word list. if (!correct) { errorList.push_back(word); } pch = std::strtok(NULL, delimiters); } } delete[] passageCopy; return errorList; } std::size_t AddDictionary(const ServiceReference& ref, IDictionaryService* dictionary) { // Lock the m_refToSvcMap member using your favorite thread library here... // MutexLocker lock(&m_refToSvcMapMutex) m_refToSvcMap.insert(std::make_pair(ref, dictionary)); return m_refToSvcMap.size(); } std::size_t RemoveDictionary(const ServiceReference& ref) { // Lock the m_refToSvcMap member using your favorite thread library here... // MutexLocker lock(&m_refToSvcMapMutex) m_refToSvcMap.erase(ref); return m_refToSvcMap.size(); } }; virtual IDictionaryService* AddingService(const ServiceReference& reference) { IDictionaryService* dictionary = m_context->GetService(reference); std::size_t count = m_spellCheckService->AddDictionary(reference, dictionary); if (!m_spellCheckReg && count > 1) { m_spellCheckReg = m_context->RegisterService(m_spellCheckService.get()); } return dictionary; } virtual void ModifiedService(const ServiceReference& /*reference*/, IDictionaryService* /*service*/) { // do nothing } virtual void RemovedService(const ServiceReference& reference, IDictionaryService* /*service*/) { if (m_spellCheckService->RemoveDictionary(reference) < 2 && m_spellCheckReg) { m_spellCheckReg.Unregister(); m_spellCheckReg = 0; } } std::auto_ptr m_spellCheckService; ServiceRegistration m_spellCheckReg; ModuleContext* m_context; std::auto_ptr > m_tracker; public: Activator() : m_context(NULL) {} /** * Implements ModuleActivator::Load(). Registers an * instance of a dictionary service using the module context; * attaches properties to the service that can be queried * when performing a service look-up. * * @param context the context for the module. */ void Load(ModuleContext* context) { m_context = context; m_spellCheckService.reset(new SpellCheckImpl); m_tracker.reset(new ServiceTracker(context, this)); m_tracker->Open(); } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unregister any registered services * and release any used services. * * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically unregistered m_tracker->Close(); } }; -US_EXPORT_MODULE_ACTIVATOR(spellcheckservice, Activator) +} + +US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/core/examples/spellcheckservice/CMakeLists.txt b/core/examples/spellcheckservice/CMakeLists.txt index a86d8153a6..6c38a331a8 100644 --- a/core/examples/spellcheckservice/CMakeLists.txt +++ b/core/examples/spellcheckservice/CMakeLists.txt @@ -1,8 +1,6 @@ set(_srcs Activator.cpp ISpellCheckService.cpp) -usFunctionGenerateModuleInit(_srcs - NAME "Spell Check Service" - LIBRARY_NAME "spellcheckservice") +usFunctionGenerateModuleInit(_srcs) set(spellcheckservice_DEPENDS dictionaryservice) CreateExample(spellcheckservice ${_srcs}) diff --git a/core/examples/spellcheckservice/ISpellCheckService.h b/core/examples/spellcheckservice/ISpellCheckService.h index 679235801b..0f4875d124 100644 --- a/core/examples/spellcheckservice/ISpellCheckService.h +++ b/core/examples/spellcheckservice/ISpellCheckService.h @@ -1,64 +1,66 @@ /*============================================================================= 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 ISPELLCHECKSERVICE_H #define ISPELLCHECKSERVICE_H //! [service] #include #include #include +#ifdef US_BUILD_SHARED_LIBS #ifdef Example_spellcheckservice_EXPORTS #define SPELLCHECKSERVICE_EXPORT US_ABI_EXPORT #else #define SPELLCHECKSERVICE_EXPORT US_ABI_IMPORT #endif +#else + #define SPELLCHECKSERVICE_EXPORT US_ABI_EXPORT +#endif /** * A simple service interface that defines a spell check service. A spell check * service checks the spelling of all words in a given passage. A passage is any * number of words separated by a space character and the following punctuation * marks: comma, period, exclamation mark, question mark, semi-colon, and colon. */ struct SPELLCHECKSERVICE_EXPORT ISpellCheckService { // Out-of-line virtual desctructor for proper dynamic cast // support with older versions of gcc. virtual ~ISpellCheckService(); /** * Checks a given passage for spelling errors. A passage is any number of * words separated by a space and any of the following punctuation marks: * comma (,), period (.), exclamation mark (!), question mark (?), * semi-colon (;), and colon(:). * * @param passage the passage to spell check. * @return A list of misspelled words. */ virtual std::vector Check(const std::string& passage) = 0; }; - -US_DECLARE_SERVICE_INTERFACE(ISpellCheckService, "ISpellCheckService/1.0") //! [service] //! #endif // ISPELLCHECKSERVICE_H diff --git a/core/include/CMakeLists.txt b/core/include/CMakeLists.txt index b06be463cd..4e39d58c68 100644 --- a/core/include/CMakeLists.txt +++ b/core/include/CMakeLists.txt @@ -1,47 +1,46 @@ #----------------------------------------------------------------------------- # Public header files #----------------------------------------------------------------------------- set(_public_headers usAny.h usLDAPProp.h usSharedData.h usSharedLibrary.h usShrinkableMap.h usShrinkableVector.h - usUncompressResourceData.h usLDAPFilter.h usPrototypeServiceFactory.h usServiceEvent.h usServiceEventListenerHook.h usServiceException.h usServiceFactory.h usServiceFindHook.h usServiceInterface.h usServiceListenerHook.h usServiceObjects.h usServiceProperties.h usServiceReference.h usServiceReferenceBase.h usServiceRegistration.h usServiceRegistrationBase.h usServiceTracker.h usServiceTrackerCustomizer.h usGetModuleContext.h usModule.h usModuleActivator.h usModuleContext.h usModuleEvent.h usModuleEventHook.h usModuleFindHook.h usModuleImport.h usModuleInfo.h usModuleInitialization.h usModuleRegistry.h usModuleResource.h usModuleResourceStream.h usModuleSettings.h usModuleVersion.h ) diff --git a/core/include/usAny.h b/core/include/usAny.h index d59848c720..bfa2250d35 100644 --- a/core/include/usAny.h +++ b/core/include/usAny.h @@ -1,397 +1,577 @@ /*============================================================================= Library: CppMicroServices Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. Extracted from Boost 1.46.1 and adapted for CppMicroServices. Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =========================================================================*/ #ifndef US_ANY_H #define US_ANY_H #include #include #include #include #include +#include #include #include US_BEGIN_NAMESPACE +class Any; + +US_Core_EXPORT std::string any_value_to_string(const Any& any); + +US_Core_EXPORT std::string any_value_to_json(const Any& val); +US_Core_EXPORT std::string any_value_to_json(const std::string& val); +US_Core_EXPORT std::string any_value_to_json(bool val); + +template +std::string any_value_to_string(const T& val) +{ + std::stringstream ss; + ss << val; + return ss.str(); +} + template -std::string any_value_to_string(const T& val); +std::string any_value_to_json(const T& val) +{ + return any_value_to_string(val); +} + +/** + * \internal + */ +template +std::string container_to_string(Iterator i1, Iterator i2) +{ + std::stringstream ss; + ss << "["; + const Iterator begin = i1; + for ( ; i1 != i2; ++i1) + { + if (i1 == begin) ss << any_value_to_string(*i1); + else ss << "," << any_value_to_string(*i1); + } + ss << "]"; + return ss.str(); +} + +/** + * \internal + */ +template +std::string container_to_json(Iterator i1, Iterator i2) +{ + std::stringstream ss; + ss << "["; + const Iterator begin = i1; + for ( ; i1 != i2; ++i1) + { + if (i1 == begin) ss << any_value_to_json(*i1); + else ss << "," << any_value_to_json(*i1); + } + ss << "]"; + return ss.str(); +} + +template +std::string any_value_to_string(const std::vector& vec) +{ + return container_to_string(vec.begin(), vec.end()); +} + +template +std::string any_value_to_json(const std::vector& vec) +{ + return container_to_json(vec.begin(), vec.end()); +} + +template +std::string any_value_to_string(const std::list& l) +{ + return container_to_string(l.begin(), l.end()); +} + +template +std::string any_value_to_json(const std::list& l) +{ + return container_to_json(l.begin(), l.end()); +} + +template +std::string any_value_to_string(const std::set& s) +{ + return container_to_string(s.begin(), s.end()); +} + +template +std::string any_value_to_json(const std::set& s) +{ + return container_to_json(s.begin(), s.end()); +} + +template +std::string any_value_to_string(const std::map& m); + +template +std::string any_value_to_string(const std::map& m); + +template +std::string any_value_to_json(const std::map& m); + +template +std::string any_value_to_json(const std::map& m); -US_Core_EXPORT std::string any_value_to_string(const std::vector& val); -US_Core_EXPORT std::string any_value_to_string(const std::list& val); /** * \ingroup MicroServicesUtils * * An Any class represents a general type and is capable of storing any type, supporting type-safe extraction * of the internally stored data. * * Code taken from the Boost 1.46.1 library. Original copyright by Kevlin Henney. Modified for CppMicroServices. */ class Any { public: /** * Creates an empty any type. */ Any(): _content(0) { } /** * Creates an Any which stores the init parameter inside. * * \param value The content of the Any * * Example: * \code * Any a(13); * Any a(string("12345")); * \endcode */ template Any(const ValueType& value) : _content(new Holder(value)) { } /** * Copy constructor, works with empty Anys and initialized Any values. * * \param other The Any to copy */ Any(const Any& other) : _content(other._content ? other._content->Clone() : 0) { } ~Any() { delete _content; } /** * Swaps the content of the two Anys. * * \param rhs The Any to swap this Any with. */ Any& Swap(Any& rhs) { std::swap(_content, rhs._content); return *this; } /** * Assignment operator for all types != Any. * * \param rhs The value which should be assigned to this Any. * * Example: * \code * Any a = 13; * Any a = string("12345"); * \endcode */ template Any& operator = (const ValueType& rhs) { Any(rhs).Swap(*this); return *this; } /** * Assignment operator for Any. * * \param rhs The Any which should be assigned to this Any. */ Any& operator = (const Any& rhs) { Any(rhs).Swap(*this); return *this; } /** * returns true if the Any is empty */ bool Empty() const { return !_content; } /** * Returns a string representation for the content. * * Custom types should either provide a std::ostream& operator<<(std::ostream& os, const CustomType& ct) * function or specialize the any_value_to_string template function for meaningful output. */ std::string ToString() const { return _content->ToString(); } + /** + * Returns a JSON representation for the content. + * + * Custom types should specialize the any_value_to_json template function for meaningful output. + */ + std::string ToJSON() const + { + return Empty() ? "null" : _content->ToJSON(); + } + /** * Returns the type information of the stored content. * If the Any is empty typeid(void) is returned. * It is suggested to always query an Any for its type info before trying to extract * data via an any_cast/ref_any_cast. */ const std::type_info& Type() const { return _content ? _content->Type() : typeid(void); } private: class Placeholder { public: virtual ~Placeholder() { } virtual std::string ToString() const = 0; + virtual std::string ToJSON() const = 0; virtual const std::type_info& Type() const = 0; virtual Placeholder* Clone() const = 0; }; template class Holder: public Placeholder { public: Holder(const ValueType& value) : _held(value) { } virtual std::string ToString() const { return any_value_to_string(_held); } + virtual std::string ToJSON() const + { + return any_value_to_json(_held); + } + virtual const std::type_info& Type() const { return typeid(ValueType); } virtual Placeholder* Clone() const { return new Holder(_held); } ValueType _held; private: // intentionally left unimplemented Holder& operator=(const Holder &); }; private: template friend ValueType* any_cast(Any*); template friend ValueType* unsafe_any_cast(Any*); Placeholder* _content; }; class BadAnyCastException : public std::bad_cast { public: BadAnyCastException(const std::string& msg = "") : std::bad_cast(), _msg(msg) {} ~BadAnyCastException() throw() {} virtual const char * what() const throw() { if (_msg.empty()) return "US_PREPEND_NAMESPACE(BadAnyCastException): " "failed conversion using US_PREPEND_NAMESPACE(any_cast)"; else return _msg.c_str(); } private: std::string _msg; }; /** * any_cast operator used to extract the ValueType from an Any*. Will return a pointer * to the stored value. * * Example Usage: * \code * MyType* pTmp = any_cast(pAny) * \endcode * Will return NULL if the cast fails, i.e. types don't match. */ template ValueType* any_cast(Any* operand) { return operand && operand->Type() == typeid(ValueType) ? &static_cast*>(operand->_content)->_held : 0; } /** * any_cast operator used to extract a const ValueType pointer from an const Any*. Will return a const pointer * to the stored value. * * Example Usage: * \code * const MyType* pTmp = any_cast(pAny) * \endcode * Will return NULL if the cast fails, i.e. types don't match. */ template const ValueType* any_cast(const Any* operand) { return any_cast(const_cast(operand)); } /** * any_cast operator used to extract a copy of the ValueType from an const Any&. * * Example Usage: * \code * MyType tmp = any_cast(anAny) * \endcode * Will throw a BadCastException if the cast fails. * Dont use an any_cast in combination with references, i.e. MyType& tmp = ... or const MyType& = ... * Some compilers will accept this code although a copy is returned. Use the ref_any_cast in * these cases. */ template ValueType any_cast(const Any& operand) { ValueType* result = any_cast(const_cast(&operand)); if (!result) throw BadAnyCastException("Failed to convert between const Any types"); return *result; } /** * any_cast operator used to extract a copy of the ValueType from an Any&. * * Example Usage: * \code * MyType tmp = any_cast(anAny) * \endcode * Will throw a BadCastException if the cast fails. * Dont use an any_cast in combination with references, i.e. MyType& tmp = ... or const MyType& tmp = ... * Some compilers will accept this code although a copy is returned. Use the ref_any_cast in * these cases. */ template ValueType any_cast(Any& operand) { ValueType* result = any_cast(&operand); if (!result) throw BadAnyCastException("Failed to convert between Any types"); return *result; } /** * ref_any_cast operator used to return a const reference to the internal data. * * Example Usage: * \code * const MyType& tmp = ref_any_cast(anAny); * \endcode */ template const ValueType& ref_any_cast(const Any & operand) { ValueType* result = any_cast(const_cast(&operand)); if (!result) throw BadAnyCastException("RefAnyCast: Failed to convert between const Any types"); return *result; } /** * ref_any_cast operator used to return a reference to the internal data. * * Example Usage: * \code * MyType& tmp = ref_any_cast(anAny); * \endcode */ template ValueType& ref_any_cast(Any& operand) { ValueType* result = any_cast(&operand); if (!result) throw BadAnyCastException("RefAnyCast: Failed to convert between Any types"); return *result; } /** * \internal * * The "unsafe" versions of any_cast are not part of the * public interface and may be removed at any time. They are * required where we know what type is stored in the any and can't * use typeid() comparison, e.g., when our types may travel across * different shared libraries. */ template ValueType* unsafe_any_cast(Any* operand) { return &static_cast*>(operand->_content)->_held; } /** * \internal * * The "unsafe" versions of any_cast are not part of the * public interface and may be removed at any time. They are * required where we know what type is stored in the any and can't * use typeid() comparison, e.g., when our types may travel across * different shared libraries. */ template const ValueType* unsafe_any_cast(const Any* operand) { return any_cast(const_cast(operand)); } -US_Core_EXPORT std::string any_value_to_string(const std::vector& val); -US_Core_EXPORT std::string any_value_to_string(const std::map& val); -template -std::string any_value_to_string(const T& val) +template +std::string any_value_to_string(const std::map& m) { std::stringstream ss; - ss << val; + ss << "{"; + typedef typename std::map::const_iterator Iterator; + Iterator i1 = m.begin(); + const Iterator begin = i1; + const Iterator end = m.end(); + for ( ; i1 != end; ++i1) + { + if (i1 == begin) ss << i1->first << " : " << i1->second.ToString(); + else ss << ", " << i1->first << " : " << i1->second.ToString(); + } + ss << "}"; + return ss.str(); +} + +template +std::string any_value_to_string(const std::map& m) +{ + std::stringstream ss; + ss << "{"; + typedef typename std::map::const_iterator Iterator; + Iterator i1 = m.begin(); + const Iterator begin = i1; + const Iterator end = m.end(); + for ( ; i1 != end; ++i1) + { + if (i1 == begin) ss << i1->first << " : " << i1->second; + else ss << ", " << i1->first << " : " << i1->second; + } + ss << "}"; + return ss.str(); +} + +template +std::string any_value_to_json(const std::map& m) +{ + std::stringstream ss; + ss << "{"; + typedef typename std::map::const_iterator Iterator; + Iterator i1 = m.begin(); + const Iterator begin = i1; + const Iterator end = m.end(); + for ( ; i1 != end; ++i1) + { + if (i1 == begin) ss << "\"" << i1->first << "\" : " << i1->second.ToJSON(); + else ss << ", " << "\"" << i1->first << "\" : " << i1->second.ToJSON(); + } + ss << "}"; + return ss.str(); +} + +template +std::string any_value_to_json(const std::map& m) +{ + std::stringstream ss; + ss << "{"; + typedef typename std::map::const_iterator Iterator; + Iterator i1 = m.begin(); + const Iterator begin = i1; + const Iterator end = m.end(); + for ( ; i1 != end; ++i1) + { + if (i1 == begin) ss << "\"" << i1->first << "\" : " << i1->second; + else ss << ", " << "\"" << i1->first << "\" : " << i1->second; + } + ss << "}"; return ss.str(); } US_END_NAMESPACE #endif // US_ANY_H diff --git a/core/include/usGetModuleContext.h b/core/include/usGetModuleContext.h index 394bd8b609..83e7f72a09 100644 --- a/core/include/usGetModuleContext.h +++ b/core/include/usGetModuleContext.h @@ -1,54 +1,56 @@ /*============================================================================= 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 USGETMODULECONTEXT_H #define USGETMODULECONTEXT_H +#ifndef US_MODULE_NAME +#error Missing preprocessor define US_MODULE_NAME +#endif + #include +#include +#include +#include US_BEGIN_NAMESPACE class ModuleContext; /** * \ingroup MicroServices * * \brief Returns the module context of the calling module. * * This function allows easy access to the ModuleContext instance from * inside a C++ Micro Services module. * * \return The ModuleContext of the calling module. - * - * \internal - * - * Note that the corresponding function definition is provided for each - * module by the usModuleInit.cpp file. This file is customized via CMake - * configure_file(...) and automatically compiled into each module. - * Consequently, the GetModuleContext function is not exported, since each - * module gets its "own version". */ -US_ABI_LOCAL ModuleContext* GetModuleContext(); +static inline ModuleContext* GetModuleContext() +{ + return ModuleRegistry::GetModule(US_STR(US_MODULE_NAME))->GetModuleContext(); +} US_END_NAMESPACE #endif // USGETMODULECONTEXT_H diff --git a/core/include/usModule.h b/core/include/usModule.h index 6a873ff649..397ab0f18f 100644 --- a/core/include/usModule.h +++ b/core/include/usModule.h @@ -1,369 +1,367 @@ /*============================================================================= 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_Core_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. + * location in 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. + * @return The vendor 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. + * @return The description 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. + * @return The auto-load directory property key. */ static const std::string& PROP_AUTOLOAD_DIR(); + /** + * Returns the property key with a value of \c module.autoloaded_modules for + * looking up this module's auto-load modules. + * The property value is of type \c std::vector and contains + * the file system locations for the auto-loaded modules triggered by this + * module. + * + * @return The auto-loaded modules property key. + */ + static const std::string& PROP_AUTOLOADED_MODULES(); + ~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. + * Returns resources in this module. * * 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. + * @return A vector of ModuleResource objects for each matching entry. */ 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_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(Module)& module); /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, US_PREPEND_NAMESPACE(Module) const * module); #endif // USMODULE_H diff --git a/core/include/usModuleActivator.h b/core/include/usModuleActivator.h index 903f68ad6c..41691efd28 100644 --- a/core/include/usModuleActivator.h +++ b/core/include/usModuleActivator.h @@ -1,137 +1,134 @@ /*============================================================================= 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 USMODULEACTIVATOR_H_ #define USMODULEACTIVATOR_H_ +#ifndef US_MODULE_NAME +#error Missing US_MODULE_NAME preprocessor define +#endif + #include +#include US_BEGIN_NAMESPACE class ModuleContext; /** * \ingroup MicroServices * * Customizes the starting and stopping of a CppMicroServices module. *

* %ModuleActivator is an interface that can be implemented by * CppMicroServices modules. The CppMicroServices library can create instances of a * module's %ModuleActivator as required. If an instance's * ModuleActivator::Load method executes successfully, it is * guaranteed that the same instance's %ModuleActivator::Unload * method will be called when the module is to be unloaded. The CppMicroServices * library does not concurrently call a %ModuleActivator object. * *

* %ModuleActivator is an abstract class interface whose implementations * must be exported via a special macro. Implementations are usually declared * and defined directly in .cpp files. * *

* \snippet uServices-activator/main.cpp 0 * *

* The class implementing the %ModuleActivator interface must have a public * default constructor so that a %ModuleActivator * object can be created by the CppMicroServices library. * */ struct ModuleActivator { virtual ~ModuleActivator() {} /** * Called when this module is loaded. This method * can be used to register services or to allocate any resources that this * module may need globally (during the whole module lifetime). * *

* This method must complete and return to its caller in a timely manner. * * @param context The execution context of the module being loaded. * @throws std::exception If this method throws an exception, this * module is marked as stopped and the framework will remove this * module's listeners, unregister all services registered by this * module, and release all services used by this module. */ virtual void Load(ModuleContext* context) = 0; /** * Called when this module is unloaded. In general, this * method should undo the work that the ModuleActivator::Load * method started. There should be no active threads that were started by * this module when this method returns. * *

* This method must complete and return to its caller in a timely manner. * * @param context The execution context of the module being unloaded. * @throws std::exception If this method throws an exception, the * module is still marked as unloaded, and the framework will remove * the module's listeners, unregister all services registered by the * module, and release all services used by the module. */ virtual void Unload(ModuleContext* context) = 0; }; US_END_NAMESPACE -#define US_MODULE_ACTIVATOR_INSTANCE_FUNCTION(type) \ - struct ScopedPointer \ - { \ - ScopedPointer(US_PREPEND_NAMESPACE(ModuleActivator)* activator = 0) : m_Activator(activator) {} \ - ~ScopedPointer() { delete m_Activator; } \ - US_PREPEND_NAMESPACE(ModuleActivator)* m_Activator; \ - }; \ - \ - static ScopedPointer activatorPtr; \ - if (activatorPtr.m_Activator == 0) activatorPtr.m_Activator = new type; \ - return activatorPtr.m_Activator; /** * \ingroup MicroServices * * \brief Export a module activator class. * - * \param _module_libname The physical name of the module, without prefix or suffix. * \param _activator_type The fully-qualified type-name of the module activator class. * * Call this macro after the definition of your module activator to make it * accessible by the CppMicroServices library. * * Example: * \snippet uServices-activator/main.cpp 0 - * - * \note If you use this macro in a source file compiled into an executable, additional - * requirements for the macro arguments apply: - * - The \c _module_libname argument must match the value of \c _module_name used in the - * \c #US_INITIALIZE_MODULE macro call. */ -#define US_EXPORT_MODULE_ACTIVATOR(_module_libname, _activator_type) \ - extern "C" US_ABI_EXPORT US_PREPEND_NAMESPACE(ModuleActivator)* _us_module_activator_instance_ ## _module_libname () \ - { \ - US_MODULE_ACTIVATOR_INSTANCE_FUNCTION(_activator_type) \ +#define US_EXPORT_MODULE_ACTIVATOR(_activator_type) \ + extern "C" US_ABI_EXPORT US_PREPEND_NAMESPACE(ModuleActivator)* US_CONCAT(_us_module_activator_instance_, US_MODULE_NAME) () \ + { \ + struct ScopedPointer \ + { \ + ScopedPointer(US_PREPEND_NAMESPACE(ModuleActivator)* activator = 0) : m_Activator(activator) {} \ + ~ScopedPointer() { delete m_Activator; } \ + US_PREPEND_NAMESPACE(ModuleActivator)* m_Activator; \ + }; \ + \ + static ScopedPointer activatorPtr; \ + if (activatorPtr.m_Activator == 0) activatorPtr.m_Activator = new _activator_type; \ + return activatorPtr.m_Activator; \ } #endif /* USMODULEACTIVATOR_H_ */ diff --git a/core/include/usModuleContext.h b/core/include/usModuleContext.h index 5abc94c1cb..19dac422d4 100644 --- a/core/include/usModuleContext.h +++ b/core/include/usModuleContext.h @@ -1,851 +1,851 @@ /*============================================================================= 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 "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_Core_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. * * @return A std::vector of Module objects which * will hold one object per known module. */ 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"); + std::string clazz = us_service_interface_iid(); + if (clazz.empty()) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); typedef std::vector BaseVectorT; - BaseVectorT serviceRefs = GetServiceReferences(std::string(clazz), filter); + BaseVectorT serviceRefs = GetServiceReferences(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))); + std::string clazz = us_service_interface_iid(); + if (clazz.empty()) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); + return ServiceReference(GetServiceReference(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)); } /** * Get the absolute path for a file or directory in the persistent * storage area provided for the module. The returned path * might be empty if no storage path has been set previously. * If the path is non-empty, it is safe to assume that the path is writable. * * @see ModuleSettings::SetStoragePath(const std::string&) * * @param filename A relative name to the file or directory to be accessed. * @return The absolute path to the persistent storage area for the given file name. */ std::string GetDataFile(const std::string& filename) const; 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/include/usModuleEvent.h b/core/include/usModuleEvent.h index 7394c5a4cb..dcaa2172dd 100644 --- a/core/include/usModuleEvent.h +++ b/core/include/usModuleEvent.h @@ -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. =============================================================================*/ #ifndef USMODULEEVENT_H #define USMODULEEVENT_H #include #include "usSharedData.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4251) #endif US_BEGIN_NAMESPACE class Module; class ModuleEventData; /** * \ingroup MicroServices * * An event from the Micro Services framework describing a module lifecycle change. *

* ModuleEvent objects are delivered to listeners connected * via ModuleContext::AddModuleListener() when a change * occurs in a modules's lifecycle. A type code is used to identify * the event type for future extendability. * * @see ModuleContext#AddModuleListener */ class US_Core_EXPORT ModuleEvent { SharedDataPointer d; public: enum Type { /** * The module has been loaded. *

* The module's * \link ModuleActivator::Load(ModuleContext*) ModuleActivator Load\endlink method * has been executed. */ LOADED, /** * The module has been unloaded. *

* The module's * \link ModuleActivator::Unload(ModuleContext*) ModuleActivator Unload\endlink method * has been executed. */ UNLOADED, /** * The module is about to be loaded. *

* The module's * \link ModuleActivator::Load(ModuleContext*) ModuleActivator Load\endlink method * is about to be called. */ LOADING, /** * The module is about to be unloaded. *

* The module's * \link ModuleActivator::Unload(ModuleContext*) ModuleActivator Unload\endlink method * is about to be called. */ UNLOADING }; /** * Creates an invalid instance. */ ModuleEvent(); ~ModuleEvent(); /** * Can be used to check if this ModuleEvent 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 module event of the specified type. * * @param type The event type. * @param module The module which had a lifecycle change. */ ModuleEvent(Type type, Module* module); ModuleEvent(const ModuleEvent& other); ModuleEvent& operator=(const ModuleEvent& other); /** * Returns the module which had a lifecycle change. * * @return The module that had a change occur in its lifecycle. */ Module* GetModule() const; /** * Returns the type of lifecyle event. The type values are: *

    *
  • {@link #LOADING} *
  • {@link #LOADED} *
  • {@link #UNLOADING} *
  • {@link #UNLOADED} *
* * @return The type of lifecycle event. */ Type GetType() const; }; -US_END_NAMESPACE - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - /** * \ingroup MicroServices * @{ */ -US_Core_EXPORT std::ostream& operator<<(std::ostream& os, US_PREPEND_NAMESPACE(ModuleEvent::Type) eventType); -US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ModuleEvent)& event); +US_Core_EXPORT std::ostream& operator<<(std::ostream& os, ModuleEvent::Type eventType); +US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const ModuleEvent& event); /** @}*/ +US_END_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif // USMODULEEVENT_H diff --git a/core/include/usModuleEventHook.h b/core/include/usModuleEventHook.h index b1b8898054..e86fd4b369 100644 --- a/core/include/usModuleEventHook.h +++ b/core/include/usModuleEventHook.h @@ -1,72 +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; /** * @ingroup MicroServices * * %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_Core_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/include/usModuleFindHook.h b/core/include/usModuleFindHook.h index 6d02b13a0f..ff02e1d699 100644 --- a/core/include/usModuleFindHook.h +++ b/core/include/usModuleFindHook.h @@ -1,73 +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; /** * @ingroup MicroServices * * %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_Core_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/include/usModuleImport.h b/core/include/usModuleImport.h index c10de0136a..d72acf0503 100644 --- a/core/include/usModuleImport.h +++ b/core/include/usModuleImport.h @@ -1,158 +1,93 @@ /*============================================================================= 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 USMODULEIMPORT_H #define USMODULEIMPORT_H #include #include US_BEGIN_NAMESPACE struct ModuleActivator; US_END_NAMESPACE /** * \ingroup MicroServices * - * \brief Import a static module. + * \brief Initialize a static module. * - * \param _import_module_libname The physical name of the module to import, without prefix or suffix. + * \param _module_name The name of the module to initialize. * - * This macro imports the static module named \c _import_module_libname. + * This macro initializes the static module named \c _module_name. * - * Inserting this macro into your application's source code will allow you to make use of - * a static module. Do not forget to list the imported module when calling the macro - * #US_LOAD_IMPORTED_MODULES and to actually link the static module to the importing - * executable or shared library. - * - * Example: - * \snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoLib - * - * \sa US_LOAD_IMPORTED_MODULES - * \sa \ref MicroServices_StaticModules - */ -#define US_IMPORT_MODULE(_import_module_libname) \ - extern "C" US_PREPEND_NAMESPACE(ModuleActivator)* _us_module_activator_instance_ ## _import_module_libname (); \ - void _dummy_reference_to_ ## _import_module_libname ## _activator() \ - { \ - _us_module_activator_instance_ ## _import_module_libname(); \ - } - -/** - * \ingroup MicroServices - * - * \brief Import a static module's resources. - * - * \param _import_module_libname The physical name of the module to import, without prefix or suffix. - * - * This macro imports the resources of the static module named \c _import_module_libname. - * - * Inserting this macro into your application's source code will allow you to make use of - * the resources embedded in a static module. Do not forget to list the imported module when - * calling the macro #US_LOAD_IMPORTED_MODULES and to actually link the static module to the - * importing executable or shared library. + * It the module provides an activator, use the #US_IMPORT_MODULE macro instead, + * to ensure that the activator is called. Do not forget to actually link + * the static module to the importing executable or shared library. * * \sa US_IMPORT_MODULE - * \sa US_LOAD_IMPORTED_MODULES + * \sa US_IMPORT_MODULE_RESOURCES * \sa \ref MicroServices_StaticModules */ -#define US_IMPORT_MODULE_RESOURCES(_import_module_libname) \ - extern "C" US_PREPEND_NAMESPACE(ModuleActivator)* _us_init_resources_ ## _import_module_libname (); \ - void _dummy_reference_to_ ## _import_module_libname ## _init_resources() \ +#define US_INITIALIZE_STATIC_MODULE(_module_name) \ + extern "C" void _us_import_module_initializer_ ## _module_name(); \ + struct StaticModuleInitializer_ ## _module_name \ { \ - _us_init_resources_ ## _import_module_libname(); \ - } + StaticModuleInitializer_ ## _module_name() \ + { \ + _us_import_module_initializer_ ## _module_name(); \ + } \ + }; \ + static StaticModuleInitializer_ ## _module_name _InitializeModule_ ## _module_name; /** * \ingroup MicroServices - * \def US_LOAD_IMPORTED_MODULES_INTO_MAIN(_static_modules) * - * \brief Import a list of static modules into an executable. + * \brief Import a static module. * - * \param _static_modules A space-deliminated list of physical module names, without prefix - * or suffix. + * \param _module_name The name of the module to import. * - * This macro ensures that the ModuleActivator::Load(ModuleContext*) function is called - * for each imported static module when the importing executable is loaded (if the static - * module provides an activator). If the static module provides embedded resources and - * the US_IMPORT_MODULE_RESOURCES macro was called, the resources will be made available - * through the importing module. + * This macro imports the static module named \c _module_name. * - * There must be exactly one call of this macro in the executable which is - * importing static modules. + * Inserting this macro into your application's source code will allow you to make use of + * a static module. It will initialize the static module and calls its + * ModuleActivator. It the module does not provide an activator, use the + * #US_INITIALIZE_STATIC_MODULE macro instead. Do not forget to actually link + * the static module to the importing executable or shared library. * * Example: * \snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoMain * - * \sa US_IMPORT_MODULE - * \sa US_LOAD_IMPORTED_MODULES - * \sa \ref MicroServices_StaticModules - */ - -#ifdef US_BUILD_SHARED_LIBS -#define US_LOAD_IMPORTED_MODULES_INTO_MAIN(_static_modules) \ - extern "C" US_ABI_EXPORT const char* _us_get_imported_modules_for_() \ - { \ - return #_static_modules; \ - } -#else -#define US_LOAD_IMPORTED_MODULES_INTO_MAIN(_static_modules) \ - extern "C" US_ABI_EXPORT const char* _us_get_imported_modules_for_CppMicroServices() \ - { \ - return #_static_modules; \ - } -#endif - -/** - * \ingroup MicroServices - * - * \brief Import a list of static modules into a shared library. - * - * \param _module_libname The physical name of the importing module, without prefix or suffix. - * \param _static_modules A space-deliminated list of physical module names, without prefix - * or suffix. - * - * This macro ensures that the ModuleActivator::Load(ModuleContext*) function is called - * for each imported static module when the importing shared library is loaded (if the static - * module provides an activator). If the static module provides embedded resources and - * the US_IMPORT_MODULE_RESOURCES macro was called, the resources will be made available - * through the importing module. - * - * There must be exactly one call of this macro in the shared library which is - * importing static modules. - * - * Example: - * \snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoLib - * - * \sa US_IMPORT_MODULE - * \sa US_LOAD_IMPORTED_MODULES_INTO_MAIN + * \sa US_INITIALIZE_STATIC_MODULE + * \sa US_IMPORT_MODULE_RESOURCES * \sa \ref MicroServices_StaticModules */ -#define US_LOAD_IMPORTED_MODULES(_module_libname, _static_modules) \ - extern "C" US_ABI_EXPORT const char* _us_get_imported_modules_for_ ## _module_libname () \ - { \ - return #_static_modules; \ +#define US_IMPORT_MODULE(_module_name) \ + US_INITIALIZE_STATIC_MODULE(_module_name) \ + extern "C" US_PREPEND_NAMESPACE(ModuleActivator)* _us_module_activator_instance_ ## _module_name (); \ + void _dummy_reference_to_ ## _module_name ## _activator() \ + { \ + _us_module_activator_instance_ ## _module_name(); \ } #endif // USMODULEREGISTRY_H diff --git a/core/include/usModuleInfo.h b/core/include/usModuleInfo.h index 0ca559bb45..e3ff629e56 100644 --- a/core/include/usModuleInfo.h +++ b/core/include/usModuleInfo.h @@ -1,77 +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 USMODULEINFO_H #define USMODULEINFO_H #include #include -#include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4251) #endif US_BEGIN_NAMESPACE struct ModuleActivator; /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. */ struct US_Core_EXPORT ModuleInfo { - ModuleInfo(const std::string& name, const std::string& libName); - - typedef ModuleActivator*(*ModuleActivatorHook)(void); - typedef int(*InitResourcesHook)(ModuleInfo*); - typedef const unsigned char* ModuleResourceData; + ModuleInfo(const std::string& name); std::string name; - std::string libName; - std::string location; - std::string autoLoadDir; - long id; - - ModuleActivatorHook activatorHook; - - // In case of statically linked (imported) modules, there could - // be more than one set of ModuleResourceData pointers. We aggregate - // all pointers here. - std::vector resourceData; - std::vector resourceNames; - std::vector resourceTree; }; US_END_NAMESPACE #ifdef _MSC_VER # pragma warning(pop) #endif #endif // USMODULEINFO_H diff --git a/core/include/usModuleInitialization.h b/core/include/usModuleInitialization.h index 9e0bc294ad..66f1fe9b3b 100644 --- a/core/include/usModuleInitialization.h +++ b/core/include/usModuleInitialization.h @@ -1,174 +1,120 @@ /*============================================================================= 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 US_MODULE_NAME +#error Missing US_MODULE_NAME preprocessor define +#endif + +#ifndef USMODULEINITIALIZATION_H +#define USMODULEINITIALIZATION_H + #include #include #include -#include -#include #include #include -#ifndef USMODULEINITIALIZATION_H -#define USMODULEINITIALIZATION_H /** * \ingroup MicroServices * * \brief Creates initialization code for a module. * * Each module which wants to register itself with the CppMicroServices library - * has to put a call to this macro in one of its source files. - * - * Example call for a module with file-name "libmylibname.so": - * \code - * US_INITIALIZE_MODULE("My Service Implementation", "mylibname") - * \endcode + * has to put a call to this macro in one of its source files. Further, the modules + * source files must be compiled with the \c US_MODULE_NAME pre-processor definition + * set to a module-unique identifier. * - * This will initialize the module for use with the CppMicroServices library, using a default - * auto-load directory named after the provided library name in \c _module_libname. + * Calling the \c US_INITIALIZE_MODULE macro will initialize the module for use with + * the CppMicroServices library, using a default auto-load directory named after the + * \c US_MODULE_NAME definition. * * \sa MicroServices_AutoLoading * * \remarks If you are using CMake, consider using the provided CMake macro * usFunctionGenerateModuleInit(). - * - * \param _module_name A human-readable name for the module. - * If you use this macro in a source file for an executable, the module name must - * be a valid C-identifier (no spaces etc.). - * \param _module_libname The physical name of the module, withou prefix or suffix. - * - * \note If you want to create initialization code for an executable, see - * #US_INITIALIZE_EXECUTABLE. */ -#define US_INITIALIZE_MODULE(_module_name, _module_libname) \ +#define US_INITIALIZE_MODULE \ US_BEGIN_NAMESPACE \ +namespace { \ \ /* Declare a file scoped ModuleInfo object */ \ -US_GLOBAL_STATIC_WITH_ARGS(ModuleInfo, moduleInfo, (_module_name, _module_libname)) \ +US_GLOBAL_STATIC_WITH_ARGS(ModuleInfo, moduleInfo, (US_STR(US_MODULE_NAME))) \ \ /* This class is used to statically initialize the library within the C++ Micro services \ library. It looks up a library specific C-style function returning an instance \ of the ModuleActivator interface. */ \ -class US_ABI_LOCAL ModuleInitializer { \ +class US_ABI_LOCAL US_CONCAT(ModuleInitializer_, US_MODULE_NAME) { \ \ public: \ \ - ModuleInitializer() \ + US_CONCAT(ModuleInitializer_, US_MODULE_NAME)() \ { \ ModuleInfo*(*moduleInfoPtr)() = moduleInfo; \ void* moduleInfoSym = NULL; \ std::memcpy(&moduleInfoSym, &moduleInfoPtr, sizeof(void*)); \ - std::string location = ModuleUtils::GetLibraryPath(moduleInfo()->libName, moduleInfoSym); \ - std::string activator_func = "_us_module_activator_instance_"; \ - if(moduleInfo()->libName.empty()) \ - { \ - activator_func.append(moduleInfo()->name); \ - } \ - else \ - { \ - activator_func.append(moduleInfo()->libName); \ - } \ - \ - moduleInfo()->location = location; \ - \ - if (moduleInfo()->libName.empty()) \ - { \ - /* make sure we retrieve symbols from the executable, if "libName" is empty */ \ - location.clear(); \ - } \ - void* activatorHookSym = ModuleUtils::GetSymbol(location, activator_func.c_str()); \ - std::memcpy(&moduleInfo()->activatorHook, &activatorHookSym, sizeof(void*)); \ + std::string location = ModuleUtils::GetLibraryPath(moduleInfoSym); \ + moduleInfoPtr()->location = location; \ \ Register(); \ } \ \ static void Register() \ { \ ModuleRegistry::Register(moduleInfo()); \ } \ \ - ~ModuleInitializer() \ + ~US_CONCAT(ModuleInitializer_, US_MODULE_NAME)() \ { \ ModuleRegistry::UnRegister(moduleInfo()); \ } \ \ }; \ \ -US_ABI_LOCAL ModuleContext* GetModuleContext() \ -{ \ - /* make sure the module is registered */ \ - if (moduleInfo()->id == 0) \ - { \ - ModuleInitializer::Register(); \ - } \ \ - return ModuleRegistry::GetModule(moduleInfo()->id)->GetModuleContext(); \ +US_DEFINE_MODULE_INITIALIZER \ } \ \ US_END_NAMESPACE \ \ -static US_PREPEND_NAMESPACE(ModuleInitializer) _InitializeModule; +/* A helper function which is called by the US_IMPORT_MODULE macro to initialize \ + static modules */ \ +extern "C" void US_ABI_LOCAL US_CONCAT(_us_import_module_initializer_, US_MODULE_NAME)() \ +{ \ + static US_PREPEND_NAMESPACE(US_CONCAT(ModuleInitializer_, US_MODULE_NAME)) US_CONCAT(_InitializeModule_, US_MODULE_NAME); \ +} -/** - * \ingroup MicroServices - * - * \brief Creates initialization code for an executable. - * - * Each executable which wants to register itself with the CppMicroServices library - * has to put a call to this macro in one of its source files. This ensures that the - * executable will get its own ModuleContext instance and can access the service registry. - * - * Example call for an executable: - * \code - * US_INITIALIZE_EXECUTABLE("my_executable") - * \endcode - * - * This will initialize the executable for use with the CppMicroServices library, using a default - * auto-load directory named after the provided executable id in \c _executable_id. - * - * \sa MicroServices_AutoLoading - * - * \remarks If you are using CMake, consider using the provided CMake macro - * usFunctionGenerateExecutableInit(). - * - * \param _executable_id A valid C identifier for the executable (no spaces etc.). - */ -#define US_INITIALIZE_EXECUTABLE(_executable_id) \ - US_INITIALIZE_MODULE(_executable_id, "") - -// If the CppMicroServices library was statically build, executables will share the -// initialization code with the CppMicroServices library. -#ifndef US_BUILD_SHARED_LIBS -#undef US_INITIALIZE_EXECUTABLE -#define US_INITIALIZE_EXECUTABLE(_a) -#endif +// Create a file-scoped static object for registering the module +// during static initialization of the shared library +#define US_DEFINE_MODULE_INITIALIZER \ +static US_CONCAT(ModuleInitializer_, US_MODULE_NAME) US_CONCAT(_InitializeModule_, US_MODULE_NAME); -// Static modules usually don't get initialization code. They are initialized within the -// module importing the static module(s). -#if defined(US_STATIC_MODULE) && !defined(US_FORCE_MODULE_INIT) -#undef US_INITIALIZE_MODULE -#define US_INITIALIZE_MODULE(_a,_b) +// Static modules don't create a file-scoped static object for initialization +// (it would be discarded during static linking anyway). The initialization code +// is triggered by the US_IMPORT_MODULE macro instead. +#if defined(US_STATIC_MODULE) +#undef US_DEFINE_MODULE_INITIALIZER +#define US_DEFINE_MODULE_INITIALIZER #endif #endif // USMODULEINITIALIZATION_H diff --git a/core/include/usModuleRegistry.h b/core/include/usModuleRegistry.h index 58a7e37a62..3ac2176804 100644 --- a/core/include/usModuleRegistry.h +++ b/core/include/usModuleRegistry.h @@ -1,92 +1,90 @@ /*============================================================================= 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_Core_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. * * @return A list which is filled with all known modules. */ static std::vector GetModules(); /** * Get all modules currently in module state LOADED. * * @return A list which is filled with all modules in * state LOADED */ static std::vector GetLoadedModules(); -private: + static void Register(ModuleInfo* info); - friend class ModuleInitializer; + static void UnRegister(const ModuleInfo* info); + +private: // disabled ModuleRegistry(); - static void Register(ModuleInfo* info); - - static void UnRegister(const ModuleInfo* info); - }; US_END_NAMESPACE #endif // USMODULEREGISTRY_H diff --git a/core/include/usModuleResource.h b/core/include/usModuleResource.h index c56f8138d0..b76a5bfd0b 100644 --- a/core/include/usModuleResource.h +++ b/core/include/usModuleResource.h @@ -1,309 +1,312 @@ /*============================================================================= 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 USMODULERESOURCE_H #define USMODULERESOURCE_H #include #include #include US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class ModuleResourcePrivate; -class ModuleResourceTree; +class ModuleResourceContainer; /** * \ingroup MicroServices * * Represents a resource (text file, image, etc.) embedded in a CppMicroServices module. * * A \c %ModuleResource object provides information about a resource (external file) which * was embedded into this module's shared library. \c %ModuleResource objects can be obtained * be calling Module#GetResource or Module#FindResources. * * Example code for retreiving a resource object and reading its contents: * \snippet uServices-resources/main.cpp 1 * * %ModuleResource objects have value semantics and copies are very inexpensive. * * \see ModuleResourceStream * \see \ref MicroServices_Resources */ class US_Core_EXPORT ModuleResource { private: typedef ModuleResourcePrivate* ModuleResource::*bool_type; public: /** * Creates in invalid %ModuleResource object. */ ModuleResource(); /** * Copy constructor. * @param resource The object to be copied. */ ModuleResource(const ModuleResource& resource); ~ModuleResource(); /** * Assignment operator. * * @param resource The %ModuleResource object which is assigned to this instance. * @return A reference to this %ModuleResource instance. */ ModuleResource& operator=(const ModuleResource& resource); /** * A less then operator using the full resource path as returned by * GetResourcePath() to define the ordering. * * @param resource The object to which this %ModuleResource object is compared to. * @return \c true if this %ModuleResource object is less then \c resource, * \c false otherwise. */ bool operator<(const ModuleResource& resource) const; /** * Equality operator for %ModuleResource objects. * * @param resource The object for testing equality. * @return \c true if this %ModuleResource object is equal to \c resource, i.e. * they are coming from the same module (shared or static) and have an equal * resource path, \c false otherwise. */ bool operator==(const ModuleResource& resource) const; /** * Inequality operator for %ModuleResource objects. * * @param resource The object for testing inequality. * @return The result of !(*this == resource). */ bool operator!=(const ModuleResource& resource) const; /** * Tests this %ModuleResource object for validity. * * Invalid %ModuleResource objects are created by the default constructor or - * can be returned by the Module class if the resource path is not found. If a - * module from which %ModuleResource objects have been obtained is un-loaded, - * these objects become invalid. + * can be returned by the Module class if the resource path is not found. * * @return \c true if this %ModuleReource object is valid and can safely be used, * \c false otherwise. */ bool IsValid() const; - /** - * Returns \c true if the resource represents a file and the resource data - * is in a compressed format, \c false otherwise. - * - * @return \c true if the resource data is compressed, \c false otherwise. - */ - bool IsCompressed() const; - /** * Boolean conversion operator using IsValid(). */ operator bool_type() const; /** * Returns the name of the resource, excluding the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string name = resource.GetName(); // name = "archive.tar.gz" * \endcode * * @return The resource name. * @see GetPath(), GetResourcePath() */ std::string GetName() const; /** * Returns the resource's path, without the file name. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); - * std::string path = resource.GetPath(); // path = "/data" + * std::string path = resource.GetPath(); // path = "/data/" * \endcode * + * The path with always begin and end with a forward slash. + * * @return The resource path without the name. * @see GetResourcePath(), GetName() and IsDir() */ std::string GetPath() const; /** * Returns the resource path including the file name. * * @return The resource path including the file name. * @see GetPath(), GetName() and IsDir() */ std::string GetResourcePath() const; /** * Returns the base name of the resource without the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string base = resource.GetBaseName(); // base = "archive" * \endcode * * @return The resource base name. * @see GetName(), GetSuffix(), GetCompleteSuffix() and GetCompleteBaseName() */ std::string GetBaseName() const; /** * Returns the complete base name of the resource without the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string base = resource.GetCompleteBaseName(); // base = "archive.tar" * \endcode * * @return The resource's complete base name. * @see GetName(), GetSuffix(), GetCompleteSuffix(), and GetBaseName() */ std::string GetCompleteBaseName() const; /** * Returns the suffix of the resource. * * The suffix consists of all characters in the resource name after (but not * including) the last '.'. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string suffix = resource.GetSuffix(); // suffix = "gz" * \endcode * * @return The resource name suffix. * @see GetName(), GetCompleteSuffix(), GetBaseName() and GetCompleteBaseName() */ std::string GetSuffix() const; /** * Returns the complete suffix of the resource. * * The suffix consists of all characters in the resource name after (but not * including) the first '.'. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string suffix = resource.GetCompleteSuffix(); // suffix = "tar.gz" * \endcode * * @return The resource name suffix. * @see GetName(), GetSuffix(), GetBaseName(), and GetCompleteBaseName() */ std::string GetCompleteSuffix() const; /** * Returns \c true if this %ModuleResource object points to a directory and thus * may have child resources. * * @return \c true if this object points to a directory, \c false otherwise. */ bool IsDir() const; /** * Returns \c true if this %ModuleResource object points to a file resource. * * @return \c true if this object points to an embedded file, \c false otherwise. */ bool IsFile() const; /** * Returns a list of resource names which are children of this object. * - * The returned names are relative to the path of this %ModuleResource object and - * may contain duplicates in case of modules which are statically linked into the - * module from which this object was retreived. + * The returned names are relative to the path of this %ModuleResource object + * and may contain file as well as directory entries. * * @return A list of child resource names. */ std::vector GetChildren() const; /** - * Returns the size of the raw embedded data for this %ModuleResource object. + * Returns a list of resource objects which are children of this object. + * + * The return ModuleResource objects may contain files as well as + * directory resources. + * + * @return A list of child resource objects. + */ + std::vector GetChildResources() const; + + /** + * Returns the size of the resource data for this %ModuleResource object. * * @return The resource data size. */ int GetSize() const; /** - * Returns a data pointer pointing to the raw data of this %ModuleResource object. - * If the resource is compressed the data returned is compressed and UncompressResourceData() - * must be used to access the data. If the resource represents a directory \c 0 is returned. + * Returns the last modified time of this resource in seconds from the epoch. * - * @return A raw pointer to the embedded data, or \c 0 if the resource is not a file resource. + * @return Last modified time of this resource. */ - const unsigned char* GetData() const; + time_t GetLastModified() const; private: - ModuleResource(const std::string& file, ModuleResourceTree* resourceTree, - const std::vector& resourceTrees); + ModuleResource(const std::string& file, const ModuleResourceContainer& resourceContainer); + ModuleResource(int index, const ModuleResourceContainer& resourceContainer); friend class Module; friend class ModulePrivate; + friend class ModuleResourceContainer; + friend class ModuleResourceStream; US_HASH_FUNCTION_FRIEND(ModuleResource); std::size_t Hash() const; + void* GetData() const; + ModuleResourcePrivate* d; }; US_END_NAMESPACE US_MSVC_POP_WARNING /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ModuleResource)& resource); US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ModuleResource)) return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USMODULERESOURCE_H diff --git a/core/include/usModuleResourceStream.h b/core/include/usModuleResourceStream.h index 047439e606..0598e7bb44 100644 --- a/core/include/usModuleResourceStream.h +++ b/core/include/usModuleResourceStream.h @@ -1,65 +1,70 @@ -/*=================================================================== +/*============================================================================= -BlueBerry Platform + Library: CppMicroServices -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + 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 -See LICENSE.txt or http://www.mitk.org for details. + 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 USMODULERESOURCESTREAM_H #define USMODULERESOURCESTREAM_H #include "usModuleResourceBuffer_p.h" #include US_BEGIN_NAMESPACE class ModuleResource; /** * \ingroup MicroServices * * An input stream class for ModuleResource objects. * * This class provides access to the resource data embedded in a module's * shared library via a STL input stream interface. * * \see ModuleResource for an example how to use this class. */ class US_Core_EXPORT ModuleResourceStream : private ModuleResourceBuffer, public std::istream { public: /** * Construct a %ModuleResourceStream object. * * @param resource The ModuleResource object for which an input stream * should be constructed. * @param mode The open mode of the stream. If \c std::ios_base::binary * is used, the resource data will be treated as binary data, otherwise * the data is interpreted as text data and the usual platform specific * end-of-line translations take place. */ ModuleResourceStream(const ModuleResource& resource, std::ios_base::openmode mode = std::ios_base::in); private: // purposely not implemented ModuleResourceStream(const ModuleResourceStream&); ModuleResourceStream& operator=(const ModuleResourceStream&); }; US_END_NAMESPACE #endif // USMODULERESOURCESTREAM_H diff --git a/core/include/usModuleSettings.h b/core/include/usModuleSettings.h index 5593c723f6..9be332bac8 100644 --- a/core/include/usModuleSettings.h +++ b/core/include/usModuleSettings.h @@ -1,153 +1,171 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULESETTINGS_H #define USMODULESETTINGS_H #include "usCoreConfig.h" #include #include US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * Query and set certain properties of the CppMicroServices library. * * The following environment variables influence the runtime behavior * of the CppMicroServices library: * * - \e US_DISABLE_AUTOLOADING If set, auto-loading of modules is disabled. * - \e US_AUTOLOAD_PATHS A ':' (Unix) or ';' (Windows) separated list of paths * from which modules should be auto-loaded. * * \remarks This class is thread safe. */ class US_Core_EXPORT ModuleSettings { public: typedef std::vector PathList; /** * Returns a special string which can be used as an argument for a * AddAutoLoadPath() call. * * When a module is loaded and this string has been added as a path * to the list of auto-load paths the CppMicroServices library will * auto-load all modules from the currently being loaded module's * auto-load directory. * * \return A string to be used in AddAutoLoadPath(). * * \remarks The returned string is contained in the default set of * auto-load paths, unless a new set of paths is given by a call to * SetAutoLoadPaths(). * * \sa MicroServices_AutoLoading * \sa US_INITIALIZE_MODULE */ static std::string CURRENT_MODULE_PATH(); /** * \return \c true if threading support has been configured into the * CppMicroServices library, \c false otherwise. */ static bool IsThreadingSupportEnabled(); /** * \return \c true if support for module auto-loading is enabled, * \c false otherwise. * * \remarks This method will always return \c false if support for auto-loading * has not been configured into the CppMicroServices library or if it has been * disabled by defining the US_DISABLE_AUTOLOADING environment variable. */ static bool IsAutoLoadingEnabled(); /** * Enable or disable auto-loading support. * * \param enable If \c true, enable auto-loading support, disable it otherwise. * * \remarks Calling this method will have no effect if support for * auto-loading has not been configured into the CppMicroServices library of it * it has been disabled by defining the US_DISABLE_AUTOLOADING envrionment variable. */ static void SetAutoLoadingEnabled(bool enable); /** * \return A list of paths in the file-system from which modules will be * auto-loaded. */ static PathList GetAutoLoadPaths(); /** * Set a list of paths in the file-system from which modules should be * auto-loaded. * @param paths A list of absolute file-system paths. */ static void SetAutoLoadPaths(const PathList& paths); /** * Add a path in the file-system to the list of paths from which modules * will be auto-loaded. * * @param path The additional absolute auto-load path in the file-system. */ static void AddAutoLoadPath(const std::string& path); /** * Set a local storage path for persistend module data. * * This path is used as a base directory for providing modules * with a storage path for writing persistent data. The callee * must ensure that the provided path exists and is writable. * * @see ModuleContext::GetDataFile(const std::string&) * * @param path An absolute path for writing persistent data. */ static void SetStoragePath(const std::string& path); /** * Get the absolute path for persistent data. The returned path * might be empty. If the path is non-empty, it is safe to assume * that the path exists and is writable. * * @return The absolute path to the persistent storage path. */ static std::string GetStoragePath(); + /** + * Set the logging level for log messages from CppMicroServices modules. + * + * Higher logging levels will discard messages with lower priority. + * E.g. a logging level of WarningMsg will discard all messages of + * type DebugMsg and InfoMsg. + * + * @param level The new logging level. + */ + static void SetLogLevel(MsgType level); + + /** + * Get the current logging level. + * + * @return The currently used logging level. + */ + static MsgType GetLogLevel(); + private: // purposely not implemented ModuleSettings(); ModuleSettings(const ModuleSettings&); ModuleSettings& operator=(const ModuleSettings&); }; US_END_NAMESPACE #endif // USMODULESETTINGS_H diff --git a/core/include/usServiceEvent.h b/core/include/usServiceEvent.h index 99e3aaec12..abcc2c3753 100644 --- a/core/include/usServiceEvent.h +++ b/core/include/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_Core_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(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_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceEvent::Type)& type); -US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceEvent)& event); +US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const ServiceEvent::Type& type); +US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const ServiceEvent& event); /** @}*/ +US_END_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif // USSERVICEEVENT_H diff --git a/core/include/usServiceEventListenerHook.h b/core/include/usServiceEventListenerHook.h index 127a7aaf19..128f1c4077 100644 --- a/core/include/usServiceEventListenerHook.h +++ b/core/include/usServiceEventListenerHook.h @@ -1,72 +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 USSERVICEEVENTLISTENERHOOK_H #define USSERVICEEVENTLISTENERHOOK_H #include "usServiceInterface.h" #include "usServiceListenerHook.h" #include "usShrinkableVector.h" #include "usShrinkableMap.h" US_BEGIN_NAMESPACE class ModuleContext; class ServiceEvent; /** * @ingroup MicroServices * * 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_Core_EXPORT ServiceEventListenerHook { typedef ShrinkableMap > ShrinkableMapType; 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, ShrinkableMapType& listeners) = 0; }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(us::ServiceEventListenerHook, "org.cppmicroservices.ServiceEventListenerHook/2.0.0") - #endif // USSERVICEEVENTLISTENERHOOK_H diff --git a/core/include/usServiceFindHook.h b/core/include/usServiceFindHook.h index a3940887f3..98378ed7b9 100644 --- a/core/include/usServiceFindHook.h +++ b/core/include/usServiceFindHook.h @@ -1,76 +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; /** * @ingroup MicroServices * * 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_Core_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/include/usServiceInterface.h b/core/include/usServiceInterface.h index b9638b9a28..351a70b97f 100644 --- a/core/include/usServiceInterface.h +++ b/core/include/usServiceInterface.h @@ -1,342 +1,343 @@ /*============================================================================= 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 +US_BEGIN_NAMESPACE +std::string GetDemangledName(const std::type_info& typeInfo); +US_END_NAMESPACE + /** * \ingroup MicroServices * - * Returns a unique id for a given type. + * Returns a unique id for a given type. By default, the + * demangled name of \c T is returned. * - * This template method is specialized in the macro - * #US_DECLARE_SERVICE_INTERFACE to return a unique id - * for each service interface. + * This template method may be specialized directly or be + * using the macro #US_DECLARE_SERVICE_INTERFACE to return + * a custom 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(); +template std::string us_service_interface_iid() +{ + return US_PREPEND_NAMESPACE(GetDemangledName)(typeid(T)); +} /// \cond -template<> inline const char* us_service_interface_iid() { return ""; } +template<> inline std::string us_service_interface_iid() { return std::string(); } /// \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. + * \brief Declare a service interface id. * * 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. + * The usage of this macro is optional and the service interface id which is automatically + * associated with any type is usually good enough (the demangled type name). However, care must + * be taken if the default id is compared with a string literal hard-coding a service interface + * id. E.g. the default id for templated types in the STL may differ between platforms. For + * user-defined types and templates the ids are typically consistent, but platform specific + * default template arguments will lead to different ids. + * + * 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>() \ + template<> inline std::string 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 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) + if (us_service_interface_iid().empty()) { 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/include/usServiceListenerHook.h b/core/include/usServiceListenerHook.h index 6fd3598e12..0c7c077621 100644 --- a/core/include/usServiceListenerHook.h +++ b/core/include/usServiceListenerHook.h @@ -1,176 +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; /** * @ingroup MicroServices * * 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_Core_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_Core_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/include/usServiceTracker.h b/core/include/usServiceTracker.h index ab0f7e77f5..5d2f794fd6 100644 --- a/core/include/usServiceTracker.h +++ b/core/include/usServiceTracker.h @@ -1,600 +1,597 @@ /*============================================================================= 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(); + //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(); + //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. + * assignable datatype. * @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 ServiceType; /// The type of the tracked object typedef typename TTT::TrackedType T; 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 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; /** * 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 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 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 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 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 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 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 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 ServiceReferenceType&, T) */ 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/include/usUncompressResourceData.h b/core/include/usUncompressResourceData.h deleted file mode 100644 index 131bf506a1..0000000000 --- a/core/include/usUncompressResourceData.h +++ /dev/null @@ -1,33 +0,0 @@ -/*============================================================================= - - 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 USUNCOMPRESSRESOURCEDATA_H -#define USUNCOMPRESSRESOURCEDATA_H - -#include "usCoreConfig.h" - -US_BEGIN_NAMESPACE - -US_Core_EXPORT unsigned char* UncompressResourceData(const unsigned char* data, std::size_t size, std::size_t* uncompressedSize); - -US_END_NAMESPACE - -#endif // USUNCOMPRESSRESOURCEDATA_H diff --git a/core/src/CMakeLists.txt b/core/src/CMakeLists.txt index b86061fd43..aeb9cf14bf 100644 --- a/core/src/CMakeLists.txt +++ b/core/src/CMakeLists.txt @@ -1,86 +1,84 @@ #----------------------------------------------------------------------------- # Source files #----------------------------------------------------------------------------- set(_srcs util/usAny.cpp - util/jsoncpp.cpp util/usLDAPProp.cpp util/usSharedLibrary.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/usModuleResourceContainer.cpp module/usModuleResourceStream.cpp - module/usModuleResourceTree.cpp module/usModuleSettings.cpp module/usModuleUtils.cpp module/usModuleVersion.cpp + + ../../third_party/jsoncpp.cpp + ../../third_party/miniz.c ) set(_private_headers util/usAtomicInt_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 - 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/usModuleResourceContainer_p.h module/usModuleUtils_p.h ) diff --git a/core/src/module/usCoreModuleActivator.cpp b/core/src/module/usCoreModuleActivator.cpp index 4dd03e8eba..cf49fd7966 100644 --- a/core/src/module/usCoreModuleActivator.cpp +++ b/core/src/module/usCoreModuleActivator.cpp @@ -1,47 +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 "usModule.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE class CoreModuleActivator : public ModuleActivator { void Load(ModuleContext* mc) { mc->GetModule()->d->coreCtx->Init(); } void Unload(ModuleContext* /*mc*/) { //mc->GetModule()->d->coreCtx->Uninit(); } }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(CppMicroServices, US_PREPEND_NAMESPACE(CoreModuleActivator)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(CoreModuleActivator)) diff --git a/core/src/module/usModule.cpp b/core/src/module/usModule.cpp index 77497b296b..976bd89666 100644 --- a/core/src/module/usModule.cpp +++ b/core/src/module/usModule.cpp @@ -1,316 +1,313 @@ /*============================================================================= 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" #include "usCoreConfig.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; } +const std::string&Module::PROP_AUTOLOADED_MODULES() +{ + static const std::string s("module.autoloaded_modules"); + 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 != 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; } } 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) + typedef ModuleActivator*(*ModuleActivatorHook)(void); + ModuleActivatorHook activatorHook = NULL; + + std::string activator_func = "_us_module_activator_instance_" + d->info.name; + void* activatorHookSym = ModuleUtils::GetSymbol(d->info, activator_func.c_str()); + std::memcpy(&activatorHook, &activatorHookSym, sizeof(void*)); + + d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADING, this)); + // try to get a ModuleActivator instance + + if (activatorHook) + { + try + { + d->moduleActivator = activatorHook(); + } + catch (...) { - try - { - d->moduleActivator = d->info.activatorHook(); - } - catch (...) - { - US_ERROR << "Creating the module activator of " << d->info.name << " failed"; - throw; - } - - d->moduleActivator->Load(d->moduleContext); + US_ERROR << "Creating the module activator of " << d->info.name << " failed"; + throw; } - d->StartStaticModules(); + // This method should be "noexcept" and by not catching exceptions + // here we semantically treat it that way since any exception during + // static initialization will either terminate the program or cause + // the dynamic loader to report an error. + d->moduleActivator->Load(d->moduleContext); + } #ifdef US_ENABLE_AUTOLOADING_SUPPORT - if (ModuleSettings::IsAutoLoadingEnabled()) + if (ModuleSettings::IsAutoLoadingEnabled()) + { + const std::vector loadedPaths = AutoLoadModules(d->info); + if (!loadedPaths.empty()) { - AutoLoadModules(d->info); + d->moduleManifest.SetValue(PROP_AUTOLOADED_MODULES(), Any(loadedPaths)); } + } #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; -// } + d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADED, this)); } 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 { this->Uninit(); } catch (...) {} throw; } 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()) + if (!d->resourceContainer.IsValid()) { 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; - } + ModuleResource result(path, d->resourceContainer); + 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->resourceContainer.IsValid()) { - 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; } + + std::string normalizedPath = path; + // add a leading and trailing slash + if (normalizedPath.empty()) normalizedPath.push_back('/'); + if (*normalizedPath.begin() != '/') normalizedPath = '/' + normalizedPath; + if (*normalizedPath.rbegin() != '/') normalizedPath.push_back('/'); + d->resourceContainer.FindNodes(d->info.name + normalizedPath, + filePattern.empty() ? "*" : filePattern, + recurse, result); 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/src/module/usModuleContext.cpp b/core/src/module/usModuleContext.cpp index 3f20f7ed21..8f4aa9c2b6 100644 --- a/core/src/module/usModuleContext.cpp +++ b/core/src/module/usModuleContext.cpp @@ -1,173 +1,196 @@ /*============================================================================= 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 "usModuleContext.h" #include "usModuleRegistry.h" #include "usModulePrivate.h" +#include "usModuleSettings.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistry_p.h" #include "usServiceReferenceBasePrivate.h" +#include + 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 d->module->coreCtx->moduleHooks.FilterModule(this, ModuleRegistry::GetModule(id)); } -Module*ModuleContext::GetModule(const std::string& name) +Module* ModuleContext::GetModule(const std::string& name) { 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); } std::string ModuleContext::GetDataFile(const std::string &filename) const { - if (d->module->storagePath.empty()) return std::string(); + // compute the module storage path +#ifdef US_PLATFORM_WINDOWS + static const char separator = '\\'; +#else + static const char separator = '/'; +#endif + + std::string baseStoragePath = ModuleSettings::GetStoragePath(); + if (baseStoragePath.empty()) return std::string(); + if (baseStoragePath != d->module->baseStoragePath) + { + d->module->baseStoragePath = baseStoragePath; + d->module->storagePath.clear(); + } + + if (d->module->storagePath.empty()) + { + char buf[50]; + sprintf(buf, "%ld", d->module->info.id); + d->module->storagePath = baseStoragePath + separator + buf + "_" + d->module->info.name + separator; + } return d->module->storagePath + filename; } US_END_NAMESPACE diff --git a/core/src/module/usModuleEvent.cpp b/core/src/module/usModuleEvent.cpp index bad71db5ad..abf57ccc38 100644 --- a/core/src/module/usModuleEvent.cpp +++ b/core/src/module/usModuleEvent.cpp @@ -1,121 +1,119 @@ /*============================================================================= 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 "usModuleEvent.h" #include "usModule.h" US_BEGIN_NAMESPACE class ModuleEventData : public SharedData { public: ModuleEventData(ModuleEvent::Type type, Module* module) : type(type), module(module) { } ModuleEventData(const ModuleEventData& other) : SharedData(other), type(other.type), module(other.module) { } const ModuleEvent::Type type; Module* const module; private: // purposely not implemented ModuleEventData& operator=(const ModuleEventData&); }; ModuleEvent::ModuleEvent() : d(0) { } ModuleEvent::~ModuleEvent() { } bool ModuleEvent::IsNull() const { return !d; } ModuleEvent::ModuleEvent(Type type, Module* module) : d(new ModuleEventData(type, module)) { } ModuleEvent::ModuleEvent(const ModuleEvent& other) : d(other.d) { } ModuleEvent& ModuleEvent::operator=(const ModuleEvent& other) { d = other.d; return *this; } Module* ModuleEvent::GetModule() const { return d->module; } ModuleEvent::Type ModuleEvent::GetType() const { return d->type; } -US_END_NAMESPACE - -US_USE_NAMESPACE - std::ostream& operator<<(std::ostream& os, ModuleEvent::Type eventType) { switch (eventType) { case ModuleEvent::LOADED: return os << "LOADED"; case ModuleEvent::UNLOADED: return os << "UNLOADED"; case ModuleEvent::LOADING: return os << "LOADING"; case ModuleEvent::UNLOADING: return os << "UNLOADING"; default: return os << "Unknown module event type (" << static_cast(eventType) << ")"; } } std::ostream& operator<<(std::ostream& os, const ModuleEvent& event) { if (event.IsNull()) return os << "NONE"; Module* m = event.GetModule(); os << event.GetType() << " #" << m->GetModuleId() << " (" << m->GetLocation() << ")"; return os; } + +US_END_NAMESPACE diff --git a/core/src/module/usModuleInfo.cpp b/core/src/module/usModuleInfo.cpp index 804c133c8a..90334976e5 100644 --- a/core/src/module/usModuleInfo.cpp +++ b/core/src/module/usModuleInfo.cpp @@ -1,34 +1,33 @@ /*============================================================================= 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 "usModuleInfo.h" US_BEGIN_NAMESPACE -ModuleInfo::ModuleInfo(const std::string& name, const std::string& libName) +ModuleInfo::ModuleInfo(const std::string& name) : name(name) - , libName(libName) , id(0) - , activatorHook(NULL) -{} +{ +} US_END_NAMESPACE diff --git a/core/src/module/usModuleManifest.cpp b/core/src/module/usModuleManifest.cpp index 7a2dde83c2..97260243bb 100644 --- a/core/src/module/usModuleManifest.cpp +++ b/core/src/module/usModuleManifest.cpp @@ -1,142 +1,154 @@ /*============================================================================= 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 "usModuleManifest_p.h" +#include "jsoncpp.h" + #include US_BEGIN_NAMESPACE +namespace { + + typedef std::map AnyMap; + typedef std::vector AnyVector; + + void ParseJsonObject(const Json::Value& jsonObject, AnyMap& anyMap); + void ParseJsonArray(const Json::Value& jsonArray, AnyVector& anyVector); + + Any ParseJsonValue(const Json::Value& jsonValue) + { + if (jsonValue.isObject()) + { + Any any = AnyMap(); + ParseJsonObject(jsonValue, ref_any_cast(any)); + return any; + } + else if (jsonValue.isArray()) + { + Any any = AnyVector(); + ParseJsonArray(jsonValue, ref_any_cast(any)); + return any; + } + else if (jsonValue.isString()) + { + return Any(jsonValue.asString()); + } + else if (jsonValue.isBool()) + { + return Any(jsonValue.asBool()); + } + else if (jsonValue.isDouble()) + { + return Any(jsonValue.asDouble()); + } + else if (jsonValue.isIntegral()) + { + return Any(jsonValue.asInt()); + } + + return Any(); + } + + void ParseJsonObject(const Json::Value& jsonObject, AnyMap& anyMap) + { + for (Json::Value::const_iterator it = jsonObject.begin(); + it != jsonObject.end(); ++it) + { + const Json::Value& jsonValue = *it; + Any anyValue = ParseJsonValue(jsonValue); + if (!anyValue.Empty()) + { + anyMap.insert(std::make_pair(it.memberName(), anyValue)); + } + } + } + + void ParseJsonArray(const Json::Value& jsonArray, AnyVector& anyVector) + { + for (Json::Value::const_iterator it = jsonArray.begin(); + it != jsonArray.end(); ++it) + { + const Json::Value& jsonValue = *it; + Any anyValue = ParseJsonValue(jsonValue); + if (!anyValue.Empty()) + { + anyVector.push_back(anyValue); + } + } + } + +} + ModuleManifest::ModuleManifest() { } void ModuleManifest::Parse(std::istream& is) { Json::Value root; Json::Reader jsonReader(Json::Features::strictMode()); if (!jsonReader.parse(is, root, false)) { throw std::runtime_error(jsonReader.getFormattedErrorMessages()); } if (!root.isObject()) { throw std::runtime_error("The Json root element must be an object."); } ParseJsonObject(root, m_Properties); } -Any ModuleManifest::ParseJsonValue(const Json::Value& jsonValue) -{ - if (jsonValue.isObject()) - { - Any any = AnyMap(); - ParseJsonObject(jsonValue, ref_any_cast(any)); - return any; - } - else if (jsonValue.isArray()) - { - Any any = AnyVector(); - ParseJsonArray(jsonValue, ref_any_cast(any)); - return any; - } - else if (jsonValue.isString()) - { - return Any(jsonValue.asString()); - } - else if (jsonValue.isBool()) - { - return Any(jsonValue.asBool()); - } - else if (jsonValue.isDouble()) - { - return Any(jsonValue.asDouble()); - } - else if (jsonValue.isIntegral()) - { - return Any(jsonValue.asInt()); - } - - return Any(); -} - -void ModuleManifest::ParseJsonObject(const Json::Value& jsonObject, std::map& anyMap) -{ - for (Json::Value::const_iterator it = jsonObject.begin(); - it != jsonObject.end(); ++it) - { - const Json::Value& jsonValue = *it; - Any anyValue = ParseJsonValue(jsonValue); - if (!anyValue.Empty()) - { - anyMap.insert(std::make_pair(it.memberName(), anyValue)); - } - } -} - -void ModuleManifest::ParseJsonArray(const Json::Value& jsonArray, ModuleManifest::AnyVector& anyVector) -{ - for (Json::Value::const_iterator it = jsonArray.begin(); - it != jsonArray.end(); ++it) - { - const Json::Value& jsonValue = *it; - Any anyValue = ParseJsonValue(jsonValue); - if (!anyValue.Empty()) - { - anyVector.push_back(anyValue); - } - } -} - bool ModuleManifest::Contains(const std::string& key) const { return m_Properties.count(key) > 0; } Any ModuleManifest::GetValue(const std::string& key) const { AnyMap::const_iterator iter = m_Properties.find(key); if (iter != m_Properties.end()) { return iter->second; } return Any(); } std::vector ModuleManifest::GetKeys() const { std::vector keys; for (AnyMap::const_iterator iter = m_Properties.begin(); iter != m_Properties.end(); ++iter) { keys.push_back(iter->first); } return keys; } void ModuleManifest::SetValue(const std::string& key, const Any& value) { m_Properties[key] = value; } US_END_NAMESPACE diff --git a/core/src/module/usModuleManifest_p.h b/core/src/module/usModuleManifest_p.h index 670094b070..71d54e7136 100644 --- a/core/src/module/usModuleManifest_p.h +++ b/core/src/module/usModuleManifest_p.h @@ -1,62 +1,54 @@ /*============================================================================= 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 USMODULEMANIFEST_P_H #define USMODULEMANIFEST_P_H #include "usAny.h" -#include "json_p.h" - US_BEGIN_NAMESPACE class ModuleManifest { public: ModuleManifest(); void Parse(std::istream& is); bool Contains(const std::string& key) const; Any GetValue(const std::string& key) const; std::vector GetKeys() const; void SetValue(const std::string& key, const Any& value); private: typedef std::map AnyMap; - typedef std::vector AnyVector; - - Any ParseJsonValue(const Json::Value& jsonValue); - - void ParseJsonObject(const Json::Value& jsonObject, AnyMap& anyMap); - void ParseJsonArray(const Json::Value& jsonArray, AnyVector& anyVector); AnyMap m_Properties; }; US_END_NAMESPACE #endif // USMODULEMANIFEST_P_H diff --git a/core/src/module/usModulePrivate.cpp b/core/src/module/usModulePrivate.cpp index 5bd101e306..1e00b80915 100644 --- a/core/src/module/usModulePrivate.cpp +++ b/core/src/module/usModulePrivate.cpp @@ -1,286 +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 "usModulePrivate.h" #include "usModule.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usModuleUtils_p.h" #include "usModuleSettings.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) + , resourceContainer(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()) + if (resourceContainer.IsValid()) { - manifestRes = ModuleResource("/manifest.json", resourceTreeIter->second, resourceTreePtrs); + ModuleResource manifestRes("/manifest.json", resourceContainer); 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)); - } - } - - // comput the module storage path -#ifdef US_PLATFORM_WINDOWS - static const char separator = '\\'; -#else - static const char separator = '/'; -#endif - - std::string baseStoragePath = ModuleSettings::GetStoragePath(); - if (!baseStoragePath.empty()) - { - char buf[50]; - sprintf(buf, "%ld", this->info.id); - storagePath = baseStoragePath + separator + buf + "_" + this->info.libName + separator; + this->info.autoLoadDir = this->info.name; + 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/src/module/usModulePrivate.h b/core/src/module/usModulePrivate.h index a292122154..7ef4ff773d 100644 --- a/core/src/module/usModulePrivate.h +++ b/core/src/module/usModulePrivate.h @@ -1,105 +1,97 @@ /*============================================================================= 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 USMODULEPRIVATE_H #define USMODULEPRIVATE_H #include #include #include "usModuleRegistry.h" #include "usModuleVersion.h" #include "usModuleInfo.h" #include "usModuleManifest_p.h" -#include "usModuleResourceTree_p.h" +#include "usModuleResourceContainer_p.h" #include "usAtomicInt_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModuleContext; struct ModuleActivator; /** * \ingroup MicroServices */ class ModulePrivate { public: /** * Construct a new module based on a ModuleInfo object. */ ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info); virtual ~ModulePrivate(); void RemoveModuleResources(); - void StartStaticModules(); - - void StopStaticModules(); - CoreModuleContext* const coreCtx; - std::vector staticModuleLibNames; - /** * Module version */ ModuleVersion version; ModuleInfo info; - std::vector resourceTreePtrs; - std::map mapLibNameToResourceTrees; + ModuleResourceContainer resourceContainer; /** * ModuleContext for the module */ ModuleContext* moduleContext; ModuleActivator* moduleActivator; ModuleManifest moduleManifest; + std::string baseStoragePath; std::string storagePath; Module* const q; private: - void InitializeResources(const std::string& location); - - std::list staticActivators; + void InitializeResources(); static AtomicInt idCounter; // purposely not implemented ModulePrivate(const ModulePrivate&); ModulePrivate& operator=(const ModulePrivate&); }; US_END_NAMESPACE #endif // USMODULEPRIVATE_H diff --git a/core/src/module/usModuleRegistry.cpp b/core/src/module/usModuleRegistry.cpp index f50d9fdac0..1865819e20 100644 --- a/core/src/module/usModuleRegistry.cpp +++ b/core/src/module/usModuleRegistry.cpp @@ -1,221 +1,224 @@ /*============================================================================= 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 "usModuleRegistry.h" #include "usModule.h" #include "usModuleInfo.h" #include "usModuleContext.h" #include "usModuleActivator.h" +#include "usModuleInitialization.h" #include "usCoreModuleContext_p.h" #include "usGetModuleContext.h" #include "usStaticInit_p.h" #include #include US_BEGIN_NAMESPACE -typedef US_UNORDERED_MAP_TYPE ModuleMap; +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(Mutex, modulesLock) /** * Lock for protecting the register count */ 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; { MutexLock lock(*modulesLock()); - module = modules()->operator[](info->id); + module = modules()->operator[](info->name); assert(module != 0); } module->Start(); } else { Module* module = 0; // check if the module is reloaded { MutexLock lock(*modulesLock()); ModuleMap* map = modules(); for (ModuleMap::const_iterator i = map->begin(); i != map->end(); ++i) { - if (i->second->GetLocation() == info->location) + if (i->second->GetLocation() == info->location && + i->second->GetName() == info->name) { module = i->second; info->id = module->GetModuleId(); } } } if (!module) { module = new Module(); countLock()->Lock(); info->id = ++regCount; + assert(info->id == 1 ? info->name == "CppMicroServices" : true); countLock()->Unlock(); module->Init(coreModuleContext(), info); MutexLock lock(*modulesLock()); ModuleMap* map = modules(); - map->insert(std::make_pair(info->id, module)); + map->insert(std::make_pair(info->name, 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) + if (info->id > 1) { - // Remove listeners from static modules if they have forgotten to do so - coreModuleContext()->listeners.RemoveAllListeners(GetModuleContext()); - - if (info->activatorHook) + Module* curr = 0; { - info->activatorHook()->Unload(0); + MutexLock lock(*modulesLock()); + curr = modules()->operator[](info->name); + assert(curr != 0); } - return; - } - - Module* curr = 0; - { - MutexLock lock(*modulesLock()); - curr = modules()->operator[](info->id); - assert(curr != 0); + curr->Stop(); } - - curr->Stop(); } Module* ModuleRegistry::GetModule(long id) { MutexLock lock(*modulesLock()); - ModuleMap::const_iterator iter = modules()->find(id); - if (iter != modules()->end()) + ModuleMap::const_iterator iter = modules()->begin(); + ModuleMap::const_iterator iterEnd = modules()->end(); + for (; iter != iterEnd; ++iter) { - return iter->second; + if (iter->second->GetModuleId() == id) + { + return iter->second; + } } return 0; } Module* ModuleRegistry::GetModule(const std::string& name) { MutexLock lock(*modulesLock()); - ModuleMap::const_iterator iter = modules()->begin(); - ModuleMap::const_iterator iterEnd = modules()->end(); - for (; iter != iterEnd; ++iter) + ModuleMap::const_iterator iter = modules()->find(name); + if (iter != modules()->end()) { - if (iter->second->GetName() == name) - { - return iter->second; - } + return iter->second; } - return 0; } std::vector ModuleRegistry::GetModules() { 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) { result.push_back(iter->second); } return result; } std::vector ModuleRegistry::GetLoadedModules() { 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()) { result.push_back(iter->second); } } return result; } +// Control the static initialization order for several core objects +struct StaticInitializationOrder +{ + StaticInitializationOrder() + { + ModuleSettings::GetLogLevel(); + modulesLock(); + countLock(); + modules(); + coreModuleContext(); + } +}; + +static StaticInitializationOrder _staticInitializationOrder; + US_END_NAMESPACE + +// We initialize the CppMicroService module after making sure +// that all other global statics have been initialized above +US_INITIALIZE_MODULE diff --git a/core/src/module/usModuleResource.cpp b/core/src/module/usModuleResource.cpp index 35cb0eb378..dd798238dc 100644 --- a/core/src/module/usModuleResource.cpp +++ b/core/src/module/usModuleResource.cpp @@ -1,271 +1,289 @@ /*============================================================================= 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 "usModuleResource.h" #include "usAtomicInt_p.h" -#include "usModuleResourceTree_p.h" +#include "usModuleResourceContainer_p.h" +#include "usModuleInfo.h" #include US_BEGIN_NAMESPACE class ModuleResourcePrivate { public: - ModuleResourcePrivate() - : associatedResourceTree(NULL) - , node(-1) - , size(0) - , data(NULL) - , isFile(false) - , isCompressed(false) + ModuleResourcePrivate(const ModuleResourceContainer* rc) + : resourceContainer(rc) , ref(1) {} - std::string fileName; - std::string path; - std::string filePath; + void InitFilePath(const std::string& file); - std::vector resourceTrees; - const ModuleResourceTree* associatedResourceTree; + const ModuleResourceContainer* const resourceContainer; - int node; - int32_t size; - const unsigned char* data; - unsigned char* uncompressedData; + ModuleResourceContainer::Stat stat; - mutable std::vector children; + std::string fileName; + std::string path; - bool isFile; - bool isCompressed; + mutable std::vector children; + mutable std::vector childNodes; /** * Reference count for implicitly shared private implementation. */ AtomicInt ref; }; -ModuleResource::ModuleResource() - : d(new ModuleResourcePrivate) -{ -} - -ModuleResource::ModuleResource(const ModuleResource &resource) - : d(resource.d) +void ModuleResourcePrivate::InitFilePath(const std::string& file) { - d->ref.Ref(); -} - -ModuleResource::ModuleResource(const std::string& _file, ModuleResourceTree* associatedResourceTree, - const std::vector& resourceTrees) - : d(new ModuleResourcePrivate) -{ - d->resourceTrees = resourceTrees; - d->associatedResourceTree = associatedResourceTree; - - std::string file = _file; - if (file.empty()) file = "/"; - if (file[0] != '/') file = std::string("/") + file; + std::string normalizedFile = file; + if (normalizedFile.empty() || normalizedFile[0] != '/') + { + normalizedFile = '/' + normalizedFile; + } - std::size_t index = file.find_last_of('/'); - if (index < file.size()-1) + std::string rawPath; + std::size_t index = normalizedFile.find_last_of('/'); + if (index == std::string::npos) + { + fileName = normalizedFile; + } + else if (index < normalizedFile.size()-1) + { + fileName = normalizedFile.substr(index+1); + rawPath = normalizedFile.substr(0,index+1); + } + else { - d->fileName = file.substr(index+1); + rawPath = normalizedFile; } - std::string rawPath = file.substr(0,index+1); // remove duplicate / std::string::value_type lastChar = 0; for (std::size_t i = 0; i < rawPath.size(); ++i) { if (rawPath[i] == '/' && lastChar == '/') { continue; } lastChar = rawPath[i]; - d->path.push_back(lastChar); + path.push_back(lastChar); } - - d->filePath = d->path + d->fileName; - - d->node = d->associatedResourceTree->FindNode(GetResourcePath()); - if (d->node != -1) + if (path.empty()) { - d->isFile = !d->associatedResourceTree->IsDir(d->node); - if (d->isFile) - { - d->data = d->associatedResourceTree->GetData(d->node, &d->size); - d->isCompressed = d->associatedResourceTree->IsCompressed(d->node); - } + path.push_back('/'); } } +ModuleResource::ModuleResource() + : d(new ModuleResourcePrivate(NULL)) +{ +} + +ModuleResource::ModuleResource(const ModuleResource &resource) + : d(resource.d) +{ + d->ref.Ref(); +} + +ModuleResource::ModuleResource(const std::string& file, const ModuleResourceContainer& resourceContainer) + : d(new ModuleResourcePrivate(&resourceContainer)) +{ + d->InitFilePath(file); + + d->stat.filePath = d->resourceContainer->GetModuleInfo()->name + d->path + d->fileName; + + d->resourceContainer->GetStat(d->stat); +} + +ModuleResource::ModuleResource(int index, const ModuleResourceContainer& resourceContainer) + : d(new ModuleResourcePrivate(&resourceContainer)) +{ + d->resourceContainer->GetStat(index, d->stat); + d->InitFilePath(d->stat.filePath.substr(d->resourceContainer->GetModuleInfo()->name.size())); +} + ModuleResource::~ModuleResource() { if (!d->ref.Deref()) delete d; } ModuleResource& ModuleResource::operator =(const ModuleResource& resource) { ModuleResourcePrivate* curr_d = d; d = resource.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } bool ModuleResource::operator <(const ModuleResource& resource) const { return this->GetResourcePath() < resource.GetResourcePath(); } bool ModuleResource::operator ==(const ModuleResource& resource) const { - return d->associatedResourceTree == resource.d->associatedResourceTree && + return d->resourceContainer == resource.d->resourceContainer && this->GetResourcePath() == resource.GetResourcePath(); } bool ModuleResource::operator !=(const ModuleResource &resource) const { return !(*this == resource); } bool ModuleResource::IsValid() const { - return d->associatedResourceTree && d->associatedResourceTree->IsValid() && d->node > -1; -} - -bool ModuleResource::IsCompressed() const -{ - return d->isCompressed; + return d->resourceContainer && d->resourceContainer->IsValid() && d->stat.index > -1; } ModuleResource::operator bool_type() const { return IsValid() ? &ModuleResource::d : NULL; } std::string ModuleResource::GetName() const { return d->fileName; } std::string ModuleResource::GetPath() const { return d->path; } std::string ModuleResource::GetResourcePath() const { - return d->filePath; + return d->path + d->fileName; } std::string ModuleResource::GetBaseName() const { return d->fileName.substr(0, d->fileName.find_first_of('.')); } std::string ModuleResource::GetCompleteBaseName() const { return d->fileName.substr(0, d->fileName.find_last_of('.')); } std::string ModuleResource::GetSuffix() const { std::size_t index = d->fileName.find_last_of('.'); return index < d->fileName.size()-1 ? d->fileName.substr(index+1) : std::string(""); } std::string ModuleResource::GetCompleteSuffix() const { std::size_t index = d->fileName.find_first_of('.'); return index < d->fileName.size()-1 ? d->fileName.substr(index+1) : std::string(""); } bool ModuleResource::IsDir() const { - return !d->isFile; + return d->stat.isDir; } bool ModuleResource::IsFile() const { - return d->isFile; + return !d->stat.isDir; } std::vector ModuleResource::GetChildren() const { - if (d->isFile || !IsValid()) return d->children; + if (!IsValid() || !IsDir()) return d->children; - if (!d->children.empty()) return d->children; - - bool indexPastAssociatedResTree = false; - for (std::size_t i = 0; i < d->resourceTrees.size(); ++i) + if (d->children.empty()) { - if (d->resourceTrees[i] == d->associatedResourceTree) - { - indexPastAssociatedResTree = true; - d->associatedResourceTree->GetChildren(d->node, d->children); - } - else if (indexPastAssociatedResTree) - { - int nodeIndex = d->resourceTrees[i]->FindNode(GetPath()); - if (nodeIndex > -1) - { - d->resourceTrees[i]->GetChildren(d->node, d->children); - } - } + d->resourceContainer->GetChildren(d->stat.filePath, true, + d->children, d->childNodes); } return d->children; } +std::vector ModuleResource::GetChildResources() const +{ + std::vector childResources; + + if (!IsValid() || !IsDir()) return childResources; + + if (d->childNodes.empty()) + { + d->resourceContainer->GetChildren(this->GetResourcePath(), true, + d->children, d->childNodes); + } + + for (std::vector::const_iterator iter = d->childNodes.begin(), + iterEnd = d->childNodes.end(); iter != iterEnd; ++iter) + { + childResources.push_back(ModuleResource(static_cast(*iter), *d->resourceContainer)); + } + return childResources; +} + int ModuleResource::GetSize() const { - return d->size; + return d->stat.uncompressedSize; } -const unsigned char* ModuleResource::GetData() const +time_t ModuleResource::GetLastModified() const { - if (!IsValid()) return NULL; - return d->data; + return d->stat.modifiedTime; } std::size_t ModuleResource::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; - return US_HASH_FUNCTION(std::string, this->GetResourcePath()); + return US_HASH_FUNCTION(std::string, d->resourceContainer->GetModuleInfo()->name + this->GetResourcePath()); +} + +void* ModuleResource::GetData() const +{ + if (!IsValid()) return NULL; + + void* data = d->resourceContainer->GetData(d->stat.index); + if (data == NULL) + { + US_WARN << "Error uncompressing resource data for " << this->GetResourcePath() << " from " + << d->resourceContainer->GetModuleInfo()->location; + } + return data; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ModuleResource& resource) { return os << resource.GetResourcePath(); } diff --git a/core/src/module/usModuleResourceBuffer.cpp b/core/src/module/usModuleResourceBuffer.cpp index 1946ebbed4..8f189a2b00 100644 --- a/core/src/module/usModuleResourceBuffer.cpp +++ b/core/src/module/usModuleResourceBuffer.cpp @@ -1,303 +1,287 @@ -/*=================================================================== +/*============================================================================= -BlueBerry Platform + Library: CppMicroServices -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + 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 -See LICENSE.txt or http://www.mitk.org for details. + 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 "usModuleResourceBuffer_p.h" -#include "usUncompressResourceData.h" #include "us_stdint.h" #include #include +#include #ifdef US_PLATFORM_WINDOWS #define DATA_NEEDS_NEWLINE_CONVERSION 1 #undef REMOVE_LAST_NEWLINE_IN_TEXT_MODE #else #undef DATA_NEEDS_NEWLINE_CONVERSION #define REMOVE_LAST_NEWLINE_IN_TEXT_MODE 1 #endif US_BEGIN_NAMESPACE class ModuleResourceBufferPrivate { public: - ModuleResourceBufferPrivate(const char* begin, std::size_t size, std::ios_base::openmode mode) + ModuleResourceBufferPrivate(void* data, std::size_t size, const char* begin, std::ios_base::openmode mode) : begin(begin) , end(begin + size) , current(begin) , mode(mode) - #ifdef US_ENABLE_RESOURCE_COMPRESSION - , uncompressedData(NULL) - #endif + , uncompressedData(reinterpret_cast(data)) #ifdef DATA_NEEDS_NEWLINE_CONVERSION , pos(0) #endif { } ~ModuleResourceBufferPrivate() { -#ifdef US_ENABLE_RESOURCE_COMPRESSION - delete[] uncompressedData; -#endif + free(uncompressedData); } const char* const begin; const char* const end; const char* current; const std::ios_base::openmode mode; -#ifdef US_ENABLE_RESOURCE_COMPRESSION - const unsigned char* uncompressedData; -#endif + unsigned char* uncompressedData; #ifdef DATA_NEEDS_NEWLINE_CONVERSION // records the stream position ignoring CR characters std::streambuf::pos_type pos; #endif }; -ModuleResourceBuffer::ModuleResourceBuffer(const unsigned char* data, std::size_t _size, - std::ios_base::openmode mode, bool compressed) +ModuleResourceBuffer::ModuleResourceBuffer(void* data, std::size_t _size, + std::ios_base::openmode mode) : d(NULL) { assert(_size < static_cast(std::numeric_limits::max())); // assert(data != NULL); - if (compressed && _size) - { -#ifdef US_ENABLE_RESOURCE_COMPRESSION - data = UncompressResourceData(data, _size, &_size); -#else - assert(!"CppMicroServices built without support for resource compression"); -#endif - } - - const char* begin = reinterpret_cast(data); + char* begin = reinterpret_cast(data); std::size_t size = _size; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (data != NULL && !(mode & std::ios_base::binary) && begin[0] == '\r') { ++begin; --size; } #endif #ifdef REMOVE_LAST_NEWLINE_IN_TEXT_MODE if (data != NULL && !(mode & std::ios_base::binary) && begin[size-1] == '\n') { --size; } #endif - d = new ModuleResourceBufferPrivate(begin, size, mode); -#ifdef US_ENABLE_RESOURCE_COMPRESSION - if (compressed) - { - d->uncompressedData = data; - } -#endif + d = new ModuleResourceBufferPrivate(data, size, begin, mode); } ModuleResourceBuffer::~ModuleResourceBuffer() { delete d; } ModuleResourceBuffer::int_type ModuleResourceBuffer::underflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current + 1 == d->end) { return traits_type::eof(); } c = d->current[1]; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::uflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current++; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current == d->end) { return traits_type::eof(); } c = *d->current++; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current++); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::pbackfail(int_type ch) { int backOffset = -1; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (!(d->mode & std::ios_base::binary)) { while ((d->current - backOffset) >= d->begin && d->current[backOffset] == '\r') { --backOffset; } // d->begin always points to a character != '\r' } #endif if (d->current == d->begin || (ch != traits_type::eof() && ch != d->current[backOffset])) { return traits_type::eof(); } d->current += backOffset; return traits_type::to_int_type(*d->current); } std::streamsize ModuleResourceBuffer::showmanyc() { assert(d->current <= d->end); #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streamsize ssize = 0; std::size_t chunkSize = d->end - d->current; for (std::size_t i = 0; i < chunkSize; ++i) { if (d->current[i] != '\r') { ++ssize; } } return ssize; #else return d->end - d->current; #endif } std::streambuf::pos_type ModuleResourceBuffer::seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*which*/) { #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streambuf::off_type step = 1; if (way == std::ios_base::beg) { d->current = d->begin; } else if (way == std::ios_base::end) { d->current = d->end; step = -1; } if (!(d->mode & std::ios_base::binary)) { if (way == std::ios_base::beg) { d->pos = 0; } else if (way == std::ios_base::end) { d->current -= 1; } std::streambuf::off_type i = 0; // scan through off amount of characters excluding '\r' while (i != off) { if (*d->current != '\r') { i += step; d->pos += step; } d->current += step; } // adjust the position in case of a "backwards" seek if (way == std::ios_base::end) { // fix pointer from previous while loop d->current += 1; d->pos = 0; i = 0; const std::streampos currInternalPos = d->current - d->begin; while (i != currInternalPos) { if (d->begin[i] != '\r') { d->pos += 1; } ++i; } } } else { d->current += off; d->pos = d->current - d->begin; } return d->pos; #else if (way == std::ios_base::beg) { d->current = d->begin + off; return off; } else if (way == std::ios_base::cur) { d->current += off; return d->current - d->begin; } else { d->current = d->end + off; return d->current - d->begin; } #endif } std::streambuf::pos_type ModuleResourceBuffer::seekpos(std::streambuf::pos_type sp, std::ios_base::openmode /*which*/) { return this->seekoff(sp, std::ios_base::beg); } US_END_NAMESPACE diff --git a/core/src/module/usModuleResourceBuffer_p.h b/core/src/module/usModuleResourceBuffer_p.h index 0f09c86b33..f98614f8ae 100644 --- a/core/src/module/usModuleResourceBuffer_p.h +++ b/core/src/module/usModuleResourceBuffer_p.h @@ -1,63 +1,68 @@ -/*=================================================================== +/*============================================================================= -BlueBerry Platform + Library: CppMicroServices -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + 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 -See LICENSE.txt or http://www.mitk.org for details. + 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 USMODULERESOURCEBUFFER_P_H #define USMODULERESOURCEBUFFER_P_H #include #include US_BEGIN_NAMESPACE class ModuleResourceBufferPrivate; class US_Core_EXPORT ModuleResourceBuffer: public std::streambuf { public: - explicit ModuleResourceBuffer(const unsigned char* data, std::size_t size, - std::ios_base::openmode mode, bool compressed); + explicit ModuleResourceBuffer(void* data, std::size_t size, + std::ios_base::openmode mode); ~ModuleResourceBuffer(); private: int_type underflow(); int_type uflow(); int_type pbackfail(int_type ch); std::streamsize showmanyc(); pos_type seekoff (off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); pos_type seekpos (pos_type sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); // purposely not implemented ModuleResourceBuffer(const ModuleResourceBuffer&); ModuleResourceBuffer& operator=(const ModuleResourceBuffer&); private: ModuleResourceBufferPrivate* d; }; US_END_NAMESPACE #endif // USMODULERESOURCEBUFFER_P_H diff --git a/core/src/module/usModuleResourceContainer.cpp b/core/src/module/usModuleResourceContainer.cpp new file mode 100644 index 0000000000..087639e056 --- /dev/null +++ b/core/src/module/usModuleResourceContainer.cpp @@ -0,0 +1,224 @@ +/*============================================================================= + + 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 "usModuleResourceContainer_p.h" + +#include "usModuleInfo.h" +#include "usModuleUtils_p.h" +#include "usModuleResource.h" +#include "usLog_p.h" + +#include "miniz.h" + +#include +#include +#include +#include + +US_BEGIN_NAMESPACE + +struct ModuleResourceContainerPrivate +{ + ModuleResourceContainerPrivate(const ModuleInfo* moduleInfo) + : m_ModuleInfo(moduleInfo) + , m_IsValid(false) + , m_ZipArchive() + {} + + typedef std::pair NameIndexPair; + + struct PairComp + { + bool operator()(const NameIndexPair& p1, const NameIndexPair& p2) const + { + return p1.first < p2.first; + } + }; + + typedef std::set SetType; + + void InitSortedEntries() + { + if (m_SortedEntries.empty()) + { + mz_uint numFiles = mz_zip_reader_get_num_files(&m_ZipArchive); + for (mz_uint fileIndex = 0; fileIndex < numFiles; ++fileIndex) + { + char fileName[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + mz_zip_reader_get_filename(&m_ZipArchive, fileIndex, fileName, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE); + m_SortedEntries.insert(std::make_pair(std::string(fileName), fileIndex)); + } + } + } + + const ModuleInfo* m_ModuleInfo; + bool m_IsValid; + + mz_zip_archive m_ZipArchive; + + std::set m_SortedEntries; +}; + +ModuleResourceContainer::ModuleResourceContainer(const ModuleInfo* moduleInfo) + : d(new ModuleResourceContainerPrivate(moduleInfo)) +{ + if (mz_zip_reader_init_file(&d->m_ZipArchive, moduleInfo->location.c_str(), 0)) + { + d->m_IsValid = true; + } + else + { + US_DEBUG << "Could not init zip archive for module " << moduleInfo->name; + } +} + +ModuleResourceContainer::~ModuleResourceContainer() +{ + if (IsValid()) + { + mz_zip_reader_end(&d->m_ZipArchive); + } + delete d; +} + +bool ModuleResourceContainer::IsValid() const +{ + return d->m_IsValid; +} + +bool ModuleResourceContainer::GetStat(ModuleResourceContainer::Stat& stat) const +{ + if (IsValid()) + { + int fileIndex = mz_zip_reader_locate_file(&d->m_ZipArchive, stat.filePath.c_str(), NULL, 0); + if (fileIndex >= 0) + { + return GetStat(fileIndex, stat); + } + } + return false; +} + +bool ModuleResourceContainer::GetStat(int index, ModuleResourceContainer::Stat& stat) const +{ + if (IsValid()) + { + if (index >= 0) + { + mz_zip_archive_file_stat zipStat; + if (!mz_zip_reader_file_stat(&d->m_ZipArchive, index, &zipStat)) + { + return false; + } + stat.index = index; + stat.filePath = zipStat.m_filename; + stat.isDir = mz_zip_reader_is_file_a_directory(&d->m_ZipArchive, index) ? true : false; + stat.modifiedTime = zipStat.m_time; + // This will limit the size info from uint64 to uint32 on 32-bit + // architectures. We don't care because we assume resources > 2GB + // don't make sense to be embedded in a module anyway. + assert(zipStat.m_comp_size < INT_MAX); + assert(zipStat.m_uncomp_size < INT_MAX); + stat.uncompressedSize = static_cast(zipStat.m_uncomp_size); + return true; + } + } + return false; +} + +void* ModuleResourceContainer::GetData(int index) const +{ + return mz_zip_reader_extract_to_heap(&d->m_ZipArchive, index, NULL, 0); +} + +const ModuleInfo*ModuleResourceContainer::GetModuleInfo() const +{ + return d->m_ModuleInfo; +} + +void ModuleResourceContainer::GetChildren(const std::string& resourcePath, bool relativePaths, + std::vector& names, std::vector& indices) const +{ + d->InitSortedEntries(); + + ModuleResourceContainerPrivate::SetType::const_iterator iter = + d->m_SortedEntries.find(std::make_pair(resourcePath, 0)); + for (++iter; iter != d->m_SortedEntries.end(); ++iter) + { + if (resourcePath.size() > iter->first.size()) break; + if (iter->first.compare(0, resourcePath.size(), resourcePath) == 0) + { + std::size_t pos = iter->first.find_first_of('/', resourcePath.size()); + if (pos == std::string::npos || pos == iter->first.size()-1) + { + if (relativePaths) + { + names.push_back(iter->first.substr(resourcePath.size())); + } + else + { + names.push_back(iter->first); + } + indices.push_back(iter->second); + } + } + } +} + +void ModuleResourceContainer::FindNodes(const std::string& path, const std::string& filePattern, + bool recurse, std::vector& resources) const +{ + std::vector names; + std::vector indices; + + this->GetChildren(path, true, names, indices); + + for(std::size_t i = 0, s = names.size(); i < s; ++i) + { + if (*names[i].rbegin() == '/' && recurse) + { + this->FindNodes(path + names[i], filePattern, recurse, resources); + } + if (this->Matches(names[i], filePattern)) + { + resources.push_back(ModuleResource(indices[i], *this)); + } + } +} + +bool ModuleResourceContainer::Matches(const std::string& name, const std::string& filePattern) const +{ + // short-cut + if (filePattern == "*") return true; + + std::stringstream ss(filePattern); + std::string tok; + std::size_t pos = 0; + while(std::getline(ss, tok, '*')) + { + std::size_t index = name.find(tok, pos); + if (index == std::string::npos) return false; + pos = index + tok.size(); + } + return true; +} + +US_END_NAMESPACE diff --git a/core/src/module/usModuleResourceContainer_p.h b/core/src/module/usModuleResourceContainer_p.h new file mode 100644 index 0000000000..31827c52f4 --- /dev/null +++ b/core/src/module/usModuleResourceContainer_p.h @@ -0,0 +1,88 @@ +/*============================================================================= + + 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 USMODULERESOURCECONTAINER_P_H +#define USMODULERESOURCECONTAINER_P_H + +#include "usGlobalConfig.h" +#include "us_stdint.h" + +#include +#include +#include + +US_BEGIN_NAMESPACE + +struct ModuleInfo; +class ModuleResource; +struct ModuleResourceContainerPrivate; + +class ModuleResourceContainer +{ + +public: + + ModuleResourceContainer(const ModuleInfo* moduleInfo); + ~ModuleResourceContainer(); + + struct Stat + { + Stat() + : index(-1) + , uncompressedSize(0) + , modifiedTime(0) + , isDir(false) + {} + + std::string filePath; + int index; + int uncompressedSize; + time_t modifiedTime; + bool isDir; + }; + + bool IsValid() const; + + bool GetStat(Stat& stat) const; + bool GetStat(int index, Stat& stat) const; + + void* GetData(int index) const; + + const ModuleInfo* GetModuleInfo() const; + + void GetChildren(const std::string& resourcePath, bool relativePaths, + std::vector& names, std::vector& indices) const; + + void FindNodes(const std::string& path, const std::string& filePattern, + bool recurse, std::vector& resources) const; + +private: + + bool Matches(const std::string& name, const std::string& filePattern) const; + + ModuleResourceContainerPrivate* d; + +}; + + +US_END_NAMESPACE + +#endif // USMODULERESOURCECONTAINER_P_H diff --git a/core/src/module/usModuleResourceStream.cpp b/core/src/module/usModuleResourceStream.cpp index fd6fa8a448..b9970b15f2 100644 --- a/core/src/module/usModuleResourceStream.cpp +++ b/core/src/module/usModuleResourceStream.cpp @@ -1,35 +1,39 @@ -/*=================================================================== +/*============================================================================= -BlueBerry Platform + Library: CppMicroServices -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + 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 -See LICENSE.txt or http://www.mitk.org for details. + 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 "usModuleResourceStream.h" #include "usModuleResource.h" // 'this' used in base member initializer list US_MSVC_PUSH_DISABLE_WARNING(4355) US_BEGIN_NAMESPACE ModuleResourceStream::ModuleResourceStream(const ModuleResource& resource, std::ios_base::openmode mode) - : ModuleResourceBuffer(resource.GetData(), resource.GetSize(), mode | std::ios_base::in, - resource.IsCompressed()) + : ModuleResourceBuffer(resource.GetData(), resource.GetSize(), mode | std::ios_base::in) , std::istream(this) { } US_END_NAMESPACE US_MSVC_POP_WARNING diff --git a/core/src/module/usModuleResourceTree.cpp b/core/src/module/usModuleResourceTree.cpp deleted file mode 100644 index 6aa4351da5..0000000000 --- a/core/src/module/usModuleResourceTree.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/*============================================================================= - - 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 "usModuleResourceTree_p.h" - -#include "usUtils_p.h" -#include "us_stdint.h" - -#include -#include - -//#define DEBUG_RESOURCE_MATCH - -US_BEGIN_NAMESPACE - -US_Core_EXPORT bool RegisterResourceData(int, ModuleInfo* moduleInfo, - ModuleInfo::ModuleResourceData resourceTree, - ModuleInfo::ModuleResourceData resourceNames, - ModuleInfo::ModuleResourceData resourceData) -{ - moduleInfo->resourceTree.push_back(resourceTree); - moduleInfo->resourceNames.push_back(resourceNames); - moduleInfo->resourceData.push_back(resourceData); - return true; -} - - -ModuleResourceTree::ModuleResourceTree(ModuleInfo::ModuleResourceData resourceTree, - ModuleInfo::ModuleResourceData resourceNames, - ModuleInfo::ModuleResourceData resourceData) - : isValid(resourceTree && resourceNames && resourceData) - , tree(resourceTree) - , names(resourceNames) - , payloads(resourceData) -{ -} - -bool ModuleResourceTree::IsValid() const -{ - return isValid; -} - -void ModuleResourceTree::Invalidate() -{ - isValid = false; -} - -inline std::string ModuleResourceTree::GetName(int node) const -{ - if(!node) // root - return std::string(); - - const int offset = FindOffset(node); - - std::string ret; - int nameOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - const int16_t nameLength = (names[nameOffset+0] << 8) + - (names[nameOffset+1] << 0); - nameOffset += 2; // jump past name length - nameOffset += 4; // jump past hash - - ret.resize(nameLength); - for(int i = 0; i < nameLength; ++i) - { - ret[i] = names[nameOffset+i]; - } - return ret; -} - -int ModuleResourceTree::FindNode(const std::string& _path) const -{ - std::string path = _path.empty() ? "/" : _path; - -#ifdef DEBUG_RESOURCE_MATCH - US_DEBUG << "***" << " START " << path; -#endif - - if(path == "/") - return 0; - - // the root node is always first - int childCount = (tree[6] << 24) + (tree[7] << 16) + - (tree[8] << 8) + (tree[9] << 0); - int child = (tree[10] << 24) + (tree[11] << 16) + - (tree[12] << 8) + (tree[13] << 0); - - int node = -1; - - // split the full path into segments - std::vector segments; - { - std::stringstream ss(path); - std::string item; - while(std::getline(ss, item, '/')) - { - if (item.empty()) continue; - segments.push_back(item); - } - } - - //now iterate up the path hierarchy - for (std::size_t i = 0; i < segments.size() && childCount; ++i) - { - const std::string& segment = segments[i]; - -#ifdef DEBUG_RESOURCE_MATCH - US_DEBUG << " CHILDREN " << segment; - for(int j = 0; j < childCount; ++j) - { - US_DEBUG << " " << child+j << " :: " << GetName(child+j); - } -#endif - - // get the hash value for the current segment - const uint32_t currHash = static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string,segment)); - - // do a binary search for the hash - int l = 0; - int r = childCount-1; - int subNode = (l+r+1)/2; - while(r != l) - { - const uint32_t subNodeHash = GetHash(child+subNode); - if(currHash == subNodeHash) - break; - else if(currHash < subNodeHash) - r = subNode - 1; - else - l = subNode; - subNode = (l+r+1) / 2; - } - subNode += child; - - // now check fo collisions and do compare using equality - bool found = false; - if(GetHash(subNode) == currHash) - { - while(subNode > child && GetHash(subNode-1) == currHash) // walk up to include all collisions - --subNode; - for(; subNode < child+childCount && GetHash(subNode) == currHash; ++subNode) - { - // now test using name comparison - if(GetName(subNode) == segment) - { - found = true; - int offset = FindOffset(subNode); -#ifdef DEBUG_RESOURCE_MATCH - US_DEBUG << " TRY " << subNode << " " << GetName(subNode) << " " << offset; -#endif - offset += 4; // jump past name - - const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); - offset += 2; - - if(i == segments.size()-1) - { -#ifdef DEBUG_RESOURCE_MATCH - US_DEBUG << "!!!!" << " FINISHED " << subNode; -#endif - return subNode; - } - - // if we are not at the end of the resource path and the current - // segment is not a directory, return "not found" (this shouldn't happen). - if(!(flags & Directory)) - return -1; - - childCount = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - offset += 4; - child = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - break; - } - } - } - if(!found) - { - break; - } - } -#ifdef DEBUG_RESOURCE_MATCH - US_DEBUG << "***" << " FINISHED " << node; -#endif - return node; -} - -void ModuleResourceTree::FindNodes(const std::string& _path, - const std::string& _filePattern, - bool recurse, std::vector& result) -{ - std::string path = _path.empty() ? std::string("/") : _path; - if (path[path.size()-1] != '/') path.append("/"); - - std::string filePattern = _filePattern.empty() ? std::string("*") : _filePattern; - - int rootNode = FindNode(path); - if (rootNode > -1) - { - this->FindNodes(result, path, rootNode, filePattern, recurse); - } -} - -short ModuleResourceTree::GetFlags(int node) const -{ - if(node == -1) - return 0; - const int offset = FindOffset(node) + 4; //jump past name - return (tree[offset+0] << 8) + (tree[offset+1] << 0); -} - -void ModuleResourceTree::FindNodes(std::vector &result, const std::string& path, - const int rootNode, - const std::string &filePattern, bool recurse) -{ - int offset = FindOffset(rootNode) + 6; // jump past name and type - - const int childCount = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - offset += 4; - const int childNode = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - - for(int i = childNode; i < childNode+childCount; ++i) - { - const int childOffset = FindOffset(i); - const short childFlags = (tree[childOffset+4] << 8) + (tree[childOffset+5] << 0); - if (!(childFlags & Directory)) - { - const std::string name = GetName(i); - if (this->Matches(name, filePattern)) - { - result.push_back(path + name); - } - } - else if (recurse) - { - this->FindNodes(result, path + GetName(i) + "/", i, filePattern, recurse); - } - } -} - -uint32_t ModuleResourceTree::GetHash(int node) const -{ - if(!node) // root node - return 0; - - const int offset = FindOffset(node); - int nameOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - nameOffset += 2; // jump past name length - return (names[nameOffset+0] << 24) + (names[nameOffset+1] << 16) + - (names[nameOffset+2] << 8) + (names[nameOffset+3] << 0); -} - -bool ModuleResourceTree::Matches(const std::string &name, const std::string &filePattern) -{ - // short-cut - if (filePattern == "*") return true; - - std::stringstream ss(filePattern); - std::string tok; - std::size_t pos = 0; - while(std::getline(ss, tok, '*')) - { - std::size_t index = name.find(tok, pos); - if (index == std::string::npos) return false; - pos = index + tok.size(); - } - return true; -} - -const unsigned char* ModuleResourceTree::GetData(int node, int32_t* size) const -{ - if(node == -1) - { - *size = 0; - return 0; - } - int offset = FindOffset(node) + 4; // jump past name - - const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); - offset += 2; - - offset += 4; // jump past the padding - - if(!(flags & Directory)) - { - const int dataOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - const int32_t dataLength = (payloads[dataOffset+0] << 24) + (payloads[dataOffset+1] << 16) + - (payloads[dataOffset+2] << 8) + (payloads[dataOffset+3] << 0); - const unsigned char* ret = payloads+dataOffset+4; - *size = dataLength; - return ret; - } - *size = 0; - return 0; -} - -void ModuleResourceTree::GetChildren(int node, std::vector& ret) const -{ - if(node == -1) - return; - - int offset = FindOffset(node) + 4; // jump past name - - const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); - offset += 2; - - if(flags & Directory) - { - const int childCount = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - offset += 4; - const int childOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + - (tree[offset+2] << 8) + (tree[offset+3] << 0); - for(int i = childOffset; i < childOffset+childCount; ++i) - { - ret.push_back(GetName(i)); - } - } -} - -US_END_NAMESPACE diff --git a/core/src/module/usModuleResourceTree_p.h b/core/src/module/usModuleResourceTree_p.h deleted file mode 100644 index 6584ae4203..0000000000 --- a/core/src/module/usModuleResourceTree_p.h +++ /dev/null @@ -1,96 +0,0 @@ -/*============================================================================= - - 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 USMODULERESOURCETREE_H -#define USMODULERESOURCETREE_H - -#include "usModuleInfo.h" -#include "us_stdint.h" - -#include - -US_BEGIN_NAMESPACE - -struct ModuleInfo; - -/* - * This class represents the triple of data pointers - * (us_resource_data, us_resource_name, us_resource_tree) generate by - * the resource compiler. - * - * Each module owns zero or one such triple but in case of a statically - * linked (imported) module, the resource trees are "merged" together. - */ -class ModuleResourceTree -{ - -private: - - enum Flags - { - Directory = 0x01, - Compressed = 0x02 - }; - - bool isValid; - const unsigned char *tree, *names, *payloads; - - // Returns the offset in the us_resource_tree array for a given node index - inline int FindOffset(int node) const { return node * 14; } // sizeof each tree element - - std::string GetName(int node) const; - short GetFlags(int node) const; - - void FindNodes(std::vector& result, const std::string& path, - const int rootNode, - const std::string& filePattern, bool recurse); - - uint32_t GetHash(int node) const; - - bool Matches(const std::string& name, const std::string& filePattern); - -public: - - ModuleResourceTree(ModuleInfo::ModuleResourceData resourceTree, - ModuleInfo::ModuleResourceData resourceNames, - ModuleInfo::ModuleResourceData resourceData); - - bool IsValid() const; - void Invalidate(); - - // Returns an index enumerating the info entries in the us_resource_tree array for - // the given resource path. - int FindNode(const std::string& path) const; - - void FindNodes(const std::string& path, const std::string& filePattern, - bool recurse, std::vector& result); - - inline bool IsCompressed(int node) const {return GetFlags(node) & Compressed ? true : false; } - inline bool IsDir(int node) const { return GetFlags(node) & Directory ? true : false; } - const unsigned char* GetData(int node, int32_t *size) const; - void GetChildren(int node, std::vector& children) const; - -}; - -US_END_NAMESPACE - -#endif // USMODULERESOURCETREE_H diff --git a/core/src/module/usModuleSettings.cpp b/core/src/module/usModuleSettings.cpp index 9249e18273..98271a8693 100644 --- a/core/src/module/usModuleSettings.cpp +++ b/core/src/module/usModuleSettings.cpp @@ -1,175 +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. =============================================================================*/ #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 MultiThreaded<> { ModuleSettingsPrivate() : autoLoadPaths() #ifdef US_ENABLE_AUTOLOADING_SUPPORT , autoLoadingEnabled(true) #else , autoLoadingEnabled(false) #endif , autoLoadingDisabled(false) + , logLevel(DebugMsg) { 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; std::string storagePath; + MsgType logLevel; }; US_GLOBAL_STATIC(ModuleSettingsPrivate, moduleSettingsPrivate) bool ModuleSettings::IsThreadingSupportEnabled() { #ifdef US_ENABLE_THREADING_SUPPORT return true; #else return false; #endif } bool ModuleSettings::IsAutoLoadingEnabled() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); #ifdef US_ENABLE_AUTOLOADING_SUPPORT return !moduleSettingsPrivate()->autoLoadingDisabled && moduleSettingsPrivate()->autoLoadingEnabled; #else return false; #endif } void ModuleSettings::SetAutoLoadingEnabled(bool enable) { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->autoLoadingEnabled = enable; } ModuleSettings::PathList ModuleSettings::GetAutoLoadPaths() { US_UNUSED(ModuleSettingsPrivate::Lock(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); US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->autoLoadPaths.clear(); moduleSettingsPrivate()->autoLoadPaths.insert(normalizedPaths.begin(), normalizedPaths.end()); } void ModuleSettings::AddAutoLoadPath(const std::string& path) { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->autoLoadPaths.insert(RemoveTrailingPathSeparator(path)); } void ModuleSettings::SetStoragePath(const std::string &path) { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->storagePath = RemoveTrailingPathSeparator(path); } std::string ModuleSettings::GetStoragePath() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); return moduleSettingsPrivate()->storagePath; } +void ModuleSettings::SetLogLevel(MsgType level) +{ + US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); + moduleSettingsPrivate()->logLevel = level; +} + +MsgType ModuleSettings::GetLogLevel() +{ + US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); + return moduleSettingsPrivate()->logLevel; +} + US_END_NAMESPACE diff --git a/core/src/module/usModuleUtils.cpp b/core/src/module/usModuleUtils.cpp index aa7c7c8db9..e38e3a5a65 100644 --- a/core/src/module/usModuleUtils.cpp +++ b/core/src/module/usModuleUtils.cpp @@ -1,176 +1,171 @@ /*============================================================================= 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 #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) +std::string GetLibraryPath_impl(void* symbol) { Dl_info info; if (dladdr(symbol, &info)) { return info.dli_fname; } else { - US_DEBUG << "GetLibraryPath_impl() dladdr() failed: " << dlerror(); + US_DEBUG << "GetLibraryPath_impl() failed for address " << symbol; } return ""; } -void* GetSymbol_impl(const std::string& libName, const char* symbol) +void* GetSymbol_impl(const ModuleInfo& moduleInfo, const char* symbol) { // Clear the last error message dlerror(); void* selfHandle = 0; - if (libName.empty() || !sharedLibMode) + if (!sharedLibMode || moduleInfo.name == "main") { // Get the handle of the executable selfHandle = dlopen(0, RTLD_LAZY); } else { - selfHandle = dlopen(libName.c_str(), RTLD_LAZY); + selfHandle = dlopen(moduleInfo.location.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) +std::string GetLibraryPath_impl(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) + BOOL handleError = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + static_cast(symbol), &handle); + if (!handleError) { // 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) +void* GetSymbol_impl(const ModuleInfo& moduleInfo, const char* symbol) { HMODULE handle = NULL; - if (libName.empty() || !sharedLibMode) + if (!sharedLibMode || moduleInfo.name == "main") { handle = GetModuleHandle(NULL); } else { - handle = GetModuleHandle(libName.c_str()); + handle = GetModuleHandle(moduleInfo.location.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) +std::string GetLibraryPath_impl(void*) { return ""; } -void* GetSymbol_impl(const std::string& libName, const char* symbol) +void* GetSymbol_impl(const ModuleInfo&, const char* symbol) { return 0; } #endif -std::string ModuleUtils::GetLibraryPath(const std::string& libName, void* symbol) +std::string ModuleUtils::GetLibraryPath(void* symbol) { - return GetLibraryPath_impl(libName, symbol); + return GetLibraryPath_impl(symbol); } -void* ModuleUtils::GetSymbol(const std::string& libName, const char* symbol) +void* ModuleUtils::GetSymbol(const ModuleInfo& module, const char* symbol) { - return GetSymbol_impl(libName, symbol); + return GetSymbol_impl(module, symbol); } US_END_NAMESPACE diff --git a/core/src/module/usModuleUtils_p.h b/core/src/module/usModuleUtils_p.h index 4a55394e42..efd7d86b29 100644 --- a/core/src/module/usModuleUtils_p.h +++ b/core/src/module/usModuleUtils_p.h @@ -1,45 +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 USMODULEUTILS_H #define USMODULEUTILS_H #include #include +#define US_STR_(x) #x +#define US_STR(x) US_STR_(x) +#define US_CONCAT_(x,y) x ## y +#define US_CONCAT(x,y) US_CONCAT_(x,y) + US_BEGIN_NAMESPACE +struct ModuleInfo; + /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. */ struct US_Core_EXPORT ModuleUtils { - static std::string GetLibraryPath(const std::string& libName, void* symbol); + static std::string GetLibraryPath(void* symbol); - static void* GetSymbol(const std::string& libName, const char* symbol); + static void* GetSymbol(const ModuleInfo& module, const char* symbol); }; US_END_NAMESPACE #endif // USMODULEUTILS_H diff --git a/core/src/service/usLDAPExpr.cpp b/core/src/service/usLDAPExpr.cpp index 252d2c8b7c..b31f1bf9b8 100644 --- a/core/src/service/usLDAPExpr.cpp +++ b/core/src/service/usLDAPExpr.cpp @@ -1,823 +1,851 @@ /*============================================================================= 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 "usLDAPExpr_p.h" #include "usAny.h" #include "usServicePropertiesImpl_p.h" #include #include #include #include #include #include #include US_BEGIN_NAMESPACE -const int LDAPExpr::AND = 0; -const int LDAPExpr::OR = 1; -const int LDAPExpr::NOT = 2; -const int LDAPExpr::EQ = 4; -const int LDAPExpr::LE = 8; -const int LDAPExpr::GE = 16; -const int LDAPExpr::APPROX = 32; -const int LDAPExpr::COMPLEX = LDAPExpr::AND | LDAPExpr::OR | LDAPExpr::NOT; -const int LDAPExpr::SIMPLE = LDAPExpr::EQ | LDAPExpr::LE | LDAPExpr::GE | LDAPExpr::APPROX; - -const LDAPExpr::Byte LDAPExpr::WILDCARD = std::numeric_limits::max(); -const std::string LDAPExpr::WILDCARD_STRING = std::string(1, LDAPExpr::WILDCARD ); -const std::string LDAPExpr::NULLQ = "Null query"; -const std::string LDAPExpr::GARBAGE = "Trailing garbage"; -const std::string LDAPExpr::EOS = "Unexpected end of query"; -const std::string LDAPExpr::MALFORMED = "Malformed query"; -const std::string LDAPExpr::OPERATOR = "Undefined operator"; +namespace LDAPExprConstants { + +static LDAPExpr::Byte WILDCARD() +{ + static LDAPExpr::Byte b = std::numeric_limits::max(); + return b; +} + +static const std::string& WILDCARD_STRING() +{ + static std::string s(1, WILDCARD()); + return s; +} + +static const std::string& NULLQ() +{ + static std::string s = "Null query"; + return s; +} + +static const std::string& GARBAGE() +{ + static std::string s = "Trailing garbage"; + return s; +} + +static const std::string& EOS() +{ + static std::string s = "Unexpected end of query"; + return s; +} + +static const std::string& MALFORMED() +{ + static std::string s = "Malformed query"; + return s; +} + +static const std::string& OPERATOR() +{ + static std::string s = "Undefined operator"; + return s; +} + +} bool stricomp(const std::string::value_type& v1, const std::string::value_type& v2) { return ::tolower(v1) == ::tolower(v2); } //! Contains the current parser position and parsing utility methods. class LDAPExpr::ParseState { private: std::size_t m_pos; std::string m_str; public: ParseState(const std::string &str); //! Move m_pos to remove the prefix \a pre bool prefix(const std::string &pre); /** Peek a char at m_pos \note If index out of bounds, throw exception */ LDAPExpr::Byte peek(); //! Increment m_pos by n void skip(int n); //! return string from m_pos until the end std::string rest() const; //! Move m_pos until there's no spaces void skipWhite(); //! Get string until special chars. Move m_pos std::string getAttributeName(); //! Get string and convert * to WILDCARD std::string getAttributeValue(); //! Throw InvalidSyntaxException exception void error(const std::string &m) const; }; class LDAPExprData : public SharedData { public: LDAPExprData( int op, const std::vector& args ) : m_operator(op), m_args(args), m_attrName(), m_attrValue() { } LDAPExprData( int op, std::string attrName, const std::string& attrValue ) : m_operator(op), m_args(), m_attrName(attrName), m_attrValue(attrValue) { } LDAPExprData( const LDAPExprData& other ) : SharedData(other), m_operator(other.m_operator), m_args(other.m_args), m_attrName(other.m_attrName), m_attrValue(other.m_attrValue) { } int m_operator; std::vector m_args; std::string m_attrName; std::string m_attrValue; }; LDAPExpr::LDAPExpr() : d() { } LDAPExpr::LDAPExpr( const std::string &filter ) : d() { ParseState ps(filter); try { LDAPExpr expr = ParseExpr(ps); if (!Trim(ps.rest()).empty()) { - ps.error(GARBAGE + " '" + ps.rest() + "'"); + ps.error(LDAPExprConstants::GARBAGE() + " '" + ps.rest() + "'"); } d = expr.d; } catch (const std::out_of_range&) { - ps.error(EOS); + ps.error(LDAPExprConstants::EOS()); } } LDAPExpr::LDAPExpr( int op, const std::vector& args ) : d(new LDAPExprData(op, args)) { } LDAPExpr::LDAPExpr( int op, const std::string &attrName, const std::string &attrValue ) : d(new LDAPExprData(op, attrName, attrValue)) { } LDAPExpr::LDAPExpr( const LDAPExpr& other ) : d(other.d) { } LDAPExpr& LDAPExpr::operator=(const LDAPExpr& other) { d = other.d; return *this; } LDAPExpr::~LDAPExpr() { } std::string LDAPExpr::Trim(std::string str) { str.erase(0, str.find_first_not_of(' ')); str.erase(str.find_last_not_of(' ')+1); return str; } bool LDAPExpr::GetMatchedObjectClasses(ObjectClassSet& objClasses) const { if (d->m_operator == EQ) { if (d->m_attrName.length() == ServiceConstants::OBJECTCLASS().length() && std::equal(d->m_attrName.begin(), d->m_attrName.end(), ServiceConstants::OBJECTCLASS().begin(), stricomp) && - d->m_attrValue.find(WILDCARD) == std::string::npos) + d->m_attrValue.find(LDAPExprConstants::WILDCARD()) == std::string::npos) { objClasses.insert( d->m_attrValue ); return true; } return false; } else if (d->m_operator == AND) { bool result = false; for (std::size_t i = 0; i < d->m_args.size( ); i++) { LDAPExpr::ObjectClassSet r; if (d->m_args[i].GetMatchedObjectClasses(r)) { result = true; if (objClasses.empty()) { objClasses = r; } else { // if AND op and classes in several operands, // then only the intersection is possible. LDAPExpr::ObjectClassSet::iterator it1 = objClasses.begin(); LDAPExpr::ObjectClassSet::iterator it2 = r.begin(); while ( (it1 != objClasses.end()) && (it2 != r.end()) ) { if (*it1 < *it2) { objClasses.erase(it1++); } else if (*it2 < *it1) { ++it2; } else { // *it1 == *it2 ++it1; ++it2; } } // Anything left in set_1 from here on did not appear in set_2, // so we remove it. objClasses.erase(it1, objClasses.end()); } } } return result; } else if (d->m_operator == OR) { for (std::size_t i = 0; i < d->m_args.size( ); i++) { LDAPExpr::ObjectClassSet r; if (d->m_args[i].GetMatchedObjectClasses(r)) { std::copy(r.begin(), r.end(), std::inserter(objClasses, objClasses.begin())); } else { objClasses.clear(); return false; } } return true; } return false; } std::string LDAPExpr::ToLower(const std::string& str) { std::string lowerStr(str); std::transform(str.begin(), str.end(), lowerStr.begin(), ::tolower); return lowerStr; } bool LDAPExpr::IsSimple(const StringList& keywords, LocalCache& cache, bool matchCase ) const { if (cache.empty()) { cache.resize(keywords.size()); } if (d->m_operator == EQ) { StringList::const_iterator index; if ((index = std::find(keywords.begin(), keywords.end(), matchCase ? d->m_attrName : ToLower(d->m_attrName))) != keywords.end() && - d->m_attrValue.find_first_of(WILDCARD) == std::string::npos) + d->m_attrValue.find_first_of(LDAPExprConstants::WILDCARD()) == std::string::npos) { cache[index - keywords.begin()] = StringList(1, d->m_attrValue); return true; } } else if (d->m_operator == OR) { for (std::size_t i = 0; i < d->m_args.size( ); i++) { if (!d->m_args[i].IsSimple(keywords, cache, matchCase)) return false; } return true; } return false; } bool LDAPExpr::IsNull() const { return !d; } bool LDAPExpr::Query( const std::string& filter, const ServicePropertiesImpl& pd) { return LDAPExpr(filter).Evaluate(pd, false); } bool LDAPExpr::Evaluate( const ServicePropertiesImpl& p, bool matchCase ) const { if ((d->m_operator & SIMPLE) != 0) { // try case sensitive match first int index = p.FindCaseSensitive(d->m_attrName); if (index < 0 && !matchCase) index = p.Find(d->m_attrName); return index < 0 ? false : Compare(p.Value(index), d->m_operator, d->m_attrValue); } else { // (d->m_operator & COMPLEX) != 0 switch (d->m_operator) { case AND: for (std::size_t i = 0; i < d->m_args.size(); i++) { if (!d->m_args[i].Evaluate(p, matchCase)) return false; } return true; case OR: for (std::size_t i = 0; i < d->m_args.size(); i++) { if (d->m_args[i].Evaluate(p, matchCase)) return true; } return false; case NOT: return !d->m_args[0].Evaluate(p, matchCase); default: return false; // Cannot happen } } } bool LDAPExpr::Compare( const Any& obj, int op, const std::string& s ) const { if (obj.Empty()) return false; - if (op == EQ && s == WILDCARD_STRING) + if (op == EQ && s == LDAPExprConstants::WILDCARD_STRING()) return true; try { const std::type_info& objType = obj.Type(); if (objType == typeid(std::string)) { return CompareString(ref_any_cast(obj), op, s); } else if (objType == typeid(std::vector)) { const std::vector& list = ref_any_cast >(obj); for (std::size_t it = 0; it != list.size(); it++) { if (CompareString(list[it], op, s)) return true; } } else if (objType == typeid(std::list)) { const std::list& list = ref_any_cast >(obj); for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) { if (CompareString(*it, op, s)) return true; } } else if (objType == typeid(char)) { return CompareString(std::string(1, ref_any_cast(obj)), op, s); } else if (objType == typeid(bool)) { if (op==LE || op==GE) return false; std::string boolVal = any_cast(obj) ? "true" : "false"; return std::equal(s.begin(), s.end(), boolVal.begin(), stricomp); } else if (objType == typeid(short)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(long long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned char)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned short)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned long long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(float)) { errno = 0; char* endptr = 0; double sFloat = strtod(s.c_str(), &endptr); if ((errno == ERANGE && (sFloat == 0 || sFloat == HUGE_VAL || sFloat == -HUGE_VAL)) || (errno != 0 && sFloat == 0) || endptr == s.c_str()) { return false; } double floatVal = static_cast(any_cast(obj)); switch(op) { case LE: return floatVal <= sFloat; case GE: return floatVal >= sFloat; default: /*APPROX and EQ*/ double diff = floatVal - sFloat; return (diff < std::numeric_limits::epsilon()) && (diff > -std::numeric_limits::epsilon()); } } else if (objType == typeid(double)) { errno = 0; char* endptr = 0; double sDouble = strtod(s.c_str(), &endptr); if ((errno == ERANGE && (sDouble == 0 || sDouble == HUGE_VAL || sDouble == -HUGE_VAL)) || (errno != 0 && sDouble == 0) || endptr == s.c_str()) { return false; } double doubleVal = any_cast(obj); switch(op) { case LE: return doubleVal <= sDouble; case GE: return doubleVal >= sDouble; default: /*APPROX and EQ*/ double diff = doubleVal - sDouble; return (diff < std::numeric_limits::epsilon()) && (diff > -std::numeric_limits::epsilon()); } } else if (objType == typeid(std::vector)) { const std::vector& list = ref_any_cast >(obj); for (std::size_t it = 0; it != list.size(); it++) { if (Compare(list[it], op, s)) return true; } } } catch (...) { // This might happen if a std::string-to-datatype conversion fails // Just consider it a false match and ignore the exception } return false; } template bool LDAPExpr::CompareIntegralType(const Any& obj, const int op, const std::string& s) const { errno = 0; char* endptr = 0; long longInt = strtol(s.c_str(), &endptr, 10); if ((errno == ERANGE && (longInt == std::numeric_limits::max() || longInt == std::numeric_limits::min())) || (errno != 0 && longInt == 0) || endptr == s.c_str()) { return false; } T sInt = static_cast(longInt); T intVal = any_cast(obj); switch(op) { case LE: return intVal <= sInt; case GE: return intVal >= sInt; default: /*APPROX and EQ*/ return intVal == sInt; } } bool LDAPExpr::CompareString( const std::string& s1, int op, const std::string& s2 ) { switch(op) { case LE: return s1.compare(s2) <= 0; case GE: return s1.compare(s2) >= 0; case EQ: return PatSubstr(s1,s2); case APPROX: return FixupString(s2) == FixupString(s1); default: return false; } } std::string LDAPExpr::FixupString( const std::string& s ) { std::string sb; sb.reserve(s.size()); std::size_t len = s.length(); for(std::size_t i=0; im_operator std::vector v; do { v.push_back(ParseExpr(ps)); ps.skipWhite(); } while (ps.peek() == '('); std::size_t n = v.size(); if (!ps.prefix(")") || n == 0 || (op == NOT && n > 1)) - ps.error(MALFORMED); + ps.error(LDAPExprConstants::MALFORMED()); return LDAPExpr(op, v); } LDAPExpr LDAPExpr::ParseSimple( ParseState &ps ) { std::string attrName = ps.getAttributeName(); if (attrName.empty()) - ps.error(MALFORMED); + ps.error(LDAPExprConstants::MALFORMED()); int op = 0; if (ps.prefix("=")) op = EQ; else if (ps.prefix("<=")) op = LE; else if(ps.prefix(">=")) op = GE; else if(ps.prefix("~=")) op = APPROX; else { // System.out.println("undef op='" + ps.peek() + "'"); - ps.error(OPERATOR); // Does not return + ps.error(LDAPExprConstants::OPERATOR()); // Does not return } std::string attrValue = ps.getAttributeValue(); if (!ps.prefix(")")) - ps.error(MALFORMED); + ps.error(LDAPExprConstants::MALFORMED()); return LDAPExpr(op, attrName, attrValue); } const std::string LDAPExpr::ToString() const { std::string res; res.append("("); if ((d->m_operator & SIMPLE) != 0) { res.append(d->m_attrName); switch (d->m_operator) { case EQ: res.append("="); break; case LE: res.append("<="); break; case GE: res.append(">="); break; case APPROX: res.append("~="); break; } for (std::size_t i = 0; i < d->m_attrValue.length(); i++) { Byte c = d->m_attrValue.at(i); if (c == '(' || c == ')' || c == '*' || c == '\\') { res.append(1, '\\'); } - else if (c == WILDCARD) + else if (c == LDAPExprConstants::WILDCARD()) { c = '*'; } res.append(1, c); } } else { switch (d->m_operator) { case AND: res.append("&"); break; case OR: res.append("|"); break; case NOT: res.append("!"); break; } for (std::size_t i = 0; i < d->m_args.size(); i++) { res.append(d->m_args[i].ToString()); } } res.append(")"); return res; } LDAPExpr::ParseState::ParseState( const std::string& str ) : m_pos(0), m_str() { if (str.empty()) { - error(NULLQ); + error(LDAPExprConstants::NULLQ()); } m_str = str; } bool LDAPExpr::ParseState::prefix( const std::string& pre ) { std::string::iterator startIter = m_str.begin() + m_pos; if (!std::equal(pre.begin(), pre.end(), startIter)) return false; m_pos += pre.size(); return true; } char LDAPExpr::ParseState::peek() { if ( m_pos >= m_str.size() ) { throw std::out_of_range( "LDAPExpr" ); } return m_str.at(m_pos); } void LDAPExpr::ParseState::skip( int n ) { m_pos += n; } std::string LDAPExpr::ParseState::rest() const { return m_str.substr(m_pos); } void LDAPExpr::ParseState::skipWhite() { while (std::isspace(peek())) { m_pos++; } } std::string LDAPExpr::ParseState::getAttributeName() { std::size_t start = m_pos; std::size_t n = 0; bool nIsSet = false; for(;; m_pos++) { Byte c = peek(); if (c == '(' || c == ')' || c == '<' || c == '>' || c == '=' || c == '~') { break; } else if (!std::isspace(c)) { n = m_pos - start + 1; nIsSet = true; } } if (!nIsSet) { return std::string(); } return m_str.substr(start, n); } std::string LDAPExpr::ParseState::getAttributeValue() { std::string sb; bool exit = false; while( !exit ) { Byte c = peek( ); switch(c) { case '(': case ')': exit = true; break; case '*': - sb.append(1, WILDCARD); + sb.append(1, LDAPExprConstants::WILDCARD()); break; case '\\': sb.append(1, m_str.at(++m_pos)); break; default: sb.append(1, c); break; } if ( !exit ) { m_pos++; } } return sb; } void LDAPExpr::ParseState::error( const std::string &m ) const { std::string errorStr = m + ": " + (m_str.empty() ? "" : m_str.substr(m_pos)); throw std::invalid_argument(errorStr); } US_END_NAMESPACE diff --git a/core/src/service/usLDAPExpr_p.h b/core/src/service/usLDAPExpr_p.h index d1da7fac93..f9be03ffae 100644 --- a/core/src/service/usLDAPExpr_p.h +++ b/core/src/service/usLDAPExpr_p.h @@ -1,188 +1,178 @@ /*============================================================================= 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 USLDAPEXPR_H #define USLDAPEXPR_H #include #include "usSharedData.h" #include #include US_BEGIN_NAMESPACE class Any; class LDAPExprData; class ServicePropertiesImpl; /** * This class is not part of the public API. */ class LDAPExpr { public: - const static int AND; // = 0; - const static int OR; // = 1; - const static int NOT; // = 2; - const static int EQ; // = 4; - const static int LE; // = 8; - const static int GE; // = 16; - const static int APPROX; // = 32; - const static int COMPLEX; // = AND | OR | NOT; - const static int SIMPLE; // = EQ | LE | GE | APPROX; + const static int AND = 0; + const static int OR = 1; + const static int NOT = 2; + const static int EQ = 4; + const static int LE = 8; + const static int GE = 16; + const static int APPROX = 32; + const static int COMPLEX = AND | OR | NOT; + const static int SIMPLE = EQ | LE | GE | APPROX; typedef char Byte; typedef std::vector StringList; typedef std::vector LocalCache; typedef US_UNORDERED_SET_TYPE ObjectClassSet; /** * Creates an invalid LDAPExpr object. Use with care. * * @see IsNull() */ LDAPExpr(); LDAPExpr(const std::string& filter); LDAPExpr(const LDAPExpr& other); LDAPExpr& operator=(const LDAPExpr& other); ~LDAPExpr(); /** * Get object class set matched by this LDAP expression. This will not work * with wildcards and NOT expressions. If a set can not be determined return false. * * \param objClasses The set of matched classes will be added to objClasses. * \return If the set cannot be determined, false is returned, true otherwise. */ bool GetMatchedObjectClasses(ObjectClassSet& objClasses) const; /** * Checks if this LDAP expression is "simple". The definition of * a simple filter is: *

    *
  • (name=value) is simple if * name is a member of the provided keywords, * and value does not contain a wildcard character;
  • *
  • (| EXPR+ ) is simple if all EXPR * expressions are simple;
  • *
  • No other expressions are simple.
  • *
* If the filter is found to be simple, the cache is * filled with mappings from the provided keywords to lists * of attribute values. The keyword-value-pairs are the ones that * satisfy this expression, for the given keywords. * * @param keywords The keywords to look for. * @param cache An array (indexed by the keyword indexes) of lists to * fill in with values saturating this expression. * @return true if this expression is simple, * false otherwise. */ bool IsSimple( const StringList& keywords, LocalCache& cache, bool matchCase) const; /** * Returns true if this instance is invalid, i.e. it was * constructed using LDAPExpr(). * * @return true if the expression is invalid, * false otherwise. */ bool IsNull() const; //! static bool Query(const std::string& filter, const ServicePropertiesImpl& pd); //! Evaluate this LDAP filter. bool Evaluate(const ServicePropertiesImpl& p, bool matchCase) const; //! const std::string ToString() const; private: class ParseState; //! LDAPExpr(int op, const std::vector& args); //! LDAPExpr(int op, const std::string& attrName, const std::string& attrValue); //! static LDAPExpr ParseExpr(ParseState& ps); //! static LDAPExpr ParseSimple(ParseState& ps); static std::string Trim(std::string str); static std::string ToLower(const std::string& str); //! bool Compare(const Any& obj, int op, const std::string& s) const; //! template bool CompareIntegralType(const Any& obj, const int op, const std::string& s) const; //! static bool CompareString(const std::string& s1, int op, const std::string& s2); //! static std::string FixupString(const std::string &s); //! static bool PatSubstr(const std::string& s, const std::string& pat); //! static bool PatSubstr(const std::string& s, int si, const std::string& pat, int pi); - - const static Byte WILDCARD; // = 65535; - const static std::string WILDCARD_STRING;// = std::string( WILDCARD ); - - const static std::string NULLQ; // = "Null query"; - const static std::string GARBAGE; // = "Trailing garbage"; - const static std::string EOS; // = "Unexpected end of query"; - const static std::string MALFORMED; // = "Malformed query"; - const static std::string OPERATOR; // = "Undefined m_operator"; - //! Shared pointer SharedDataPointer d; }; US_END_NAMESPACE #endif // USLDAPEXPR_H diff --git a/core/src/service/usServiceEvent.cpp b/core/src/service/usServiceEvent.cpp index e1b88f64f4..2e351a4887 100644 --- a/core/src/service/usServiceEvent.cpp +++ b/core/src/service/usServiceEvent.cpp @@ -1,132 +1,130 @@ /*============================================================================= 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 "usServiceEvent.h" #include "usServiceProperties.h" US_BEGIN_NAMESPACE class ServiceEventData : public SharedData { public: ServiceEventData(const ServiceEvent::Type& type, const ServiceReferenceBase& reference) : type(type), reference(reference) { } ServiceEventData(const ServiceEventData& other) : SharedData(other), type(other.type), reference(other.reference) { } const ServiceEvent::Type type; const ServiceReferenceBase reference; private: // purposely not implemented ServiceEventData& operator=(const ServiceEventData&); }; ServiceEvent::ServiceEvent() : d(0) { } ServiceEvent::~ServiceEvent() { } bool ServiceEvent::IsNull() const { return !d; } ServiceEvent::ServiceEvent(Type type, const ServiceReferenceBase& reference) : d(new ServiceEventData(type, reference)) { } ServiceEvent::ServiceEvent(const ServiceEvent& other) : d(other.d) { } ServiceEvent& ServiceEvent::operator=(const ServiceEvent& other) { d = other.d; return *this; } ServiceReferenceU ServiceEvent::GetServiceReference() const { return d->reference; } ServiceEvent::Type ServiceEvent::GetType() const { return d->type; } -US_END_NAMESPACE - -US_USE_NAMESPACE - std::ostream& operator<<(std::ostream& os, const ServiceEvent::Type& type) { switch(type) { case ServiceEvent::MODIFIED: return os << "MODIFIED"; case ServiceEvent::MODIFIED_ENDMATCH: return os << "MODIFIED_ENDMATCH"; case ServiceEvent::REGISTERED: return os << "REGISTERED"; case ServiceEvent::UNREGISTERING: return os << "UNREGISTERING"; default: return os << "unknown service event type (" << static_cast(type) << ")"; } } std::ostream& operator<<(std::ostream& os, const ServiceEvent& event) { if (event.IsNull()) return os << "NONE"; os << event.GetType(); ServiceReferenceU sr = event.GetServiceReference(); if (sr) { // Some events will not have a service reference long int sid = any_cast(sr.GetProperty(ServiceConstants::SERVICE_ID())); os << " " << sid; Any classes = sr.GetProperty(ServiceConstants::OBJECTCLASS()); os << " objectClass=" << classes.ToString() << ")"; } return os; } + +US_END_NAMESPACE diff --git a/core/src/service/usServiceHooks.cpp b/core/src/service/usServiceHooks.cpp index a34d170a6f..c11d2b4ff4 100644 --- a/core/src/service/usServiceHooks.cpp +++ b/core/src/service/usServiceHooks.cpp @@ -1,283 +1,286 @@ /*============================================================================= 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() { US_UNUSED(Lock(this)); listenerHookTracker = new ServiceTracker(GetModuleContext(), this); listenerHookTracker->Open(); bOpen = true; } void ServiceHooks::Close() { US_UNUSED(Lock(this)); - listenerHookTracker->Close(); - delete listenerHookTracker; - listenerHookTracker = NULL; + if (listenerHookTracker) + { + listenerHookTracker->Close(); + delete listenerHookTracker; + listenerHookTracker = NULL; + } bOpen = false; } bool ServiceHooks::IsOpen() const { US_UNUSED(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/src/service/usServiceListenerHook_p.h b/core/src/service/usServiceListenerHook_p.h index dfc84dc011..083a693ec3 100644 --- a/core/src/service/usServiceListenerHook_p.h +++ b/core/src/service/usServiceListenerHook_p.h @@ -1,43 +1,48 @@ -/*=================================================================== +/*============================================================================= -BlueBerry Platform + Library: CppMicroServices -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + 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 -See LICENSE.txt or http://www.mitk.org for details. + 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_P_H #define USSERVICELISTENERHOOK_P_H #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); virtual ~ListenerInfoData(); ModuleContext* const mc; ServiceListenerEntry::ServiceListener listener; void* data; std::string filter; bool bRemoved; }; US_END_NAMESPACE #endif // USSERVICELISTENERHOOK_P_H diff --git a/core/src/service/usServiceListeners.cpp b/core/src/service/usServiceListeners.cpp index f86ee2ba3c..39217e79ea 100644 --- a/core/src/service/usServiceListeners.cpp +++ b/core/src/service/usServiceListeners.cpp @@ -1,329 +1,334 @@ /*============================================================================= 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" US_BEGIN_NAMESPACE const int ServiceListeners::OBJECTCLASS_IX = 0; const int ServiceListeners::SERVICE_ID_IX = 1; 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) { US_UNUSED(Lock(this)); ServiceListenerEntry sle(mc, listener, data, filter); 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, listener, data); US_UNUSED(Lock(this)); RemoveServiceListener_unlocked(entryToRemove); } void ServiceListeners::RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove) { ServiceListenerEntries::const_iterator it = serviceSet.find(entryToRemove); if (it != serviceSet.end()) { it->SetRemoved(true); coreCtx->serviceHooks.HandleServiceListenerUnreg(*it); RemoveFromCache(*it); serviceSet.erase(it); } } void ServiceListeners::AddModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data) { 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) { MutexLock lock(moduleListenerMapMutex); moduleListenerMap[mc].remove_if(std::bind1st(ModuleListenerCompare(), std::make_pair(listener, data))); } void ServiceListeners::ModuleChanged(const ModuleEvent& evt) { ModuleListenerMap filteredModuleListeners; coreCtx->moduleHooks.FilterModuleEventReceivers(evt, filteredModuleListeners); for(ModuleListenerMap::iterator iter = filteredModuleListeners.begin(), end = filteredModuleListeners.end(); iter != end; ++iter) { for (ModuleListenerMap::mapped_type::iterator iter2 = iter->second.begin(), end2 = iter->second.end(); iter2 != end2; ++iter2) { - (iter2->first)(evt); + try + { + (iter2->first)(evt); + } + catch (const std::exception& e) + { + US_WARN << "Module listener threw an exception: " << e.what(); + } } } } void ServiceListeners::RemoveAllListeners(ModuleContext* mc) { { US_UNUSED(Lock(this)); for (ServiceListenerEntries::iterator it = serviceSet.begin(); it != serviceSet.end(); ) { if (it->GetModuleContext() == mc) { RemoveFromCache(*it); serviceSet.erase(it++); } else { ++it; } } } { MutexLock lock(moduleListenerMapMutex); moduleListenerMap.erase(mc); } } void ServiceListeners::HooksModuleStopped(ModuleContext* mc) { US_UNUSED(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(ServiceListenerEntries& receivers, const ServiceEvent& evt, ServiceListenerEntries& matchBefore) { int n = 0; 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 + << " in " << l->GetModuleContext()->GetModule()->GetName() << " threw an exception!"; } } } //US_DEBUG << "Notified " << n << " listeners"; } void ServiceListeners::GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& set, bool lockProps) { US_UNUSED(Lock(this)); // Filter the original set of listeners ServiceListenerEntries receivers = serviceSet; coreCtx->serviceHooks.FilterServiceEventReceivers(evt, receivers); // Check complicated or empty listener filters for (std::list::const_iterator sse = complicatedListeners.begin(); sse != complicatedListeners.end(); ++sse) { if (receivers.count(*sse) == 0) continue; const LDAPExpr& ldapExpr = sse->GetLDAPExpr(); if (ldapExpr.IsNull() || 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 > (evt.GetServiceReference().d->GetProperty(ServiceConstants::OBJECTCLASS(), lockProps))); for (std::vector::const_iterator objClass = c.begin(); objClass != c.end(); ++objClass) { AddToSet(set, receivers, OBJECTCLASS_IX, *objClass); } long service_id = any_cast(evt.GetServiceReference().d->GetProperty(ServiceConstants::SERVICE_ID(), lockProps)); std::stringstream ss; ss << service_id; AddToSet(set, receivers, SERVICE_ID_IX, ss.str()); } std::vector ServiceListeners::GetListenerInfoCollection() const { US_UNUSED(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) { if (receivers.count(*entry)) { set.insert(*entry); } } } else { //US_DEBUG << hashedServiceKeys[cache_ix] << " matches none"; } } US_END_NAMESPACE diff --git a/core/src/service/usServiceReferenceBase.cpp b/core/src/service/usServiceReferenceBase.cpp index f785148c74..0a57413fa3 100644 --- a/core/src/service/usServiceReferenceBase.cpp +++ b/core/src/service/usServiceReferenceBase.cpp @@ -1,215 +1,221 @@ /*============================================================================= 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" +#include US_BEGIN_NAMESPACE 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 { MutexLock lock(d->registration->propsLock); return d->registration->properties.Value(key); } void ServiceReferenceBase::GetPropertyKeys(std::vector& keys) const { 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 { 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); + const Any anyR1 = GetProperty(ServiceConstants::SERVICE_RANKING()); + const Any anyR2 = reference.GetProperty(ServiceConstants::SERVICE_RANKING()); + assert(anyR1.Empty() || anyR1.Type() == typeid(int)); + assert(anyR2.Empty() || anyR2.Type() == typeid(int)); + const int r1 = anyR1.Empty() ? 0 : *any_cast(&anyR1); + const int r2 = anyR2.Empty() ? 0 : *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())); + const Any anyId1 = GetProperty(ServiceConstants::SERVICE_ID()); + const Any anyId2 = reference.GetProperty(ServiceConstants::SERVICE_ID()); + assert(anyId1.Type() == typeid(long int)); + assert(anyId2.Type() == typeid(long int)); + const long int id1 = *any_cast(&anyId1); + const long int id2 = *any_cast(&anyId2); // 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) { + assert(serviceRef.GetModule() != NULL); + 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/src/service/usServiceRegistry.cpp b/core/src/service/usServiceRegistry.cpp index c6df274ef1..e6e67d88ba 100644 --- a/core/src/service/usServiceRegistry.cpp +++ b/core/src/service/usServiceRegistry.cpp @@ -1,336 +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 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)); { 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; ServiceEvent registeredEvent(ServiceEvent::REGISTERED, r); module->coreCtx->listeners.GetMatchingServiceListeners(registeredEvent, listeners); module->coreCtx->listeners.ServiceChanged(listeners, registeredEvent); return res; } void ServiceRegistry::UpdateServiceRegistrationOrder(const ServiceRegistrationBase& sr, const std::vector& classes) { 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 { 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 { 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 { 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 { 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) { MutexLock lock(mutex); + assert(sr.d->properties.Value(ServiceConstants::OBJECTCLASS()).Type() == typeid(std::vector)); 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 { 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 { 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/src/service/usServiceTracker.tpp b/core/src/service/usServiceTracker.tpp index abc01853d3..e03355c012 100644 --- a/core/src/service/usServiceTracker.tpp +++ b/core/src/service/usServiceTracker.tpp @@ -1,463 +1,464 @@ /*============================================================================= 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 #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 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"); + std::string clazz = us_service_interface_iid(); + if (clazz.empty()) 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; { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); if (d->trackedService) { return; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::Open: " << d->filter; t = new _TrackedService(this, d->customizer); { US_UNUSED(typename _TrackedService::Lock(*t)); try { d->context->AddServiceListener(t, &_TrackedService::ServiceChanged, d->listenerFilter); 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; { US_UNUSED(typename _ServiceTrackerPrivate::Lock(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 */ { US_UNUSED(typename _TrackedService::Lock(outgoing)); outgoing->NotifyAll(); /* wake up any waiters */ } for(typename std::vector::const_iterator ref = references.begin(); ref != references.end(); ++ref) { outgoing->Untrack(*ref, ServiceEvent()); } if (d->DEBUG_OUTPUT) { US_UNUSED(typename _ServiceTrackerPrivate::Lock(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(); } { US_UNUSED(typename _TrackedService::Lock(t)); if (t->Size() == 0) { t->Wait(timeoutMillis); } } object = GetService(); } return object; } template std::vector::ServiceReferenceType> ServiceTracker::GetServiceReferences() const { std::vector refs; _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return refs; } { US_UNUSED(typename _TrackedService::Lock(t)); d->GetServiceReferences_unlocked(refs, t); } return refs; } template typename ServiceTracker::ServiceReferenceType ServiceTracker::GetServiceReference() const { ServiceReferenceType reference; { US_UNUSED(typename _ServiceTrackerPrivate::Lock(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::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(); 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(); 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; } } } { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); d->cachedReference = *selectedRef; return d->cachedReference; } } template typename ServiceTracker::T ServiceTracker::GetService(const ServiceReferenceType& reference) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return TTT::DefaultValue(); } { US_UNUSED(typename _TrackedService::Lock(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; } { US_UNUSED(typename _TrackedService::Lock(t)); std::vector references; d->GetServiceReferences_unlocked(references, t); 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 { { US_UNUSED(typename _ServiceTrackerPrivate::Lock(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 { ServiceReferenceType reference = GetServiceReference(); if (reference.GetModule() == 0) { return TTT::DefaultValue(); } { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); return d->cachedService = GetService(reference); } } catch (const ServiceException&) { return TTT::DefaultValue(); } } template 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; } { US_UNUSED(typename _TrackedService::Lock(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; } { US_UNUSED(typename _TrackedService::Lock(t)); return t->GetTrackingCount(); } } template void ServiceTracker::GetTracked(TrackingMap& map) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } { US_UNUSED(typename _TrackedService::Lock(t)); t->CopyEntries(map); } } template bool ServiceTracker::IsEmpty() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return true; } { US_UNUSED(typename _TrackedService::Lock(t)); return t->IsEmpty(); } } template typename ServiceTracker::T ServiceTracker::AddingService(const ServiceReferenceType& reference) { return TTT::ConvertToTrackedType(d->context->GetService(reference)); } template void ServiceTracker::ModifiedService(const ServiceReferenceType& /*reference*/, T /*service*/) { /* do nothing */ } template void ServiceTracker::RemovedService(const ServiceReferenceType& reference, T /*service*/) { d->context->UngetService(reference); } US_END_NAMESPACE diff --git a/core/src/util/tinfl.c b/core/src/util/tinfl.c deleted file mode 100644 index a17a156b6c..0000000000 --- a/core/src/util/tinfl.c +++ /dev/null @@ -1,592 +0,0 @@ -/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c) - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated May 20, 2011 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers. -*/ -#ifndef TINFL_HEADER_INCLUDED -#define TINFL_HEADER_INCLUDED - -#include - -typedef unsigned char mz_uint8; -typedef signed short mz_int16; -typedef unsigned short mz_uint16; -typedef unsigned int mz_uint32; -typedef unsigned int mz_uint; -typedef unsigned long long mz_uint64; - -#if defined(_M_IX86) || defined(_M_X64) -// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. -#define MINIZ_LITTLE_ENDIAN 1 -#endif - -#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) -// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) -#define MINIZ_HAS_64BIT_REGISTERS 1 -#endif - -// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. -#ifdef _MSC_VER - #define MZ_MACRO_END while (0, 0) -#else - #define MZ_MACRO_END while (0) -#endif - -// Decompression flags used by tinfl_decompress(). -// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. -// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. -// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). -// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. -enum -{ - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -// High level decompression functions: -// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. -// On return: -// Function returns a pointer to the decompressed data, or NULL on failure. -// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must free() the returned block when it's no longer needed. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. -// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. -// Returns 1 on success or 0 on failure. -typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; - -// Max size of LZ dictionary. -#define TINFL_LZ_DICT_SIZE 32768 - -// Return status. -typedef enum -{ - TINFL_STATUS_BAD_PARAM = -3, - TINFL_STATUS_ADLER32_MISMATCH = -2, - TINFL_STATUS_FAILED = -1, - TINFL_STATUS_DONE = 0, - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -// Initializes the decompressor to its initial state. -#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - -// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. -// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); - -// Internal/private bits follow. -enum -{ - TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} tinfl_huff_table; - -#if MINIZ_HAS_64BIT_REGISTERS - #define TINFL_USE_64BIT_BITBUF 1 -#endif - -#if TINFL_USE_64BIT_BITBUF - typedef mz_uint64 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (64) -#else - typedef mz_uint32 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -#endif // #ifdef TINFL_HEADER_INCLUDED - -// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) - -#ifndef TINFL_HEADER_FILE_ONLY - -#include - -// MZ_MALLOC, etc. are only used by the optional high-level helper functions. -#ifdef MINIZ_NO_MALLOC - #define MZ_MALLOC(x) NULL - #define MZ_FREE(x) x, ((void)0) - #define MZ_REALLOC(p, x) NULL -#else - #define MZ_MALLOC(x) malloc(x) - #define MZ_FREE(x) free(x) - #define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) -#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) - #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else - #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) - #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define TINFL_CR_BEGIN switch(r->m_state) { case 0: -#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END -#define TINFL_CR_FINISH } - -// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never -// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. -#define TINFL_GET_BYTE(state_index, c) do { \ - if (pIn_buf_cur >= pIn_buf_end) { \ - for ( ; ; ) { \ - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ - TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ - if (pIn_buf_cur < pIn_buf_end) { \ - c = *pIn_buf_cur++; \ - break; \ - } \ - } else { \ - c = 0; \ - break; \ - } \ - } \ - } else c = *pIn_buf_cur++; } MZ_MACRO_END - -#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END - -// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. -// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a -// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the -// bit buffer contains >=15 bits (deflate's max. Huffman code size). -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ - } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ - } while (num_bits < 15); - -// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read -// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully -// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. -// The slow path is only executed at the very end of the input buffer. -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ - int temp; mz_uint code_len, c; \ - if (num_bits < 15) { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } else { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else { \ - code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ - } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END - -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; - static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } - - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } - } - - do - { - TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } - while (pIn_buf_cur >= pIn_buf_end) - { - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) - { - TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); - } - else - { - TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); - } - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; - r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } - r->m_table_sizes[2] = 19; - } - for ( ; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; - cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) - { - mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for ( ; ; ) - { - mz_uint8 *pSrc; - for ( ; ; ) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } -#else - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - counter = sym2; bit_buf >>= code_len; num_bits -= code_len; - if (counter & 256) - break; - -#if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - bit_buf >>= code_len; num_bits -= code_len; - - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) break; - - num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } - - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - TINFL_CR_FINISH - -common_exit: - r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -// Higher level helper functions. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; - *pOut_len = 0; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - src_buf_ofs += src_buf_size; - *pOut_len += dst_buf_size; - if (status == TINFL_STATUS_DONE) break; - new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; - pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; - } - return pBuf; -} - -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); - status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -} - -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - int result = 0; - tinfl_decompressor decomp; - mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; - if (!pDict) - return TINFL_STATUS_FAILED; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); - in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) - break; - if (status != TINFL_STATUS_HAS_MORE_OUTPUT) - { - result = (status == TINFL_STATUS_DONE); - break; - } - dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); - } - MZ_FREE(pDict); - *pIn_buf_size = in_buf_ofs; - return result; -} - -#endif // #ifndef TINFL_HEADER_FILE_ONLY - -/* - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to -*/ diff --git a/core/src/util/usAny.cpp b/core/src/util/usAny.cpp index bac8be2580..723477b145 100644 --- a/core/src/util/usAny.cpp +++ b/core/src/util/usAny.cpp @@ -1,78 +1,46 @@ /*============================================================================= 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 "usAny.h" US_BEGIN_NAMESPACE -std::ostream& operator<< (std::ostream& os, const Any& any) +std::string any_value_to_string(const Any& any) { - return os << any.ToString(); + return any.ToString(); } -template -std::string container_to_string(Iterator i1, Iterator i2) +std::string any_value_to_json(const Any& val) { - std::stringstream ss; - ss << "("; - const Iterator begin = i1; - for ( ; i1 != i2; ++i1) - { - if (i1 == begin) ss << *i1; - else ss << "," << *i1; - } - ss << ")"; - return ss.str(); + return val.ToJSON(); } -std::string any_value_to_string(const std::vector& val) +std::string any_value_to_json(const std::string& val) { - return container_to_string(val.begin(), val.end()); + return '"' + val + '"'; } -std::string any_value_to_string(const std::list& val) +std::string any_value_to_json(bool val) { - return container_to_string(val.begin(), val.end()); -} - -std::string any_value_to_string(const std::vector& val) -{ - return container_to_string(val.begin(), val.end()); -} - -std::string any_value_to_string(const std::map& val) -{ - std::stringstream ss; - ss << "["; - typedef std::map::const_iterator Iterator; - Iterator i1 = val.begin(); - const Iterator begin = i1; - const Iterator end = val.end(); - for ( ; i1 != end; ++i1) - { - if (i1 == begin) ss << "\"" << i1->first << "\" => " << i1->second; - else ss << ", " << "\"" << i1->first << "\" => " << i1->second; - } - ss << "]"; - return ss.str(); + return val ? "true" : "false"; } US_END_NAMESPACE diff --git a/core/src/util/usLog_p.h b/core/src/util/usLog_p.h index bd65a8f9dd..ff9304d0b9 100644 --- a/core/src/util/usLog_p.h +++ b/core/src/util/usLog_p.h @@ -1,99 +1,94 @@ /*============================================================================= 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 #include US_BEGIN_NAMESPACE US_Core_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() + LogMsg(MsgType t, const char* file, int ln, const char* func) + : type(t), enabled(true), buffer() { buffer << "In " << func << " at " << file << ":" << ln << " : "; } + LogMsg() + : type(DebugMsg), enabled(false), buffer() + {} + + LogMsg(const LogMsg& other) + : type(other.type), enabled(other.enabled), buffer() + {} + ~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__) + #define US_DEBUG (US_PREPEND_NAMESPACE(ModuleSettings)::GetLogLevel() > US_PREPEND_NAMESPACE(DebugMsg) ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(DebugMsg), __FILE__, __LINE__, __FUNCTION__)) #else - #define US_DEBUG true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() + #define US_DEBUG true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() #endif #if !defined(US_NO_INFO_OUTPUT) - #define US_INFO US_PREPEND_NAMESPACE(LogMsg)(1, __FILE__, __LINE__, __FUNCTION__) + #define US_INFO (US_PREPEND_NAMESPACE(ModuleSettings)::GetLogLevel() > US_PREPEND_NAMESPACE(InfoMsg) ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(InfoMsg), __FILE__, __LINE__, __FUNCTION__)) #else - #define US_INFO true ? US_PREPEND_NAMESPACE(NoLogMsg)() : US_PREPEND_NAMESPACE(NoLogMsg)() + #define US_INFO true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() #endif #if !defined(US_NO_WARNING_OUTPUT) - #define US_WARN US_PREPEND_NAMESPACE(LogMsg)(2, __FILE__, __LINE__, __FUNCTION__) + #define US_WARN (US_PREPEND_NAMESPACE(ModuleSettings)::GetLogLevel() > US_PREPEND_NAMESPACE(WarningMsg) ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(WarningMsg), __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__) +#define US_ERROR US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(ErrorMsg), __FILE__, __LINE__, __FUNCTION__) #endif // USLOG_P_H diff --git a/core/src/util/usUncompressResourceData.c b/core/src/util/usUncompressResourceData.c deleted file mode 100644 index 310491ed82..0000000000 --- a/core/src/util/usUncompressResourceData.c +++ /dev/null @@ -1,59 +0,0 @@ -/*============================================================================= - - 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 "tinfl.c" - -#include - -static char us_uncompress_error_msg[256]; - -const char* us_uncompress_resource_error() -{ - return us_uncompress_error_msg; -} - -void us_uncompress_resource_data(const unsigned char* data, size_t size, - unsigned char* uncompressedData, size_t uncompressedSize) -{ - size_t bytesWritten = 0; - - memset(us_uncompress_error_msg, 0, sizeof(us_uncompress_error_msg)); - - if (data == NULL) - { - return; - } - - if (uncompressedData == NULL) - { - sprintf(us_uncompress_error_msg, "us_uncompress_resource_data: Buffer for uncomcpressing data is NULL"); - return; - } - - bytesWritten = tinfl_decompress_mem_to_mem(uncompressedData, uncompressedSize, - data, size, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if (bytesWritten != uncompressedSize) - { - sprintf(us_uncompress_error_msg, "us_uncompress_resource_data: tinfl_decompress_mem_to_mem failed"); - } -} diff --git a/core/src/util/usUncompressResourceData.cpp b/core/src/util/usUncompressResourceData.cpp deleted file mode 100644 index c7f9332ebf..0000000000 --- a/core/src/util/usUncompressResourceData.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/*============================================================================= - - 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 "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/src/util/usUtils.cpp b/core/src/util/usUtils.cpp index e7d8d05b9f..834761511d 100644 --- a/core/src/util/usUtils.cpp +++ b/core/src/util/usUtils.cpp @@ -1,280 +1,348 @@ /*============================================================================= 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 #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" + #include "dirent_win32.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); + if (handle == NULL) + { + US_WARN << dlerror(); + } 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()); + if (handle == NULL) + { + US_WARN << us::GetLastErrorStr(); + } 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::vector AutoLoadModulesFromPath(const std::string& absoluteBasePath, const std::string& subDir) { + std::vector loadedModules; + 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) + if (indexOfLastSeparator != std::string::npos) { 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; + US_DEBUG << "Auto-loading module " << libPath; if (!load_impl(libPath)) { - US_WARN << "Auto-loading of module " << libPath << " failed: " << GetLastErrorStr(); + US_WARN << "Auto-loading of module " << libPath << " failed."; + } + else + { + loadedModules.push_back(libPath); } } closedir(dir); } + return loadedModules; } -void AutoLoadModules(const ModuleInfo& moduleInfo) +std::vector AutoLoadModules(const ModuleInfo& moduleInfo) { + std::vector loadedModules; + if (moduleInfo.autoLoadDir.empty()) { - return; + return loadedModules; } 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); + std::vector paths = AutoLoadModulesFromPath(*i, moduleInfo.autoLoadDir); + loadedModules.insert(loadedModules.end(), paths.begin(), paths.end()); } + return loadedModules; } 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 } } +#ifdef US_HAVE_CXXABI_H +#include +#endif + +US_Core_EXPORT ::std::string GetDemangledName(const std::type_info& typeInfo) +{ + ::std::string result; +#ifdef US_HAVE_CXXABI_H + int status = 0; + char* demangled = abi::__cxa_demangle(typeInfo.name(), 0, 0, &status); + if (demangled && status == 0) + { + result = demangled; + free(demangled); + } +#elif defined(US_PLATFORM_WINDOWS) + const char* demangled = typeInfo.name(); + if (demangled != NULL) + { + result = demangled; + // remove "struct" qualifiers + std::size_t pos = 0; + while (pos != std::string::npos) + { + if ((pos = result.find("struct ", pos)) != std::string::npos) + { + result = result.substr(0, pos) + result.substr(pos + 7); + pos += 8; + } + } + // remove "class" qualifiers + pos = 0; + while (pos != std::string::npos) + { + if ((pos = result.find("class ", pos)) != std::string::npos) + { + result = result.substr(0, pos) + result.substr(pos + 6); + pos += 7; + } + } + } +#else + (void)typeInfo; +#endif + return result; +} + US_END_NAMESPACE diff --git a/core/src/util/usUtils_p.h b/core/src/util/usUtils_p.h index b097924d4d..778bca5291 100644 --- a/core/src/util/usUtils_p.h +++ b/core/src/util/usUtils_p.h @@ -1,52 +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. =============================================================================*/ #ifndef USUTILS_H #define USUTILS_H #include #include +#include //------------------------------------------------------------------- // Module auto-loading //------------------------------------------------------------------- US_BEGIN_NAMESPACE struct ModuleInfo; -void AutoLoadModules(const ModuleInfo& moduleInfo); +std::vector AutoLoadModules(const ModuleInfo& moduleInfo); US_END_NAMESPACE //------------------------------------------------------------------- // Error handling //------------------------------------------------------------------- US_BEGIN_NAMESPACE US_Core_EXPORT std::string GetLastErrorStr(); US_END_NAMESPACE #endif // USUTILS_H diff --git a/core/test/CMakeLists.txt b/core/test/CMakeLists.txt index 04a58b2da7..3f8320b956 100644 --- a/core/test/CMakeLists.txt +++ b/core/test/CMakeLists.txt @@ -1,93 +1,100 @@ #----------------------------------------------------------------------------- # Configure files, include dirs, etc. #----------------------------------------------------------------------------- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/usTestingConfig.h.in" "${PROJECT_BINARY_DIR}/include/usTestingConfig.h") include_directories(${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 + usAnyTest usLDAPFilterTest + usLogTest + usModuleHooksTest + usModuleManifestTest usModuleTest usModuleResourceTest usServiceFactoryTest usServiceHooksTest usServiceRegistryPerformanceTest usServiceRegistryTest usServiceTemplateTest usServiceTrackerTest usStaticModuleResourceTest usStaticModuleTest ) if(US_BUILD_SHARED_LIBS) list(APPEND _tests - usModuleHooksTest - usModuleManifestTest usServiceListenerTest usSharedLibraryTest ) if(US_ENABLE_AUTOLOADING_SUPPORT) list(APPEND _tests usModuleAutoLoadTest) endif() endif() set(_additional_srcs + usTestDriverActivator.cpp usTestManager.cpp usTestUtilModuleListener.cpp ) set(_test_driver us${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() +usFunctionGenerateModuleInit(_srcs) -add_executable(${_test_driver} ${_srcs} ${_additional_srcs}) +add_executable(${_test_driver} ${_srcs} ${_additional_srcs} ${_test_driver}_resources.cpp) +set_property(TARGET ${_test_driver} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=main) +set_property(TARGET ${_test_driver} PROPERTY US_MODULE_NAME main) if(NOT US_BUILD_SHARED_LIBS) + set_property(TARGET ${_test_driver} APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) target_link_libraries(${_test_driver} ${_us_test_module_libs}) endif() + target_link_libraries(${_test_driver} ${Core_TARGET}) if(UNIX AND NOT APPLE) target_link_libraries(${_test_driver} rt) endif() +# Add resources +usFunctionAddResources(TARGET ${_test_driver} + FILES usTestResource.txt manifest.json + ZIP_ARCHIVES ${Core_TARGET} ${_us_test_module_libs}) + # 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/test/modules/libA/usTestModuleA.cpp b/core/test/modules/libA/usTestModuleA.cpp index 11e145faec..ce8c625065 100644 --- a/core/test/modules/libA/usTestModuleA.cpp +++ b/core/test/modules/libA/usTestModuleA.cpp @@ -1,77 +1,77 @@ /*============================================================================= 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 "usTestModuleAService.h" #include #include #include US_BEGIN_NAMESPACE struct TestModuleA : public TestModuleAService { TestModuleA(ModuleContext* mc) { US_INFO << "Registering TestModuleAService"; sr = mc->RegisterService(this); } void Unregister() { if (sr) { sr.Unregister(); sr = 0; } } private: ServiceRegistration sr; }; class TestModuleAActivator : public ModuleActivator { public: TestModuleAActivator() : s(0) {} ~TestModuleAActivator() { delete s; } void Load(ModuleContext* context) { s = new TestModuleA(context); } void Unload(ModuleContext*) { } private: TestModuleA* s; }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleA, US_PREPEND_NAMESPACE(TestModuleAActivator)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleAActivator)) diff --git a/core/test/modules/libA/usTestModuleAService.h b/core/test/modules/libA/usTestModuleAService.h index 3ae29ec0bf..5aa89a6e6e 100644 --- a/core/test/modules/libA/usTestModuleAService.h +++ b/core/test/modules/libA/usTestModuleAService.h @@ -1,40 +1,38 @@ /*============================================================================= 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 USTESTMODULEASERVICE_H #define USTESTMODULEASERVICE_H #include #include US_BEGIN_NAMESPACE struct TestModuleAService { virtual ~TestModuleAService() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleAService), "org.cppmicroservices.TestModuleAService") - #endif // USTESTMODULEASERVICE_H diff --git a/core/test/modules/libA2/usTestModuleA2.cpp b/core/test/modules/libA2/usTestModuleA2.cpp index d2d03adeeb..dbc67185bb 100644 --- a/core/test/modules/libA2/usTestModuleA2.cpp +++ b/core/test/modules/libA2/usTestModuleA2.cpp @@ -1,76 +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. =============================================================================*/ #include "usTestModuleA2Service.h" #include #include US_BEGIN_NAMESPACE struct TestModuleA2 : public TestModuleA2Service { TestModuleA2(ModuleContext* mc) { US_INFO << "Registering TestModuleA2Service"; sr = mc->RegisterService(this); } void Unregister() { if (sr) { sr.Unregister(); } } private: ServiceRegistration sr; }; class TestModuleA2Activator : public ModuleActivator { public: TestModuleA2Activator() : s(0) {} ~TestModuleA2Activator() { delete s; } void Load(ModuleContext* context) { s = new TestModuleA2(context); } void Unload(ModuleContext* /*context*/) { s->Unregister(); } private: TestModuleA2* s; }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleA2, US_PREPEND_NAMESPACE(TestModuleA2Activator)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleA2Activator)) diff --git a/core/test/modules/libA2/usTestModuleA2Service.h b/core/test/modules/libA2/usTestModuleA2Service.h index 3160ed106b..93be47ab88 100644 --- a/core/test/modules/libA2/usTestModuleA2Service.h +++ b/core/test/modules/libA2/usTestModuleA2Service.h @@ -1,40 +1,38 @@ /*============================================================================= 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 USTESTMODULEA2SERVICE_H #define USTESTMODULEA2SERVICE_H #include #include US_BEGIN_NAMESPACE struct TestModuleA2Service { virtual ~TestModuleA2Service() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleA2Service), "org.us.TestModuleA2Service") - #endif // USTESTMODULEA2SERVICE_H diff --git a/core/test/modules/libBWithStatic/CMakeLists.txt b/core/test/modules/libBWithStatic/CMakeLists.txt index 30b9cf7be6..80faf30ef9 100644 --- a/core/test/modules/libBWithStatic/CMakeLists.txt +++ b/core/test/modules/libBWithStatic/CMakeLists.txt @@ -1,12 +1,13 @@ -usFunctionCreateTestModuleWithResources(TestModuleB - SOURCES usTestModuleB.cpp - RESOURCES dynamic.txt res.txt) - set(BUILD_SHARED_LIBS 0) usFunctionCreateTestModuleWithResources(TestModuleImportedByB SOURCES usTestModuleImportedByB.cpp RESOURCES static.txt res.txt - RESOURCES_ROOT resources_static) + RESOURCES_ROOT resources_static + SKIP_MODULE_LIST) -target_link_libraries(TestModuleB TestModuleImportedByB) +set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) +usFunctionCreateTestModuleWithResources(TestModuleB + SOURCES usTestModuleB.cpp + RESOURCES dynamic.txt res.txt + LINK_LIBRARIES TestModuleImportedByB) diff --git a/core/test/modules/libBWithStatic/usTestModuleB.cpp b/core/test/modules/libBWithStatic/usTestModuleB.cpp index cfe626f7d8..70b5befedf 100644 --- a/core/test/modules/libBWithStatic/usTestModuleB.cpp +++ b/core/test/modules/libBWithStatic/usTestModuleB.cpp @@ -1,70 +1,66 @@ /*============================================================================= 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 "usTestModuleBService.h" #include #include #include US_BEGIN_NAMESPACE struct TestModuleB : public TestModuleBService { TestModuleB(ModuleContext* mc) { US_INFO << "Registering TestModuleBService"; mc->RegisterService(this); } }; class TestModuleBActivator : public ModuleActivator { public: TestModuleBActivator() : s(0) {} ~TestModuleBActivator() { delete s; } void Load(ModuleContext* context) { s = new TestModuleB(context); } void Unload(ModuleContext*) { } private: TestModuleB* s; }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleB, US_PREPEND_NAMESPACE(TestModuleBActivator)) - +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleBActivator)) US_IMPORT_MODULE(TestModuleImportedByB) -US_IMPORT_MODULE_RESOURCES(TestModuleImportedByB) - -US_LOAD_IMPORTED_MODULES(TestModuleB, TestModuleImportedByB) diff --git a/core/test/modules/libBWithStatic/usTestModuleBService.h b/core/test/modules/libBWithStatic/usTestModuleBService.h index 044d0853e8..441ccfb14d 100644 --- a/core/test/modules/libBWithStatic/usTestModuleBService.h +++ b/core/test/modules/libBWithStatic/usTestModuleBService.h @@ -1,40 +1,38 @@ /*============================================================================= 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 USTESTMODULEBSERVICE_H #define USTESTMODULEBSERVICE_H #include #include US_BEGIN_NAMESPACE struct TestModuleBService { virtual ~TestModuleBService() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleBService), "org.cppmicroservices.TestModuleBService") - #endif // USTESTMODULEASERVICE_H diff --git a/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp b/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp index 30b5d331cb..b4a446fe03 100644 --- a/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp +++ b/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp @@ -1,64 +1,64 @@ /*============================================================================= 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 "usTestModuleBService.h" #include #include US_BEGIN_NAMESPACE struct TestModuleImportedByB : public TestModuleBService { TestModuleImportedByB(ModuleContext* mc) { US_INFO << "Registering TestModuleImportedByB"; mc->RegisterService(this); } }; class TestModuleImportedByBActivator : public ModuleActivator { public: TestModuleImportedByBActivator() : s(0) {} ~TestModuleImportedByBActivator() { delete s; } void Load(ModuleContext* context) { s = new TestModuleImportedByB(context); } void Unload(ModuleContext*) { } private: TestModuleImportedByB* s; }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleImportedByB, US_PREPEND_NAMESPACE(TestModuleImportedByBActivator)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleImportedByBActivator)) diff --git a/core/test/modules/libH/usTestModuleH.cpp b/core/test/modules/libH/usTestModuleH.cpp index b004be226a..497b9b0025 100644 --- a/core/test/modules/libH/usTestModuleH.cpp +++ b/core/test/modules/libH/usTestModuleH.cpp @@ -1,147 +1,140 @@ /*============================================================================= 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 US_BEGIN_NAMESPACE struct TestModuleH { virtual ~TestModuleH() {} }; struct TestModuleH2 { virtual ~TestModuleH2() {} }; -US_END_NAMESPACE - -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH), "org.cppmicroservices.TestModuleH") -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH2), "org.cppmicroservices.TestModuleH2") - -US_BEGIN_NAMESPACE - class TestProduct : public TestModuleH { // Module* caller; public: TestProduct(Module* /*caller*/) //: caller(caller) {} }; class TestProduct2 : public TestProduct, public TestModuleH2 { public: TestProduct2(Module* caller) : TestProduct(caller) {} }; class TestModuleHPrototypeServiceFactory : public PrototypeServiceFactory { std::map > fcbind; // Map calling module with implementation public: InterfaceMap GetService(Module* caller, const ServiceRegistrationBase& /*sReg*/) { std::cout << "GetService (prototype) in H" << std::endl; TestProduct2* product = new TestProduct2(caller); fcbind[caller->GetModuleId()].push_back(product); return MakeInterfaceMap(product); } void UngetService(Module* caller, const ServiceRegistrationBase& /*sReg*/, const InterfaceMap& service) { TestProduct2* product = dynamic_cast(ExtractInterface(service)); delete product; fcbind[caller->GetModuleId()].remove(product); } }; class TestModuleHActivator : public ModuleActivator, public ServiceFactory { std::string thisServiceName; ServiceRegistration factoryService; ServiceRegistration prototypeFactoryService; ModuleContext* mc; std::map fcbind; // Map calling module with implementation TestModuleHPrototypeServiceFactory prototypeFactory; public: TestModuleHActivator() : thisServiceName(us_service_interface_iid()) , mc(NULL) {} void Load(ModuleContext* mc) { std::cout << "start in H" << std::endl; this->mc = mc; factoryService = mc->RegisterService(this); prototypeFactoryService = mc->RegisterService(static_cast(&prototypeFactory)); } void Unload(ModuleContext* /*mc*/) { factoryService.Unregister(); } InterfaceMap GetService(Module* caller, const ServiceRegistrationBase& /*sReg*/) { std::cout << "GetService in H" << std::endl; TestProduct* product = new TestProduct(caller); fcbind.insert(std::make_pair(caller->GetModuleId(), product)); return MakeInterfaceMap(product); } void UngetService(Module* caller, const ServiceRegistrationBase& /*sReg*/, const InterfaceMap& service) { TestModuleH* product = ExtractInterface(service); delete product; fcbind.erase(caller->GetModuleId()); } }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleH, us::TestModuleHActivator) +US_EXPORT_MODULE_ACTIVATOR(us::TestModuleHActivator) diff --git a/core/test/modules/libM/usTestModuleM.cpp b/core/test/modules/libM/usTestModuleM.cpp index 934056c84b..1a89029c2a 100644 --- a/core/test/modules/libM/usTestModuleM.cpp +++ b/core/test/modules/libM/usTestModuleM.cpp @@ -1,43 +1,43 @@ /*============================================================================= 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 US_BEGIN_NAMESPACE class TestModuleMActivator : public ModuleActivator { public: void Load(ModuleContext*) { } void Unload(ModuleContext*) { } }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleM, US_PREPEND_NAMESPACE(TestModuleMActivator)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleMActivator)) diff --git a/core/test/modules/libRWithResources/CMakeLists.txt b/core/test/modules/libRWithResources/CMakeLists.txt index e5ff2c8109..9d25945705 100644 --- a/core/test/modules/libRWithResources/CMakeLists.txt +++ b/core/test/modules/libRWithResources/CMakeLists.txt @@ -1,13 +1,22 @@ set(resource_files icons/compressable.bmp icons/cppmicroservices.png icons/readme.txt foo.txt special_chars.dummy.txt test.xml ) -usFunctionCreateTestModuleWithResources(TestModuleR - SOURCES usTestModuleR.cpp - RESOURCES ${resource_files}) +configure_file(resources/foo.txt ${CMAKE_CURRENT_BINARY_DIR}/foo2.txt @COPYONLY) + +#usFunctionCreateTestModuleWithResources(TestModuleR +# SOURCES usTestModuleR.cpp +# RESOURCES ${resource_files}) + +usFunctionCreateTestModule(TestModuleR) +usFunctionAddResources( + TARGET TestModuleR + WORKING_DIRECTORY resources + FILES ${resource_files} + ) diff --git a/core/test/modules/libRWithResources/usTestModuleR.cpp b/core/test/modules/libRWithResources/usTestModuleR.cpp index be8c0291ca..f2d811c366 100644 --- a/core/test/modules/libRWithResources/usTestModuleR.cpp +++ b/core/test/modules/libRWithResources/usTestModuleR.cpp @@ -1,43 +1,43 @@ /*============================================================================= 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 US_BEGIN_NAMESPACE class TestModuleRActivator : public ModuleActivator { public: void Load(ModuleContext*) { } void Unload(ModuleContext*) { } }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleR, US_PREPEND_NAMESPACE(TestModuleRActivator)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleRActivator)) diff --git a/core/test/modules/libS/usTestModuleS.cpp b/core/test/modules/libS/usTestModuleS.cpp index 8a4f7bc827..75cf59331c 100644 --- a/core/test/modules/libS/usTestModuleS.cpp +++ b/core/test/modules/libS/usTestModuleS.cpp @@ -1,142 +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. =============================================================================*/ #include "../../usServiceControlInterface.h" #include "usTestModuleSService0.h" #include "usTestModuleSService1.h" #include "usTestModuleSService2.h" #include "usTestModuleSService3.h" #include #include #include US_BEGIN_NAMESPACE class TestModuleS : public ServiceControlInterface, public TestModuleSService0, public TestModuleSService1, public TestModuleSService2, public TestModuleSService3 { public: TestModuleS(ModuleContext* mc) : mc(mc) { for(int i = 0; i <= 3; ++i) { servregs.push_back(ServiceRegistrationU()); } sreg = mc->RegisterService(this); sciReg = mc->RegisterService(this); } virtual const char* GetNameOfClass() const { return "TestModuleS"; } void ServiceControl(int offset, const std::string& operation, int ranking) { if (0 <= offset && offset <= 3) { if (operation == "register") { if (!servregs[offset]) { std::stringstream servicename; servicename << SERVICE << offset; InterfaceMap ifm; ifm.insert(std::make_pair(servicename.str(), static_cast(this))); ServiceProperties props; props.insert(std::make_pair(ServiceConstants::SERVICE_RANKING(), Any(ranking))); servregs[offset] = mc->RegisterService(ifm, props); } } if (operation == "unregister") { if (servregs[offset]) { ServiceRegistrationU sr1 = servregs[offset]; sr1.Unregister(); servregs[offset] = 0; } } } } void Unregister() { if (sreg) { sreg.Unregister(); } if (sciReg) { sciReg.Unregister(); } } private: - static const std::string SERVICE; // = "org.cppmicroservices.TestModuleSService" + static const std::string SERVICE; // = "us::TestModuleSService" ModuleContext* mc; std::vector servregs; ServiceRegistration sreg; ServiceRegistration sciReg; }; -const std::string TestModuleS::SERVICE = "org.cppmicroservices.TestModuleSService"; +const std::string TestModuleS::SERVICE = "us::TestModuleSService"; class TestModuleSActivator : public ModuleActivator { public: TestModuleSActivator() : s(0) {} ~TestModuleSActivator() { delete s; } void Load(ModuleContext* context) { s = new TestModuleS(context); } void Unload(ModuleContext* /*context*/) { #ifndef US_BUILD_SHARED_LIBS s->Unregister(); #endif } private: TestModuleS* s; }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleS, US_PREPEND_NAMESPACE(TestModuleSActivator)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleSActivator)) diff --git a/core/test/modules/libS/usTestModuleSService0.h b/core/test/modules/libS/usTestModuleSService0.h index 5208c16775..82a0b7e22d 100644 --- a/core/test/modules/libS/usTestModuleSService0.h +++ b/core/test/modules/libS/usTestModuleSService0.h @@ -1,39 +1,37 @@ /*============================================================================= 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 USTESTMODULESSERVICE0_H #define USTESTMODULESSERVICE0_H #include US_BEGIN_NAMESPACE struct TestModuleSService0 { virtual ~TestModuleSService0() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleSService0), "org.cppmicroservices.TestModuleSService0") - #endif // USTESTMODULESSERVICE0_H diff --git a/core/test/modules/libS/usTestModuleSService1.h b/core/test/modules/libS/usTestModuleSService1.h index 2fadbe121c..84a56b7793 100644 --- a/core/test/modules/libS/usTestModuleSService1.h +++ b/core/test/modules/libS/usTestModuleSService1.h @@ -1,39 +1,37 @@ /*============================================================================= 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 USTESTMODULESSERVICE1_H #define USTESTMODULESSERVICE1_H #include US_BEGIN_NAMESPACE struct TestModuleSService1 { virtual ~TestModuleSService1() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleSService1), "org.cppmicroservices.TestModuleSService1") - #endif // USTESTMODULESSERVICE1_H diff --git a/core/test/modules/libS/usTestModuleSService2.h b/core/test/modules/libS/usTestModuleSService2.h index 901bd463a0..07e6633254 100644 --- a/core/test/modules/libS/usTestModuleSService2.h +++ b/core/test/modules/libS/usTestModuleSService2.h @@ -1,39 +1,37 @@ /*============================================================================= 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 USTESTMODULESSERVICE2_H #define USTESTMODULESSERVICE2_H #include US_BEGIN_NAMESPACE struct TestModuleSService2 { virtual ~TestModuleSService2() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleSService2), "org.cppmicroservices.TestModuleSService2") - #endif // USTESTMODULESSERVICE0_H diff --git a/core/test/modules/libS/usTestModuleSService3.h b/core/test/modules/libS/usTestModuleSService3.h index 57b0230e05..360e83d3a5 100644 --- a/core/test/modules/libS/usTestModuleSService3.h +++ b/core/test/modules/libS/usTestModuleSService3.h @@ -1,39 +1,37 @@ /*============================================================================= 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 USTESTMODULESSERVICE3_H #define USTESTMODULESSERVICE3_H #include US_BEGIN_NAMESPACE struct TestModuleSService3 { virtual ~TestModuleSService3() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleSService3), "org.cppmicroservices.TestModuleSService3") - #endif // USTESTMODULESSERVICE0_H diff --git a/core/test/modules/libSL1/usActivatorSL1.cpp b/core/test/modules/libSL1/usActivatorSL1.cpp index 55dcc4dd46..7c1419babe 100644 --- a/core/test/modules/libSL1/usActivatorSL1.cpp +++ b/core/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 ServiceReferenceType& reference) { props["serviceAdded"] = true; FooService* fooService = context->GetService(reference); fooService->foo(); return fooService; } void ModifiedService(const ServiceReferenceType& /*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)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(ActivatorSL1)) diff --git a/core/test/modules/libSL1/usFooService.h b/core/test/modules/libSL1/usFooService.h index 461cf12af0..8432d0de5e 100644 --- a/core/test/modules/libSL1/usFooService.h +++ b/core/test/modules/libSL1/usFooService.h @@ -1,40 +1,38 @@ /*============================================================================= 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 USFOOSERVICE_H #define USFOOSERVICE_H #include US_BEGIN_NAMESPACE struct FooService { virtual ~FooService() {} virtual void foo() = 0; }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(FooService), "org.us.testing.FooService") - #endif // USFOOSERVICE_H diff --git a/core/test/modules/libSL3/usActivatorSL3.cpp b/core/test/modules/libSL3/usActivatorSL3.cpp index beae9c9362..17cb010005 100644 --- a/core/test/modules/libSL3/usActivatorSL3.cpp +++ b/core/test/modules/libSL3/usActivatorSL3.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 #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 ServiceReferenceType& reference) { props["serviceAdded"] = true; US_INFO << "SL3: Adding reference =" << reference; FooService* fooService = context->GetService(reference); fooService->foo(); return fooService; } void ModifiedService(const ServiceReferenceType& /*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)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(ActivatorSL3)) diff --git a/core/test/modules/libSL4/usActivatorSL4.cpp b/core/test/modules/libSL4/usActivatorSL4.cpp index cea41ce6fb..70d3952b7b 100644 --- a/core/test/modules/libSL4/usActivatorSL4.cpp +++ b/core/test/modules/libSL4/usActivatorSL4.cpp @@ -1,64 +1,64 @@ /*============================================================================= 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 US_BEGIN_NAMESPACE class ActivatorSL4 : public ModuleActivator, public FooService { public: ~ActivatorSL4() { } void foo() { US_INFO << "TestModuleSL4: Doing foo"; } void Load(ModuleContext* context) { sr = context->RegisterService(this); US_INFO << "TestModuleSL4: Registered " << sr; } void Unload(ModuleContext* /*context*/) { } private: ServiceRegistration sr; }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleSL4, US_PREPEND_NAMESPACE(ActivatorSL4)) +US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(ActivatorSL4)) diff --git a/core/test/usAnyTest.cpp b/core/test/usAnyTest.cpp new file mode 100644 index 0000000000..8282484089 --- /dev/null +++ b/core/test/usAnyTest.cpp @@ -0,0 +1,147 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + +#include + +#include "usTestingMacros.h" + +#include + +US_USE_NAMESPACE + +int usAnyTest(int /*argc*/, char* /*argv*/[]) +{ + US_TEST_BEGIN("AnyTest"); + + Any anyBool = true; + US_TEST_CONDITION(anyBool.Type() == typeid(bool), "Any[bool].Type()") + US_TEST_CONDITION(any_cast(anyBool) == true, "any_cast()") + US_TEST_CONDITION(anyBool.ToString() == "1", "Any[bool].ToString()") + US_TEST_CONDITION(anyBool.ToJSON() == "true", "Any[bool].ToJSON()") + anyBool = false; + US_TEST_CONDITION(anyBool.ToString() == "0", "Any[bool].ToString()") + US_TEST_CONDITION(anyBool.ToJSON() == "false", "Any[bool].ToJSON()") + + Any anyInt = 13; + US_TEST_CONDITION(anyInt.Type() == typeid(int), "Any[int].Type()") + US_TEST_CONDITION(any_cast(anyInt) == 13, "any_cast()") + US_TEST_CONDITION(anyInt.ToString() == "13", "Any[int].ToString()") + US_TEST_CONDITION(anyInt.ToJSON() == "13", "Any[int].ToJSON()") + + Any anyChar = 'a'; + US_TEST_CONDITION(anyChar.Type() == typeid(char), "Any[char].Type()") + US_TEST_CONDITION(any_cast(anyChar) == 'a', "any_cast()") + US_TEST_CONDITION(anyChar.ToString() == "a", "Any[char].ToString()") + US_TEST_CONDITION(anyChar.ToJSON() == "a", "Any[char].ToJSON()") + + Any anyFloat = 0.2f; + US_TEST_CONDITION(anyFloat.Type() == typeid(float), "Any[float].Type()") + US_TEST_CONDITION(any_cast(anyFloat) - 0.2f < std::numeric_limits::epsilon(), "any_cast()") + US_TEST_CONDITION(anyFloat.ToString() == "0.2", "Any[float].ToString()") + US_TEST_CONDITION(anyFloat.ToString() == "0.2", "Any[float].ToJSON()") + + Any anyDouble = 0.5; + US_TEST_CONDITION(anyDouble.Type() == typeid(double), "Any[double].Type()") + US_TEST_CONDITION(any_cast(anyDouble) - 0.5 < std::numeric_limits::epsilon(), "any_cast()") + US_TEST_CONDITION(anyDouble.ToString() == "0.5", "Any[double].ToString()") + US_TEST_CONDITION(anyDouble.ToString() == "0.5", "Any[double].ToJSON()") + + Any anyString = std::string("hello"); + US_TEST_CONDITION(anyString.Type() == typeid(std::string), "Any[std::string].Type()") + US_TEST_CONDITION(any_cast(anyString) == "hello", "any_cast()") + US_TEST_CONDITION(anyString.ToString() == "hello", "Any[std::string].ToString()") + US_TEST_CONDITION(anyString.ToJSON() == "\"hello\"", "Any[std::string].ToJSON()") + + std::vector vecInts; + vecInts.push_back(1); + vecInts.push_back(2); + Any anyVectorOfInts = vecInts; + US_TEST_CONDITION(anyVectorOfInts.Type() == typeid(std::vector), "Any[std::vector].Type()") + US_TEST_CONDITION(any_cast >(anyVectorOfInts) == vecInts, "any_cast>()") + US_TEST_CONDITION(anyVectorOfInts.ToString() == "[1,2]", "Any[std::vector].ToString()") + US_TEST_CONDITION(anyVectorOfInts.ToJSON() == "[1,2]", "Any[std::vector].ToJSON()") + + std::list listInts; + listInts.push_back(1); + listInts.push_back(2); + Any anyListOfInts = listInts; + US_TEST_CONDITION(anyListOfInts.Type() == typeid(std::list), "Any[std::list].Type()") + US_TEST_CONDITION(any_cast >(anyListOfInts) == listInts, "any_cast>()") + US_TEST_CONDITION(anyListOfInts.ToString() == "[1,2]", "Any[std::list].ToString()") + US_TEST_CONDITION(anyListOfInts.ToJSON() == "[1,2]", "Any[std::list].ToJSON()") + + std::set setInts; + setInts.insert(1); + setInts.insert(2); + Any anySetOfInts = setInts; + US_TEST_CONDITION(anySetOfInts.Type() == typeid(std::set), "Any[std::set].Type()") + US_TEST_CONDITION(any_cast >(anySetOfInts) == setInts, "any_cast>()") + US_TEST_CONDITION(anySetOfInts.ToString() == "[1,2]", "Any[std::set].ToString()") + US_TEST_CONDITION(anySetOfInts.ToJSON() == "[1,2]", "Any[std::set].ToJSON()") + + std::vector vecAny; + vecAny.push_back(1); + vecAny.push_back(std::string("hello")); + Any anyVectorOfAnys = vecAny; + US_TEST_CONDITION(anyVectorOfAnys.Type() == typeid(std::vector), "Any[std::vector].Type()") + US_TEST_CONDITION(anyVectorOfAnys.ToString() == "[1,hello]", "Any[std::vector].ToString()") + US_TEST_CONDITION(anyVectorOfAnys.ToJSON() == "[1,\"hello\"]", "Any[std::vector].ToJSON()") + + std::list listAny; + listAny.push_back(1); + listAny.push_back(std::string("hello")); + Any anyListOfAnys = listAny; + US_TEST_CONDITION(anyListOfAnys.Type() == typeid(std::list), "Any[std::list].Type()") + US_TEST_CONDITION(anyListOfAnys.ToString() == "[1,hello]", "Any[std::list].ToString()") + US_TEST_CONDITION(anyListOfAnys.ToJSON() == "[1,\"hello\"]", "Any[std::list].ToJSON()") + + std::map map1; + map1["one"] = 1; + map1["two"] = 2; + Any anyMap1 = map1; + US_TEST_CONDITION(anyMap1.Type() == typeid(std::map), "Any[std::map].Type()") + US_TEST_CONDITION((any_cast >(anyMap1) == map1), "any_cast>()") + US_TEST_CONDITION(anyMap1.ToString() == "{one : 1, two : 2}", "Any[std::map].ToString()") + US_TEST_CONDITION(anyMap1.ToJSON() == "{\"one\" : 1, \"two\" : 2}", "Any[std::map].ToJSON()") + + std::map map2; + map2[1] = 0.3; + map2[3] = std::string("bye"); + Any anyMap2 = map2; + US_TEST_CONDITION(anyMap2.Type() == typeid(std::map), "Any[std::map].Type()") + US_TEST_CONDITION(anyMap2.ToString() == "{1 : 0.3, 3 : bye}", "Any[std::map].ToString()") + US_TEST_CONDITION(anyMap2.ToJSON() == "{\"1\" : 0.3, \"3\" : \"bye\"}", "Any[std::map].ToJSON()") + + std::map map3; + map3["number"] = 5; + std::vector numbers; + numbers.push_back(9); + numbers.push_back(8); + numbers.push_back(7); + map3["vector"] = numbers; + map3["map"] = map2; + Any anyMap3 = map3; + US_TEST_CONDITION(anyMap3.Type() == typeid(std::map), "Any[std::map].Type()") + US_TEST_CONDITION(anyMap3.ToString() == "{map : {1 : 0.3, 3 : bye}, number : 5, vector : [9,8,7]}", "Any[std::map].ToString()") + US_TEST_CONDITION(anyMap3.ToJSON() == "{\"map\" : {\"1\" : 0.3, \"3\" : \"bye\"}, \"number\" : 5, \"vector\" : [9,8,7]}", "Any[std::map].ToJSON()") + + US_TEST_END() +} diff --git a/core/test/usDebugOutputTest.cpp b/core/test/usLogTest.cpp similarity index 61% rename from core/test/usDebugOutputTest.cpp rename to core/test/usLogTest.cpp index ae87a6eb32..13839cdf45 100644 --- a/core/test/usDebugOutputTest.cpp +++ b/core/test/usLogTest.cpp @@ -1,99 +1,177 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usTestingMacros.h" 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*/[]) +void logMsg(MsgType msgType, int logLevel) { - US_TEST_BEGIN("DebugOutputTest"); + resetLastMsg(); + std::string logMsg; + switch (msgType) + { + case DebugMsg: + { + logMsg = "Debug msg"; + US_DEBUG << logMsg; +#if !defined(US_ENABLE_DEBUG_OUTPUT) + if (logLevel == DebugMsg) logLevel = InfoMsg; +#endif + break; + } + case InfoMsg: + { + logMsg = "Info msg"; + US_INFO << logMsg; + break; + } + case WarningMsg: + { + logMsg = "Warning msg"; + US_WARN << logMsg; + break; + } + case ErrorMsg: + { + // Skip error messages + logLevel = 100; + break; + } + } + + if (msgType >= logLevel) + { + US_TEST_CONDITION(lastMsgType == msgType && lastMsg.find(logMsg) != std::string::npos, "Testing for logged message") + } + else + { + US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing for skipped log message") + } +} +void testLogMessages() +{ // Use the default message handler + installMsgHandler(0); { 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") + resetLastMsg(); +} + +void testLogLevels() +{ + installMsgHandler(handleMessages); + + MsgType logLevel = ModuleSettings::GetLogLevel(); + US_TEST_CONDITION_REQUIRED(logLevel == DebugMsg, "Default log level") + + logMsg(DebugMsg, logLevel); + logMsg(InfoMsg, logLevel); + logMsg(WarningMsg, logLevel); + logMsg(ErrorMsg, logLevel); + + for (int level = ErrorMsg; level >= 0; --level) + { + ModuleSettings::SetLogLevel(static_cast(level)); + logMsg(DebugMsg, level); + logMsg(InfoMsg, level); + logMsg(WarningMsg, level); + logMsg(ErrorMsg, level); + } + + installMsgHandler(0); + resetLastMsg(); +} + +int usLogTest(int /*argc*/, char* /*argv*/[]) +{ + US_TEST_BEGIN("DebugOutputTest"); + + testLogMessages(); + testLogLevels(); US_TEST_END() } diff --git a/core/test/usModuleAutoLoadTest.cpp b/core/test/usModuleAutoLoadTest.cpp index db5dae1a76..08b09d0215 100644 --- a/core/test/usModuleAutoLoadTest.cpp +++ b/core/test/usModuleAutoLoadTest.cpp @@ -1,176 +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. =============================================================================*/ #include #include #include #include #include #include #include #include #include "usTestUtilModuleListener.h" #include "usTestingMacros.h" -#include +#include 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 void testDefaultAutoLoadPath(bool autoLoadEnabled) { ModuleContext* mc = GetModuleContext(); assert(mc); TestModuleListener listener; - try - { - mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); - } - catch (const std::logic_error& ise) - { - US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); - throw; - } + ModuleListenerRegistrationHelper listenerReg(mc, &listener, &TestModuleListener::ModuleChanged); SharedLibrary libAL(LIB_PATH, "TestModuleAL"); try { libAL.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } - Module* moduleAL = ModuleRegistry::GetModule("TestModuleAL Module"); + Module* moduleAL = ModuleRegistry::GetModule("TestModuleAL"); US_TEST_CONDITION_REQUIRED(moduleAL != NULL, "Test for existing module TestModuleAL") - US_TEST_CONDITION(moduleAL->GetName() == "TestModuleAL Module", "Test module name") + US_TEST_CONDITION(moduleAL->GetName() == "TestModuleAL", "Test module name") // check the listeners for events std::vector pEvts; pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL)); - Module* moduleAL_1 = ModuleRegistry::GetModule("TestModuleAL_1 Module"); + Any loadedModules = moduleAL->GetProperty(Module::PROP_AUTOLOADED_MODULES()); + Module* moduleAL_1 = ModuleRegistry::GetModule("TestModuleAL_1"); if (autoLoadEnabled) { US_TEST_CONDITION_REQUIRED(moduleAL_1 != NULL, "Test for existing auto-loaded module TestModuleAL_1") - US_TEST_CONDITION(moduleAL_1->GetName() == "TestModuleAL_1 Module", "Test module name") + US_TEST_CONDITION(moduleAL_1->GetName() == "TestModuleAL_1", "Test module name") + US_TEST_CONDITION_REQUIRED(!loadedModules.Empty(), "Test for PROP_AUTOLOADED_MODULES property") + US_TEST_CONDITION_REQUIRED(loadedModules.Type() == typeid(std::vector), "Test for PROP_AUTOLOADED_MODULES property type") + std::vector loadedModulesVec = any_cast >(loadedModules); + US_TEST_CONDITION_REQUIRED(loadedModulesVec.size() == 1, "Test for PROP_AUTOLOADED_MODULES vector size") + US_TEST_CONDITION_REQUIRED(loadedModulesVec[0] == moduleAL_1->GetLocation(), "Test for PROP_AUTOLOADED_MODULES vector content") pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL_1)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL_1)); } else { US_TEST_CONDITION_REQUIRED(moduleAL_1 == NULL, "Test for non-existing auto-loaded module TestModuleAL_1") + US_TEST_CONDITION_REQUIRED(loadedModules.Empty(), "Test for empty PROP_AUTOLOADED_MODULES property") } pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL)); US_TEST_CONDITION(listener.CheckListenerEvents(pEvts), "Test for unexpected events"); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); libAL.Unload(); } void testCustomAutoLoadPath() { ModuleContext* mc = GetModuleContext(); assert(mc); TestModuleListener listener; try { mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); throw; } SharedLibrary libAL2(LIB_PATH, "TestModuleAL2"); try { libAL2.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } - Module* moduleAL2 = ModuleRegistry::GetModule("TestModuleAL2 Module"); + Module* moduleAL2 = ModuleRegistry::GetModule("TestModuleAL2"); US_TEST_CONDITION_REQUIRED(moduleAL2 != NULL, "Test for existing module TestModuleAL2") - US_TEST_CONDITION(moduleAL2->GetName() == "TestModuleAL2 Module", "Test module name") + US_TEST_CONDITION(moduleAL2->GetName() == "TestModuleAL2", "Test module name") // check the listeners for events std::vector pEvts; pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL2)); - Module* moduleAL2_1 = ModuleRegistry::GetModule("TestModuleAL2_1 Module"); + Module* moduleAL2_1 = ModuleRegistry::GetModule("TestModuleAL2_1"); #ifdef US_ENABLE_AUTOLOADING_SUPPORT US_TEST_CONDITION_REQUIRED(moduleAL2_1 != NULL, "Test for existing auto-loaded module TestModuleAL2_1") - US_TEST_CONDITION(moduleAL2_1->GetName() == "TestModuleAL2_1 Module", "Test module name") + US_TEST_CONDITION(moduleAL2_1->GetName() == "TestModuleAL2_1", "Test module name") pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL2_1)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL2_1)); #else US_TEST_CONDITION_REQUIRED(moduleAL2_1 == NULL, "Test for non-existing aut-loaded module TestModuleAL2_1") #endif pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL2)); US_TEST_CONDITION(listener.CheckListenerEvents(pEvts), "Test for unexpected events"); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); } } // end unnamed namespace int usModuleAutoLoadTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleLoaderTest"); ModuleSettings::SetAutoLoadingEnabled(false); testDefaultAutoLoadPath(false); ModuleSettings::SetAutoLoadingEnabled(true); testDefaultAutoLoadPath(true); testCustomAutoLoadPath(); US_TEST_END() } diff --git a/core/test/usModuleHooksTest.cpp b/core/test/usModuleHooksTest.cpp index b1dea8ccdc..b9c68bdf56 100644 --- a/core/test/usModuleHooksTest.cpp +++ b/core/test/usModuleHooksTest.cpp @@ -1,187 +1,194 @@ /*============================================================================= 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") + if ((*i)->GetName() == "TestModuleA") { 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"); + +#ifdef US_BUILD_SHARED_LIBS try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } +#endif - Module* moduleA = GetModuleContext()->GetModule("TestModuleA Module"); + Module* moduleA = GetModuleContext()->GetModule("TestModuleA"); 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->GetName() == "TestModuleA", "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") + if((*i)->GetName() == "TestModuleA") { US_TEST_FAILED_MSG(<< "TestModuleA not filtered from GetModules()") } } findHookReg.Unregister(); libA.Unload(); } +#ifdef US_BUILD_SHARED_LIBS 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); } +#endif } // end unnamed namespace int usModuleHooksTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleHooksTest"); TestFindHook(); + +#ifdef US_BUILD_SHARED_LIBS TestEventHook(); +#endif US_TEST_END() } diff --git a/core/test/usModuleManifestTest.cpp b/core/test/usModuleManifestTest.cpp index 757a38da59..62f7eb0388 100644 --- a/core/test/usModuleManifestTest.cpp +++ b/core/test/usModuleManifestTest.cpp @@ -1,96 +1,96 @@ /*============================================================================= 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 } // end unnamed namespace int usModuleManifestTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleManifestTest"); SharedLibrary target(LIB_PATH, "TestModuleM"); - // Start the test target +#ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } +#endif - Module* moduleM = ModuleRegistry::GetModule("TestModuleM Module"); + Module* moduleM = ModuleRegistry::GetModule("TestModuleM"); US_TEST_CONDITION_REQUIRED(moduleM != 0, "Test for existing module TestModuleM") - US_TEST_CONDITION(moduleM->GetProperty(Module::PROP_NAME()).ToString() == "TestModuleM Module", "Module name") - US_TEST_CONDITION(moduleM->GetName() == "TestModuleM Module", "Module name 2") + US_TEST_CONDITION(moduleM->GetProperty(Module::PROP_NAME()).ToString() == "TestModuleM", "Module name") + US_TEST_CONDITION(moduleM->GetName() == "TestModuleM", "Module name 2") US_TEST_CONDITION(moduleM->GetProperty(Module::PROP_DESCRIPTION()).ToString() == "My Module description", "Module description") US_TEST_CONDITION(moduleM->GetLocation() == moduleM->GetProperty(Module::PROP_LOCATION()).ToString(), "Module location") US_TEST_CONDITION(moduleM->GetProperty(Module::PROP_VERSION()).ToString() == "1.0.0", "Module version") US_TEST_CONDITION(moduleM->GetVersion() == ModuleVersion(1,0,0), "Module version 2") Any anyVector = moduleM->GetProperty("vector"); US_TEST_CONDITION_REQUIRED(anyVector.Type() == typeid(std::vector), "vector type") std::vector& vec = ref_any_cast >(anyVector); US_TEST_CONDITION_REQUIRED(vec.size() == 3, "vector size") US_TEST_CONDITION_REQUIRED(vec[0].Type() == typeid(std::string), "vector 0 type") US_TEST_CONDITION_REQUIRED(vec[0].ToString() == "first", "vector 0 value") US_TEST_CONDITION_REQUIRED(vec[1].Type() == typeid(int), "vector 1 type") US_TEST_CONDITION_REQUIRED(any_cast(vec[1]) == 2, "vector 1 value") Any anyMap = moduleM->GetProperty("map"); US_TEST_CONDITION_REQUIRED(anyMap.Type() == typeid(std::map), "map type") std::map& m = ref_any_cast >(anyMap); US_TEST_CONDITION_REQUIRED(m.size() == 3, "map size") US_TEST_CONDITION_REQUIRED(m["string"].Type() == typeid(std::string), "map 0 type") US_TEST_CONDITION_REQUIRED(m["string"].ToString() == "hi", "map 0 value") US_TEST_CONDITION_REQUIRED(m["number"].Type() == typeid(int), "map 1 type") US_TEST_CONDITION_REQUIRED(any_cast(m["number"]) == 4, "map 1 value") US_TEST_CONDITION_REQUIRED(m["list"].Type() == typeid(std::vector), "map 2 type") US_TEST_CONDITION_REQUIRED(any_cast >(m["list"]).size() == 2, "map 2 value size") target.Unload(); US_TEST_END() } diff --git a/core/test/usModulePropsInterface.h b/core/test/usModulePropsInterface.h index 27bd6e7568..d5254ecf09 100644 --- a/core/test/usModulePropsInterface.h +++ b/core/test/usModulePropsInterface.h @@ -1,44 +1,42 @@ /*============================================================================= 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 USMODULEPROPSINTERFACE_H #define USMODULEPROPSINTERFACE_H #include #include US_BEGIN_NAMESPACE struct ModulePropsInterface { typedef ServiceProperties Properties; virtual ~ModulePropsInterface() {} virtual const Properties& GetProperties() const = 0; }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(ModulePropsInterface), "org.us.testing.ModulePropsInterface") - #endif // USMODULEPROPSINTERFACE_H diff --git a/core/test/usModuleResourceTest.cpp b/core/test/usModuleResourceTest.cpp index 734cc0b7fb..12daaa523c 100644 --- a/core/test/usModuleResourceTest.cpp +++ b/core/test/usModuleResourceTest.cpp @@ -1,542 +1,450 @@ /*============================================================================= 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 +#include #include US_USE_NAMESPACE namespace { + // Please confirm that a character count differing from the following targets is not due to + // a misconfiguration of your versioning software (Correct line endings for your system) + // See issue #18 ( https://github.com/saschazelzer/CppMicroServices/issues/18 ) void checkResourceInfo(const ModuleResource& res, const std::string& path, const std::string& baseName, const std::string& completeBaseName, const std::string& suffix, const std::string& completeSuffix, - int size, bool children = false, bool compressed = false) + int size, bool children = false) { US_TEST_CONDITION_REQUIRED(res.IsValid(), "Valid resource") US_TEST_CONDITION(res.GetBaseName() == baseName, "GetBaseName()") US_TEST_CONDITION(res.GetChildren().empty() == !children, "No children") US_TEST_CONDITION(res.GetCompleteBaseName() == completeBaseName, "GetCompleteBaseName()") US_TEST_CONDITION(res.GetName() == completeBaseName + "." + suffix, "GetName()") US_TEST_CONDITION(res.GetResourcePath() == path + completeBaseName + "." + suffix, "GetResourcePath()") US_TEST_CONDITION(res.GetPath() == path, "GetPath()") US_TEST_CONDITION(res.GetSize() == size, "Data size") US_TEST_CONDITION(res.GetSuffix() == suffix, "Suffix") US_TEST_CONDITION(res.GetCompleteSuffix() == completeSuffix, "Complete suffix") - US_TEST_CONDITION(res.IsCompressed() == compressed, "Compression flag") } void testTextResource(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(12); const std::string fileData = "foo and\nbar\n"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); rs.clear(); rs.seekg(0); US_TEST_CONDITION_REQUIRED(rs.tellg() == std::streampos(0), "Move to start") US_TEST_CONDITION_REQUIRED(rs.good(), "Start re-reading"); std::vector lines; std::string line; while (std::getline(rs, line)) { lines.push_back(line); } US_TEST_CONDITION_REQUIRED(lines.size() > 1, "Number of lines") US_TEST_CONDITION(lines[0] == "foo and", "Check first line") US_TEST_CONDITION(lines[1] == "bar", "Check second line") } void testTextResourceAsBinary(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(16); const std::string fileData = "foo and\r\nbar\r\n\r\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #endif ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } -#ifdef US_BUILD_SHARED_LIBS void testInvalidResource(Module* module) { ModuleResource res = module->GetResource("invalid"); US_TEST_CONDITION_REQUIRED(res.IsValid() == false, "Check invalid resource") US_TEST_CONDITION(res.GetName().empty(), "Check empty name") US_TEST_CONDITION(res.GetPath().empty(), "Check empty path") US_TEST_CONDITION(res.GetResourcePath().empty(), "Check empty resource path") US_TEST_CONDITION(res.GetBaseName().empty(), "Check empty base name") US_TEST_CONDITION(res.GetCompleteBaseName().empty(), "Check empty complete base name") US_TEST_CONDITION(res.GetSuffix().empty(), "Check empty suffix") US_TEST_CONDITION(res.GetChildren().empty(), "Check empty children") US_TEST_CONDITION(res.GetSize() == 0, "Check zero size") - US_TEST_CONDITION(res.GetData() == NULL, "Check NULL data") ModuleResourceStream rs(res); US_TEST_CONDITION(rs.good() == true, "Check invalid resource stream") rs.ignore(); US_TEST_CONDITION(rs.good() == false, "Check invalid resource stream") US_TEST_CONDITION(rs.eof() == true, "Check invalid resource stream") } -#endif void testSpecialCharacters(Module* module) { ModuleResource res = module->GetResource("special_chars.dummy.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 56, false); const std::streampos ssize(54); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)\n"; #else checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 54, false); const std::streampos ssize(53); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios_base::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios_base::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testBinaryResource(Module* module) { ModuleResource res = module->GetResource("/icons/cppmicroservices.png"); checkResourceInfo(res, "/icons/", "cppmicroservices", "cppmicroservices", "png", "png", 2424, false); ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios_base::end); std::streampos resLength = rs.tellg(); rs.seekg(0); std::ifstream png(US_CORE_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/cppmicroservices.png", std::ifstream::in | std::ifstream::binary); US_TEST_CONDITION_REQUIRED(png.is_open(), "Open reference file") png.seekg(0, std::ios_base::end); std::streampos pngLength = png.tellg(); png.seekg(0); US_TEST_CONDITION(res.GetSize() == resLength, "Check resource size") US_TEST_CONDITION_REQUIRED(resLength == pngLength, "Compare sizes") char c1 = 0; char c2 = 0; bool isEqual = true; int count = 0; while (png.get(c1) && rs.get(c2)) { ++count; if (c1 != c2) { isEqual = false; break; } } US_TEST_CONDITION_REQUIRED(count == pngLength, "Check if everything was read"); US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); US_TEST_CONDITION(png.eof(), "EOF check"); } -#ifdef US_ENABLE_RESOURCE_COMPRESSION void testCompressedResource(Module* module) { ModuleResource res = module->GetResource("/icons/compressable.bmp"); - checkResourceInfo(res, "/icons/", "compressable", "compressable", "bmp", "bmp", 411, false, true); + checkResourceInfo(res, "/icons/", "compressable", "compressable", "bmp", "bmp", 300122, false); ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios_base::end); std::streampos resLength = rs.tellg(); rs.seekg(0); std::ifstream bmp(US_CORE_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/compressable.bmp", std::ifstream::in | std::ifstream::binary); US_TEST_CONDITION_REQUIRED(bmp.is_open(), "Open reference file") bmp.seekg(0, std::ios_base::end); std::streampos bmpLength = bmp.tellg(); bmp.seekg(0); US_TEST_CONDITION(300122 == resLength, "Check resource size") US_TEST_CONDITION_REQUIRED(resLength == bmpLength, "Compare sizes") char c1 = 0; char c2 = 0; bool isEqual = true; int count = 0; while (bmp.get(c1) && rs.get(c2)) { ++count; if (c1 != c2) { isEqual = false; break; } } US_TEST_CONDITION_REQUIRED(count == bmpLength, "Check if everything was read"); US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); US_TEST_CONDITION(bmp.eof(), "EOF check"); } -#endif struct ResourceComparator { bool operator()(const ModuleResource& mr1, const ModuleResource& mr2) const { return mr1 < mr2; } }; -#ifdef US_BUILD_SHARED_LIBS void testResourceTree(Module* module) { ModuleResource res = module->GetResource(""); US_TEST_CONDITION(res.GetResourcePath() == "/", "Check root file path") US_TEST_CONDITION(res.IsDir() == true, "Check type") std::vector children = res.GetChildren(); std::sort(children.begin(), children.end()); US_TEST_CONDITION_REQUIRED(children.size() == 4, "Check child count") US_TEST_CONDITION(children[0] == "foo.txt", "Check child name") - US_TEST_CONDITION(children[1] == "icons", "Check child name") + US_TEST_CONDITION(children[1] == "icons/", "Check child name") US_TEST_CONDITION(children[2] == "special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(children[3] == "test.xml", "Check child name") ModuleResource readme = module->GetResource("/icons/readme.txt"); US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") - ModuleResource icons = module->GetResource("icons"); + ModuleResource icons = module->GetResource("icons/"); US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") children = icons.GetChildren(); US_TEST_CONDITION_REQUIRED(children.size() == 3, "Check icons child count") std::sort(children.begin(), children.end()); US_TEST_CONDITION(children[0] == "compressable.bmp", "Check child name") US_TEST_CONDITION(children[1] == "cppmicroservices.png", "Check child name") US_TEST_CONDITION(children[2] == "readme.txt", "Check child name") ResourceComparator resourceComparator; // find all .txt files std::vector nodes = module->FindResources("", "*.txt", false); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 2, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") nodes = module->FindResources("", "*.txt", true); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 3, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/icons/readme.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") // find all resources nodes = module->FindResources("", "", true); - US_TEST_CONDITION(nodes.size() == 6, "Total resource number") + US_TEST_CONDITION(nodes.size() == 7, "Total resource number") nodes = module->FindResources("", "**", true); - US_TEST_CONDITION(nodes.size() == 6, "Total resource number") + US_TEST_CONDITION(nodes.size() == 7, "Total resource number") // test pattern matching nodes.clear(); nodes = module->FindResources("/icons", "*micro*.png", false); US_TEST_CONDITION(nodes.size() == 1 && nodes[0].GetResourcePath() == "/icons/cppmicroservices.png", "Check file pattern matches") nodes.clear(); nodes = module->FindResources("", "*.txt", true); US_TEST_CONDITION(nodes.size() == 3, "Check recursive pattern matches") } -#else - -void testResourceTree(Module* module) -{ - ModuleResource res = module->GetResource(""); - US_TEST_CONDITION(res.GetResourcePath() == "/", "Check root file path") - US_TEST_CONDITION(res.IsDir() == true, "Check type") - - std::vector children = res.GetChildren(); - std::sort(children.begin(), children.end()); - US_TEST_CONDITION_REQUIRED(children.size() == 10, "Check child count") - US_TEST_CONDITION(children[0] == "dynamic.txt", "Check dynamic.txt child name") - US_TEST_CONDITION(children[1] == "foo.txt", "Check foo.txt child name") - US_TEST_CONDITION(children[2] == "icons", "Check icons child name") - US_TEST_CONDITION(children[3] == "manifest.json", "Check manifest.json child name") - US_TEST_CONDITION(children[4] == "manifest.json", "Check manifest.json child name") - US_TEST_CONDITION(children[5] == "res.txt", "Check res.txt child name") - US_TEST_CONDITION(children[6] == "res.txt", "Check res.txt child name") - US_TEST_CONDITION(children[7] == "special_chars.dummy.txt", "Check special_chars.dummy.txt child name") - US_TEST_CONDITION(children[8] == "static.txt", "Check static.txt child name") - US_TEST_CONDITION(children[9] == "test.xml", "Check test.xml child name") - - - ModuleResource readme = module->GetResource("/icons/readme.txt"); - US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") - - ModuleResource icons = module->GetResource("icons"); - US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") - - children = icons.GetChildren(); - US_TEST_CONDITION_REQUIRED(children.size() == 3, "Check icons child count") - std::sort(children.begin(), children.end()); - US_TEST_CONDITION(children[0] == "compressable.bmp", "Check child name") - US_TEST_CONDITION(children[1] == "cppmicroservices.png", "Check child name") - US_TEST_CONDITION(children[2] == "readme.txt", "Check child name") - - ResourceComparator resourceComparator; - - // find all .txt files - std::vector nodes = module->FindResources("", "*.txt", false); - std::sort(nodes.begin(), nodes.end(), resourceComparator); - US_TEST_CONDITION_REQUIRED(nodes.size() == 6, "Found child count") - US_TEST_CONDITION(nodes[0].GetResourcePath() == "/dynamic.txt", "Check dynamic.txt child name") - US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo.txt", "Check child name") - US_TEST_CONDITION(nodes[2].GetResourcePath() == "/res.txt", "Check res.txt child name") - US_TEST_CONDITION(nodes[3].GetResourcePath() == "/res.txt", "Check res.txt child name") - US_TEST_CONDITION(nodes[4].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") - US_TEST_CONDITION(nodes[5].GetResourcePath() == "/static.txt", "Check static.txt child name") - - nodes = module->FindResources("", "*.txt", true); - std::sort(nodes.begin(), nodes.end(), resourceComparator); - US_TEST_CONDITION_REQUIRED(nodes.size() == 7, "Found child count") - US_TEST_CONDITION(nodes[0].GetResourcePath() == "/dynamic.txt", "Check dynamic.txt child name") - US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo.txt", "Check child name") - US_TEST_CONDITION(nodes[2].GetResourcePath() == "/icons/readme.txt", "Check child name") - US_TEST_CONDITION(nodes[3].GetResourcePath() == "/res.txt", "Check res.txt child name") - US_TEST_CONDITION(nodes[4].GetResourcePath() == "/res.txt", "Check res.txt child name") - US_TEST_CONDITION(nodes[5].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") - US_TEST_CONDITION(nodes[6].GetResourcePath() == "/static.txt", "Check static.txt child name") - - // find all resources - nodes = module->FindResources("", "", true); - US_TEST_CONDITION(nodes.size() == 12, "Total resource number") - nodes = module->FindResources("", "**", true); - US_TEST_CONDITION(nodes.size() == 12, "Total resource number") - - - // test pattern matching - nodes.clear(); - nodes = module->FindResources("/icons", "*micro*.png", false); - US_TEST_CONDITION(nodes.size() == 1 && nodes[0].GetResourcePath() == "/icons/cppmicroservices.png", "Check file pattern matches") - - nodes.clear(); - nodes = module->FindResources("", "*.txt", true); - US_TEST_CONDITION(nodes.size() == 7, "Check recursive pattern matches") -} - -#endif - void testResourceOperators(Module* module) { ModuleResource invalid = module->GetResource("invalid"); ModuleResource foo = module->GetResource("foo.txt"); US_TEST_CONDITION_REQUIRED(foo.IsValid() && foo, "Check valid resource") ModuleResource foo2(foo); US_TEST_CONDITION(foo == foo, "Check equality operator") US_TEST_CONDITION(foo == foo2, "Check copy constructor and equality operator") US_TEST_CONDITION(foo != invalid, "Check inequality with invalid resource") ModuleResource xml = module->GetResource("/test.xml"); US_TEST_CONDITION_REQUIRED(xml.IsValid() && xml, "Check valid resource") US_TEST_CONDITION(foo != xml, "Check inequality") US_TEST_CONDITION(foo < xml, "Check operator<") // check operator< by using a set std::set resources; resources.insert(foo); resources.insert(foo); resources.insert(xml); US_TEST_CONDITION(resources.size() == 2, "Check operator< with set") // check hash function specialization US_UNORDERED_SET_TYPE resources2; resources2.insert(foo); resources2.insert(foo); resources2.insert(xml); US_TEST_CONDITION(resources2.size() == 2, "Check operator< with unordered set") // check operator<< std::ostringstream oss; oss << foo; US_TEST_CONDITION(oss.str() == foo.GetResourcePath(), "Check operator<<") } -#ifdef US_BUILD_SHARED_LIBS void testResourceFromExecutable(Module* module) { ModuleResource resource = module->GetResource("usTestResource.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid executable resource") std::string line; ModuleResourceStream rs(resource); std::getline(rs, line); US_TEST_CONDITION(line == "meant to be compiled into the test driver", "Check executable resource content") } -#endif } // end unnamed namespace int usModuleResourceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleResourceTest"); ModuleContext* mc = GetModuleContext(); assert(mc); #ifdef US_BUILD_SHARED_LIBS #ifdef US_PLATFORM_WINDOWS const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif SharedLibrary libR(LIB_PATH, "TestModuleR"); try { libR.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } +#endif - Module* moduleR = ModuleRegistry::GetModule("TestModuleR Module"); + Module* moduleR = ModuleRegistry::GetModule("TestModuleR"); US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module TestModuleR") - US_TEST_CONDITION(moduleR->GetName() == "TestModuleR Module", "Test module name") + US_TEST_CONDITION(moduleR->GetName() == "TestModuleR", "Test module name") testInvalidResource(moduleR); - testResourceFromExecutable(mc->GetModule()); -#else - Module* moduleR = mc->GetModule(); - US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module 0") - US_TEST_CONDITION(moduleR->GetName() == "CppMicroServices", "Test module name") -#endif + testResourceFromExecutable(mc->GetModule()); testResourceTree(moduleR); testResourceOperators(moduleR); testTextResource(moduleR); testTextResourceAsBinary(moduleR); testSpecialCharacters(moduleR); testBinaryResource(moduleR); -#ifdef US_ENABLE_RESOURCE_COMPRESSION testCompressedResource(moduleR); -#endif -#ifdef US_BUILD_SHARED_LIBS ModuleResource foo = moduleR->GetResource("foo.txt"); US_TEST_CONDITION(foo.IsValid() == true, "Valid resource") +#ifdef US_BUILD_SHARED_LIBS libR.Unload(); - US_TEST_CONDITION(foo.IsValid() == false, "Invalidated resource") - US_TEST_CONDITION(foo.GetData() == NULL, "NULL data") + US_TEST_CONDITION(foo.IsValid() == true, "Still valid resource") #endif US_TEST_END() } diff --git a/core/test/usModuleTest.cpp b/core/test/usModuleTest.cpp index 2194399d9b..28f024804b 100644 --- a/core/test/usModuleTest.cpp +++ b/core/test/usModuleTest.cpp @@ -1,343 +1,350 @@ /*============================================================================= 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 "usTestUtilModuleListener.h" +#include "usTestDriverActivator.h" #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '\\'; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '/'; #endif +// Check that the executable's activator was loaded and called +void frame01() +{ + US_TEST_CONDITION_REQUIRED(TestDriverActivator::LoadCalled(), "ModuleActivator::Load() called for executable") +} + // Verify that the same member function pointers registered as listeners // with different receivers works. void frame02a() { ModuleContext* mc = GetModuleContext(); TestModuleListener listener1; TestModuleListener listener2; try { mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener2, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "module listener registration failed " << ise.what() << " : frameSL02a:FAIL" ); } SharedLibrary target(LIB_PATH, "TestModuleA"); #ifdef US_BUILD_SHARED_LIBS // Start the test target try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } +#endif - Module* moduleA = ModuleRegistry::GetModule("TestModuleA Module"); + Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for existing module TestModuleA") -#endif std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; US_TEST_CONDITION(listener1.CheckListenerEvents(pEvts, seEvts), "Check first module listener") US_TEST_CONDITION(listener2.CheckListenerEvents(pEvts, seEvts), "Check second module listener") mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); target.Unload(); } // Verify information from the ModuleInfo struct void frame005a(ModuleContext* mc) { Module* m = mc->GetModule(); // check expected headers -#ifdef US_BUILD_SHARED_LIBS - US_TEST_CONDITION("usCoreTestDriver" == m->GetName(), "Test module name") + US_TEST_CONDITION("main" == m->GetName(), "Test module name") US_TEST_CONDITION(ModuleVersion(0,1,0) == m->GetVersion(), "Test test driver module version") US_TEST_CONDITION(ModuleVersion(CppMicroServices_MAJOR_VERSION, CppMicroServices_MINOR_VERSION, CppMicroServices_PATCH_VERSION) == ModuleRegistry::GetModule(1)->GetVersion(), "Test CppMicroServices version") -#else - US_TEST_CONDITION("CppMicroServices" == m->GetName(), "Test module name") - US_TEST_CONDITION(ModuleVersion(US_CORE_MAJOR_VERSION, US_CORE_MINOR_VERSION, US_CORE_PATCH_VERSION) == m->GetVersion(), "Test module version") -#endif } // Get context id, location and status of the module void frame010a(ModuleContext* mc) { Module* m = mc->GetModule(); long int contextid = m->GetModuleId(); US_DEBUG << "CONTEXT ID:" << contextid; std::string location = m->GetLocation(); US_DEBUG << "LOCATION:" << location; US_TEST_CONDITION(!location.empty(), "Test for non-empty module location") US_TEST_CONDITION(m->IsLoaded(), "Test for loaded flag") US_TEST_CONDITION(ModuleSettings::GetStoragePath().empty(), "Test for empty base storage path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("").empty(), "Test for empty data path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("bla").empty(), "Test for empty data file path") } //---------------------------------------------------------------------------- //Test result of GetService(ServiceReference()). Should throw std::invalid_argument void frame018a(ModuleContext* mc) { try { mc->GetService(ServiceReferenceU()); US_DEBUG << "Got service object, expected std::invalid_argument exception"; US_TEST_FAILED_MSG(<< "Got service object, excpected std::invalid_argument exception") } catch (const std::invalid_argument& ) {} catch (...) { US_TEST_FAILED_MSG(<< "Got wrong exception, expected std::invalid_argument") } } // Load libA and check that it exists and that the service it registers exists, // also check that the expected events occur and that the storage paths are correct void frame020a(ModuleContext* mc, TestModuleListener& listener, #ifdef US_BUILD_SHARED_LIBS SharedLibrary& libA) { - ModuleSettings::SetStoragePath(std::string("/tmp") + PATH_SEPARATOR); - US_TEST_CONDITION(ModuleSettings::GetStoragePath() == "/tmp", "Test for valid base storage path") - try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } +#else + SharedLibrary& /*libA*/) +{ +#endif - Module* moduleA = ModuleRegistry::GetModule("TestModuleA Module"); + ModuleSettings::SetStoragePath(std::string("/tmp") + PATH_SEPARATOR); + US_TEST_CONDITION(ModuleSettings::GetStoragePath() == "/tmp", "Test for valid base storage path") + + Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); 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->GetName() == "TestModuleA", "Test module name") - std::cout << moduleA->GetModuleContext()->GetDataFile(""); + std::cout << moduleA->GetModuleContext()->GetDataFile("") << std::endl; std::stringstream ss; ss << moduleA->GetModuleId(); const std::string baseStoragePath = std::string("/tmp") + PATH_SEPARATOR + ss.str() + "_TestModuleA" + PATH_SEPARATOR; US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("") == baseStoragePath, "Test for valid data path") US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("bla") == baseStoragePath + "bla", "Test for valid data file path") -#else - SharedLibrary& /*libA*/) -{ -#endif // Check if libA registered the expected service try { - ServiceReferenceU sr1 = mc->GetServiceReference("org.cppmicroservices.TestModuleAService"); + ServiceReferenceU sr1 = mc->GetServiceReference("us::TestModuleAService"); InterfaceMap o1 = mc->GetService(sr1); US_TEST_CONDITION(!o1.empty(), "Test if service object found"); try { US_TEST_CONDITION(mc->UngetService(sr1), "Test if Service UnGet returns true"); } catch (const std::logic_error le) { US_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) } // check the listeners for events std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } catch (const ServiceException& /*se*/) { US_TEST_FAILED_MSG(<< "test module, expected service not found"); } -#ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleA->IsLoaded() == true, "Test if loaded correctly"); -#endif } // Unload libA and check for correct events void frame030b(ModuleContext* mc, TestModuleListener& listener, SharedLibrary& libA) { -#ifdef US_BUILD_SHARED_LIBS - Module* moduleA = ModuleRegistry::GetModule("TestModuleA Module"); + Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for non-null module") -#endif ServiceReferenceU sr1 - = mc->GetServiceReference("org.cppmicroservices.TestModuleAService"); + = mc->GetServiceReference("us::TestModuleAService"); US_TEST_CONDITION(sr1, "Test for valid service reference") try { libA.Unload(); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleA->IsLoaded() == false, "Test for unloaded state") #endif } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) } std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } struct LocalListener { void ServiceChanged(const ServiceEvent) {} }; // Add a service listener with a broken LDAP filter to Get an exception void frame045a(ModuleContext* mc) { LocalListener sListen1; std::string brokenFilter = "A broken LDAP filter"; try { mc->AddServiceListener(&sListen1, &LocalListener::ServiceChanged, brokenFilter); } catch (const std::invalid_argument& /*ia*/) { //assertEquals("InvalidSyntaxException.GetFilter should be same as input string", brokenFilter, ise.GetFilter()); } catch (...) { US_TEST_FAILED_MSG(<< "test module, wrong exception on broken LDAP filter:"); } } } // end unnamed namespace int usModuleTest(int /*argc*/, char* /*argv*/[]) { - US_TEST_BEGIN("ModuleTest"); + //US_TEST_BEGIN("ModuleTest"); + + std::vector modules = ModuleRegistry::GetModules(); + for (std::vector::iterator iter = modules.begin(), iterEnd = modules.end(); + iter != iterEnd; ++iter) + { + std::cout << "----- " << (*iter)->GetName() << std::endl; + } + frame01(); frame02a(); ModuleContext* mc = GetModuleContext(); TestModuleListener listener; try { mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); throw; } try { mc->AddServiceListener(&listener, &TestModuleListener::ServiceChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); throw; } frame005a(mc); frame010a(mc); frame018a(mc); SharedLibrary libA(LIB_PATH, "TestModuleA"); frame020a(mc, listener, libA); frame030b(mc, listener, libA); frame045a(mc); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); mc->RemoveServiceListener(&listener, &TestModuleListener::ServiceChanged); - US_TEST_END() + //US_TEST_END() + return 0; } diff --git a/core/test/usServiceControlInterface.h b/core/test/usServiceControlInterface.h index c6172a4778..5ed36ca6bd 100644 --- a/core/test/usServiceControlInterface.h +++ b/core/test/usServiceControlInterface.h @@ -1,45 +1,43 @@ /*============================================================================= 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 USSERVICECONTROLINTERFACE_H #define USSERVICECONTROLINTERFACE_H #include #include #include US_BEGIN_NAMESPACE struct ServiceControlInterface { virtual ~ServiceControlInterface() {} virtual void ServiceControl(int service, const std::string& operation, int ranking) = 0; }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(ServiceControlInterface), "org.us.testing.ServiceControlInterface") - #endif // USSERVICECONTROLINTERFACE_H diff --git a/core/test/usServiceFactoryTest.cpp b/core/test/usServiceFactoryTest.cpp index fa75a65922..1a7d0bde39 100644 --- a/core/test/usServiceFactoryTest.cpp +++ b/core/test/usServiceFactoryTest.cpp @@ -1,236 +1,231 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif } // end unnamed namespace US_BEGIN_NAMESPACE struct TestModuleH { virtual ~TestModuleH() {} }; struct TestModuleH2 { virtual ~TestModuleH2() {} }; US_END_NAMESPACE -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH), "org.cppmicroservices.TestModuleH") -US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH2), "org.cppmicroservices.TestModuleH2") - void TestServiceFactoryModuleScope() { // Install and start test module H, a service factory and test that the methods // in that interface works. SharedLibrary target(LIB_PATH, "TestModuleH"); #ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what()) } +#endif - Module* moduleH = ModuleRegistry::GetModule("TestModuleH Module"); + Module* moduleH = ModuleRegistry::GetModule("TestModuleH"); US_TEST_CONDITION_REQUIRED(moduleH != 0, "Test for existing module TestModuleH") std::vector registeredRefs = moduleH->GetRegisteredServices(); US_TEST_CONDITION_REQUIRED(registeredRefs.size() == 2, "# of registered services") US_TEST_CONDITION(registeredRefs[0].GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_MODULE(), "service scope") US_TEST_CONDITION(registeredRefs[1].GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") -#endif ModuleContext* mc = GetModuleContext(); // Check that a service reference exist - const ServiceReferenceU sr1 = mc->GetServiceReference("org.cppmicroservices.TestModuleH"); + const ServiceReferenceU sr1 = mc->GetServiceReference("us::TestModuleH"); US_TEST_CONDITION_REQUIRED(sr1, "Service shall be present.") US_TEST_CONDITION(sr1.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_MODULE(), "service scope") InterfaceMap service = mc->GetService(sr1); US_TEST_CONDITION_REQUIRED(service.size() >= 1, "GetService()") - InterfaceMap::const_iterator serviceIter = service.find("org.cppmicroservices.TestModuleH"); + InterfaceMap::const_iterator serviceIter = service.find("us::TestModuleH"); US_TEST_CONDITION_REQUIRED(serviceIter != service.end(), "GetService()") US_TEST_CONDITION_REQUIRED(serviceIter->second != NULL, "GetService()") InterfaceMap service2 = mc->GetService(sr1); US_TEST_CONDITION(service == service2, "Same service pointer") -#ifdef US_BUILD_SHARED_LIBS std::vector usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") US_TEST_CONDITION(usedRefs[0] == sr1, "service ref in use") InterfaceMap service3 = moduleH->GetModuleContext()->GetService(sr1); US_TEST_CONDITION(service != service3, "Different service pointer") US_TEST_CONDITION(moduleH->GetModuleContext()->UngetService(sr1), "UngetService()") -#endif US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == false, "ungetService()") US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == true, "ungetService()") target.Unload(); } void TestServiceFactoryPrototypeScope() { // Install and start test module H, a service factory and test that the methods // in that interface works. SharedLibrary target(LIB_PATH, "TestModuleH"); #ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what()) } - Module* moduleH = ModuleRegistry::GetModule("TestModuleH Module"); + Module* moduleH = ModuleRegistry::GetModule("TestModuleH"); US_TEST_CONDITION_REQUIRED(moduleH != 0, "Test for existing module TestModuleH") #endif ModuleContext* mc = GetModuleContext(); // Check that a service reference exist const ServiceReference sr1 = mc->GetServiceReference(); US_TEST_CONDITION_REQUIRED(sr1, "Service shall be present.") US_TEST_CONDITION(sr1.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") ServiceObjects svcObjects = mc->GetServiceObjects(sr1); TestModuleH2* prototypeServiceH2 = svcObjects.GetService(); const ServiceReferenceU sr1void = mc->GetServiceReference(us_service_interface_iid()); ServiceObjects svcObjectsVoid = mc->GetServiceObjects(sr1void); InterfaceMap prototypeServiceH2Void = svcObjectsVoid.GetService(); US_TEST_CONDITION_REQUIRED(prototypeServiceH2Void.find(us_service_interface_iid()) != prototypeServiceH2Void.end(), "ServiceObjects::GetService()") #ifdef US_BUILD_SHARED_LIBS // There should be only one service in use US_TEST_CONDITION_REQUIRED(mc->GetModule()->GetServicesInUse().size() == 1, "services in use") #endif TestModuleH2* moduleScopeService = mc->GetService(sr1); US_TEST_CONDITION_REQUIRED(moduleScopeService && moduleScopeService != prototypeServiceH2, "GetService()") US_TEST_CONDITION_REQUIRED(prototypeServiceH2 != prototypeServiceH2Void.find(us_service_interface_iid())->second, "GetService()") svcObjectsVoid.UngetService(prototypeServiceH2Void); TestModuleH2* moduleScopeService2 = mc->GetService(sr1); US_TEST_CONDITION(moduleScopeService == moduleScopeService2, "Same service pointer") #ifdef US_BUILD_SHARED_LIBS std::vector usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") US_TEST_CONDITION(usedRefs[0] == sr1, "service ref in use") #endif std::string filter = "(" + ServiceConstants::SERVICE_ID() + "=" + sr1.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + ")"; const ServiceReference sr2 = mc->GetServiceReferences(filter).front(); US_TEST_CONDITION_REQUIRED(sr2, "Service shall be present.") US_TEST_CONDITION(sr2.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") US_TEST_CONDITION(any_cast(sr2.GetProperty(ServiceConstants::SERVICE_ID())) == any_cast(sr1.GetProperty(ServiceConstants::SERVICE_ID())), "same service id") try { svcObjects.UngetService(moduleScopeService2); US_TEST_FAILED_MSG(<< "std::invalid_argument exception expected") } catch (const std::invalid_argument&) { // this is expected } #ifdef US_BUILD_SHARED_LIBS // There should still be only one service in use usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") #endif ServiceObjects svcObjects2 = svcObjects; ServiceObjects svcObjects3 = mc->GetServiceObjects(sr1); try { svcObjects3.UngetService(prototypeServiceH2); US_TEST_FAILED_MSG(<< "std::invalid_argument exception expected") } catch (const std::invalid_argument&) { // this is expected } svcObjects2.UngetService(prototypeServiceH2); prototypeServiceH2 = svcObjects2.GetService(); TestModuleH2* prototypeServiceH2_2 = svcObjects3.GetService(); US_TEST_CONDITION_REQUIRED(prototypeServiceH2_2 && prototypeServiceH2_2 != prototypeServiceH2, "prototype service") svcObjects2.UngetService(prototypeServiceH2); svcObjects3.UngetService(prototypeServiceH2_2); US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == false, "ungetService()") US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == true, "ungetService()") target.Unload(); } int usServiceFactoryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceFactoryTest"); TestServiceFactoryModuleScope(); TestServiceFactoryPrototypeScope(); US_TEST_END() } diff --git a/core/test/usServiceHooksTest.cpp b/core/test/usServiceHooksTest.cpp index a9821498bc..be44b68a4c 100644 --- a/core/test/usServiceHooksTest.cpp +++ b/core/test/usServiceHooksTest.cpp @@ -1,414 +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"); + std::vector refs = context->GetServiceReferences("us::TestModuleAService"); US_TEST_CONDITION(refs.empty(), "Empty references"); - ServiceReferenceU ref = context->GetServiceReference("org.cppmicroservices.TestModuleAService"); + ServiceReferenceU ref = context->GetServiceReference("us::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"); + refs = context->GetServiceReferences("us::TestModuleAService"); US_TEST_CONDITION(!refs.empty(), "Non-empty references"); - ref = context->GetServiceReference("org.cppmicroservices.TestModuleAService"); + ref = context->GetServiceReference("us::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/test/usServiceRegistryPerformanceTest.cpp b/core/test/usServiceRegistryPerformanceTest.cpp index 8de3197608..d1a8f16000 100644 --- a/core/test/usServiceRegistryPerformanceTest.cpp +++ b/core/test/usServiceRegistryPerformanceTest.cpp @@ -1,424 +1,428 @@ /*============================================================================= 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 "usTestingMacros.h" #include #include US_USE_NAMESPACE #ifdef US_PLATFORM_APPLE #include #elif defined(US_PLATFORM_POSIX) #include #include #ifndef _POSIX_MONOTONIC_CLOCK #error Monotonic clock support missing on this POSIX platform #endif #elif defined(US_PLATFORM_WINDOWS) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef VC_EXTRA_LEAN +#define VC_EXTRA_LEAN +#endif #include #else #error High precision timer support nod available on this platform #endif #include class HighPrecisionTimer { public: inline HighPrecisionTimer(); inline void Start(); inline long long ElapsedMilli(); inline long long ElapsedMicro(); private: #ifdef US_PLATFORM_APPLE static double timeConvert; uint64_t startTime; #elif defined(US_PLATFORM_POSIX) timespec startTime; #elif defined(US_PLATFORM_WINDOWS) LARGE_INTEGER timerFrequency; LARGE_INTEGER startTime; #endif }; #ifdef US_PLATFORM_APPLE double HighPrecisionTimer::timeConvert = 0.0; inline HighPrecisionTimer::HighPrecisionTimer() : startTime(0) { if (timeConvert == 0) { mach_timebase_info_data_t timeBase; mach_timebase_info(&timeBase); timeConvert = static_cast(timeBase.numer) / static_cast(timeBase.denom) / 1000.0; } } inline void HighPrecisionTimer::Start() { startTime = mach_absolute_time(); } inline long long HighPrecisionTimer::ElapsedMilli() { uint64_t current = mach_absolute_time(); return static_cast(current - startTime) * timeConvert / 1000.0; } inline long long HighPrecisionTimer::ElapsedMicro() { uint64_t current = mach_absolute_time(); return static_cast(current - startTime) * timeConvert; } #elif defined(US_PLATFORM_POSIX) inline HighPrecisionTimer::HighPrecisionTimer() { startTime.tv_nsec = 0; startTime.tv_sec = 0; } inline void HighPrecisionTimer::Start() { clock_gettime(CLOCK_MONOTONIC, &startTime); } inline long long HighPrecisionTimer::ElapsedMilli() { timespec current; clock_gettime(CLOCK_MONOTONIC, ¤t); return (static_cast(current.tv_sec)*1000 + current.tv_nsec/1000/1000) - (static_cast(startTime.tv_sec)*1000 + startTime.tv_nsec/1000/1000); } inline long long HighPrecisionTimer::ElapsedMicro() { timespec current; clock_gettime(CLOCK_MONOTONIC, ¤t); return (static_cast(current.tv_sec)*1000*1000 + current.tv_nsec/1000) - (static_cast(startTime.tv_sec)*1000*1000 + startTime.tv_nsec/1000); } #elif defined(US_PLATFORM_WINDOWS) inline HighPrecisionTimer::HighPrecisionTimer() { if (!QueryPerformanceFrequency(&timerFrequency)) throw std::runtime_error("QueryPerformanceFrequency() failed"); } inline void HighPrecisionTimer::Start() { //DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0); QueryPerformanceCounter(&startTime); //SetThreadAffinityMask(GetCurrentThread(), oldmask); } inline long long HighPrecisionTimer::ElapsedMilli() { LARGE_INTEGER current; QueryPerformanceCounter(¤t); return (current.QuadPart - startTime.QuadPart) / (timerFrequency.QuadPart / 1000); } inline long long HighPrecisionTimer::ElapsedMicro() { LARGE_INTEGER current; QueryPerformanceCounter(¤t); return (current.QuadPart - startTime.QuadPart) / (timerFrequency.QuadPart / (1000*1000)); } #endif class MyServiceListener; struct IPerfTestService { virtual ~IPerfTestService() {} }; -US_DECLARE_SERVICE_INTERFACE(IPerfTestService, "org.cppmicroservices.test.IPerfTestService") - class ServiceRegistryPerformanceTest { private: friend class MyServiceListener; ModuleContext* mc; int nListeners; int nServices; std::size_t nRegistered; std::size_t nUnregistering; std::size_t nModified; std::vector > regs; std::vector listeners; std::vector services; public: ServiceRegistryPerformanceTest(ModuleContext* context); void InitTestCase(); void CleanupTestCase(); void TestAddListeners(); void TestRegisterServices(); void TestModifyServices(); void TestUnregisterServices(); private: std::ostream& Log() const { return std::cout; } void AddListeners(int n); void RegisterServices(int n); void ModifyServices(); void UnregisterServices(); }; class MyServiceListener { private: ServiceRegistryPerformanceTest* ts; public: MyServiceListener(ServiceRegistryPerformanceTest* ts) : ts(ts) { } void ServiceChanged(const ServiceEvent ev) { switch(ev.GetType()) { case ServiceEvent::REGISTERED: ts->nRegistered++; break; case ServiceEvent::UNREGISTERING: ts->nUnregistering++; break; case ServiceEvent::MODIFIED: ts->nModified++; break; default: break; } } }; ServiceRegistryPerformanceTest::ServiceRegistryPerformanceTest(ModuleContext* context) : mc(context) , nListeners(100) , nServices(1000) , nRegistered(0) , nUnregistering(0) , nModified(0) { } void ServiceRegistryPerformanceTest::InitTestCase() { Log() << "Initialize event counters\n"; nRegistered = 0; nUnregistering = 0; nModified = 0; } void ServiceRegistryPerformanceTest::CleanupTestCase() { Log() << "Remove all service listeners\n"; for(std::size_t i = 0; i < listeners.size(); i++) { try { MyServiceListener* l = listeners[i]; mc->RemoveServiceListener(l, &MyServiceListener::ServiceChanged); delete l; } catch (const std::exception& e) { Log() << e.what(); } } listeners.clear(); } void ServiceRegistryPerformanceTest::TestAddListeners() { AddListeners(nListeners); } void ServiceRegistryPerformanceTest::AddListeners(int n) { Log() << "adding " << n << " service listeners\n"; for(int i = 0; i < n; i++) { MyServiceListener* l = new MyServiceListener(this); try { listeners.push_back(l); mc->AddServiceListener(l, &MyServiceListener::ServiceChanged, "(perf.service.value>=0)"); } catch (const std::exception& e) { Log() << e.what(); } } Log() << "listener count=" << listeners.size() << "\n"; } void ServiceRegistryPerformanceTest::TestRegisterServices() { Log() << "Register services, and check that we get #of services (" << nServices << ") * #of listeners (" << nListeners << ") REGISTERED events\n"; Log() << "registering " << nServices << " services, listener count=" << listeners.size() << "\n"; HighPrecisionTimer t; t.Start(); RegisterServices(nServices); long long ms = t.ElapsedMilli(); Log() << "register took " << ms << "ms\n"; US_TEST_CONDITION_REQUIRED(nServices * listeners.size() == nRegistered, "# REGISTERED events must be same as # of registered services * # of listeners"); } void ServiceRegistryPerformanceTest::RegisterServices(int n) { class PerfTestService : public IPerfTestService { }; std::string pid("my.service."); for(int i = 0; i < n; i++) { ServiceProperties props; std::stringstream ss; ss << pid << i; props["service.pid"] = ss.str(); props["perf.service.value"] = i+1; PerfTestService* service = new PerfTestService(); services.push_back(service); ServiceRegistration reg = mc->RegisterService(service, props); regs.push_back(reg); } } void ServiceRegistryPerformanceTest::TestModifyServices() { Log() << "Modify all services, and check that we get #of services (" << nServices << ") * #of listeners (" << nListeners << ") MODIFIED events\n"; HighPrecisionTimer t; t.Start(); ModifyServices(); long long ms = t.ElapsedMilli(); Log() << "modify took " << ms << "ms\n"; US_TEST_CONDITION_REQUIRED(nServices * listeners.size() == nModified, "# MODIFIED events must be same as # of modified services * # of listeners"); } void ServiceRegistryPerformanceTest::ModifyServices() { Log() << "modifying " << regs.size() << " services, listener count=" << listeners.size() << "\n"; for(std::size_t i = 0; i < regs.size(); i++) { ServiceRegistration reg = regs[i]; ServiceProperties props; props["perf.service.value"] = i * 2; reg.SetProperties(props); } } void ServiceRegistryPerformanceTest::TestUnregisterServices() { Log() << "Unregister all services, and check that we get #of services (" << nServices << ") * #of listeners (" << nListeners << ") UNREGISTERING events\n"; HighPrecisionTimer t; t.Start(); UnregisterServices(); long long ms = t.ElapsedMilli(); Log() << "unregister took " << ms << "ms\n"; US_TEST_CONDITION_REQUIRED(nServices * listeners.size() == nUnregistering, "# UNREGISTERING events must be same as # of (un)registered services * # of listeners"); } void ServiceRegistryPerformanceTest::UnregisterServices() { Log() << "unregistering " << regs.size() << " services, listener count=" << listeners.size() << "\n"; for(std::size_t i = 0; i < regs.size(); i++) { ServiceRegistration reg = regs[i]; reg.Unregister(); } regs.clear(); } int usServiceRegistryPerformanceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceRegistryPerformanceTest") ServiceRegistryPerformanceTest perfTest(GetModuleContext()); perfTest.InitTestCase(); perfTest.TestAddListeners(); perfTest.TestRegisterServices(); perfTest.TestModifyServices(); perfTest.TestUnregisterServices(); perfTest.CleanupTestCase(); US_TEST_END() } diff --git a/core/test/usServiceRegistryTest.cpp b/core/test/usServiceRegistryTest.cpp index 8943242082..a755db97bf 100644 --- a/core/test/usServiceRegistryTest.cpp +++ b/core/test/usServiceRegistryTest.cpp @@ -1,138 +1,140 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usTestingMacros.h" #include #include #include #include US_USE_NAMESPACE struct ITestServiceA { virtual ~ITestServiceA() {} }; -US_DECLARE_SERVICE_INTERFACE(ITestServiceA, "org.cppmicroservices.testing.ITestServiceA") -int TestMultipleServiceRegistrations() +void TestServiceInterfaceId() +{ + US_TEST_CONDITION(us_service_interface_iid() == "int", "Service interface id int") + US_TEST_CONDITION(us_service_interface_iid() == "ITestServiceA", "Service interface id ITestServiceA") +} + +void TestMultipleServiceRegistrations() { struct TestServiceA : public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; TestServiceA s2; ServiceRegistration reg1 = context->RegisterService(&s1); ServiceRegistration reg2 = context->RegisterService(&s2); std::vector > refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Testing for two registered ITestServiceA services") reg2.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 1, "Testing for one registered ITestServiceA services") reg1.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.empty(), "Testing for no ITestServiceA services") ServiceReference ref = context->GetServiceReference(); US_TEST_CONDITION_REQUIRED(!ref, "Testing for invalid service reference") - - return EXIT_SUCCESS; } -int TestServicePropertiesUpdate() +void TestServicePropertiesUpdate() { struct TestServiceA : public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; ServiceProperties props; props["string"] = std::string("A std::string"); props["bool"] = false; const char* str = "A const char*"; props["const char*"] = str; ServiceRegistration reg1 = context->RegisterService(&s1, props); ServiceReference ref1 = context->GetServiceReference(); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 1, "Testing service count") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == false, "Testing bool property") // register second service with higher rank TestServiceA s2; ServiceProperties props2; props2[ServiceConstants::SERVICE_RANKING()] = 50; ServiceRegistration reg2 = context->RegisterService(&s2, props2); // Get the service with the highest rank, this should be s2. ServiceReference ref2 = context->GetServiceReference(); TestServiceA* service = dynamic_cast(context->GetService(ref2)); US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") props["bool"] = true; // change the service ranking props[ServiceConstants::SERVICE_RANKING()] = 100; reg1.SetProperties(props); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 2, "Testing service count") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == true, "Testing bool property") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty(ServiceConstants::SERVICE_RANKING())) == 100, "Testing updated ranking") // Service with the highest ranking should now be s1 service = dynamic_cast(context->GetService(ref1)); US_TEST_CONDITION_REQUIRED(service == &s1, "Testing highest service rank") reg1.Unregister(); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count") service = dynamic_cast(context->GetService(ref2)); US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") reg2.Unregister(); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().empty(), "Testing service count") - - return EXIT_SUCCESS; } int usServiceRegistryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceRegistryTest"); - US_TEST_CONDITION(TestMultipleServiceRegistrations() == EXIT_SUCCESS, "Testing service registrations: ") - US_TEST_CONDITION(TestServicePropertiesUpdate() == EXIT_SUCCESS, "Testing service property update: ") + TestServiceInterfaceId(); + TestMultipleServiceRegistrations(); + TestServicePropertiesUpdate(); US_TEST_END() } diff --git a/core/test/usServiceTemplateTest.cpp b/core/test/usServiceTemplateTest.cpp index ef7ab792bb..b91dae1bd5 100644 --- a/core/test/usServiceTemplateTest.cpp +++ b/core/test/usServiceTemplateTest.cpp @@ -1,211 +1,208 @@ /*============================================================================= 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(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(&s2), "interface1 ptr") i1 = NULL; 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(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(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(InterfaceType())), "unget interface2 factory ptr") i1 = mc->GetService(sr3.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(&s3), "interface1 ptr") i1 = NULL; 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(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(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(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(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(InterfaceType())), "unget interface3 factory ptr") sr1.Unregister(); sr2.Unregister(); sr3.Unregister(); US_TEST_END() } diff --git a/core/test/usServiceTrackerTest.cpp b/core/test/usServiceTrackerTest.cpp index 7031e0da4d..f0a4871099 100644 --- a/core/test/usServiceTrackerTest.cpp +++ b/core/test/usServiceTrackerTest.cpp @@ -1,281 +1,284 @@ -/*=================================================================== +/*============================================================================= -The Medical Imaging Interaction Toolkit (MITK) + Library: CppMicroServices -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + 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 -See LICENSE.txt or http://www.mitk.org for details. + 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 "usServiceControlInterface.h" #include US_USE_NAMESPACE bool CheckConvertibility(const std::vector& refs, std::vector::const_iterator idBegin, std::vector::const_iterator idEnd) { std::vector ids; ids.assign(idBegin, idEnd); for (std::vector::const_iterator sri = refs.begin(); sri != refs.end(); ++sri) { for (std::vector::iterator idIter = ids.begin(); idIter != ids.end(); ++idIter) { if (sri->IsConvertibleTo(*idIter)) { ids.erase(idIter); break; } } } return ids.empty(); } struct MyInterfaceOne { virtual ~MyInterfaceOne() {} }; -US_DECLARE_SERVICE_INTERFACE(MyInterfaceOne, "org.cppmicroservices.servicetrackertest.MyInterfaceOne") struct MyInterfaceTwo { virtual ~MyInterfaceTwo() {} }; -US_DECLARE_SERVICE_INTERFACE(MyInterfaceTwo, "org.cppmicroservices.servicetrackertest.MyInterfaceTwo") class MyCustomizer : public us::ServiceTrackerCustomizer { public: MyCustomizer(us::ModuleContext* context) : m_context(context) {} virtual MyInterfaceOne* AddingService(const ServiceReferenceType& reference) { US_TEST_CONDITION_REQUIRED(reference, "AddingService() valid reference") return m_context->GetService(reference); } virtual void ModifiedService(const ServiceReferenceType& reference, MyInterfaceOne* service) { US_TEST_CONDITION(reference, "ModifiedService() valid reference") US_TEST_CONDITION(service, "ModifiedService() valid service") } virtual void RemovedService(const ServiceReferenceType& reference, MyInterfaceOne* service) { US_TEST_CONDITION(reference, "RemovedService() valid reference") US_TEST_CONDITION(service, "RemovedService() valid service") } private: us::ModuleContext* m_context; }; void TestFilterString() { us::ModuleContext* context = us::GetModuleContext(); MyCustomizer customizer(context); us::LDAPFilter filter("(" + us::ServiceConstants::SERVICE_ID() + ">=0)"); us::ServiceTracker tracker(context, filter, &customizer); tracker.Open(); struct MyServiceOne : public MyInterfaceOne {}; struct MyServiceTwo : public MyInterfaceTwo {}; MyServiceOne serviceOne; MyServiceTwo serviceTwo; context->RegisterService(&serviceOne); context->RegisterService(&serviceTwo); 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"); + std::string s1("us::TestModuleSService"); ServiceReferenceU servref = mc->GetServiceReference(s1 + "0"); - US_TEST_CONDITION_REQUIRED(servref != 0, "Test if registered service of id org.cppmicroservices.TestModuleSService0"); + US_TEST_CONDITION_REQUIRED(servref != 0, "Test if registered service of id us::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/test/usStaticModuleResourceTest.cpp b/core/test/usStaticModuleResourceTest.cpp index fd068d07c4..ab5985f005 100644 --- a/core/test/usStaticModuleResourceTest.cpp +++ b/core/test/usStaticModuleResourceTest.cpp @@ -1,157 +1,146 @@ /*============================================================================= 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 "usTestingMacros.h" #include "usTestingConfig.h" -#include +#include #include US_USE_NAMESPACE namespace { std::string GetResourceContent(const ModuleResource& resource) { std::string line; ModuleResourceStream rs(resource); std::getline(rs, line); return line; } struct ResourceComparator { bool operator()(const ModuleResource& mr1, const ModuleResource& mr2) const { return mr1 < mr2; } }; void testResourceOperators(Module* module) { std::vector resources = module->FindResources("", "res.txt", false); - US_TEST_CONDITION_REQUIRED(resources.size() == 2, "Check resource count") - US_TEST_CONDITION(resources[0] != resources[1], "Check non-equality for equally named resources") + US_TEST_CONDITION_REQUIRED(resources.size() == 1, "Check resource count") } void testResourcesWithStaticImport(Module* module) { ModuleResource resource = module->GetResource("res.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid res.txt resource") std::string line = GetResourceContent(resource); US_TEST_CONDITION(line == "dynamic resource", "Check dynamic resource content") resource = module->GetResource("dynamic.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid dynamic.txt resource") line = GetResourceContent(resource); US_TEST_CONDITION(line == "dynamic", "Check dynamic resource content") resource = module->GetResource("static.txt"); + US_TEST_CONDITION_REQUIRED(!resource.IsValid(), "Check in-valid static.txt resource") + + Module* importedByBModule = ModuleRegistry::GetModule("TestModuleImportedByB"); + US_TEST_CONDITION_REQUIRED(importedByBModule != NULL, "Check valid static module") + resource = importedByBModule->GetResource("static.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid static.txt resource") line = GetResourceContent(resource); - US_TEST_CONDITION(line == "static", "Check dynamic resource content") + US_TEST_CONDITION(line == "static", "Check static resource content") std::vector resources = module->FindResources("", "*.txt", false); std::stable_sort(resources.begin(), resources.end(), ResourceComparator()); -#ifdef US_BUILD_SHARED_LIBS - US_TEST_CONDITION(resources.size() == 4, "Check imported resource count") + std::vector importedResources = importedByBModule->FindResources("", "*.txt", false); + std::stable_sort(importedResources.begin(), importedResources.end(), ResourceComparator()); + + US_TEST_CONDITION(resources.size() == 2, "Check resource count") + US_TEST_CONDITION(importedResources.size() == 2, "Check resource count") line = GetResourceContent(resources[0]); US_TEST_CONDITION(line == "dynamic", "Check dynamic.txt resource content") line = GetResourceContent(resources[1]); US_TEST_CONDITION(line == "dynamic resource", "Check res.txt (from importing module) resource content") - line = GetResourceContent(resources[2]); - US_TEST_CONDITION(line == "static resource", "Check res.txt (from imported module) resource content") - line = GetResourceContent(resources[3]); - US_TEST_CONDITION(line == "static", "Check static.txt (from importing module) resource content") -#else - US_TEST_CONDITION(resources.size() == 6, "Check imported resource count") - line = GetResourceContent(resources[0]); - US_TEST_CONDITION(line == "dynamic", "Check dynamic.txt resource content") - // skip foo.txt - line = GetResourceContent(resources[2]); - US_TEST_CONDITION(line == "dynamic resource", "Check res.txt (from importing module) resource content") - line = GetResourceContent(resources[3]); + line = GetResourceContent(importedResources[0]); US_TEST_CONDITION(line == "static resource", "Check res.txt (from imported module) resource content") - // skip special_chars.dummy.txt - line = GetResourceContent(resources[5]); + line = GetResourceContent(importedResources[1]); US_TEST_CONDITION(line == "static", "Check static.txt (from importing module) resource content") -#endif } } // end unnamed namespace int usStaticModuleResourceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("StaticModuleResourceTest"); assert(GetModuleContext()); #ifdef US_BUILD_SHARED_LIBS #ifdef US_PLATFORM_WINDOWS const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif SharedLibrary libB(LIB_PATH, "TestModuleB"); try { libB.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } +#endif - Module* module = ModuleRegistry::GetModule("TestModuleB Module"); + Module* module = ModuleRegistry::GetModule("TestModuleB"); US_TEST_CONDITION_REQUIRED(module != NULL, "Test for existing module TestModuleB") - - US_TEST_CONDITION(module->GetName() == "TestModuleB Module", "Test module name") -#else - Module* module = GetModuleContext()->GetModule(); -#endif + US_TEST_CONDITION(module->GetName() == "TestModuleB", "Test module name") testResourceOperators(module); testResourcesWithStaticImport(module); -#ifdef US_BUILD_SHARED_LIBS - ModuleResource resource = module->GetResource("static.txt"); + ModuleResource resource = ModuleRegistry::GetModule("TestModuleImportedByB")->GetResource("static.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid static.txt resource") - +#ifdef US_BUILD_SHARED_LIBS libB.Unload(); - - US_TEST_CONDITION_REQUIRED(resource.IsValid() == false, "Check invalid static.txt resource") + US_TEST_CONDITION_REQUIRED(resource.IsValid() == true, "Check still valid static.txt resource") #endif US_TEST_END() } diff --git a/core/test/usStaticModuleTest.cpp b/core/test/usStaticModuleTest.cpp index d158c6a742..187a8cf642 100644 --- a/core/test/usStaticModuleTest.cpp +++ b/core/test/usStaticModuleTest.cpp @@ -1,195 +1,183 @@ /*============================================================================= 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 "usTestUtilModuleListener.h" #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 // Load libTestModuleB and check that it exists and that the service it registers exists, // also check that the expected events occur void frame020a(ModuleContext* mc, TestModuleListener& listener, #ifdef US_BUILD_SHARED_LIBS SharedLibrary& libB) { try { libB.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } - - Module* moduleB = ModuleRegistry::GetModule("TestModuleB Module"); - US_TEST_CONDITION_REQUIRED(moduleB != 0, "Test for existing module TestModuleB") - - US_TEST_CONDITION(moduleB->GetName() == "TestModuleB Module", "Test module name") #else SharedLibrary& /*libB*/) { #endif + Module* moduleB = ModuleRegistry::GetModule("TestModuleB"); + US_TEST_CONDITION_REQUIRED(moduleB != 0, "Test for existing module TestModuleB") + + Module* moduleImportedByB = ModuleRegistry::GetModule("TestModuleImportedByB"); + US_TEST_CONDITION_REQUIRED(moduleImportedByB != 0, "Test for existing module TestModuleImportedByB") + + US_TEST_CONDITION(moduleB->GetName() == "TestModuleB", "Test module name") + // Check if libB registered the expected service try { - std::vector refs = mc->GetServiceReferences("org.cppmicroservices.TestModuleBService"); + std::vector refs = mc->GetServiceReferences("us::TestModuleBService"); US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Test that both the service from the shared and imported library are regsitered"); InterfaceMap o1 = mc->GetService(refs.front()); US_TEST_CONDITION(!o1.empty(), "Test if first service object found"); InterfaceMap o2 = mc->GetService(refs.back()); US_TEST_CONDITION(!o2.empty(), "Test if second service object found"); try { US_TEST_CONDITION(mc->UngetService(refs.front()), "Test if Service UnGet for first service returns true"); US_TEST_CONDITION(mc->UngetService(refs.back()), "Test if Service UnGet for second service returns true"); } catch (const std::logic_error le) { US_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) } // check the listeners for events std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleB)); + pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleImportedByB)); + pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleImportedByB)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, refs.back())); seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, refs.front())); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } catch (const ServiceException& /*se*/) { US_TEST_FAILED_MSG(<< "test module, expected service not found"); } #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleB->IsLoaded() == true, "Test if loaded correctly"); #endif } // Unload libB and check for correct events void frame030b(ModuleContext* mc, TestModuleListener& listener, SharedLibrary& libB) { -#ifdef US_BUILD_SHARED_LIBS - Module* moduleB = ModuleRegistry::GetModule("TestModuleB Module"); + Module* moduleB = ModuleRegistry::GetModule("TestModuleB"); US_TEST_CONDITION_REQUIRED(moduleB != 0, "Test for non-null module") -#endif + + Module* moduleImportedByB = ModuleRegistry::GetModule("TestModuleImportedByB"); + US_TEST_CONDITION_REQUIRED(moduleImportedByB != 0, "Test for non-null module") std::vector refs - = mc->GetServiceReferences("org.cppmicroservices.TestModuleBService"); + = mc->GetServiceReferences("us::TestModuleBService"); US_TEST_CONDITION(refs.front(), "Test for first valid service reference") US_TEST_CONDITION(refs.back(), "Test for second valid service reference") try { libB.Unload(); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleB->IsLoaded() == false, "Test for unloaded state") #endif } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) } std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS + pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleImportedByB)); + pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleImportedByB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleB)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS - seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, refs.back())); seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, refs.front())); + seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, refs.back())); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } } // end unnamed namespace int usStaticModuleTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("StaticModuleTest"); ModuleContext* mc = GetModuleContext(); TestModuleListener listener; - try - { - mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); - } - catch (const std::logic_error& ise) - { - US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); - throw; - } - - try - { - mc->AddServiceListener(&listener, &TestModuleListener::ServiceChanged); - } - catch (const std::logic_error& ise) - { - US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); - throw; - } + ModuleListenerRegistrationHelper ml(mc, &listener, &TestModuleListener::ModuleChanged); + ServiceListenerRegistrationHelper sl(mc, &listener, &TestModuleListener::ServiceChanged); SharedLibrary libB(LIB_PATH, "TestModuleB"); frame020a(mc, listener, libB); frame030b(mc, listener, libB); - mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); - mc->RemoveServiceListener(&listener, &TestModuleListener::ServiceChanged); - US_TEST_END() } diff --git a/core/test/usTestManager.cpp b/core/test/usTestDriverActivator.cpp similarity index 60% copy from core/test/usTestManager.cpp copy to core/test/usTestDriverActivator.cpp index def9cee003..c929f22ace 100644 --- a/core/test/usTestManager.cpp +++ b/core/test/usTestDriverActivator.cpp @@ -1,83 +1,67 @@ /*============================================================================= 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 "usTestDriverActivator.h" #include "usModuleImport.h" US_BEGIN_NAMESPACE -TestManager& TestManager::GetInstance() -{ - static TestManager instance; - return instance; -} - -void TestManager::Initialize() -{ - m_FailedTests = 0; - m_PassedTests = 0; -} +TestDriverActivator* TestDriverActivator::m_Instance = 0; -int TestManager::NumberOfFailedTests() +TestDriverActivator::TestDriverActivator() + : m_LoadCalled(false) { - return m_FailedTests; } -int TestManager::NumberOfPassedTests() +bool TestDriverActivator::LoadCalled() { - return m_PassedTests; + return m_Instance ? m_Instance->m_LoadCalled : false; } -void TestManager::TestFailed() +void TestDriverActivator::Load(ModuleContext*) { - m_FailedTests++; + this->m_Instance = this; + this->m_LoadCalled = true; } -void TestManager::TestPassed() +void TestDriverActivator::Unload(ModuleContext*) { - m_PassedTests++; + this->m_Instance = 0; } US_END_NAMESPACE +US_EXPORT_MODULE_ACTIVATOR(us::TestDriverActivator) + #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_INITIALIZE_STATIC_MODULE(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 - ) +US_IMPORT_MODULE(main) #endif diff --git a/core/test/modules/libM/usTestModuleM.cpp b/core/test/usTestDriverActivator.h similarity index 73% copy from core/test/modules/libM/usTestModuleM.cpp copy to core/test/usTestDriverActivator.h index 934056c84b..30a6cc2f4e 100644 --- a/core/test/modules/libM/usTestModuleM.cpp +++ b/core/test/usTestDriverActivator.h @@ -1,43 +1,49 @@ /*============================================================================= 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 USTESTDRIVERACTIVATOR_H +#define USTESTDRIVERACTIVATOR_H #include US_BEGIN_NAMESPACE -class TestModuleMActivator : public ModuleActivator +class TestDriverActivator : public ModuleActivator { public: - void Load(ModuleContext*) - { - } + TestDriverActivator(); - void Unload(ModuleContext*) - { - } + static bool LoadCalled(); + void Load(ModuleContext*); + + void Unload(ModuleContext* ); + +private: + + static TestDriverActivator* m_Instance; + bool m_LoadCalled; }; US_END_NAMESPACE -US_EXPORT_MODULE_ACTIVATOR(TestModuleM, US_PREPEND_NAMESPACE(TestModuleMActivator)) +#endif // USTESTDRIVERACTIVATOR_H diff --git a/core/test/usTestManager.cpp b/core/test/usTestManager.cpp index def9cee003..7bc5deadaf 100644 --- a/core/test/usTestManager.cpp +++ b/core/test/usTestManager.cpp @@ -1,83 +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. =============================================================================*/ #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/test/usTestUtilModuleListener.h b/core/test/usTestUtilModuleListener.h index b8a75c8647..dd3e313244 100644 --- a/core/test/usTestUtilModuleListener.h +++ b/core/test/usTestUtilModuleListener.h @@ -1,66 +1,141 @@ /*============================================================================= 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 USTESTUTILMODULELISTENER_H #define USTESTUTILMODULELISTENER_H #include "usModuleEvent.h" #include "usServiceEvent.h" +#include "usModuleContext.h" + +#include "usTestingMacros.h" US_BEGIN_NAMESPACE class ModuleContext; class TestModuleListener { public: TestModuleListener(); void ModuleChanged(const ModuleEvent event); void ServiceChanged(const ServiceEvent event); ModuleEvent GetModuleEvent() const; ServiceEvent GetServiceEvent() const; bool CheckListenerEvents( bool pexp, ModuleEvent::Type ptype, bool sexp, ServiceEvent::Type stype, Module* moduleX, ServiceReferenceU* servX); bool CheckListenerEvents(const std::vector& pEvts); bool CheckListenerEvents(const std::vector& seEvts); bool CheckListenerEvents(const std::vector& pEvts, const std::vector& seEvts); private: std::vector serviceEvents; std::vector moduleEvents; }; +template +class ModuleListenerRegistrationHelper +{ + +public: + + typedef void(Receiver::*CallbackType)(const ModuleEvent); + + ModuleListenerRegistrationHelper(ModuleContext* context, Receiver* receiver, CallbackType callback) + : context(context) + , receiver(receiver) + , callback(callback) + { + try + { + context->AddModuleListener(receiver, callback); + } + catch (const std::logic_error& ise) + { + US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); + throw; + } + } + + ~ModuleListenerRegistrationHelper() + { + context->RemoveModuleListener(receiver, callback); + } + +private: + + ModuleContext* context; + Receiver* receiver; + CallbackType callback; +}; + +template +class ServiceListenerRegistrationHelper +{ + +public: + + typedef void(Receiver::*CallbackType)(const ServiceEvent); + + ServiceListenerRegistrationHelper(ModuleContext* context, Receiver* receiver, CallbackType callback) + : context(context) + , receiver(receiver) + , callback(callback) + { + try + { + context->AddServiceListener(receiver, callback); + } + catch (const std::logic_error& ise) + { + US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); + throw; + } + } + + ~ServiceListenerRegistrationHelper() + { + context->RemoveServiceListener(receiver, callback); + } + +private: + + ModuleContext* context; + Receiver* receiver; + CallbackType callback; +}; + US_END_NAMESPACE #endif // USTESTUTILMODULELISTENER_H diff --git a/core/test/usTestingMacros.h b/core/test/usTestingMacros.h index 44ec95e0d5..b7a2b2d04b 100644 --- a/core/test/usTestingMacros.h +++ b/core/test/usTestingMacros.h @@ -1,133 +1,138 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ +#ifndef USTESTINGMACROS_H_ +#define USTESTINGMACROS_H_ + #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) + +#endif // USTESTINGMACROS_H_ diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index a12f7b2599..3e0e7613c5 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,77 +1,78 @@ if(NOT US_IS_EMBEDDED AND NOT US_NO_DOCUMENTATION) find_package(Doxygen) if(DOXYGEN_FOUND) option(US_DOCUMENTATION_FOR_WEBPAGE "Build Doxygen documentation for the webpage" OFF) set(US_DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Doxygen output directory") mark_as_advanced(US_DOCUMENTATION_FOR_WEBPAGE US_DOXYGEN_OUTPUT_DIR) set(US_HAVE_DOT "NO") if(DOXYGEN_DOT_EXECUTABLE) set(US_HAVE_DOT "YES") endif() if(NOT DEFINED US_DOXYGEN_DOT_NUM_THREADS) set(US_DOXYGEN_DOT_NUM_THREADS 4) endif() # We are in standalone mode, so we generate a "mainpage" set(US_DOXYGEN_MAIN_PAGE_CMD "\\mainpage") set(US_DOXYGEN_ENABLED_SECTIONS "us_standalone") if(US_DOCUMENTATION_FOR_WEBPAGE) configure_file(doxygen/header.html ${CMAKE_CURRENT_BINARY_DIR}/header.html COPY_ONLY) set(US_DOXYGEN_HEADER header.html) configure_file(doxygen/footer.html ${CMAKE_CURRENT_BINARY_DIR}/footer.html COPY_ONLY) set(US_DOXYGEN_FOOTER footer.html) configure_file(doxygen/doxygen_extra.css ${CMAKE_CURRENT_BINARY_DIR}/doxygen_extra.css COPY_ONLY) set(US_DOXYGEN_EXTRA_CSS doxygen_extra.css) set(US_DOXYGEN_OUTPUT_DIR ${PROJECT_SOURCE_DIR}/gh-pages) if(${PROJECT_NAME}_MINOR_VERSION EQUAL 99) set(US_DOXYGEN_HTML_OUTPUT "doc_latest") else() set(US_DOXYGEN_HTML_OUTPUT "doc_${${PROJECT_NAME}_MAJOR_VERSION}_${${PROJECT_NAME}_MINOR_VERSION}") endif() else() set(US_DOXYGEN_HEADER ) set(US_DOXYGEN_FOOTER ) set(US_DOXYGEN_CSS ) set(US_DOXYGEN_HTML_OUTPUT "html") endif() # Compile a command line tool which transforms comments in CMake scripts into # Doxygen parseable C code. set(CMakeDoxygenFilter_EXECUTABLE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CMakeDoxygenFilter${CMAKE_EXECUTABLE_SUFFIX}") try_compile(_result_var "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/CMakeDoxygenFilter.cpp" OUTPUT_VARIABLE _compile_output COPY_FILE ${CMakeDoxygenFilter_EXECUTABLE} ) if(NOT _result_var) message(FATAL_ERROR "error: Faild to compile ${CMAKE_CURRENT_SOURCE_DIR}/CMakeDoxygenFilter.cpp (result: ${result_var})\n${_compile_output}") endif() configure_file(doxygen.conf.in ${CMAKE_CURRENT_BINARY_DIR}/doxygen.conf) add_custom_target(doc ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.conf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + VERBATIM ) install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${PROJECT_BINARY_DIR}\" --target doc)") - install(DIRECTORY ${US_DOXYGEN_OUTPUT_DIR}/${US_DOXYGEN_HTML_OUTPUT} - DESTINATION ${AUXILIARY_INSTALL_DIR}/doc/ + install(DIRECTORY "${US_DOXYGEN_OUTPUT_DIR}/${US_DOXYGEN_HTML_OUTPUT}" + DESTINATION "${AUXILIARY_INSTALL_DIR}/doc/" COMPONENT doc) endif() endif() diff --git a/doc/doxygen.conf.in b/doc/doxygen.conf.in index 5caf947d09..85ebf73053 100644 --- a/doc/doxygen.conf.in +++ b/doc/doxygen.conf.in @@ -1,2305 +1,2306 @@ # Doxyfile 1.8.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "C++ Micro Services" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @CppMicroServices_VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "A dynamic OSGi-like C++ service registry" # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = "@US_DOXYGEN_OUTPUT_DIR@" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- # Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, # Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, # Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, # Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = "FIXME=\par Fix Me's:\n" \ "embmainpage{1}=@US_DOXYGEN_MAIN_PAGE_CMD@" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = YES # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = YES # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = YES # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = @US_DOXYGEN_ENABLED_SECTIONS@ # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 0 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = NO # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See # also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = "@PROJECT_SOURCE_DIR@" \ - "@PROJECT_SOURCE_DIR@/cmake/usFunctionEmbedResources.cmake" \ + "@PROJECT_SOURCE_DIR@/cmake/usFunctionAddResources.cmake" \ "@PROJECT_SOURCE_DIR@/cmake/usFunctionGenerateModuleInit.cmake" \ - "@PROJECT_SOURCE_DIR@/cmake/usFunctionGenerateExecutableInit.cmake" \ - "@PROJECT_BINARY_DIR@/include/usGlobalConfig.h" + "@PROJECT_BINARY_DIR@/include/usGlobalConfig.h" \ + "@PROJECT_BINARY_DIR@/core/include" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.h \ *.dox \ *.md # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = "@PROJECT_SOURCE_DIR@/README.md" \ "@PROJECT_SOURCE_DIR@/gh-pages/" \ + "@PROJECT_SOURCE_DIR@/third_party/" \ "@PROJECT_SOURCE_DIR@/.git/" # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = */test/* \ */snippets/* \ - */examples/* \ + */core/examples/* \ */.git/* \ *_p.h \ *Private.* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = us \ US_NAMESPACE \ *Private* \ ModuleInfo \ ServiceObjectsBase* \ TrackedService* # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = "@PROJECT_SOURCE_DIR@/core/doc/snippets/" \ "@PROJECT_SOURCE_DIR@/core/examples/" # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = *.cmake=@CMakeDoxygenFilter_EXECUTABLE@ # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = "@US_DOXYGEN_HTML_OUTPUT@" # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = "@US_DOXYGEN_HEADER@" # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = "@US_DOXYGEN_FOOTER@" # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = "@US_DOXYGEN_EXTRA_CSS@" # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 300 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /