diff --git a/CMake/mitkMacroCreateModule.cmake b/CMake/mitkMacroCreateModule.cmake index 3d904551ed..d8d77972e9 100644 --- a/CMake/mitkMacroCreateModule.cmake +++ b/CMake/mitkMacroCreateModule.cmake @@ -1,238 +1,267 @@ ################################################################## # # MITK_CREATE_MODULE # #! Creates a module for the automatic module dependency system within MITK. #! Configurations are generated in the moduleConf directory. #! #! USAGE: #! #! \code #! MITK_CREATE_MODULE( #! [INCLUDE_DIRS ] #! [INTERNAL_INCLUDE_DIRS ] #! [DEPENDS ] #! [PACKAGE_DEPENDS ] #! [TARGET_DEPENDS #! [EXPORT_DEFINE ] #! [QT_MODULE] #! \endcode #! #! \param MODULE_NAME_IN The name for the new module # ################################################################## MACRO(MITK_CREATE_MODULE MODULE_NAME_IN) MACRO_PARSE_ARGUMENTS(MODULE - "SUBPROJECTS;INCLUDE_DIRS;INTERNAL_INCLUDE_DIRS;DEPENDS;DEPENDS_INTERNAL;PACKAGE_DEPENDS;TARGET_DEPENDS;EXPORT_DEFINE;ADDITIONAL_LIBS;GENERATED_CPP" - "QT_MODULE;FORCE_STATIC;HEADERS_ONLY;GCC_DEFAULT_VISIBILITY" + "SUBPROJECTS;VERSION;INCLUDE_DIRS;INTERNAL_INCLUDE_DIRS;DEPENDS;DEPENDS_INTERNAL;PACKAGE_DEPENDS;TARGET_DEPENDS;EXPORT_DEFINE;ADDITIONAL_LIBS;GENERATED_CPP" + "QT_MODULE;FORCE_STATIC;HEADERS_ONLY;GCC_DEFAULT_VISIBILITY;NO_INIT" ${ARGN}) SET(MODULE_NAME ${MODULE_NAME_IN}) IF(MODULE_HEADERS_ONLY) SET(MODULE_PROVIDES ) ELSE() SET(MODULE_PROVIDES ${MODULE_NAME}) ENDIF() IF(NOT MODULE_SUBPROJECTS) IF(MITK_DEFAULT_SUBPROJECTS) SET(MODULE_SUBPROJECTS ${MITK_DEFAULT_SUBPROJECTS}) ENDIF() ENDIF() # check if the subprojects exist as targets IF(MODULE_SUBPROJECTS) FOREACH(subproject ${MODULE_SUBPROJECTS}) IF(NOT TARGET ${subproject}) MESSAGE(SEND_ERROR "The subproject ${subproject} does not have a corresponding target") ENDIF() ENDFOREACH() ENDIF() # assume worst case SET(MODULE_IS_ENABLED 0) # first we check if we have an explicit module build list IF(MITK_MODULES_TO_BUILD) LIST(FIND MITK_MODULES_TO_BUILD ${MODULE_NAME} _MOD_INDEX) IF(_MOD_INDEX EQUAL -1) SET(MODULE_IS_EXCLUDED 1) ENDIF() ENDIF() IF(NOT MODULE_IS_EXCLUDED) # first of all we check for the dependencies MITK_CHECK_MODULE(_MISSING_DEP ${MODULE_DEPENDS}) IF(_MISSING_DEP) MESSAGE("Module ${MODULE_NAME} won't be built, missing dependency: ${_MISSING_DEP}") SET(MODULE_IS_ENABLED 0) ELSE(_MISSING_DEP) SET(MODULE_IS_ENABLED 1) # now check for every package if it is enabled. This overlaps a bit with # MITK_CHECK_MODULE ... FOREACH(_package ${MODULE_PACKAGE_DEPENDS}) - IF((DEFINED MITK_USE_${_package}) AND NOT (MITK_USE_${_package})) - MESSAGE("Module ${MODULE_NAME} won't be built. Turn on MITK_USE_${_package} if you want to use it.") - SET(MODULE_IS_ENABLED 0) - ENDIF() + IF((DEFINED MITK_USE_${_package}) AND NOT (MITK_USE_${_package})) + MESSAGE("Module ${MODULE_NAME} won't be built. Turn on MITK_USE_${_package} if you want to use it.") + SET(MODULE_IS_ENABLED 0) + ENDIF() ENDFOREACH() IF(MODULE_IS_ENABLED) - IF(NOT MODULE_QT_MODULE OR MITK_USE_QT) - SET(MODULE_IS_ENABLED 1) - _MITK_CREATE_MODULE_CONF() - IF(NOT MODULE_EXPORT_DEFINE) - SET(MODULE_EXPORT_DEFINE ${MODULE_NAME}_EXPORT) - ENDIF(NOT MODULE_EXPORT_DEFINE) - CONFIGURE_FILE(${MITK_SOURCE_DIR}/CMake/moduleExports.h.in ${MITK_MODULES_CONF_DIR}/${MODULE_NAME}Exports.h @ONLY) - IF(MITK_GENERATE_MODULE_DOT) - MESSAGE("MODULEDOTNAME ${MODULE_NAME}") - FOREACH(dep ${MODULE_DEPENDS}) - MESSAGE("MODULEDOT \"${MODULE_NAME}\" -> \"${dep}\" ; ") - ENDFOREACH(dep) - ENDIF(MITK_GENERATE_MODULE_DOT) - - SET(DEPENDS "${MODULE_DEPENDS}") - SET(DEPENDS_BEFORE "not initialized") - SET(PACKAGE_DEPENDS "${MODULE_PACKAGE_DEPENDS}") - MITK_USE_MODULE("${MODULE_DEPENDS}") - - # ok, now create the module itself - INCLUDE_DIRECTORIES(. ${ALL_INCLUDE_DIRECTORIES}) - INCLUDE(files.cmake) - - SET(module_compile_flags ) - # MinGW does not export all symbols automatically, so no need to set flags - IF(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW AND NOT MODULE_GCC_DEFAULT_VISIBILITY) - IF(${GCC_VERSION} VERSION_GREATER "4.5.0") - # With gcc < 4.5, type_info objects need special care. Especially exceptions - # and inline definitions of classes from 3rd party libraries would need - # to be wrapped with pragma GCC visibility statements if the library is not - # prepared to handle hidden visibility. This would need too many changes in - # MITK and would be too fragile. - SET(module_compile_flags "${module_compile_flags} -fvisibility=hidden -fvisibility-inlines-hidden") - ENDIF() - ENDIF() - - IF(NOT MODULE_QT_MODULE) - ORGANIZE_SOURCES(SOURCE ${CPP_FILES} - HEADER ${H_FILES} - TXX ${TXX_FILES} - DOC ${DOX_FILES} - ) - - IF(MODULE_FORCE_STATIC) + IF(NOT MODULE_QT_MODULE OR MITK_USE_QT) + SET(MODULE_IS_ENABLED 1) + _MITK_CREATE_MODULE_CONF() + IF(NOT MODULE_EXPORT_DEFINE) + SET(MODULE_EXPORT_DEFINE ${MODULE_NAME}_EXPORT) + ENDIF(NOT MODULE_EXPORT_DEFINE) + CONFIGURE_FILE(${MITK_SOURCE_DIR}/CMake/moduleExports.h.in ${MITK_MODULES_CONF_DIR}/${MODULE_NAME}Exports.h @ONLY) + + IF(MITK_GENERATE_MODULE_DOT) + MESSAGE("MODULEDOTNAME ${MODULE_NAME}") + FOREACH(dep ${MODULE_DEPENDS}) + MESSAGE("MODULEDOT \"${MODULE_NAME}\" -> \"${dep}\" ; ") + ENDFOREACH(dep) + ENDIF(MITK_GENERATE_MODULE_DOT) + + IF(NOT MODULE_NO_INIT) + # Create variables of the ModuleInfo object, created in CMake/mitkModuleInit.cpp + SET(MODULE_LIBNAME ${MODULE_PROVIDES}) + SET(MODULE_DEPENDS_STR "") + FOREACH(_dep ${MODULE_DEPENDS} ${MODULE_DEPENDS_INTERNAL}) + SET(MODULE_DEPENDS_STR "${MODULE_DEPENDS_STR} ${_dep}") + ENDFOREACH() + SET(MODULE_PACKAGE_DEPENDS_STR "") + FOREACH(_dep ${MODULE_PACKAGE_DEPENDS}) + SET(MODULE_PACKAGE_DEPENDS_STR "${MODULE_PACKAGE_DEPENDS_STR} ${_dep}") + ENDFOREACH() + IF(MODULE_QT_MODULE) + SET(MODULE_QT_BOOL "true") + ELSE() + SET(MODULE_QT_BOOL "false") + ENDIF() + SET(module_init_src_file "${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}_init.cpp") + CONFIGURE_FILE(${MITK_SOURCE_DIR}/CMake/mitkModuleInit.cpp ${module_init_src_file} @ONLY) + ENDIF() + + SET(DEPENDS "${MODULE_DEPENDS}") + SET(DEPENDS_BEFORE "not initialized") + SET(PACKAGE_DEPENDS "${MODULE_PACKAGE_DEPENDS}") + MITK_USE_MODULE("${MODULE_DEPENDS}") + + # ok, now create the module itself + INCLUDE_DIRECTORIES(. ${ALL_INCLUDE_DIRECTORIES}) + INCLUDE(files.cmake) + + SET(module_compile_flags ) + # MinGW does not export all symbols automatically, so no need to set flags + IF(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW AND NOT MODULE_GCC_DEFAULT_VISIBILITY) + IF(${GCC_VERSION} VERSION_GREATER "4.5.0") + # With gcc < 4.5, type_info objects need special care. Especially exceptions + # and inline definitions of classes from 3rd party libraries would need + # to be wrapped with pragma GCC visibility statements if the library is not + # prepared to handle hidden visibility. This would need too many changes in + # MITK and would be too fragile. + SET(module_compile_flags "${module_compile_flags} -fvisibility=hidden -fvisibility-inlines-hidden") + ENDIF() + ENDIF() + + IF(NOT MODULE_NO_INIT) + LIST(APPEND CPP_FILES ${module_init_src_file}) + ENDIF() + + IF(NOT MODULE_QT_MODULE) + ORGANIZE_SOURCES(SOURCE ${CPP_FILES} + HEADER ${H_FILES} + TXX ${TXX_FILES} + DOC ${DOX_FILES} + ) + + IF(MODULE_FORCE_STATIC) SET(_STATIC STATIC) ELSE() SET(_STATIC ) - ENDIF(MODULE_FORCE_STATIC) - - SET(coverage_sources ${CPP_FILES} ${H_FILES} ${GLOBBED__H_FILES} ${CORRESPONDING__H_FILES} ${TXX_FILES} ${TOOL_CPPS}) - IF(MODULE_SUBPROJECTS) - SET_PROPERTY(SOURCE ${coverage_sources} APPEND PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) - ENDIF() - - IF(NOT MODULE_HEADERS_ONLY) - IF(ALL_LIBRARY_DIRS) - # LINK_DIRECTORIES applies only to targets which are added after the call to LINK_DIRECTORIES - LINK_DIRECTORIES(${ALL_LIBRARY_DIRS}) - ENDIF(ALL_LIBRARY_DIRS) + ENDIF(MODULE_FORCE_STATIC) + + SET(coverage_sources ${CPP_FILES} ${H_FILES} ${GLOBBED__H_FILES} ${CORRESPONDING__H_FILES} ${TXX_FILES} ${TOOL_CPPS}) + IF(MODULE_SUBPROJECTS) + SET_PROPERTY(SOURCE ${coverage_sources} APPEND PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) + ENDIF() + + IF(NOT MODULE_HEADERS_ONLY) + IF(ALL_LIBRARY_DIRS) + # LINK_DIRECTORIES applies only to targets which are added after the call to LINK_DIRECTORIES + LINK_DIRECTORIES(${ALL_LIBRARY_DIRS}) + ENDIF(ALL_LIBRARY_DIRS) ADD_LIBRARY(${MODULE_PROVIDES} ${_STATIC} ${coverage_sources} ${CPP_FILES_GENERATED} ${DOX_FILES} ${UI_FILES}) - IF(MODULE_TARGET_DEPENDS) - ADD_DEPENDENCIES(${MODULE_PROVIDES} ${MODULE_TARGET_DEPENDS}) - ENDIF() - IF(MODULE_SUBPROJECTS) - SET_PROPERTY(TARGET ${MODULE_PROVIDES} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) - FOREACH(subproject ${MODULE_SUBPROJECTS}) - ADD_DEPENDENCIES(${subproject} ${MODULE_PROVIDES}) - ENDFOREACH() - ENDIF() - IF(ALL_LIBRARIES) - TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ${ALL_LIBRARIES}) - ENDIF(ALL_LIBRARIES) - - IF(MINGW) - TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ssp) # add stack smash protection lib - ENDIF() - ENDIF() - - ELSE(NOT MODULE_QT_MODULE) + IF(MODULE_TARGET_DEPENDS) + ADD_DEPENDENCIES(${MODULE_PROVIDES} ${MODULE_TARGET_DEPENDS}) + ENDIF() + IF(MODULE_SUBPROJECTS) + SET_PROPERTY(TARGET ${MODULE_PROVIDES} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) + FOREACH(subproject ${MODULE_SUBPROJECTS}) + ADD_DEPENDENCIES(${subproject} ${MODULE_PROVIDES}) + ENDFOREACH() + ENDIF() + IF(ALL_LIBRARIES) + TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ${ALL_LIBRARIES}) + ENDIF(ALL_LIBRARIES) - INCLUDE(files.cmake) - - IF(UI_FILES) - QT4_WRAP_UI(Q${KITNAME}_GENERATED_UI_CPP ${UI_FILES}) - ENDIF(UI_FILES) - - IF(MOC_H_FILES) - QT4_WRAP_CPP(Q${KITNAME}_GENERATED_MOC_CPP ${MOC_H_FILES}) - ENDIF(MOC_H_FILES) - - IF(QRC_FILES) - QT4_ADD_RESOURCES(Q${KITNAME}_GENERATED_QRC_CPP ${QRC_FILES}) - ENDIF(QRC_FILES) - - SET(Q${KITNAME}_GENERATED_CPP ${Q${KITNAME}_GENERATED_CPP} ${Q${KITNAME}_GENERATED_UI_CPP} ${Q${KITNAME}_GENERATED_MOC_CPP} ${Q${KITNAME}_GENERATED_QRC_CPP}) - - ORGANIZE_SOURCES(SOURCE ${CPP_FILES} - HEADER ${H_FILES} - TXX ${TXX_FILES} - DOC ${DOX_FILES} - UI ${UI_FILES} - QRC ${QRC_FILES} - MOC ${Q${KITNAME}_GENERATED_MOC_CPP} - GEN_QRC ${Q${KITNAME}_GENERATED_QRC_CPP} - GEN_UI ${Q${KITNAME}_GENERATED_UI_CPP}) - - # MITK_GENERATE_TOOLS_LIBRARY(Qmitk${LIBPOSTFIX} "NO") - - SET(coverage_sources ${CPP_FILES} ${CORRESPONDING__H_FILES} ${GLOBBED__H_FILES} ${TXX_FILES} ${TOOL_GUI_CPPS}) - SET_PROPERTY(SOURCE ${coverage_sources} APPEND PROPERTY LABELS ${MODULE_SUBPROJECTS}) - - IF(NOT MODULE_HEADERS_ONLY) - IF(ALL_LIBRARY_DIRS) - # LINK_DIRECTORIES applies only to targets which are added after the call to LINK_DIRECTORIES - LINK_DIRECTORIES(${ALL_LIBRARY_DIRS}) - ENDIF(ALL_LIBRARY_DIRS) - ADD_LIBRARY(${MODULE_PROVIDES} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) - TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ${QT_LIBRARIES} ${ALL_LIBRARIES} QVTK) - IF(MODULE_TARGET_DEPENDS) - ADD_DEPENDENCIES(${MODULE_PROVIDES} ${MODULE_TARGET_DEPENDS}) - ENDIF() - IF(MINGW) - TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ssp) # add stack smash protection lib - ENDIF() - IF(MODULE_SUBPROJECTS) - SET_PROPERTY(TARGET ${MODULE_PROVIDES} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) - FOREACH(subproject ${MODULE_SUBPROJECTS}) - ADD_DEPENDENCIES(${subproject} ${MODULE_PROVIDES}) - ENDFOREACH() - ENDIF() - ENDIF() - - ENDIF(NOT MODULE_QT_MODULE) + IF(MINGW) + TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ssp) # add stack smash protection lib + ENDIF() + ENDIF() - IF(NOT MODULE_HEADERS_ONLY) - # Apply properties to the module target. - SET_TARGET_PROPERTIES(${MODULE_PROVIDES} PROPERTIES - COMPILE_FLAGS "${module_compile_flags}" - ) - ENDIF() + ELSE(NOT MODULE_QT_MODULE) + + INCLUDE(files.cmake) + IF(NOT MODULE_NO_INIT) + LIST(APPEND CPP_FILES ${module_init_src_file}) + ENDIF() + + IF(UI_FILES) + QT4_WRAP_UI(Q${KITNAME}_GENERATED_UI_CPP ${UI_FILES}) + ENDIF(UI_FILES) + + IF(MOC_H_FILES) + QT4_WRAP_CPP(Q${KITNAME}_GENERATED_MOC_CPP ${MOC_H_FILES}) + ENDIF(MOC_H_FILES) + + IF(QRC_FILES) + QT4_ADD_RESOURCES(Q${KITNAME}_GENERATED_QRC_CPP ${QRC_FILES}) + ENDIF(QRC_FILES) - # install only if shared lib (for now) - IF(NOT _STATIC OR MINGW) - IF(NOT MODULE_HEADERS_ONLY) - # # deprecated: MITK_INSTALL_TARGETS(${MODULE_PROVIDES}) - ENDIF() - ENDIF(NOT _STATIC OR MINGW) - - ENDIF(NOT MODULE_QT_MODULE OR MITK_USE_QT) + SET(Q${KITNAME}_GENERATED_CPP ${Q${KITNAME}_GENERATED_CPP} ${Q${KITNAME}_GENERATED_UI_CPP} ${Q${KITNAME}_GENERATED_MOC_CPP} ${Q${KITNAME}_GENERATED_QRC_CPP}) + + ORGANIZE_SOURCES(SOURCE ${CPP_FILES} + HEADER ${H_FILES} + TXX ${TXX_FILES} + DOC ${DOX_FILES} + UI ${UI_FILES} + QRC ${QRC_FILES} + MOC ${Q${KITNAME}_GENERATED_MOC_CPP} + GEN_QRC ${Q${KITNAME}_GENERATED_QRC_CPP} + GEN_UI ${Q${KITNAME}_GENERATED_UI_CPP}) + + # MITK_GENERATE_TOOLS_LIBRARY(Qmitk${LIBPOSTFIX} "NO") + + SET(coverage_sources ${CPP_FILES} ${CORRESPONDING__H_FILES} ${GLOBBED__H_FILES} ${TXX_FILES} ${TOOL_GUI_CPPS}) + SET_PROPERTY(SOURCE ${coverage_sources} APPEND PROPERTY LABELS ${MODULE_SUBPROJECTS}) + + IF(NOT MODULE_HEADERS_ONLY) + IF(ALL_LIBRARY_DIRS) + # LINK_DIRECTORIES applies only to targets which are added after the call to LINK_DIRECTORIES + LINK_DIRECTORIES(${ALL_LIBRARY_DIRS}) + ENDIF(ALL_LIBRARY_DIRS) + ADD_LIBRARY(${MODULE_PROVIDES} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) + TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ${QT_LIBRARIES} ${ALL_LIBRARIES} QVTK) + IF(MODULE_TARGET_DEPENDS) + ADD_DEPENDENCIES(${MODULE_PROVIDES} ${MODULE_TARGET_DEPENDS}) + ENDIF() + IF(MINGW) + TARGET_LINK_LIBRARIES(${MODULE_PROVIDES} ssp) # add stack smash protection lib + ENDIF() + IF(MODULE_SUBPROJECTS) + SET_PROPERTY(TARGET ${MODULE_PROVIDES} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) + FOREACH(subproject ${MODULE_SUBPROJECTS}) + ADD_DEPENDENCIES(${subproject} ${MODULE_PROVIDES}) + ENDFOREACH() + ENDIF() + ENDIF() + + ENDIF(NOT MODULE_QT_MODULE) + + IF(NOT MODULE_HEADERS_ONLY) + # Apply properties to the module target. + SET_TARGET_PROPERTIES(${MODULE_PROVIDES} PROPERTIES + COMPILE_FLAGS "${module_compile_flags}" + ) + ENDIF() + + # install only if shared lib (for now) + IF(NOT _STATIC OR MINGW) + IF(NOT MODULE_HEADERS_ONLY) + # # deprecated: MITK_INSTALL_TARGETS(${MODULE_PROVIDES}) + ENDIF() + ENDIF(NOT _STATIC OR MINGW) + + ENDIF(NOT MODULE_QT_MODULE OR MITK_USE_QT) ENDIF(MODULE_IS_ENABLED) ENDIF(_MISSING_DEP) ENDIF(NOT MODULE_IS_EXCLUDED) - IF(NOT MODULE_IS_ENABLED) + IF(NOT MODULE_IS_ENABLED) _MITK_CREATE_MODULE_CONF() - ENDIF(NOT MODULE_IS_ENABLED) + ENDIF(NOT MODULE_IS_ENABLED) + ENDMACRO(MITK_CREATE_MODULE) diff --git a/CMake/mitkMacroCreateModuleTests.cmake b/CMake/mitkMacroCreateModuleTests.cmake index 4f1f5f06f8..e7948abb0e 100644 --- a/CMake/mitkMacroCreateModuleTests.cmake +++ b/CMake/mitkMacroCreateModuleTests.cmake @@ -1,85 +1,85 @@ # # Create tests and testdriver for this module # # Usage: MITK_CREATE_MODULE_TESTS( [EXTRA_DRIVER_INIT init_code] ) # # EXTRA_DRIVER_INIT is inserted as c++ code in the testdriver and will be executed before each test # MACRO(MITK_CREATE_MODULE_TESTS) MACRO_PARSE_ARGUMENTS(MODULE_TEST "EXTRA_DRIVER_INIT;EXTRA_DRIVER_INCLUDE" "" ${ARGN}) IF(BUILD_TESTING AND MODULE_IS_ENABLED) SET(OLD_MOC_H_FILES ${MOC_H_FILES}) SET(MOC_H_FILES) INCLUDE(files.cmake) INCLUDE_DIRECTORIES(.) IF(DEFINED MOC_H_FILES) QT4_WRAP_CPP(MODULE_TEST_GENERATED_MOC_CPP ${MOC_H_FILES}) ENDIF(DEFINED MOC_H_FILES) SET(CMAKE_TESTDRIVER_BEFORE_TESTMAIN "mitk::LoggingBackend::Register(); ${MODULE_TEST_EXTRA_DRIVER_INIT};") SET(CMAKE_TESTDRIVER_AFTER_TESTMAIN "mitk::LoggingBackend::Unregister();") IF(NOT MODULE_TEST_EXTRA_DRIVER_INCLUDE) # this is necessary to make the LoggingBackend calls available if nothing else is included SET(MODULE_TEST_EXTRA_DRIVER_INCLUDE "mitkLog.h") ENDIF(NOT MODULE_TEST_EXTRA_DRIVER_INCLUDE) CREATE_TEST_SOURCELIST(MODULETEST_SOURCE ${MODULE_NAME}TestDriver.cpp ${MODULE_TESTS} ${MODULE_IMAGE_TESTS} ${MODULE_CUSTOM_TESTS} EXTRA_INCLUDE ${MODULE_TEST_EXTRA_DRIVER_INCLUDE} ) SET(TESTDRIVER ${MODULE_NAME}TestDriver) - ADD_EXECUTABLE(${TESTDRIVER} ${MODULETEST_SOURCE} ${MODULE_TEST_GENERATED_MOC_CPP}) + ADD_EXECUTABLE(${TESTDRIVER} ${MODULETEST_SOURCE} ${MODULE_TEST_GENERATED_MOC_CPP} ${TEST_CPP_FILES}) TARGET_LINK_LIBRARIES(${TESTDRIVER} ${MODULE_PROVIDES} ${ALL_LIBRARIES}) IF(MODULE_SUBPROJECTS) FOREACH(subproject ${MODULE_SUBPROJECTS}) ADD_DEPENDENCIES(${subproject} ${TESTDRIVER}) ENDFOREACH() ENDIF() # # Now tell CMake which tests should be run. This is done automatically # for all tests in ${KITNAME}_TESTS and ${KITNAME}_IMAGE_TESTS. The IMAGE_TESTS # are run for each image in the TESTIMAGES list. # FOREACH( test ${MODULE_TESTS} ) GET_FILENAME_COMPONENT(TName ${test} NAME_WE) ADD_TEST(${TName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName}) # Add labels for CDash subproject support IF(MODULE_SUBPROJECTS) SET_PROPERTY(TEST ${TName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) ENDIF() ENDFOREACH( test ) FOREACH(image ${MODULE_TESTIMAGES} ${ADDITIONAL_TEST_IMAGES} ) IF(EXISTS ${image}) SET(IMAGE_FULL_PATH ${image}) ELSE(EXISTS ${image}) # todo: maybe search other paths as well # yes, please in mitk/Testing/Data, too SET(IMAGE_FULL_PATH ${MITK_DATA_DIR}/${image}) ENDIF(EXISTS ${image}) IF(EXISTS ${IMAGE_FULL_PATH}) FOREACH( test ${MODULE_IMAGE_TESTS} ) GET_FILENAME_COMPONENT(TName ${test} NAME_WE) GET_FILENAME_COMPONENT(ImageName ${IMAGE_FULL_PATH} NAME) ADD_TEST(${TName}_${ImageName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName} ${IMAGE_FULL_PATH}) # Add labels for CDash subproject support IF(MODULE_SUBPROJECTS) SET_PROPERTY(TEST ${TName}_${ImageName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) ENDIF() ENDFOREACH( test ) ELSE(EXISTS ${IMAGE_FULL_PATH}) MESSAGE("!!!!! No such file: ${IMAGE_FULL_PATH} !!!!!") ENDIF(EXISTS ${IMAGE_FULL_PATH}) ENDFOREACH( image ) SET(MOC_H_FILES ${OLD_MOC_H_FILES}) ENDIF(BUILD_TESTING AND MODULE_IS_ENABLED) ENDMACRO(MITK_CREATE_MODULE_TESTS) diff --git a/CMake/mitkModuleInit.cpp b/CMake/mitkModuleInit.cpp new file mode 100644 index 0000000000..cab644a9e3 --- /dev/null +++ b/CMake/mitkModuleInit.cpp @@ -0,0 +1,82 @@ +/*============================================================================= + + Library: CTK + + 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 "mitkStaticInit.h" + +#include "mitkModuleRegistry.h" +#include "mitkModuleContext.h" +#include "mitkModule.h" +#include "mitkModuleInfo.h" +#include "mitkModuleUtils.h" + +namespace mitk { + +MITK_GLOBAL_STATIC_WITH_ARGS(ModuleInfo, moduleInfo, ("@MODULE_NAME@", "@MODULE_LIBNAME@", "@MODULE_DEPENDS_STR@", "@MODULE_PACKAGE_DEPENDS_STR@", "@MODULE_VERSION@", @MODULE_QT_BOOL@)) + +#if defined(__GNUC__) +class __attribute__ ((visibility ("hidden"))) ModuleInitializer { +#else +class ModuleInitializer { +#endif + +public: + + ModuleInitializer() + { + std::string location = ModuleUtils::GetLibraryPath(moduleInfo()->libName, (void*)moduleInfo); + std::string activator_func = "_mitk_module_activator_instance_"; + activator_func.append(moduleInfo()->name); + + moduleInfo()->location = location; + moduleInfo()->activatorHook = (ModuleInfo::ModuleActivatorHook)ModuleUtils::GetSymbol(location, activator_func.c_str()); + + Register(); + } + + static void Register() + { + ModuleRegistry::Register(moduleInfo()); + } + + ~ModuleInitializer() + { + ModuleRegistry::UnRegister(moduleInfo()); + } + +}; + +ModuleContext* GetModuleContext() +{ + // make sure the module is registered + if (moduleInfo()->id == 0) + { + ModuleInitializer::Register(); + } + + return ModuleRegistry::GetModule(moduleInfo()->id)->GetModuleContext(); +} + +} + +static mitk::ModuleInitializer coreModule; + + + diff --git a/CMake/mitkSetupVariables.cmake b/CMake/mitkSetupVariables.cmake index b907f922c0..412bd20206 100644 --- a/CMake/mitkSetupVariables.cmake +++ b/CMake/mitkSetupVariables.cmake @@ -1,151 +1,151 @@ if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() set(LIBPOSTFIX "") # MITK_VERSION set(MITK_VERSION_MAJOR "0") set(MITK_VERSION_MINOR "15") set(MITK_VERSION_PATCH "1") set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") if(NOT UNIX AND NOT MINGW) set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms") endif() # build the MITK_INCLUDE_DIRS variable set(MITK_INCLUDE_DIRS ${PROJECT_BINARY_DIR}) -set(CORE_DIRECTORIES DataManagement Algorithms IO Rendering Interactions Controllers) +set(CORE_DIRECTORIES DataManagement Algorithms IO Rendering Interactions Controllers Service) foreach(d ${CORE_DIRECTORIES}) list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/Core/Code/${d}) endforeach() #list(APPEND MITK_INCLUDE_DIRS #${ITK_INCLUDE_DIRS} #${VTK_INCLUDE_DIRS} # ) foreach(d Utilities Utilities/ipPic Utilities/IIL4MITK Utilities/pic2vtk Utilities/tinyxml Utilities/mbilog) list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/${d}) endforeach() list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/Utilities/mbilog) if(WIN32) list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipPic/win32) endif() # additional include dirs variables set(ANN_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ann/include) set(IPSEGMENTATION_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipSegmentation) # variables containing librariy names set(MITK_CORE_LIBRARIES Mitk) set(VTK_FOR_MITK_LIBRARIES vtkGraphics vtkCommon vtkFiltering vtkftgl vtkGraphics vtkHybrid vtkImaging vtkIO vtkParallel vtkRendering vtkVolumeRendering vtkWidgets ${VTK_JPEG_LIBRARIES} ${VTK_PNG_LIBRARIES} ${VTK_ZLIB_LIBRARIES} ${VTK_EXPAT_LIBRARIES} ${VTK_FREETYPE_LIBRARIES} ) # TODO: maybe solve this with lib depends mechanism of CMake set(UTIL_FOR_MITK_LIBRARIES mitkIpPic mitkIpFunc mbilog) set(LIBRARIES_FOR_MITK_CORE ${UTIL_FOR_MITK_LIBRARIES} ${VTK_FOR_MITK_LIBRARIES} ${ITK_LIBRARIES} ) set(MITK_LIBRARIES ${MITK_CORE_LIBRARIES} ${LIBRARIES_FOR_MITK_CORE} pic2vtk IIL4MITK ipSegmentation ann ) # variables used in CMake macros which are called from external projects set(MITK_VTK_LIBRARY_DIRS ${VTK_LIBRARY_DIRS}) set(MITK_ITK_LIBRARY_DIRS ${ITK_LIBRARY_DIRS}) # variables containing link directories set(MITK_LIBRARY_DIRS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set(MITK_LINK_DIRECTORIES ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${ITK_LIBRARY_DIRS} ${VTK_LIBRARY_DIRS} ${GDCM_LIBRARY_DIRS}) # Qt support if(MITK_USE_QT) find_package(Qt4 REQUIRED) set(QMITK_INCLUDE_DIRS ${MITK_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/CoreUI/Qmitk ${PROJECT_BINARY_DIR}/CoreUI/Qmitk ) foreach(d QmitkApplicationBase QmitkModels QmitkPropertyObservers) list(APPEND QMITK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/CoreUI/Qmitk/${d}) endforeach() list(APPEND QMITK_INCLUDE_DIRS ${QWT_INCLUDE_DIR}) set(QMITK_LIBRARIES Qmitk ${MITK_LIBRARIES} ${QT_LIBRARIES}) set(QMITK_LINK_DIRECTORIES ${MITK_LINK_DIRECTORIES} ${QT_LIBRARY_DIR}) endif() if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() # create a list of types for template instantiations of itk image access functions function(_create_type_seq TYPES seq_var seqdim_var) set(_seq ) set(_seq_dim ) string(REPLACE "," ";" _pixeltypes "${TYPES}") foreach(_pixeltype ${_pixeltypes}) set(_seq "${_seq}(${_pixeltype})") set(_seq_dim "${_seq_dim}((${_pixeltype},dim))") endforeach() set(${seq_var} "${_seq}" PARENT_SCOPE) set(${seqdim_var} "${_seq_dim}" PARENT_SCOPE) endfunction() set(MITK_ACCESSBYITK_PIXEL_TYPES ) set(MITK_ACCESSBYITK_PIXEL_TYPES_SEQ ) set(MITK_ACCESSBYITK_TYPES_DIMN_SEQ ) foreach(_type INTEGRAL FLOATING COMPOSITE) set(_typelist "${MITK_ACCESSBYITK_${_type}_PIXEL_TYPES}") if(_typelist) if(MITK_ACCESSBYITK_PIXEL_TYPES) set(MITK_ACCESSBYITK_PIXEL_TYPES "${MITK_ACCESSBYITK_PIXEL_TYPES},${_typelist}") else() set(MITK_ACCESSBYITK_PIXEL_TYPES "${_typelist}") endif() endif() _create_type_seq("${_typelist}" MITK_ACCESSBYITK_${_type}_PIXEL_TYPES_SEQ MITK_ACCESSBYITK_${_type}_TYPES_DIMN_SEQ) set(MITK_ACCESSBYITK_PIXEL_TYPES_SEQ "${MITK_ACCESSBYITK_PIXEL_TYPES_SEQ}${MITK_ACCESSBYITK_${_type}_PIXEL_TYPES_SEQ}") set(MITK_ACCESSBYITK_TYPES_DIMN_SEQ "${MITK_ACCESSBYITK_TYPES_DIMN_SEQ}${MITK_ACCESSBYITK_${_type}_TYPES_DIMN_SEQ}") endforeach() set(MITK_ACCESSBYITK_DIMENSIONS_SEQ ) string(REPLACE "," ";" _dimensions "${MITK_ACCESSBYITK_DIMENSIONS}") foreach(_dimension ${_dimensions}) set(MITK_ACCESSBYITK_DIMENSIONS_SEQ "${MITK_ACCESSBYITK_DIMENSIONS_SEQ}(${_dimension})") endforeach() diff --git a/Core/Code/CMakeLists.txt b/Core/Code/CMakeLists.txt index b8097fa4b2..52435db386 100644 --- a/Core/Code/CMakeLists.txt +++ b/Core/Code/CMakeLists.txt @@ -1,53 +1,53 @@ FIND_PACKAGE(OpenGL) IF(NOT OPENGL_FOUND) MESSAGE("GL is required for MITK rendering") ENDIF(NOT OPENGL_FOUND ) SET(TOOL_CPPS "") MITK_CREATE_MODULE( Mitk - INCLUDE_DIRS Algorithms DataManagement Controllers Interactions IO Rendering ${MITK_BINARY_DIR} + INCLUDE_DIRS Algorithms DataManagement Controllers Interactions IO Rendering Service ${MITK_BINARY_DIR} INTERNAL_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR} ${IPSEGMENTATION_INCLUDE_DIR} ${ANN_INCLUDE_DIR} DEPENDS mitkIpFunc mbilog tinyxml DEPENDS_INTERNAL IIL4MITK pic2vtk PACKAGE_DEPENDS ITK VTK EXPORT_DEFINE MITK_CORE_EXPORT ) # this is needed for libraries which link to Mitk and need # symbols from explicitly instantiated templates like # mitk::SurfaceVtkWriter which is referenced in # QmitkCommonFunctionality in the QmitkExt library. IF(MINGW) GET_TARGET_PROPERTY(_mitkCore_MINGW_linkflags Mitk LINK_FLAGS) IF(NOT _mitkCore_MINGW_linkflags) SET(_mitkCore_MINGW_linkflags "") ENDIF(NOT _mitkCore_MINGW_linkflags) SET_TARGET_PROPERTIES(Mitk PROPERTIES LINK_FLAGS "${_mitkCore_MINGW_linkflags} -Wl,--export-all-symbols") ENDIF(MINGW) # replacing Mitk by Mitk [due to removing the PROVIDES macro TARGET_LINK_LIBRARIES(Mitk ${LIBRARIES_FOR_${KITNAME}_CORE} ${IPFUNC_LIBRARY} ipSegmentation ann) TARGET_LINK_LIBRARIES(Mitk ${OPENGL_LIBRARIES} ) IF(MSVC_IDE OR MSVC_VERSION OR MINGW) TARGET_LINK_LIBRARIES(Mitk psapi.lib) ENDIF(MSVC_IDE OR MSVC_VERSION OR MINGW) # verify ITK has been built with GDCM >= 2.0.14 set(GDCM_FULL_VERSION "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}.${GDCM_BUILD_VERSION}") set(MITK_REQUIRED_GDCM_VERSION "2.0.14") if(GDCM_FULL_VERSION VERSION_LESS MITK_REQUIRED_GDCM_VERSION) message(SEND_ERROR "Mitk: MITK requires ITK with at least GDCM version ${MITK_REQUIRED_GDCM_VERSION}.\nFound version ${GDCM_FULL_VERSION} (GDCM NOT found if you don't see a version here)") else(GDCM_FULL_VERSION VERSION_LESS MITK_REQUIRED_GDCM_VERSION) message(STATUS "Mitk: Found GDCM version ${GDCM_FULL_VERSION}") endif(GDCM_FULL_VERSION VERSION_LESS MITK_REQUIRED_GDCM_VERSION) # build tests? OPTION(BUILD_TESTING "Build the MITK Core tests." ON) IF(BUILD_TESTING) ENABLE_TESTING() ADD_SUBDIRECTORY(Testing) ENDIF(BUILD_TESTING) diff --git a/Core/Code/DataManagement/mitkCommon.h b/Core/Code/DataManagement/mitkCommon.h index fa0d9ef3c8..b5063273e7 100644 --- a/Core/Code/DataManagement/mitkCommon.h +++ b/Core/Code/DataManagement/mitkCommon.h @@ -1,107 +1,124 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITK_COMMON_H_DEFINED #define MITK_COMMON_H_DEFINED #ifdef _MSC_VER // This warns about truncation to 255 characters in debug/browse info #pragma warning (disable : 4786) #pragma warning (disable : 4068 ) /* disable unknown pragma warnings */ #endif //add only those headers here that are really necessary for all classes! #include "itkObject.h" #include "mitkConfig.h" #include "mitkLogMacros.h" +#include "mitkExportMacros.h" #ifndef MITK_UNMANGLE_IPPIC #define mitkIpPicDescriptor mitkIpPicDescriptor #endif typedef unsigned int MapperSlotId; #define mitkClassMacro(className,SuperClassName) \ typedef className Self; \ typedef SuperClassName Superclass; \ typedef itk::SmartPointer Pointer; \ typedef itk::SmartPointer ConstPointer; \ itkTypeMacro(className,SuperClassName) /** * Macro for Constructors with one parameter for classes derived from itk::Lightobject **/ #define mitkNewMacro1Param(classname,type) \ static Pointer New(type _arg) \ { \ Pointer smartPtr = new classname ( _arg ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with two parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro2Param(classname,typea,typeb) \ static Pointer New(typea _arga, typeb _argb) \ { \ Pointer smartPtr = new classname ( _arga, _argb ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with three parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro3Param(classname,typea,typeb,typec) \ static Pointer New(typea _arga, typeb _argb, typec _argc) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with three parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro4Param(classname,typea,typeb,typec,typed) \ static Pointer New(typea _arga, typeb _argb, typec _argc, typed _argd) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc, _argd ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** Get a smart const pointer to an object. Creates the member * Get"name"() (e.g., GetPoints()). */ #define mitkGetObjectMacroConst(name,type) \ virtual type * Get##name () const \ { \ itkDebugMacro("returning " #name " address " << this->m_##name ); \ return this->m_##name.GetPointer(); \ } /** Creates a Clone() method for "Classname". Returns a smartPtr of a clone of the calling object*/ #define mitkCloneMacro(classname) \ virtual Pointer Clone() const \ { \ Pointer smartPtr = new classname(*this); \ return smartPtr; \ } + +#define MITK_EXPORT_MODULE_ACTIVATOR(moduleName, type) \ + extern "C" MITK_EXPORT mitk::ModuleActivator* _mitk_module_activator_instance_ ## moduleName () \ + { \ + struct ScopedPointer \ + { \ + ScopedPointer(mitk::ModuleActivator* activator = 0) : m_Activator(activator) {} \ + ~ScopedPointer() { delete m_Activator; } \ + mitk::ModuleActivator* m_Activator; \ + }; \ + \ + static ScopedPointer activatorPtr; \ + if (activatorPtr.m_Activator == 0) activatorPtr.m_Activator = new type; \ + return activatorPtr.m_Activator; \ + } + #endif // MITK_COMMON_H_DEFINED diff --git a/Core/Code/Service/mitkAny.cpp b/Core/Code/Service/mitkAny.cpp new file mode 100644 index 0000000000..874c6e13cc --- /dev/null +++ b/Core/Code/Service/mitkAny.cpp @@ -0,0 +1,51 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkAny.h" + +namespace mitk { + +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 << *i1; + else ss << "," << *i1; + } + return ss.str(); +} + +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::list& 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()); +} + +} diff --git a/Core/Code/Service/mitkAny.h b/Core/Code/Service/mitkAny.h new file mode 100644 index 0000000000..5fb6158f60 --- /dev/null +++ b/Core/Code/Service/mitkAny.h @@ -0,0 +1,401 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. +Extracted from Boost 1.46.1 and adapted for MITK + +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 MITK_ANY_H +#define MITK_ANY_H + +#include +#include +#include +#include +#include + +#include + +namespace mitk { + +template +std::string any_value_to_string(const T& val); + +MITK_CORE_EXPORT std::string any_value_to_string(const std::vector& val); +MITK_CORE_EXPORT std::string any_value_to_string(const std::list& val); + +/** + * 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 MITK. + */ +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 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 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 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 "mitk::BadAnyCastException: " + "failed conversion using mitk::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)); +} + +MITK_CORE_EXPORT std::string any_value_to_string(const std::vector& val); + +template +std::string any_value_to_string(const T& val) +{ + std::stringstream ss; + ss << val; + return ss.str(); +} + +} // namespace mitk + +inline std::ostream& operator<< (std::ostream& os, const mitk::Any& any) +{ + return os << any.ToString(); +} + +#endif // MITK_ANY_H diff --git a/Core/Code/Service/mitkAtomicInt.cpp b/Core/Code/Service/mitkAtomicInt.cpp new file mode 100644 index 0000000000..031e993bc3 --- /dev/null +++ b/Core/Code/Service/mitkAtomicInt.cpp @@ -0,0 +1,100 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkAtomicInt.h" + +#if defined(__APPLE__) + // OSAtomic.h optimizations only used in 10.5 and later + #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 + #include + #endif + +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) + #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) + # include + #else + # include + #endif + +#endif + + +namespace mitk +{ + +AtomicInt::AtomicInt(int value) + : m_ReferenceCount(value) +{ + +} + +bool AtomicInt::Ref() const +{ + // Windows optimization +#if (defined(WIN32) || defined(_WIN32)) + return InterlockedIncrement(&m_ReferenceCount); + + // Mac optimization +#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) + #if defined (__LP64__) && __LP64__ + return OSAtomicIncrement64Barrier(&m_ReferenceCount); + #else + return OSAtomicIncrement32Barrier(&m_ReferenceCount); + #endif + + // gcc optimization +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) + return __sync_add_and_fetch(&m_ReferenceCount, 1); + + // General case +#else + m_ReferenceCountLock.Lock(); + InternalReferenceCountType ref = ++m_ReferenceCount; + m_ReferenceCountLock.Unlock(); + return ref; +#endif +} + +bool AtomicInt::Deref() const +{ + // Windows optimization +#if (defined(WIN32) || defined(_WIN32)) + return InterlockedDecrement(&m_ReferenceCount); + +// Mac optimization +#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) + #if defined (__LP64__) && __LP64__ + return OSAtomicDecrement64Barrier(&m_ReferenceCount); + #else + return OSAtomicDecrement32Barrier(&m_ReferenceCount); + #endif + +// gcc optimization +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) + return __sync_add_and_fetch(&m_ReferenceCount, -1); + +// General case +#else + m_ReferenceCountLock.Lock(); + InternalReferenceCountType ref = --m_ReferenceCount; + m_ReferenceCountLock.Unlock(); + return ref; +#endif +} + + +} // end namespace itk diff --git a/Core/Code/Service/mitkAtomicInt.h b/Core/Code/Service/mitkAtomicInt.h new file mode 100644 index 0000000000..3f4c5d9255 --- /dev/null +++ b/Core/Code/Service/mitkAtomicInt.h @@ -0,0 +1,94 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKATOMICINT_H +#define MITKATOMICINT_H + +#include "itkFastMutexLock.h" + +#include + +namespace mitk { + +/** + * This class acts as an atomic integer. + * + * The integer value represented by this class can be incremented + * and decremented atomically. This is often useful in reference + * counting scenarios to minimize locking overhead in multi-threaded + * environments. + */ +class MITK_CORE_EXPORT AtomicInt { + +public: + + AtomicInt(int value = 0); + + /** + * Increase the reference count atomically by 1. + * + * \return true if the new value is unequal to zero, false + * otherwise. + */ + bool Ref() const; + + /** + * Decrease the reference count atomically by 1. + * + * \return true if the new value is unequal to zero, false + * otherwise. + */ + bool Deref() const; + + // Non-atomic API + + /** + * Returns the current value. + * + * This operator is not atomic. + */ + inline operator int() const + { + return m_ReferenceCount; + } + +private: + + /** Define the type of the reference count according to the + target. This allows the use of atomic operations */ +#if (defined(WIN32) || defined(_WIN32)) + typedef LONG InternalReferenceCountType; +#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) + #if defined (__LP64__) && __LP64__ + typedef volatile int64_t InternalReferenceCountType; + #else + typedef volatile int32_t InternalReferenceCountType; + #endif +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) + typedef _Atomic_word InternalReferenceCountType; +#else + typedef int InternalReferenceCountType; + mutable itk::SimpleFastMutexLock m_ReferenceCountLock; +#endif + + mutable InternalReferenceCountType m_ReferenceCount; +}; + +} + +#endif // MITKATOMICINT_H diff --git a/Core/Code/Service/mitkCoreActivator.cpp b/Core/Code/Service/mitkCoreActivator.cpp new file mode 100644 index 0000000000..14c7a0c45c --- /dev/null +++ b/Core/Code/Service/mitkCoreActivator.cpp @@ -0,0 +1,47 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkRenderingManager.h" + +#include + +/* + * This is the module activator for the "Mitk" module. It registers core services + * like ... + */ +class MitkCoreActivator : public mitk::ModuleActivator +{ +public: + + void Load(mitk::ModuleContext* context) + { + //m_RenderingManager = mitk::RenderingManager::New(); + //context->RegisterService(renderingManager.GetPointer()); + } + + void Unload(mitk::ModuleContext* ) + { + + } + +private: + + mitk::RenderingManager::Pointer m_RenderingManager; +}; + +MITK_EXPORT_MODULE_ACTIVATOR(MitkCoreActivator) + diff --git a/Core/Code/Service/mitkCoreModuleContext.cpp b/Core/Code/Service/mitkCoreModuleContext.cpp new file mode 100644 index 0000000000..7255248f2a --- /dev/null +++ b/Core/Code/Service/mitkCoreModuleContext.cpp @@ -0,0 +1,32 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkCoreModuleContext_p.h" + +namespace mitk { + +CoreModuleContext::CoreModuleContext() + : services(this) +{ +} + +CoreModuleContext::~CoreModuleContext() +{ +} + +} diff --git a/Core/Code/Service/mitkCoreModuleContext_p.h b/Core/Code/Service/mitkCoreModuleContext_p.h new file mode 100644 index 0000000000..2c642c3b9a --- /dev/null +++ b/Core/Code/Service/mitkCoreModuleContext_p.h @@ -0,0 +1,59 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKCOREMODULECONTEXT_H +#define MITKCOREMODULECONTEXT_H + +#include "mitkServiceListeners_p.h" +#include "mitkServiceRegistry_p.h" + +namespace mitk { + +class ModuleRegistry; +class Module; + +/** + * This class is not part of the public API. + */ +class CoreModuleContext +{ +public: + + /** + * All listeners in this framework. + */ + ServiceListeners listeners; + + /** + * All registered services in this framework. + */ + ServiceRegistry services; + + /** + * Contruct a core context + * + */ + CoreModuleContext(); + + ~CoreModuleContext(); + +}; + +} + +#endif // MITKCOREMODULECONTEXT_H diff --git a/Core/Code/Service/mitkGetModuleContext.h b/Core/Code/Service/mitkGetModuleContext.h new file mode 100644 index 0000000000..95f46e567c --- /dev/null +++ b/Core/Code/Service/mitkGetModuleContext.h @@ -0,0 +1,48 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKGETMODULECONTEXT_H +#define MITKGETMODULECONTEXT_H + +namespace mitk { + +class ModuleContext; + +/** + * Returns the module context of the calling module. + * + * This function allows easy access to the own ModuleContext instance from + * inside a MITK module. + * + * \internal + * + * Note that the corresponding function definition is provided for each + * module by the mitkModuleInit.cpp file. This file is customized via CMake + * configure_file(...) and automatically compiled into each MITK module. + * Consequently, the GetModuleContext function is not exported, since each + * module gets its "own version". + */ +#if defined(__GNUC__) +__attribute__ ((visibility ("hidden"))) ModuleContext* GetModuleContext(); +#else +ModuleContext* GetModuleContext(); +#endif + +} + +#endif // MITKGETMODULECONTEXT_H diff --git a/Core/Code/Service/mitkItkHashMap.h b/Core/Code/Service/mitkItkHashMap.h new file mode 100644 index 0000000000..19b310fd81 --- /dev/null +++ b/Core/Code/Service/mitkItkHashMap.h @@ -0,0 +1,355 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/** + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Copyright (c) 1997 + * Moscow Center for SPARC Technology + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Moscow Center for SPARC Technology makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef __itk_hash_map_h +#define __itk_hash_map_h + +#if defined(_MSC_VER) +#pragma warning ( disable : 4786 ) +#endif + +#if (defined(__GNUC__) && (((__GNUC__==3) && (__GNUC_MINOR__>=1) || (__GNUC__>3) ) || ( (__GNUC__==4) && defined(__INTEL_COMPILER) ) )) || (defined(__IBMCPP__) && __IBMCPP__ >= 600) +// Use this hash_map for GNU_C versions >= 3.1, IBMCPP >=600, or Intel compilers with GCCv4 + +// #if (defined(__GNUC__) && ((__GNUC__==4) && (__GNUC_MINOR__>=3) ) ) +// in gcc 4.3 the header was deprecated and replaced with . +// note that this is still experimental in gcc 4.3 +// #include +// #else +#include +// #endif + +namespace itk +{ + using __gnu_cxx::hash; + using __gnu_cxx::hash_map; + using __gnu_cxx::hash_multimap; +} + +#else + +#include "mitkItkHashTable.h" +#include "itk_alloc.h" + + +// The following is required for CodeWarrior +#if defined(__MWERKS__) +#include "vcl_functional.h" +#endif + +#include "vcl_compiler.h" + + +namespace itk +{ + +# define VCL_IMPORT_CONTAINER_TYPEDEFS(super) \ + typedef typename super::value_type value_type; \ + typedef typename super::reference reference; \ + typedef typename super::size_type size_type; \ + typedef typename super::const_reference const_reference; \ + typedef typename super::difference_type difference_type; + +# define VCL_IMPORT_ITERATORS(super) \ + typedef typename super::iterator iterator; \ + typedef typename super::const_iterator const_iterator; + +# define VCL_IMPORT_REVERSE_ITERATORS(super) \ + typedef typename super::const_reverse_iterator const_reverse_iterator; \ + typedef typename super::reverse_iterator reverse_iterator; + +template +class hash_map; +template +class hash_multimap; + +template +bool operator==(const hash_map&, + const hash_map&); +template +bool operator==(const hash_multimap&, + const hash_multimap&); + +/** \class hash_map + * \brief Replacement for STL hash map because some systems do not support it, + * or support it incorrectly. + */ +template ), + VCL_DFL_TMPL_PARAM_STLDECL(EqualKey,std::equal_to), + VCL_DFL_TYPE_PARAM_STLDECL(Alloc,std::allocator ) > +class hash_map +{ +private: + typedef std::select1st > sel1st; + typedef hashtable, Key, HashFcn, sel1st, EqualKey, Alloc> ht; + typedef hash_map self; +public: + VCL_IMPORT_CONTAINER_TYPEDEFS(ht) + VCL_IMPORT_ITERATORS(ht) + typedef typename ht::key_type key_type; + typedef typename ht::hasher hasher; + typedef typename ht::key_equal key_equal; + typedef T data_type; + typedef typename ht::pointer pointer; + typedef typename ht::const_pointer const_pointer; +private: + ht rep; + +public: + hasher hash_funct() const { return rep.hash_funct(); } + key_equal key_eq() const { return rep.key_eq(); } + +public: + hash_map() : rep(100, hasher(), key_equal()) {} + hash_map(size_type n) : rep(n, hasher(), key_equal()) {} + hash_map(size_type n, const hasher& hf) : rep(n, hf, key_equal()) {} + hash_map(size_type n, const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) {} + + hash_map(const value_type* f, const value_type* l) + : rep(100, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_map(const value_type* f, const value_type* l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_map(const value_type* f, const value_type* l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_unique(f, l); } + hash_map(const value_type* f, const value_type* l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_unique(f, l); } + + hash_map(const_iterator f, const_iterator l) + : rep(100, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_map(const_iterator f, const_iterator l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_map(const_iterator f, const_iterator l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_unique(f, l); } + hash_map(const_iterator f, const_iterator l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_unique(f, l); } + +public: + size_type size() const { return rep.size(); } + size_type max_size() const { return rep.max_size(); } + bool empty() const { return rep.empty(); } + void swap(self& hs) { rep.swap(hs.rep); } + + friend bool operator==ITK_FRIEND_TEMPLATE_FUNCTION_ARGUMENT(self)(const self &, const self &); + + iterator begin() { return rep.begin(); } + iterator end() { return rep.end(); } + const_iterator begin() const { return rep.begin(); } + const_iterator end() const { return rep.end(); } + +public: + std::pair insert(const value_type& obj) + { return rep.insert_unique(obj); } + void insert(const value_type* f, const value_type* l) { rep.insert_unique(f,l); } + void insert(const_iterator f, const_iterator l) { rep.insert_unique(f, l); } + std::pair insert_noresize(const value_type& obj) + { return rep.insert_unique_noresize(obj); } + + iterator find(const key_type& key) { return rep.find(key); } + const_iterator find(const key_type& key) const { return rep.find(key); } + + T& operator[](const key_type& key) + { + value_type val(key, T()); + return rep.find_or_insert(val).second; + } + + size_type count(const key_type& key) const { return rep.count(key); } + + std::pair equal_range(const key_type& key) + { return rep.equal_range(key); } + std::pair equal_range(const key_type& key) const + { return rep.equal_range(key); } + + size_type erase(const key_type& key) {return rep.erase(key); } + void erase(iterator it) { rep.erase(it); } + void erase(iterator f, iterator l) { rep.erase(f, l); } + void clear() { rep.clear(); } + +public: + void resize(size_type hint) { rep.resize(hint); } + size_type bucket_count() const { return rep.bucket_count(); } + size_type max_bucket_count() const { return rep.max_bucket_count(); } + size_type elems_in_bucket(size_type n) const + { return rep.elems_in_bucket(n); } +}; + + +template ), + VCL_DFL_TMPL_PARAM_STLDECL(EqualKey,std::equal_to), + VCL_DFL_TYPE_PARAM_STLDECL(Alloc,std::allocator ) > +class hash_multimap +{ +private: + typedef hashtable, Key, HashFcn, + std::select1st >, EqualKey, Alloc> ht; + typedef hash_multimap self; +public: + VCL_IMPORT_CONTAINER_TYPEDEFS(ht) + VCL_IMPORT_ITERATORS(ht) + typedef typename ht::key_type key_type; + typedef typename ht::hasher hasher; + typedef typename ht::key_equal key_equal; + typedef T data_type; + typedef typename ht::pointer pointer; + typedef typename ht::const_pointer const_pointer; + + hasher hash_funct() const { return rep.hash_funct(); } + key_equal key_eq() const { return rep.key_eq(); } +private: + ht rep; + +public: + hash_multimap() : rep(100, hasher(), key_equal()) {} + hash_multimap(size_type n) : rep(n, hasher(), key_equal()) {} + hash_multimap(size_type n, const hasher& hf) : rep(n, hf, key_equal()) {} + hash_multimap(size_type n, const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) {} + + hash_multimap(const value_type* f, const value_type* l) + : rep(100, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multimap(const value_type* f, const value_type* l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multimap(const value_type* f, const value_type* l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_equal(f, l); } + hash_multimap(const value_type* f, const value_type* l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_equal(f, l); } + + hash_multimap(const_iterator f, const_iterator l) + : rep(100, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multimap(const_iterator f, const_iterator l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multimap(const_iterator f, const_iterator l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_equal(f, l); } + hash_multimap(const_iterator f, const_iterator l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_equal(f, l); } + +public: + size_type size() const { return rep.size(); } + size_type max_size() const { return rep.max_size(); } + bool empty() const { return rep.empty(); } + void swap(self& hs) { rep.swap(hs.rep); } + + friend bool operator==ITK_FRIEND_TEMPLATE_FUNCTION_ARGUMENT(self)(const self &, const self &); + + iterator begin() { return rep.begin(); } + iterator end() { return rep.end(); } + const_iterator begin() const { return rep.begin(); } + const_iterator end() const { return rep.end(); } + +public: + iterator insert(const value_type& obj) { return rep.insert_equal(obj); } + void insert(const value_type* f, const value_type* l) { rep.insert_equal(f,l); } + void insert(const_iterator f, const_iterator l) { rep.insert_equal(f, l); } + iterator insert_noresize(const value_type& obj) + { return rep.insert_equal_noresize(obj); } + + iterator find(const key_type& key) { return rep.find(key); } + const_iterator find(const key_type& key) const { return rep.find(key); } + + size_type count(const key_type& key) const { return rep.count(key); } + + std::pair equal_range(const key_type& key) + { return rep.equal_range(key); } + std::pair equal_range(const key_type& key) const + { return rep.equal_range(key); } + + size_type erase(const key_type& key) {return rep.erase(key); } + void erase(iterator it) { rep.erase(it); } + void erase(iterator f, iterator l) { rep.erase(f, l); } + void clear() { rep.clear(); } + +public: + void resize(size_type hint) { rep.resize(hint); } + size_type bucket_count() const { return rep.bucket_count(); } + size_type max_bucket_count() const { return rep.max_bucket_count(); } + size_type elems_in_bucket(size_type n) const + { return rep.elems_in_bucket(n); } +}; + +/** This method MUST NOT be declared "inline" because it a specialization of its template is + declared as friend of a class. The hash_map class, in this case */ +template +bool operator==(const hash_map& hm1, + const hash_map& hm2) +{ + return hm1.rep == hm2.rep; +} + +/** This method MUST NOT be declared "inline" because it a specialization of its template is + declared as friend of a class. The hash_map class, in this case */ +template +bool operator==(const hash_multimap& hm1, + const hash_multimap& hm2) +{ + return hm1.rep == hm2.rep; +} + + +#define HASH_MAP_INSTANTIATE \ +extern "please include emulation/hash_map.txx instead" + +} // end namespace itk + +#endif + +#endif // itk_emulation_hash_map_h diff --git a/Core/Code/Service/mitkItkHashSet.h b/Core/Code/Service/mitkItkHashSet.h new file mode 100644 index 0000000000..b49aefe0f3 --- /dev/null +++ b/Core/Code/Service/mitkItkHashSet.h @@ -0,0 +1,377 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/** + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Copyright (c) 1997 + * Moscow Center for SPARC Technology + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Moscow Center for SPARC Technology makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef __itk_hash_set_h +#define __itk_hash_set_h + +#if (defined(__GNUC__) && (((__GNUC__==3) && (__GNUC_MINOR__>=1) || (__GNUC__>3) ) || ( (__GNUC__==4) && defined(__INTEL_COMPILER) ) )) || (defined(__IBMCPP__) && __IBMCPP__ >= 600) +// Use this hash_map for GNU_C versions >= 3.1, IBMCPP >=600, or Intel compilers with GCCv4 +#include + +namespace itk +{ + using __gnu_cxx::hash; + using __gnu_cxx::hash_set; + using __gnu_cxx::hash_multiset; +} + +#else + +#include "mitkItkHashTable.h" +#include + +// --- + +namespace itk +{ + +/** \class hash_set + * \brief Replacement for STL hash set because some systems do not support it, + * or support it incorrectly. + */ +template ), + VCL_DFL_TMPL_PARAM_STLDECL(EqualKey,std::equal_to), + VCL_DFL_TYPE_PARAM_STLDECL(Alloc,std::allocator ) > +class hash_set +{ +private: + typedef hashtable, + EqualKey, Alloc> ht; + typedef hash_set self; +public: + typedef typename ht::key_type key_type; + typedef typename ht::value_type value_type; + typedef typename ht::hasher hasher; + typedef typename ht::key_equal key_equal; + + typedef typename ht::size_type size_type; + typedef typename ht::difference_type difference_type; + typedef typename ht::const_pointer pointer; + typedef typename ht::const_pointer const_pointer; + typedef typename ht::const_reference reference; + typedef typename ht::const_reference const_reference; + // SunPro bug + typedef typename ht::const_iterator const_iterator; + typedef const_iterator iterator; + + // vc6 addition + typedef typename ht::iterator ht_iterator; + + hasher hash_funct() const { return rep.hash_funct(); } + key_equal key_eq() const { return rep.key_eq(); } + +private: + ht rep; + +public: + hash_set() : rep(100, hasher(), key_equal()) {} + hash_set(size_type n) : rep(n, hasher(), key_equal()) {} + hash_set(size_type n, const hasher& hf) : rep(n, hf, key_equal()) {} + hash_set(size_type n, const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) {} + + hash_set(const value_type* f, const value_type* l) + : rep(100, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_set(const value_type* f, const value_type* l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_set(const value_type* f, const value_type* l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_unique(f, l); } + hash_set(const value_type* f, const value_type* l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_unique(f, l); } + + hash_set(const_iterator f, const_iterator l) + : rep(100, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_set(const_iterator f, const_iterator l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_unique(f, l); } + hash_set(const_iterator f, const_iterator l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_unique(f, l); } + hash_set(const_iterator f, const_iterator l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_unique(f, l); } + +public: + size_type size() const { return rep.size(); } + size_type max_size() const { return rep.max_size(); } + bool empty() const { return rep.empty(); } + void swap(self& hs) { rep.swap(hs.rep); } + + friend bool operator==ITK_FRIEND_TEMPLATE_FUNCTION_ARGUMENT(self)(const self &, const self &); + + iterator begin() const { return rep.begin(); } + iterator end() const { return rep.end(); } + +public: + std::pair insert(const value_type& obj) + { +#ifdef _MSC_VER + std::pair< ht::iterator, bool> p = rep.insert_unique(obj); +#else + std::pair p = rep.insert_unique(obj); +#endif + return std::pair(p.first, p.second); + } + void insert(const value_type* f, const value_type* l) { rep.insert_unique(f,l); } + void insert(const_iterator f, const_iterator l) { rep.insert_unique(f, l); } + std::pair insert_noresize(const value_type& obj) + { +#ifdef _MSC_VER + std::pair p = rep.insert_unique_noresize(obj); +#else + std::pair p = rep.insert_unique_noresize(obj); +#endif + return std::pair(p.first, p.second); + } + + iterator find(const key_type& key) const { return rep.find(key); } + + size_type count(const key_type& key) const { return rep.count(key); } + + std::pair equal_range(const key_type& key) const + { return rep.equal_range(key); } + + size_type erase(const key_type& key) {return rep.erase(key); } + void erase(iterator it) { rep.erase(it); } + void erase(iterator f, iterator l) { rep.erase(f, l); } + void clear() { rep.clear(); } + +public: + void resize(size_type hint) { rep.resize(hint); } + size_type bucket_count() const { return rep.bucket_count(); } + size_type max_bucket_count() const { return rep.max_bucket_count(); } + size_type elems_in_bucket(size_type n) const + { return rep.elems_in_bucket(n); } +}; + + +template ), + VCL_DFL_TMPL_PARAM_STLDECL(EqualKey,std::equal_to), + VCL_DFL_TYPE_PARAM_STLDECL(Alloc,std::allocator ) > +class hash_multiset +{ +private: + typedef hashtable, + EqualKey, Alloc> ht; + typedef hash_multiset self; +public: + typedef typename ht::key_type key_type; + typedef typename ht::value_type value_type; + typedef typename ht::hasher hasher; + typedef typename ht::key_equal key_equal; + + typedef typename ht::size_type size_type; + typedef typename ht::difference_type difference_type; + typedef typename ht::const_pointer pointer; + typedef typename ht::const_pointer const_pointer; + typedef typename ht::const_reference reference; + typedef typename ht::const_reference const_reference; + + typedef typename ht::const_iterator const_iterator; + // SunPro bug + typedef const_iterator iterator; + + hasher hash_funct() const { return rep.hash_funct(); } + key_equal key_eq() const { return rep.key_eq(); } +private: + ht rep; + +public: + hash_multiset() : rep(100, hasher(), key_equal()) {} + hash_multiset(size_type n) : rep(n, hasher(), key_equal()) {} + hash_multiset(size_type n, const hasher& hf) : rep(n, hf, key_equal()) {} + hash_multiset(size_type n, const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) {} + + hash_multiset(const value_type* f, const value_type* l) + : rep(100, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multiset(const value_type* f, const value_type* l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multiset(const value_type* f, const value_type* l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_equal(f, l); } + hash_multiset(const value_type* f, const value_type* l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_equal(f, l); } + + hash_multiset(const_iterator f, const_iterator l) + : rep(100, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multiset(const_iterator f, const_iterator l, size_type n) + : rep(n, hasher(), key_equal()) { rep.insert_equal(f, l); } + hash_multiset(const_iterator f, const_iterator l, size_type n, + const hasher& hf) + : rep(n, hf, key_equal()) { rep.insert_equal(f, l); } + hash_multiset(const_iterator f, const_iterator l, size_type n, + const hasher& hf, const key_equal& eql) + : rep(n, hf, eql) { rep.insert_equal(f, l); } + +public: + size_type size() const { return rep.size(); } + size_type max_size() const { return rep.max_size(); } + bool empty() const { return rep.empty(); } + void swap(self& hs) { rep.swap(hs.rep); } + + friend bool operator==ITK_FRIEND_TEMPLATE_FUNCTION_ARGUMENT(self)(const self &, const self &); + + iterator begin() const { return rep.begin(); } + iterator end() const { return rep.end(); } + +public: + iterator insert(const value_type& obj) { return rep.insert_equal(obj); } + void insert(const value_type* f, const value_type* l) { rep.insert_equal(f,l); } + void insert(const_iterator f, const_iterator l) { rep.insert_equal(f, l); } + iterator insert_noresize(const value_type& obj) + { return rep.insert_equal_noresize(obj); } + + iterator find(const key_type& key) const { return rep.find(key); } + + size_type count(const key_type& key) const { return rep.count(key); } + + std::pair equal_range(const key_type& key) const + { return rep.equal_range(key); } + + size_type erase(const key_type& key) {return rep.erase(key); } + void erase(iterator it) { rep.erase(it); } + void erase(iterator f, iterator l) { rep.erase(f, l); } + void clear() { rep.clear(); } + +public: + void resize(size_type hint) { rep.resize(hint); } + size_type bucket_count() const { return rep.bucket_count(); } + size_type max_bucket_count() const { return rep.max_bucket_count(); } + size_type elems_in_bucket(size_type n) const + { return rep.elems_in_bucket(n); } +}; + + +/** This method MUST NOT be declared "inline" because it a specialization of its template is + declared as friend of a class. The hash_set class, in this case */ +template +bool operator==(const hash_set& hs1, + const hash_set& hs2) +{ + return hs1.rep == hs2.rep; +} + +/** This method MUST NOT be declared "inline" because it a specialization of its template is + declared as friend of a class. The hash_set class, in this case */ +template +bool operator==(const hash_multiset& hs1, + const hash_multiset& hs2) +{ + return hs1.rep == hs2.rep; +} + +# if defined (__STL_CLASS_PARTIAL_SPECIALIZATION ) +template +inline void swap(hash_multiset& a, + hash_multiset& b) { a.swap(b); } +template +inline void swap(hash_set& a, + hash_set& b) { a.swap(b); } +# endif + +} // end namespace itk + + +namespace std { + +// Specialization of insert_iterator so that it will work for hash_set +// and hash_multiset. +template +class insert_iterator > +{ +protected: + typedef itk::hash_set<_Value, _HashFcn, _EqualKey, _Alloc> _Container; + _Container* container; + +public: + typedef _Container container_type; + typedef output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + insert_iterator(_Container& __x) + : container(&__x) {} + + insert_iterator(_Container& __x, typename _Container::iterator) + : container(&__x) {} + + insert_iterator<_Container>& + operator=(const typename _Container::value_type& value) + { + container->insert(value); + return *this; + } + + insert_iterator<_Container>& + operator*() + { return *this; } + + insert_iterator<_Container>& + operator++() + { return *this; } + + insert_iterator<_Container>& + operator++(int) + { return *this; } +}; + +} + +#endif +#endif // itk_emulation_hash_set_h diff --git a/Core/Code/Service/mitkItkHashTable.h b/Core/Code/Service/mitkItkHashTable.h new file mode 100644 index 0000000000..a7adfcbeb0 --- /dev/null +++ b/Core/Code/Service/mitkItkHashTable.h @@ -0,0 +1,1188 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/** + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Exception Handling: + * Copyright (c) 1997 + * Mark of the Unicorn, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Mark of the Unicorn makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Adaptation: + * Copyright (c) 1997 + * Moscow Center for SPARC Technology + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Moscow Center for SPARC Technology makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + + +#ifndef __itk_hashtable_h +#define __itk_hashtable_h + +#if defined(_MSC_VER) +// unreachable code +#pragma warning ( disable : 4702 ) +// assignment operator could not be generated +#pragma warning ( disable : 4512 ) +#endif + +#if (defined(__GNUC__) && (((__GNUC__==3) && (__GNUC_MINOR__>=1) || (__GNUC__>3) ) || ( (__GNUC__==4) && defined(__INTEL_COMPILER) ) )) || (defined(__IBMCPP__) && __IBMCPP__ >= 600) +// Use this hashtable that is already define for GNU_C versions >= 3.1, IBMCPP >=600, or Intel compilers with GCCv4 + +#else +/** \brief Hashtable class, used to implement the hashed associative containers + * itk_hash_set, itk_hash_map, itk_hash_multiset, and itk_hash_multimap. + */ +#include "itkMacro.h" +#include +#include "itk_alloc.h" +#include +#include +#include +#include "vcl_compiler.h" +#include +#include +#include + + +namespace itk +{ +template struct hash { }; + +inline size_t hash_string(const char* s) +{ + unsigned long h = 0; + for (; *s; ++s) + { + h = 5*h + *s; + } + return size_t(h); +} + +template<> +struct hash +{ + size_t operator()(const char* s) const { return hash_string(s); } +}; + +template<> +struct hash +{ + size_t operator()(const char* s) const { return hash_string(s); } +}; + +template<> +struct hash +{ + size_t operator()(char x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(unsigned char x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(unsigned char x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(short x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(unsigned short x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(int x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(unsigned int x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(long x) const { return x; } +}; + +template<> +struct hash +{ + size_t operator()(unsigned long x) const { return x; } +}; + +#ifdef _WIN64 +template<> +struct hash +{ + size_t operator()(size_t x) const { return x; } +}; +#endif + +template +struct hashtable_node +{ + typedef hashtable_node self; + self* next; + Value val; +}; + +template )> +class hashtable; + +template +struct hashtable_iterator; + +template +struct hashtable_const_iterator; + +template +struct hashtable_iterator +{ + typedef hashtable hash_table; + typedef hashtable_iterator iterator; + typedef hashtable_const_iterator + const_iterator; + typedef hashtable_node node; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef Value value_type; + typedef size_t size_type; + typedef Value& reference; + typedef Value* pointer; + typedef const Value& const_reference; + + node* cur; + hash_table* ht; + + hashtable_iterator(node* n, hash_table* tab) : cur(n), ht(tab) {} + hashtable_iterator() {} + reference operator*() const + { + return cur->val; + } + pointer operator->() const { return &(operator*()); } + + IUEi_STL_INLINE iterator& operator++(); + IUEi_STL_INLINE iterator operator++(int); + bool operator==(const iterator& it) const { return cur == it.cur; } + bool operator!=(const iterator& it) const { return cur != it.cur; } +}; + + +template +struct hashtable_const_iterator +{ + typedef hashtable + hash_table; + typedef hashtable_iterator iterator; + typedef hashtable_const_iterator const_iterator; + typedef hashtable_node node; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef Value value_type; + typedef size_t size_type; + typedef Value& reference; + typedef const Value& const_reference; + typedef const Value* pointer; + + const node* cur; + const hash_table* ht; + + hashtable_const_iterator(const node* n, const hash_table* tab) : cur(n), ht(tab) {} + hashtable_const_iterator() {} + hashtable_const_iterator(const iterator& it) : cur(it.cur), ht(it.ht) {} + + const_reference operator*() const { return cur->val; } + pointer operator->() const { return &(operator*()); } + IUEi_STL_INLINE const_iterator& operator++(); + IUEi_STL_INLINE const_iterator operator++(int); + bool operator==(const const_iterator& it) const { return cur == it.cur; } + bool operator!=(const const_iterator& it) const { return cur != it.cur; } +}; + +// Note: assumes long is at least 32 bits. +// fbp: try to avoid intances in every module +enum { num_primes = 28 }; + +#if ( __STL_STATIC_TEMPLATE_DATA > 0 ) && ! defined (WIN32) +# define prime_list prime::list_ +template +struct prime { +public: + static const unsigned long list_[]; +}; +static const unsigned long prime_list_dummy[num_primes] = +# else +# if ( __STL_WEAK_ATTRIBUTE > 0 ) + extern const unsigned long prime_list[num_primes] __attribute__((weak)) = +# else + // give up + static const unsigned long prime_list[num_primes] = +# endif /* __STL_WEAK_ATTRIBUTE */ +#endif /* __STL_STATIC_TEMPLATE_DATA */ +{ + 53, 97, 193, 389, 769, + 1543, 3079, 6151, 12289, 24593, + 49157, 98317, 196613, 393241, 786433, + 1572869, 3145739, 6291469, 12582917, 25165843, + 50331653, 100663319, 201326611, 402653189, 805306457, + 1610612741, 3221225473U, 4294967291U +}; + +inline unsigned long next_prime(unsigned long n) +{ + const unsigned long* first = prime_list; + const unsigned long* last = prime_list; + last += num_primes; + const unsigned long* pos = std::lower_bound(first, last, n); + return pos == last ? *(last - 1) : *pos; +} + +template +class hashtable_base +{ +private: + typedef Value value_type; + typedef size_t size_type; + typedef hashtable_node node; + typedef itk_simple_alloc node_allocator; +public: // These are public to get around restriction on protected access + typedef std::vector buckets_type; + buckets_type buckets; // awf killed optional allocator + size_type num_elements; +protected: + IUEi_STL_INLINE void clear(); + + node* new_node(const value_type& obj) + { + node* n = node_allocator::allocate(); + try + { + new (&(n->val)) value_type(obj); + } + catch (...) + { + node_allocator::deallocate(n); + throw ""; + } + n->next = 0; + return n; + } + + void delete_node(node* n) + { +#define vcli_destroy(T, p) ((T*)p)->~T() + vcli_destroy(Value, &(n->val)); +#undef vcli_destroy + node_allocator::deallocate(n); + } + + IUEi_STL_INLINE void copy_from(const hashtable_base& ht); + +public: // These are public to get around restriction on protected access + hashtable_base() : num_elements(0) { } +// hashtable_base(size_type n) : num_elements(0) {} + ~hashtable_base() { clear(); } +}; + + +// forward declarations +template class hashtable; +template + bool operator== (hashtableconst&,hashtableconst&); + +template +class hashtable : protected hashtable_base +{ + typedef hashtable_base super; + typedef hashtable self; +public: + typedef Key key_type; + typedef Value value_type; + typedef HashFcn hasher; + typedef EqualKey key_equal; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + + hasher hash_funct() const { return hashfun; } + key_equal key_eq() const { return equals; } + +private: + hasher hashfun; + key_equal equals; + ExtractKey get_key; + + typedef hashtable_node node; + typedef itk_simple_alloc node_allocator; + +public: + typedef hashtable_iterator iterator; + typedef hashtable_const_iterator const_iterator; + friend struct + hashtable_iterator; + friend struct + hashtable_const_iterator; + +public: + hashtable(size_type n, + const HashFcn& hf, + const EqualKey& eql, + const ExtractKey& ext) + : hashfun(hf), equals(eql), get_key(ext) + { + initialize_buckets(n); + } + + hashtable(size_type n, + const HashFcn& hf, + const EqualKey& eql) + : hashfun(hf), equals(eql), get_key(ExtractKey()) + { + initialize_buckets(n); + } + + hashtable(const self& ht) + : hashfun(ht.hashfun), equals(ht.equals), get_key(ht.get_key) + { + copy_from(ht); + } + + self& operator= (const self& ht) + { + if (&ht != this) + { + hashfun = ht.hashfun; + equals = ht.equals; + get_key = ht.get_key; + clear(); + this->buckets.clear(); + copy_from(ht); + } + return *this; + } + + ~hashtable() {} + + size_type size() const { return this->num_elements; } + size_type max_size() const { return size_type(-1); } + bool empty() const { return size() == 0; } + + void swap(self& ht) + { + std::swap(hashfun, ht.hashfun); + std::swap(equals, ht.equals); + std::swap(get_key, ht.get_key); + this->buckets.swap(ht.buckets); + std::swap(this->num_elements, ht.num_elements); + } + + iterator begin() + { + for (size_type n = 0; n < this->buckets.size(); ++n) + { + if (this->buckets[n]) + { + return iterator(this->buckets[n], this); + } + } + return end(); + } + + iterator end() { return iterator((node*)0, this); } + + const_iterator begin() const + { + for (size_type n = 0; n < this->buckets.size(); ++n) + { + if (this->buckets[n]) + { + return const_iterator(this->buckets[n], this); + } + } + return end(); + } + + const_iterator end() const { return const_iterator((node*)0, this); } + + friend bool operator==ITK_FRIEND_TEMPLATE_FUNCTION_ARGUMENT(self)(const self&,const self&); + +public: + + size_type bucket_count() const { return this->buckets.size(); } + + size_type max_bucket_count() const + { return prime_list[num_primes - 1]; } + + size_type elems_in_bucket(size_type bucket) const + { + size_type result = 0; + for (node* cur = this->buckets[bucket]; cur; cur = cur->next) + { + result += 1; + } + return result; + } + + std::pair insert_unique(const value_type& obj) + { + resize(this->num_elements + 1); + return insert_unique_noresize(obj); + } + + iterator insert_equal(const value_type& obj) + { + resize(this->num_elements + 1); + return insert_equal_noresize(obj); + } + + IUEi_STL_INLINE std::pair insert_unique_noresize(const value_type& obj); + IUEi_STL_INLINE iterator insert_equal_noresize(const value_type& obj); + + void insert_unique(const value_type* f, const value_type* l) + { + size_type n = l - f; + resize(this->num_elements + n); + for (; n > 0; --n) + { + insert_unique_noresize(*f++); + } + } + + void insert_equal(const value_type* f, const value_type* l) + { + size_type n = l - f; + resize(this->num_elements + n); + for (; n > 0; --n) + { + insert_equal_noresize(*f++); + } + } + + void insert_unique(const_iterator f, const_iterator l) + { + size_type n = std::distance(f, l); + resize(this->num_elements + n); + for (; n > 0; --n) + { + insert_unique_noresize(*f++); + } + } + + void insert_equal(const_iterator f, const_iterator l) + { + size_type n = std::distance(f, l); + resize(this->num_elements + n); + for (; n > 0; --n) + { + insert_equal_noresize(*f++); + } + } + + IUEi_STL_INLINE reference find_or_insert(const value_type& obj); + + iterator find(const key_type& key) + { + size_type n = bkt_num_key(key); + node* first; + for ( first = this->buckets[n]; + first && !equals(get_key(first->val), key); + first = first->next) + {} + return iterator(first, this); + } + + const_iterator find(const key_type& key) const + { + size_type n = bkt_num_key(key); + const node* first; + for ( first = this->buckets[n]; + first && !equals(get_key(first->val), key); + first = first->next) + {} + return const_iterator(first, this); + } + + size_type count(const key_type& key) const + { + const size_type n = bkt_num_key(key); + size_type result = 0; + + for (const node* cur = this->buckets[n]; cur; cur = cur->next) + { + if (equals(get_key(cur->val), key)) + { + ++result; + } + } + return result; + } + + IUEi_STL_INLINE std::pair equal_range(const key_type& key); + IUEi_STL_INLINE std::pair equal_range(const key_type& key) const; + + IUEi_STL_INLINE size_type erase(const key_type& key); + IUEi_STL_INLINE void erase(const iterator& it); + IUEi_STL_INLINE void erase(iterator first, iterator last); + + IUEi_STL_INLINE void erase(const const_iterator& it); + IUEi_STL_INLINE void erase(const_iterator first, const_iterator last); + + IUEi_STL_INLINE void resize(size_type num_elements_hint); + void clear() { super::clear(); } +private: + size_type next_size(size_type n) const + { + return static_cast( + next_prime( static_cast(n) ) ); + } + + void initialize_buckets(size_type n) + { + const size_type n_buckets = next_size(n); + this->buckets.reserve(n_buckets); + this->buckets.insert(this->buckets.end(), n_buckets, (node*) 0); + this->num_elements = 0; + } + size_type bkt_num_key(const key_type& key) const + { + return bkt_num_key(key, this->buckets.size()); + } + + size_type bkt_num(const value_type& obj) const + { + return bkt_num_key(get_key(obj)); + } + + size_type bkt_num_key(const key_type& key, size_t n) const + { + return hashfun(key) % n; + } + + size_type bkt_num(const value_type& obj, size_t n) const + { + return bkt_num_key(get_key(obj), n); + } + IUEi_STL_INLINE void erase_bucket(const size_type n, node* first, node* last); + IUEi_STL_INLINE void erase_bucket(const size_type n, node* last); +}; + +// fbp: these defines are for outline methods definitions. +// needed to definitions to be portable. Should not be used in method bodies. + +# if defined ( __STL_NESTED_TYPE_PARAM_BUG ) +# define __difference_type__ ptrdiff_t +# define __size_type__ size_t +# define __value_type__ Value +# define __key_type__ Key +# define __node__ hashtable_node +# define __reference__ Value& +# else +# define __difference_type__ typename hashtable::difference_type +# define __size_type__ typename hashtable::size_type +# define __value_type__ typename hashtable::value_type +# define __key_type__ typename hashtable::key_type +# define __node__ typename hashtable::node +# define __reference__ typename hashtable::reference +# endif + +template +inline hashtable_iterator& +hashtable_iterator::operator++() +{ + const node* old = cur; + cur = cur->next; + if (!cur) + { + size_type bucket = ht->bkt_num(old->val); + while (!cur && ++bucket < ht->buckets.size()) + { + cur = ht->buckets[bucket]; + } + } + return *this; +} + +template +inline hashtable_iterator +hashtable_iterator::operator++(int) +{ + iterator tmp = *this; + ++*this; + return tmp; +} + +template +inline hashtable_const_iterator& +hashtable_const_iterator::operator++() +{ + const node* old = cur; + cur = cur->next; + if (!cur) + { + size_type bucket = ht->bkt_num(old->val); + while (!cur && ++bucket < ht->buckets.size()) + { + cur = ht->buckets[bucket]; + } + } + return *this; +} + +template +inline hashtable_const_iterator +hashtable_const_iterator::operator++(int) +{ + const_iterator tmp = *this; + ++*this; + return tmp; +} + +template +inline std::forward_iterator_tag +iterator_category (const hashtable_iterator&) +{ + return std::forward_iterator_tag(); +} + +template +inline Value* +value_type(const hashtable_iterator&) +{ + return (Value*) 0; +} + +template +inline ptrdiff_t* +distance_type(const hashtable_iterator&) +{ + return (ptrdiff_t*) 0; +} + +template +inline std::forward_iterator_tag +iterator_category (const hashtable_const_iterator&) +{ + return std::forward_iterator_tag(); +} + +template +inline Value* +value_type(const hashtable_const_iterator&) +{ + return (Value*) 0; +} + +template +inline ptrdiff_t* +distance_type(const hashtable_const_iterator&) +{ + return (ptrdiff_t*) 0; +} + +/** This method MUST NOT be declared "inline" because it a specialization of its template is + declared as friend of a class. The hashtable class, in this case */ +template +bool operator==(const hashtable& ht1, + const hashtable& ht2) +{ + typedef typename hashtable::node node; + if (ht1.buckets.size() != ht2.buckets.size()) + { + return false; + } + for (int n = 0; n < ht1.buckets.size(); ++n) + { + node* cur1 = ht1.buckets[n]; + node* cur2 = ht2.buckets[n]; + for (; cur1 && cur2 && cur1->val == cur2->val; + cur1 = cur1->next, cur2 = cur2->next) + {} + if (cur1 || cur2) + { + return false; + } + } + return true; +} + +template +std::pair, bool> +hashtable::insert_unique_noresize(const __value_type__& obj) +{ + const size_type n = bkt_num(obj); + node* first = this->buckets[n]; + + for (node* cur = first; cur; cur = cur->next) + if (equals(get_key(cur->val), get_key(obj))) + return std::pair(iterator(cur, this), false); + + node* tmp = new_node(obj); + tmp->next = first; + this->buckets[n] = tmp; + ++this->num_elements; + return std::pair(iterator(tmp, this), true); +} + +template +hashtable_iterator +hashtable::insert_equal_noresize(const __value_type__& obj) +{ + const size_type n = bkt_num(obj); + node* first = this->buckets[n]; + + for (node* cur = first; cur; cur = cur->next) + { + if (equals(get_key(cur->val), get_key(obj))) + { + node* tmp = new_node(obj); + tmp->next = cur->next; + cur->next = tmp; + ++this->num_elements; + return iterator(tmp, this); + } + } + node* tmp = new_node(obj); + tmp->next = first; + this->buckets[n] = tmp; + ++this->num_elements; + return iterator(tmp, this); +} + +template +__reference__ +hashtable::find_or_insert(const __value_type__& obj) +{ + resize(this->num_elements + 1); + + size_type n = bkt_num(obj); + node* first = this->buckets[n]; + + for (node* cur = first; cur; cur = cur->next) + if (equals(get_key(cur->val), get_key(obj))) + return cur->val; + + node* tmp = new_node(obj); + tmp->next = first; + this->buckets[n] = tmp; + ++this->num_elements; + return tmp->val; +} + +template +std::pair, + hashtable_iterator > +hashtable::equal_range(const __key_type__& key) +{ + typedef std::pair pii; + const size_type n = bkt_num_key(key); + + for (node* first = this->buckets[n]; first; first = first->next) + { + if (equals(get_key(first->val), key)) + { + for (node* cur = first->next; cur; cur = cur->next) + { + if (!equals(get_key(cur->val), key)) + return pii(iterator(first, this), iterator(cur, this)); + } + for (size_type m = n + 1; m < this->buckets.size(); ++m) + { + if (this->buckets[m]) + { + return pii(iterator(first, this), + iterator(this->buckets[m], this)); + } + } + return pii(iterator(first, this), end()); + } + } + return pii(end(), end()); +} + +template +std::pair, + hashtable_const_iterator > +hashtable::equal_range(const __key_type__& key) const +{ + typedef std::pair pii; + const size_type n = bkt_num_key(key); + + for (const node* first = this->buckets[n]; first; first = first->next) + { + if (equals(get_key(first->val), key)) + { + for (const node* cur = first->next; cur; cur = cur->next) + { + if (!equals(get_key(cur->val), key)) + { + return pii(const_iterator(first, this), + const_iterator(cur, this)); + } + } + for (size_type m = n + 1; m < this->buckets.size(); ++m) + { + if (this->buckets[m]) + { + return pii(const_iterator(first, this), + const_iterator(this->buckets[m], this)); + } + } + return pii(const_iterator(first, this), end()); + } + } + return pii(end(), end()); +} + +template +__size_type__ +hashtable::erase(const __key_type__& key) +{ + const size_type n = bkt_num_key(key); + node* first = this->buckets[n]; + size_type erased = 0; + + if (first) + { + node* cur = first; + node* next = cur->next; + while (next) + { + if (equals(get_key(next->val), key)) + { + cur->next = next->next; + delete_node(next); + next = cur->next; + ++erased; + } + else + { + cur = next; + next = cur->next; + } + } + if (equals(get_key(first->val), key)) + { + this->buckets[n] = first->next; + delete_node(first); + ++erased; + } + } + this->num_elements -= erased; + return erased; +} + +template +void +hashtable::erase(const hashtable_iterator& it) +{ + node* const p = it.cur; + if (p) + { + const size_type n = bkt_num(p->val); + node* cur = this->buckets[n]; + + if (cur == p) + { + this->buckets[n] = cur->next; + delete_node(cur); + --this->num_elements; + } + else + { + node* next = cur->next; + while (next) + { + if (next == p) + { + cur->next = next->next; + delete_node(next); + --this->num_elements; + break; + } + else + { + cur = next; + next = cur->next; + } + } + } + } +} + +template +void +hashtable::erase(hashtable_iterator first, + hashtable_iterator last) +{ + size_type f_bucket = first.cur ? bkt_num(first.cur->val) : this->buckets.size(); + size_type l_bucket = last.cur ? bkt_num(last.cur->val) : this->buckets.size(); + if (first.cur == last.cur) + return; + else if (f_bucket == l_bucket) + erase_bucket(f_bucket, first.cur, last.cur); + else + { + erase_bucket(f_bucket, first.cur, 0); + for (size_type n = f_bucket + 1; n < l_bucket; ++n) + erase_bucket(n, 0); + if (l_bucket != this->buckets.size()) + erase_bucket(l_bucket, last.cur); + } +} + +template +inline void +hashtable::erase(hashtable_const_iterator first, + hashtable_const_iterator last) +{ + erase(iterator(const_cast(first.cur), + const_cast(first.ht)), + iterator(const_cast(last.cur), + const_cast(last.ht))); +} + +template +inline void +hashtable::erase(const hashtable_const_iterator& it) +{ + erase(iterator(const_cast(it.cur), + const_cast(it.ht))); +} + +template +void +hashtable::resize(__size_type__ num_elements_hint) +{ + const size_type old_n = this->buckets.size(); + if (num_elements_hint > old_n) + { + const size_type n = next_size(num_elements_hint); + if (n > old_n) + { + typename hashtable::buckets_type tmp(n, (node*)0); + for (size_type bucket = 0; bucket < old_n; ++bucket) + { + node* first = this->buckets[bucket]; + while (first) + { + size_type new_bucket = bkt_num(first->val, n); + this->buckets[bucket] = first->next; + first->next = tmp[new_bucket]; + tmp[new_bucket] = first; + first = this->buckets[bucket]; + } + } + this->buckets.clear(); + this->buckets.swap(tmp); + } + } +} + + +template +void +hashtable::erase_bucket(const size_t n, + hashtable_node* first, + hashtable_node* last) +{ + node* cur = this->buckets[n]; + if (cur == first) + erase_bucket(n, last); + else + { + node* next; + for (next = cur->next; next != first; cur = next, next = cur->next); + while (next) + { + cur->next = next->next; + delete_node(next); + next = cur->next; + --this->num_elements; + } + } +} + +template +void +hashtable::erase_bucket(const size_t n, + hashtable_node* last) +{ + node* cur = this->buckets[n]; + while (cur != last) + { + node* next = cur->next; + delete_node(cur); + cur = next; + this->buckets[n] = cur; + --this->num_elements; + } +} + +template +void hashtable_base::clear() +{ + for (size_type i = 0; i < buckets.size(); ++i) + { + node* cur = buckets[i]; + while (cur != 0) + { + node* next = cur->next; + delete_node(cur); + cur = next; + } + buckets[i] = 0; + } + num_elements = 0; +} + + +template +void hashtable_base::copy_from(const hashtable_base& ht) +{ + buckets.reserve(ht.buckets.size()); + buckets.insert(buckets.end(), ht.buckets.size(), (node*) 0); + for (size_type i = 0; i < ht.buckets.size(); ++i) + { + const node* cur = ht.buckets[i]; + if (cur) + { + node* copy = new_node(cur->val); + buckets[i] = copy; + ++num_elements; + + for (node* next = cur->next; next; cur = next, next = cur->next) + { + copy->next = new_node(next->val); + ++num_elements; + copy = copy->next; + } + } + } +} + +}// end namespace itk + + +# undef __difference_type__ +# undef __size_type__ +# undef __value_type__ +# undef __key_type__ +# undef __node__ + +// the following is added for itk compatability: + +// -- + +// A few compatability fixes. Placed here for automatic include in +// both the hash_set and the hash_map sources. +# if (defined (_MSC_VER)&&(_MSC_VER < 1600 )) || defined(__BORLANDC__) || ((defined(__ICC)||defined(__ECC)) && defined(linux)) +// This should be replaced with a try_compile that tests the availability of std::identity. FIXME +namespace std +{ +template +struct identity : public std::unary_function { +public: + const T& operator()(const T& x) const { return x; } +}; +} + +#endif + +# if defined (_MSC_VER) || defined(__BORLANDC__) || ((defined(__ICC)||defined(__ECC)) && defined(linux)) +// This should be replaced with a try_compile that tests the availability of std::select*. FIXME + +template +struct itk_Select1st : public std::unary_function<_Pair, typename _Pair::first_type> { + typename _Pair::first_type const & operator()(_Pair const & __x) const { return __x.first; } +}; + +template +struct itk_Select2nd : public std::unary_function<_Pair, typename _Pair::second_type> { + typename _Pair::second_type const & operator()(_Pair const & __x) const { return __x.second; } +}; + +// Add select* to std. +namespace std { +template +struct select1st : public itk_Select1st<_Pair> {}; +template struct select2nd : public itk_Select2nd<_Pair> {}; +} + +#endif + +#endif + +#endif // itk_emulation_hashtable_h diff --git a/Core/Code/Service/mitkLDAPExpr.cpp b/Core/Code/Service/mitkLDAPExpr.cpp new file mode 100644 index 0000000000..01f2fe8aff --- /dev/null +++ b/Core/Code/Service/mitkLDAPExpr.cpp @@ -0,0 +1,771 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "mitkLDAPExpr_p.h" +#include "mitkServiceUtils.h" + +namespace mitk { + +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"; + +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) throw (std::invalid_argument); + + //! 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 throw (std::invalid_argument); + +}; + + +class LDAPExprData : public SharedData +{ +public: + + LDAPExprData( int op, const std::vector& args ) + : m_operator(op), m_args(args) + { + } + + LDAPExprData( int op, std::string attrName, const std::string& attrValue ) + : m_operator(op), 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() +{ +} + +LDAPExpr::LDAPExpr( const std::string &filter ) +{ + ParseState ps(filter); + try + { + LDAPExpr expr = ParseExpr(ps); + + if (!Trim(ps.rest()).empty()) + { + ps.error(GARBAGE + " '" + ps.rest() + "'"); + } + + d = expr.d; + } + catch (const std::out_of_range&) + { + ps.error(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 (std::equal(d->m_attrName.begin(), d->m_attrName.end(), ServiceConstants::OBJECTCLASS().begin(), stricomp) && + d->m_attrValue.find(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) + { + 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 ServiceProperties &pd ) +{ + return LDAPExpr(filter).Evaluate(pd, false); +} + +bool LDAPExpr::Evaluate( const ServiceProperties& p, bool matchCase ) const +{ + if ((d->m_operator & SIMPLE) != 0) + { + Any propVal; + ServiceProperties::const_iterator it = p.find(d->m_attrName); + if (it != p.end() && (matchCase ? d->m_attrName == (std::string)it->first : true)) + { + propVal = it->second; + } + return Compare(propVal, 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) + 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(Byte) || objType == typeid(int)) + { + int sInt; + std::stringstream ss(s); + ss >> sInt; + int intVal = any_cast(obj); + + switch(op) + { + case LE: + return intVal <= sInt; + case GE: + return intVal >= sInt; + default: /*APPROX and EQ*/ + return intVal == sInt; + } + } + else if (objType == typeid(float)) + { + float sFloat; + std::stringstream ss(s); + ss >> sFloat; + float floatVal = any_cast(obj); + + switch(op) + { + case LE: + return floatVal <= sFloat; + case GE: + return floatVal >= sFloat; + default: /*APPROX and EQ*/ + float diff = floatVal - sFloat; + return (diff < std::numeric_limits::epsilon()) && (diff > -std::numeric_limits::epsilon()); + } + } + else if (objType == typeid(double)) + { + double sDouble; + std::stringstream ss(s); + ss >> sDouble; + 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(long long int)) + { + long long int sLongInt; + std::stringstream ss(s); + ss >> sLongInt; + long long int longIntVal = any_cast(obj); + + switch(op) + { + case LE: + return longIntVal <= sLongInt; + case GE: + return longIntVal >= sLongInt; + default: /*APPROX and EQ*/ + return longIntVal == sLongInt; + } + } + 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; +} + +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; + int len = s.length(); + for(int i=0; im_operator + + std::vector v; + do + { + v.push_back(ParseExpr(ps)); + ps.skipWhite(); + } while (ps.peek() == '('); + + int n = v.size(); + if (!ps.prefix(")") || n == 0 || (op == NOT && n > 1)) + ps.error(MALFORMED); + + return LDAPExpr(op, v); +} + +LDAPExpr LDAPExpr::ParseSimple( ParseState &ps ) +{ + std::string attrName = ps.getAttributeName(); + if (attrName.empty()) + ps.error(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 + } + std::string attrValue = ps.getAttributeValue(); + if (!ps.prefix(")")) + ps.error(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) + { + 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 ) throw (std::invalid_argument) +{ + if (str.empty()) + { + error(NULLQ); + } + + m_str = str; + m_pos = 0; +} + +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() +{ + int start = m_pos; + int n = -1; + for(;; m_pos++) + { + Byte c = peek(); + if (c == '(' || c == ')' || + c == '<' || c == '>' || + c == '=' || c == '~') { + break; + } + else if (!std::isspace(c)) + { + n = m_pos - start + 1; + } + } + if (n == -1) + { + 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); + 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 throw (std::invalid_argument) +{ + std::string error = m + ": " + (m_str.empty() ? "" : m_str.substr(m_pos)); + throw std::invalid_argument(error); +} + +} diff --git a/Core/Code/Service/mitkLDAPExpr_p.h b/Core/Code/Service/mitkLDAPExpr_p.h new file mode 100644 index 0000000000..2b2049f982 --- /dev/null +++ b/Core/Code/Service/mitkLDAPExpr_p.h @@ -0,0 +1,188 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKLDAPEXPR_H +#define MITKLDAPEXPR_H + +#include +#include + +#include + +#ifdef MITK_HAS_UNORDERED_SET_H +#include +#else +#include "mitkItkHashSet.h" +#endif + +#include "mitkSharedData.h" +#include "mitkServiceProperties.h" + +namespace mitk { + +class LDAPExprData; + +/** + * 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; + + typedef char Byte; + typedef std::vector StringList; + typedef std::vector LocalCache; +#ifdef MITK_HAS_UNORDERED_SET_H + typedef std::unordered_set ObjectClassSet; +#else + typedef itk::hash_set ObjectClassSet; +#endif + + /** + * 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 ServiceProperties& pd); + + //! Evaluate this LDAP filter. + bool Evaluate(const ServiceProperties& 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; + + //! + 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; + +}; + +} + +#endif // MITKLDAPEXPR_H diff --git a/Core/Code/Service/mitkLDAPFilter.cpp b/Core/Code/Service/mitkLDAPFilter.cpp new file mode 100644 index 0000000000..9f099f42b1 --- /dev/null +++ b/Core/Code/Service/mitkLDAPFilter.cpp @@ -0,0 +1,112 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkLDAPFilter.h" + +#include "mitkLDAPExpr_p.h" +#include "mitkServiceReferencePrivate.h" + +namespace mitk { + +class LDAPFilterData : public SharedData +{ +public: + + LDAPFilterData() + {} + + LDAPFilterData(const std::string& filter) + : ldapExpr(filter) + {} + + LDAPFilterData(const LDAPFilterData& other) + : SharedData(other), ldapExpr(other.ldapExpr) + {} + + LDAPExpr ldapExpr; +}; + +LDAPFilter::LDAPFilter() + : d(0) +{ +} + +LDAPFilter::LDAPFilter(const std::string& filter) + : d(0) +{ + try + { + d = new LDAPFilterData(filter); + } + catch (const std::exception& e) + { + throw std::invalid_argument(e.what()); + } +} + +LDAPFilter::LDAPFilter(const LDAPFilter& other) + : d(other.d) +{ +} + +LDAPFilter::~LDAPFilter() +{ +} + +LDAPFilter::operator bool() const +{ + return d; +} + +bool LDAPFilter::Match(const ServiceReference& reference) const +{ + return d->ldapExpr.Evaluate(reference.d->GetProperties(), true); +} + +bool LDAPFilter::Match(const ServiceProperties& dictionary) const +{ + return d->ldapExpr.Evaluate(dictionary, false); +} + +bool LDAPFilter::MatchCase(const ServiceProperties& dictionary) const +{ + return d->ldapExpr.Evaluate(dictionary, true); +} + +std::string LDAPFilter::ToString() const +{ + return d->ldapExpr.ToString(); +} + +bool LDAPFilter::operator==(const LDAPFilter& other) const +{ + return d->ldapExpr.ToString() == other.d->ldapExpr.ToString(); +} + +LDAPFilter& LDAPFilter::operator=(const LDAPFilter& filter) +{ + d = filter.d; + + return *this; +} + +} + +std::ostream& operator<<(std::ostream& os, const mitk::LDAPFilter& filter) +{ + return os << filter.ToString(); +} diff --git a/Core/Code/Service/mitkLDAPFilter.h b/Core/Code/Service/mitkLDAPFilter.h new file mode 100644 index 0000000000..8f859b6a32 --- /dev/null +++ b/Core/Code/Service/mitkLDAPFilter.h @@ -0,0 +1,163 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKLDAPFILTER_H +#define MITKLDAPFILTER_H + +#include "mitkCommon.h" + +#include "mitkServiceReference.h" +#include "mitkServiceProperties.h" + +#include "mitkSharedData.h" + +namespace mitk { + +class LDAPFilterData; + +/** + * \ingroup MicroServices + * + * An RFC 1960-based Filter. + * + *

+ * A LDAPFilter can be used numerous times to determine if the match + * argument matches the filter string that was used to create the LDAPFilter. + *

+ * Some examples of LDAP filters are: + * + * - "(cn=Babs Jensen)" + * - "(!(cn=Tim Howes))" + * - "(&(" + ServiceConstants::OBJECTCLASS() + "=Person)(|(sn=Jensen)(cn=Babs J*)))" + * - "(o=univ*of*mich*)" + * + * \remarks This class is thread safe. + */ +class MITK_CORE_EXPORT LDAPFilter { + +public: + + /** + * Creates in invalid LDAPFilter object. + * Test the validity by using the boolean conversion operator. + * + *

+ * Calling methods on an invalid LDAPFilter + * will result in undefined behavior. + */ + LDAPFilter(); + + /** + * Creates a LDAPFilter object. This LDAPFilter + * object may be used to match a ServiceReference object or a + * ServiceProperties object. + * + *

+ * If the filter cannot be parsed, an std::invalid_argument will be + * thrown with a human readable message where the filter became unparsable. + * + * @param filter The filter string. + * @return A LDAPFilter object encapsulating the filter string. + * @throws std::invalid_argument If filter contains an invalid + * filter string that cannot be parsed. + * @see "Framework specification for a description of the filter string syntax." TODO! + */ + LDAPFilter(const std::string& filter); + + LDAPFilter(const LDAPFilter& other); + + ~LDAPFilter(); + + operator bool() const; + + /** + * Filter using a service's properties. + *

+ * This LDAPFilter is executed using the keys and values of the + * referenced service's properties. The keys are looked up in a case + * insensitive manner. + * + * @param reference The reference to the service whose properties are used + * in the match. + * @return true if the service's properties match this + * LDAPFilter false otherwise. + */ + bool Match(const ServiceReference& reference) const; + + /** + * Filter using a ServiceProperties object with case insensitive key lookup. This + * LDAPFilter is executed using the specified ServiceProperties's keys + * and values. The keys are looked up in a case insensitive manner. + * + * @param dictionary The ServiceProperties whose key/value pairs are used + * in the match. + * @return true if the ServiceProperties's values match this + * filter; false otherwise. + */ + bool Match(const ServiceProperties& dictionary) const; + + /** + * Filter using a ServiceProperties. This LDAPFilter is executed using + * the specified ServiceProperties's keys and values. The keys are looked + * up in a normal manner respecting case. + * + * @param dictionary The ServiceProperties whose key/value pairs are used + * in the match. + * @return true if the ServiceProperties's values match this + * filter; false otherwise. + */ + bool MatchCase(const ServiceProperties& dictionary) const; + + /** + * Returns this LDAPFilter's filter string. + *

+ * The filter string is normalized by removing whitespace which does not + * affect the meaning of the filter. + * + * @return This LDAPFilter's filter string. + */ + std::string ToString() const; + + /** + * Compares this LDAPFilter to another LDAPFilter. + * + *

+ * This implementation returns the result of calling + * this->ToString() == other.ToString(). + * + * @param other The object to compare against this LDAPFilter. + * @return Returns the result of calling + * this->ToString() == other.ToString(). + */ + bool operator==(const LDAPFilter& other) const; + + LDAPFilter& operator=(const LDAPFilter& filter); + +protected: + + SharedDataPointer d; + +}; + +} + +/** + * \ingroup MicroServices + */ +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::LDAPFilter& filter); + +#endif // MITKLDAPFILTER_H diff --git a/Core/Code/Service/mitkModule.cpp b/Core/Code/Service/mitkModule.cpp new file mode 100644 index 0000000000..d7321ee6f4 --- /dev/null +++ b/Core/Code/Service/mitkModule.cpp @@ -0,0 +1,223 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkModule.h" + +#include "mitkModuleContext.h" +#include "mitkModuleActivator.h" +#include "mitkModulePrivate.h" +#include "mitkCoreModuleContext_p.h" + +namespace mitk { + +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_MODULE_DEPENDS() +{ + static const std::string s("module.module_depends"); + return s; +} +const std::string& Module::PROP_LIB_DEPENDS() +{ + static const std::string s("module.lib_depends"); + return s; +} +const std::string& Module::PROP_PACKAGE_DEPENDS() +{ + static const std::string s("module.package_depends"); + return s; +} +const std::string& Module::PROP_VERSION() +{ + static const std::string s("module.version"); + return s; +} +const std::string& Module::PROP_QT() +{ + static const std::string s("module.qt"); + 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; +} + +bool Module::IsLoaded() const +{ + return d->moduleContext != 0; +} + +void Module::Start() +{ + + if (d->moduleContext) + { + MITK_WARN << "Module " << d->info.name << " already started."; + return; + } + + d->moduleContext = new ModuleContext(this->d); + +// try +// { + d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADING, this)); + // try to get a ModuleActivator instance + if (d->info.activatorHook) + { + try + { + d->moduleActivator = d->info.activatorHook(); + } + catch (...) + { + MITK_ERROR << "Creating the module activator of " << d->info.name << " failed"; + throw; + } + + d->moduleActivator->Load(d->moduleContext); + } + + 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)); +// MITK_ERROR << "Calling the module activator Load() method of " << d->info.name << " failed!"; +// throw; +// } +} + +void Module::Stop() +{ + if (d->moduleContext == 0) + { + MITK_WARN << "Module " << d->info.name << " already stopped."; + return; + } + + try + { + d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); + if (d->moduleActivator) + { + d->moduleActivator->Unload(d->moduleContext); + } + } + catch (...) + { + MITK_ERROR << "Calling the module activator Unload() method of " << d->info.name << " failed!"; + + try + { + d->RemoveModuleResources(); + } + catch (...) {} + + delete d->moduleContext; + d->moduleContext = 0; + + d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); + + throw; + } + + d->RemoveModuleResources(); + delete d->moduleContext; + d->moduleContext = 0; + d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); +} + +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; +} + +std::string Module::GetProperty(const std::string& key) const +{ + if (d->properties.count(key) == 0) return ""; + return d->properties[key]; +} + +} // end namespace mitk + +std::ostream& operator<<(std::ostream& os, const mitk::Module& module) +{ + os << "Module[" << "id=" << module.GetModuleId() << + ", loc=" << module.GetLocation() << + ", name=" << module.GetName() << "]"; + return os; +} + +std::ostream& operator<<(std::ostream& os, mitk::Module const * module) +{ + return operator<<(os, *module); +} diff --git a/Core/Code/Service/mitkModule.h b/Core/Code/Service/mitkModule.h new file mode 100644 index 0000000000..59d580050d --- /dev/null +++ b/Core/Code/Service/mitkModule.h @@ -0,0 +1,243 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKMODULE_H +#define MITKMODULE_H + +#include + +#include "mitkModuleVersion.h" + +namespace mitk { + +class CoreModuleContext; +class ModuleInfo; +class ModuleContext; +class ModulePrivate; + +/** + * \ingroup MicroServices + * + * Represents a MITK module. + * + *

+ * A %Module object is the access point to a MITK module. + * Each MITK 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 MITK_CORE_EXPORT Module +{ + +public: + + static const std::string& PROP_ID(); + static const std::string& PROP_NAME(); + static const std::string& PROP_LOCATION(); + static const std::string& PROP_MODULE_DEPENDS(); + static const std::string& PROP_PACKAGE_DEPENDS(); + static const std::string& PROP_LIB_DEPENDS(); + static const std::string& PROP_VERSION(); + static const std::string& PROP_QT(); + + ~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 and persistent. + *
  • 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 + * MITK_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 + * MITK_CREATE_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 string 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. + */ + std::string GetProperty(const std::string& key) const; + +private: + + friend class ModuleRegistry; + friend class ServiceReferencePrivate; + + ModulePrivate* d; + + Module(); + Module(const Module&); + + void Init(CoreModuleContext* coreCtx, ModuleInfo* info); + + void Start(); + void Stop(); + +}; + +} + +#ifdef MITK_HAS_UNORDERED_MAP_H +namespace std { +#elif defined(__GNUC__) +namespace __gnu_cxx { +#else +namespace itk { +#endif + +template class hash; + +template<> class hash +{ +public: + std::size_t operator()(const mitk::Module* module) const + { +#ifdef MITK_HAS_HASH_SIZE_T + return hash()(reinterpret_cast(module)); +#else + std::size_t key = reinterpret_cast(module); + return std::size_t(key & (~0U)); +#endif + } +}; + +/** + * \ingroup MicroServices + */ +namespace ModuleConstants { + +} + +} + +/** + * \ingroup MicroServices + */ +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::Module& module); +/** + * \ingroup MicroServices + */ +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, mitk::Module const * module); + +#endif // MITKMODULE_H diff --git a/Core/Code/Service/mitkModuleAbstractTracked.h b/Core/Code/Service/mitkModuleAbstractTracked.h new file mode 100644 index 0000000000..a838b22a51 --- /dev/null +++ b/Core/Code/Service/mitkModuleAbstractTracked.h @@ -0,0 +1,293 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKMODULEABSTRACTTRACKED_H +#define MITKMODULEABSTRACTTRACKED_H + +#include +#include + +#include + +#include "mitkAtomicInt.h" +#include "mitkAny.h" + +namespace mitk { + +/** + * This class is not intended to be used directly. It is exported to support + * the MITK module system. + * + * Abstract class to track items. If a Tracker is reused (closed then reopened), + * then a new ModuleAbstractTracked object is used. This class acts as a map of tracked + * item -> customized object. Subclasses of this class will act as the listener + * object for the tracker. This class is used to synchronize access to the + * tracked items. This is not a public class. It is only for use by the + * implementation of the Tracker class. + * + * @tparam S The tracked item. It is the key. + * @tparam T The value mapped to the tracked item. + * @tparam R The reason the tracked item is being tracked or untracked. + * @ThreadSafe + */ +template +class ModuleAbstractTracked : public itk::SimpleMutexLock +{ + +public: + + /* set this to true to compile in debug messages */ + static const bool DEBUG; // = false; + + typedef std::map TrackingMap; + + /** + * ModuleAbstractTracked constructor. + */ + ModuleAbstractTracked(); + + virtual ~ModuleAbstractTracked(); + + void Wait(); + void WakeAll(); + + /** + * Set initial list of items into tracker before events begin to be + * received. + * + * This method must be called from Tracker's open method while synchronized + * on this object in the same synchronized block as the add listener call. + * + * @param list The initial list of items to be tracked. null + * entries in the list are ignored. + * @GuardedBy this + */ + void SetInitial(const std::list& list); + + /** + * Track the initial list of items. This is called after events can begin to + * be received. + * + * This method must be called from Tracker's open method while not + * synchronized on this object after the add listener call. + * + */ + void TrackInitial(); + + /** + * Called by the owning Tracker object when it is closed. + */ + void Close(); + + /** + * Begin to track an item. + * + * @param item S to be tracked. + * @param related Action related object. + */ + void Track(S item, R related); + + /** + * Discontinue tracking the item. + * + * @param item S to be untracked. + * @param related Action related object. + */ + void Untrack(S item, R related); + + /** + * Returns the number of tracked items. + * + * @return The number of tracked items. + * + * @GuardedBy this + */ + std::size_t Size() const; + + /** + * Returns if the tracker is empty. + * + * @return Whether the tracker is empty. + * + * @GuardedBy this + */ + bool IsEmpty() const; + + /** + * Return the customized object for the specified item + * + * @param item The item to lookup in the map + * @return The customized object for the specified item. + * + * @GuardedBy this + */ + T GetCustomizedObject(S item) const; + + /** + * Return the list of tracked items. + * + * @return The tracked items. + * @GuardedBy this + */ + void GetTracked(std::list& items) const; + + /** + * Increment the modification count. If this method is overridden, the + * overriding method MUST call this method to increment the tracking count. + * + * @GuardedBy this + */ + virtual void Modified(); + + /** + * Returns the tracking count for this ServiceTracker object. + * + * The tracking count is initialized to 0 when this object is opened. Every + * time an item is added, modified or removed from this object the tracking + * count is incremented. + * + * @GuardedBy this + * @return The tracking count for this object. + */ + int GetTrackingCount() const; + + /** + * Copy the tracked items and associated values into the specified map. + * + * @param map The map into which to copy the tracked items and associated + * values. This map must not be a user provided map so that user code + * is not executed while synchronized on this. + * @return The specified map. + * @GuardedBy this + */ + void CopyEntries(TrackingMap& map) const; + + /** + * Call the specific customizer adding method. This method must not be + * called while synchronized on this object. + * + * @param item S to be tracked. + * @param related Action related object. + * @return Customized object for the tracked item or null if + * the item is not to be tracked. + */ + virtual T CustomizerAdding(S item, const R& related) = 0; + + /** + * Call the specific customizer modified method. This method must not be + * called while synchronized on this object. + * + * @param item Tracked item. + * @param related Action related object. + * @param object Customized object for the tracked item. + */ + virtual void CustomizerModified(S item, const R& related, + T object) = 0; + + /** + * Call the specific customizer removed method. This method must not be + * called while synchronized on this object. + * + * @param item Tracked item. + * @param related Action related object. + * @param object Customized object for the tracked item. + */ + virtual void CustomizerRemoved(S item, const R& related, + T object) = 0; + + /** + * List of items in the process of being added. This is used to deal with + * nesting of events. Since events may be synchronously delivered, events + * can be nested. For example, when processing the adding of a service and + * the customizer causes the service to be unregistered, notification to the + * nested call to untrack that the service was unregistered can be made to + * the track method. + * + * Since the std::vector implementation is not synchronized, all access to + * this list must be protected by the same synchronized object for + * thread-safety. + * + * @GuardedBy this + */ + std::list adding; + + /** + * true if the tracked object is closed. + * + * This field is volatile because it is set by one thread and read by + * another. + */ + volatile bool closed; + + /** + * Initial list of items for the tracker. This is used to correctly process + * the initial items which could be modified before they are tracked. This + * is necessary since the initial set of tracked items are not "announced" + * by events and therefore the event which makes the item untracked could be + * delivered before we track the item. + * + * An item must not be in both the initial and adding lists at the same + * time. An item must be moved from the initial list to the adding list + * "atomically" before we begin tracking it. + * + * Since the LinkedList implementation is not synchronized, all access to + * this list must be protected by the same synchronized object for + * thread-safety. + * + * @GuardedBy this + */ + std::list initial; + + /** + * Common logic to add an item to the tracker used by track and + * trackInitial. The specified item must have been placed in the adding list + * before calling this method. + * + * @param item S to be tracked. + * @param related Action related object. + */ + void TrackAdding(S item, R related); + +private: + + itk::ConditionVariable::Pointer waitCond; + + /** + * Map of tracked items to customized objects. + * + * @GuardedBy this + */ + TrackingMap tracked; + + /** + * Modification count. This field is initialized to zero and incremented by + * modified. + * + * @GuardedBy this + */ + AtomicInt trackingCount; + + bool CustomizerAddingFinal(S item, const T& custom); + +}; + +} + +#include "mitkModuleAbstractTracked.tpp" + +#endif // MITKMODULEABSTRACTTRACKED_H diff --git a/Core/Code/Service/mitkModuleAbstractTracked.tpp b/Core/Code/Service/mitkModuleAbstractTracked.tpp new file mode 100644 index 0000000000..9a79d0b3ec --- /dev/null +++ b/Core/Code/Service/mitkModuleAbstractTracked.tpp @@ -0,0 +1,325 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include + +namespace mitk { + +typedef itk::MutexLockHolder MutexLocker; + +template +const bool ModuleAbstractTracked::DEBUG = false; + +template +ModuleAbstractTracked::ModuleAbstractTracked() + : waitCond(itk::ConditionVariable::New()) +{ + closed = false; +} + +template +ModuleAbstractTracked::~ModuleAbstractTracked() +{ + +} + +template +void ModuleAbstractTracked::Wait() +{ + waitCond->Wait(this); +} + +template +void ModuleAbstractTracked::WakeAll() +{ + waitCond->Broadcast(); +} + +template +void ModuleAbstractTracked::SetInitial(const std::list& initiallist) +{ + initial = initiallist; + + if (DEBUG) + { + for(typename std::list::const_iterator item = initiallist.begin(); + item != initiallist.end(); ++item) + { + MITK_DEBUG(true) << "ModuleAbstractTracked::setInitial: " << (*item); + } + } +} + +template +void ModuleAbstractTracked::TrackInitial() +{ + while (true) + { + S item(0); + { + itk::MutexLockHolder lock(*this); + if (closed || (initial.size() == 0)) + { + /* + * if there are no more initial items + */ + return; /* we are done */ + } + /* + * move the first item from the initial list to the adding list + * within this synchronized block. + */ + item = initial.front(); + initial.pop_front(); + if (tracked[item]) + { + /* if we are already tracking this item */ + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::trackInitial[already tracked]: " << item; + continue; /* skip this item */ + } + if (std::find(adding.begin(), adding.end(), item) != adding.end()) + { + /* + * if this item is already in the process of being added. + */ + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::trackInitial[already adding]: " << item; + continue; /* skip this item */ + } + adding.push_back(item); + } + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::trackInitial: " << item; + TrackAdding(item, R()); + /* + * Begin tracking it. We call trackAdding + * since we have already put the item in the + * adding list. + */ + } +} + +template +void ModuleAbstractTracked::Close() +{ + closed = true; +} + +template +void ModuleAbstractTracked::Track(S item, R related) +{ + T object(0); + { + itk::MutexLockHolder lock(*this); + if (closed) + { + return; + } + object = tracked[item]; + if (!object) + { /* we are not tracking the item */ + if (std::find(adding.begin(), adding.end(),item) != adding.end()) + { + /* if this item is already in the process of being added. */ + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::track[already adding]: " << item; + return; + } + adding.push_back(item); /* mark this item is being added */ + } + else + { /* we are currently tracking this item */ + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::track[modified]: " << item; + Modified(); /* increment modification count */ + } + } + + if (!object) + { /* we are not tracking the item */ + TrackAdding(item, related); + } + else + { + /* Call customizer outside of synchronized region */ + CustomizerModified(item, related, object); + /* + * If the customizer throws an unchecked exception, it is safe to + * let it propagate + */ + } +} + +template +void ModuleAbstractTracked::Untrack(S item, R related) +{ + T object(0); + { + itk::MutexLockHolder lock(*this); + std::size_t initialSize = initial.size(); + initial.remove(item); + if (initialSize != initial.size()) + { /* if this item is already in the list + * of initial references to process + */ + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::untrack[removed from initial]: " << item; + return; /* we have removed it from the list and it will not be + * processed + */ + } + + std::size_t addingSize = adding.size(); + adding.remove(item); + if (addingSize != adding.size()) + { /* if the item is in the process of + * being added + */ + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::untrack[being added]: " << item; + return; /* + * in case the item is untracked while in the process of + * adding + */ + } + object = tracked[item]; + /* + * must remove from tracker before + * calling customizer callback + */ + tracked.erase(item); + if (!object) + { /* are we actually tracking the item */ + return; + } + Modified(); /* increment modification count */ + } + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::untrack[removed]: " << item; + /* Call customizer outside of synchronized region */ + CustomizerRemoved(item, related, object); + /* + * If the customizer throws an unchecked exception, it is safe to let it + * propagate + */ +} + +template +std::size_t ModuleAbstractTracked::Size() const +{ + return tracked.size(); +} + +template +bool ModuleAbstractTracked::IsEmpty() const +{ + return tracked.empty(); +} + +template +T ModuleAbstractTracked::GetCustomizedObject(S item) const +{ + typename TrackingMap::const_iterator i = tracked.find(item); + if (i != tracked.end()) return i->second; + return T(); +} + +template +void ModuleAbstractTracked::GetTracked(std::list& items) const +{ + for (typename TrackingMap::const_iterator i = tracked.begin(); + i != tracked.end(); ++i) + { + items.push_back(i->first); + } +} + +template +void ModuleAbstractTracked::Modified() +{ + trackingCount.Ref(); +} + +template +int ModuleAbstractTracked::GetTrackingCount() const +{ + return trackingCount; +} + +template +void ModuleAbstractTracked::CopyEntries(TrackingMap& map) const +{ + map.insert(tracked.begin(), tracked.end()); +} + +template +bool ModuleAbstractTracked::CustomizerAddingFinal(S item, const T& custom) +{ + itk::MutexLockHolder lock(*this); + std::size_t addingSize = adding.size(); + adding.remove(item); + if (addingSize != adding.size() && !closed) + { + /* + * if the item was not untracked during the customizer + * callback + */ + if (custom) + { + tracked[item] = custom; + Modified(); /* increment modification count */ + waitCond->Broadcast(); /* notify any waiters */ + } + return false; + } + else + { + return true; + } +} + +template +void ModuleAbstractTracked::TrackAdding(S item, R related) +{ + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::trackAdding:" << item; + T object(0); + bool becameUntracked = false; + /* Call customizer outside of synchronized region */ + try + { + object = CustomizerAdding(item, related); + becameUntracked = this->CustomizerAddingFinal(item, object); + } + catch (...) + { + /* + * If the customizer throws an exception, it will + * propagate after the cleanup code. + */ + this->CustomizerAddingFinal(item, object); + throw; + } + + /* + * The item became untracked during the customizer callback. + */ + if (becameUntracked && object) + { + MITK_DEBUG(DEBUG) << "ModuleAbstractTracked::trackAdding[removed]: " << item; + /* Call customizer outside of synchronized region */ + CustomizerRemoved(item, related, object); + /* + * If the customizer throws an unchecked exception, it is safe to + * let it propagate + */ + } +} + +} diff --git a/Core/Code/Service/mitkModuleActivator.h b/Core/Code/Service/mitkModuleActivator.h new file mode 100644 index 0000000000..589ffb50c8 --- /dev/null +++ b/Core/Code/Service/mitkModuleActivator.h @@ -0,0 +1,95 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKMODULEACTIVATOR_H_ +#define MITKMODULEACTIVATOR_H_ + +namespace mitk { + +class ModuleContext; + +/** + * \ingroup MicroServices + * + * Customizes the starting and stopping of a MITK module. + *

+ * %ModuleActivator is an interface that can be implemented by + * MITK modules. The MITK core 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 MITK core 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 MITK core. + * + */ +struct ModuleActivator +{ +public: + + 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; + +}; + +} // end namespace mitk + +#endif /* MITKMODULEACTIVATOR_H_ */ diff --git a/Core/Code/Service/mitkModuleContext.cpp b/Core/Code/Service/mitkModuleContext.cpp new file mode 100644 index 0000000000..27fd22abce --- /dev/null +++ b/Core/Code/Service/mitkModuleContext.cpp @@ -0,0 +1,130 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkModuleContext.h" + +#include "mitkModuleRegistry.h" +#include "mitkModulePrivate.h" +#include "mitkCoreModuleContext_p.h" +#include "mitkServiceRegistry_p.h" +#include "mitkServiceReferencePrivate.h" + +namespace mitk { + +class ModuleContextPrivate { + +public: + + ModuleContextPrivate(ModulePrivate* module) + : module(module) + {} + + ModulePrivate* module; +}; + + +ModuleContext::ModuleContext(ModulePrivate* module) + : d(new ModuleContextPrivate(module)) +{} + +ModuleContext::~ModuleContext() +{ + delete d; +} + +Module* ModuleContext::GetModule() const +{ + return d->module->q; +} + +Module* ModuleContext::GetModule(long id) const +{ + return ModuleRegistry::GetModule(id); +} + +void ModuleContext::GetModules(std::vector& modules) const +{ + ModuleRegistry::GetModules(modules); +} + +ServiceRegistration ModuleContext::RegisterService(const std::list& clazzes, + itk::LightObject* service, + const ServiceProperties& properties) +{ + return d->module->coreCtx->services.RegisterService(d->module, clazzes, service, properties); +} + +ServiceRegistration ModuleContext::RegisterService(const char* clazz, itk::LightObject* service, + const ServiceProperties& properties) +{ + std::list clazzes; + clazzes.push_back(clazz); + return d->module->coreCtx->services.RegisterService(d->module, clazzes, service, properties); +} + +std::list ModuleContext::GetServiceReferences(const std::string& clazz, + const std::string& filter) +{ + std::list result; + d->module->coreCtx->services.Get(clazz, filter, 0, result); + return result; +} + +ServiceReference ModuleContext::GetServiceReference(const std::string& clazz) +{ + return d->module->coreCtx->services.Get(d->module, clazz); +} + +itk::LightObject* ModuleContext::GetService(const ServiceReference& reference) +{ + if (!reference) + { + throw std::invalid_argument("Default constructed mitk::ServiceReference is not a valid input to getService()"); + } + ServiceReference internalRef(reference); + return internalRef.d->GetService(d->module->q); +} + +bool ModuleContext::UngetService(const ServiceReference& reference) +{ + ServiceReference ref = reference; + return ref.d->UngetService(d->module->q, true); +} + +void ModuleContext::AddServiceListener(const ServiceListenerDelegate& delegate, + const std::string& filter) +{ + d->module->coreCtx->listeners.AddServiceListener(this, delegate, filter); +} + +void ModuleContext::RemoveServiceListener(const ServiceListenerDelegate& delegate) +{ + d->module->coreCtx->listeners.RemoveServiceListener(this, delegate); +} + +void ModuleContext::AddModuleListener(const ModuleListenerDelegate& delegate) +{ + d->module->coreCtx->listeners.AddModuleListener(this, delegate); +} + +void ModuleContext::RemoveModuleListener(const ModuleListenerDelegate& delegate) +{ + d->module->coreCtx->listeners.RemoveModuleListener(this, delegate); +} + +} + diff --git a/Core/Code/Service/mitkModuleContext.h b/Core/Code/Service/mitkModuleContext.h new file mode 100644 index 0000000000..d1388ee58e --- /dev/null +++ b/Core/Code/Service/mitkModuleContext.h @@ -0,0 +1,659 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKMODULECONTEXT_H_ +#define MITKMODULECONTEXT_H_ + +#include + +#include "mitkServiceInterface.h" +#include "mitkMessage.h" +#include "mitkServiceEvent.h" +#include "mitkServiceRegistration.h" +#include "mitkServiceException.h" +#include "mitkModuleEvent.h" + +namespace mitk { + +typedef MessageAbstractDelegate1 ServiceListenerDelegate; +typedef MessageAbstractDelegate1 ModuleListenerDelegate; + +class ModuleContextPrivate; + +/** + * \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 MITK_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; + + + /** + * Returns a list of all known modules. + *

+ * This method returns a list of all modules loaded in the module + * environment at the time of the call to this method. This list will + * also contain modules which might already have been unloaded. + * + * @param modules A std::vector of Module objects which + * will hold one object per known module. + */ + void GetModules(std::vector& modules) const; + + /** + * 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 + * {@link ServiceFactory} 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 {@link ServiceConstants#SERVICE_ID} identifying the + * registration number of the service
    + * A property named {@link ServiceConstants#OBJECTCLASS} containing all the + * specified classes.
    + * 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 {@link ServiceEvent#REGISTERED} is fired. + *
  4. A ServiceRegistration object for this registration is + * returned. + *
+ * + * @param clazzes The class names under which the service can be located. + * The class names will be stored in the service's + * properties under the key {@link ServiceConstants#OBJECTCLASS}. + * @param service The service object or a ServiceFactory + * object. + * @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 + */ + ServiceRegistration RegisterService(const std::list& clazzes, + itk::LightObject* service, + const ServiceProperties& properties = ServiceProperties()); + + /** + * Registers the specified service object with the specified properties + * under the specified class name with the framework. + * + *

+ * This method is otherwise identical to + * RegisterService(const std:vector&, itk::LighObject*, const ServiceProperties&) + * and is provided as a convenience when service will only be registered under a single + * class name. Note that even in this case the value of the service's + * ServiceConstants::OBJECTCLASS property will be a std::list, rather + * than just a single string. + * + * @param clazz The class name 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. + * @see RegisterService(const std:list&, itk::LighObject*, const ServiceProperties&) + */ + ServiceRegistration RegisterService(const char* clazz, itk::LightObject* 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 char*, itk::LightObject*, const ServiceProperties&) but should be preferred + * since it avoids errors in the string literal identifying the class name or interface identifier. + * + * @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. + * @see RegisterService(const char*, itk::LighObject*, const ServiceProperties&) + */ + template + ServiceRegistration RegisterService(itk::LightObject* service, const ServiceProperties& properties = ServiceProperties()) + { + const char* clazz = mitk_service_interface_iid(); + if (clazz == 0) + { + throw ServiceException(std::string("The interface class you are registering your service ") + + service->GetNameOfClass() + " against has no MITK_DECLARE_SERVICE_INTERFACE macro"); + } + return RegisterService(clazz, service, 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 {@link 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::list 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::tring&, 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. + * @see GetServiceReferences(const std::string&, const std::string&) + */ + template + std::list GetServiceReferences(const std::string& filter = std::string()) + { + const char* clazz = mitk_service_interface_iid(); + if (clazz == 0) throw ServiceException("The service interface class has no MITK_DECLARE_SERVICE_INTERFACE macro"); + return GetServiceReferences(std::string(clazz), filter); + } + + /** + * 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 {@link ServiceConstants::SERVICE_RANKING} property) is returned. + *

+ * If there is a tie in ranking, the service with the lowest service ID (as + * specified in its {@link 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&) + */ + ServiceReference 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 = mitk_service_interface_iid(); + if (clazz == 0) throw ServiceException("The service interface class has no MITK_DECLARE_SERVICE_INTERFACE macro"); + return GetServiceReference(std::string(clazz)); + } + + /** + * Returns the service object referenced by the specified + * ServiceReference 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 ServiceReference&)} 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 + * ServiceReference is invalid (default constructed). + * @see #UngetService(const ServiceReference&) + * @see ServiceFactory + */ + itk::LightObject* GetService(const ServiceReference& reference); + + /** + * Returns the service object referenced by the specified + * ServiceReference object. + *

+ * This is a convenience method which is identical to itk::LightObject* GetService(const ServiceReference&) + * 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 ServiceReference&) + * @see #UngetService(const ServiceReference&) + * @see ServiceFactory + */ + template + S* GetService(const ServiceReference& reference) + { + return dynamic_cast(GetService(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 ServiceReference& reference); + + /** + * 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 + * {@link 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 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()) + { + MessageDelegate1 delegate(receiver, callback); + AddServiceListener(delegate, 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 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&)) + { + MessageDelegate1 delegate(receiver, callback); + RemoveServiceListener(delegate); + } + + /** + * 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 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&)) + { + MessageDelegate1 delegate(receiver, callback); + AddModuleListener(delegate); + } + + /** + * 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 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&)) + { + MessageDelegate1 delegate(receiver, callback); + RemoveModuleListener(delegate); + } + + +private: + + friend class Module; + friend class ModulePrivate; + + ModuleContext(ModulePrivate* module); + + void AddServiceListener(const ServiceListenerDelegate& delegate, + const std::string& filter); + void RemoveServiceListener(const ServiceListenerDelegate& delegate); + + void AddModuleListener(const ModuleListenerDelegate& delegate); + void RemoveModuleListener(const ModuleListenerDelegate& delegate); + + ModuleContextPrivate * const d; +}; + +} + +#ifdef MITK_HAS_UNORDERED_MAP_H +namespace std { +#elif defined(__GNUC__) +namespace __gnu_cxx { +#else +namespace itk { +#endif + +template<> struct hash +{ + std::size_t operator()(const mitk::ModuleContext* context) const + { +#ifdef MITK_HAS_HASH_SIZE_T + return hash()(reinterpret_cast(context)); +#else + std::size_t key = reinterpret_cast(context); + return std::size_t(key & (~0U)); +#endif + } +}; + +} + +#endif /* MITKMODULECONTEXT_H_ */ diff --git a/Core/Code/Service/mitkModuleEvent.cpp b/Core/Code/Service/mitkModuleEvent.cpp new file mode 100644 index 0000000000..3a85833eda --- /dev/null +++ b/Core/Code/Service/mitkModuleEvent.cpp @@ -0,0 +1,110 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkModuleEvent.h" + +#include "mitkModule.h" + +namespace mitk { + +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; +}; + +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; +} + +} + +std::ostream& operator<<(std::ostream& os, mitk::ModuleEvent::Type eventType) +{ + switch (eventType) + { + case mitk::ModuleEvent::LOADED: return os << "LOADED"; + case mitk::ModuleEvent::UNLOADED: return os << "UNLOADED"; + case mitk::ModuleEvent::LOADING: return os << "LOADING"; + case mitk::ModuleEvent::UNLOADING: return os << "UNLOADING"; + + default: return os << "Unknown module event type (" << static_cast(eventType) << ")"; + } +} + +std::ostream& operator<<(std::ostream& os, const mitk::ModuleEvent& event) +{ + if (event.IsNull()) return os << "NONE"; + + mitk::Module* m = event.GetModule(); + os << event.GetType() << " #" << m->GetModuleId() << " (" << m->GetLocation() << ")"; + return os; +} diff --git a/Core/Code/Service/mitkModuleEvent.h b/Core/Code/Service/mitkModuleEvent.h new file mode 100644 index 0000000000..9da048ce1b --- /dev/null +++ b/Core/Code/Service/mitkModuleEvent.h @@ -0,0 +1,147 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKMODULEEVENT_H +#define MITKMODULEEVENT_H + +#include "mitkSharedData.h" + +namespace mitk { + +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#connectModuleListener + */ +class MITK_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; + +}; + +} + +/** + * \ingroup MicroServices + * @{ + */ +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, mitk::ModuleEvent::Type eventType); +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::ModuleEvent& event); +/** @}*/ + +#endif // MITKMODULEEVENT_H diff --git a/Core/Code/Service/mitkModuleInfo.cpp b/Core/Code/Service/mitkModuleInfo.cpp new file mode 100644 index 0000000000..cec6f79e8c --- /dev/null +++ b/Core/Code/Service/mitkModuleInfo.cpp @@ -0,0 +1,30 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkModuleInfo.h" + +namespace mitk { + +ModuleInfo::ModuleInfo(const std::string& name, const std::string& libName, const std::string& moduleDeps, + const std::string& packageDeps, const std::string& version, bool qtModule) + : name(name), libName(libName), moduleDeps(moduleDeps), packageDeps(packageDeps), + version(version), qtModule(qtModule), id(0), + activatorHook(0) +{} + +} diff --git a/Core/Code/Service/mitkModuleInfo.h b/Core/Code/Service/mitkModuleInfo.h new file mode 100644 index 0000000000..0fccc21a7a --- /dev/null +++ b/Core/Code/Service/mitkModuleInfo.h @@ -0,0 +1,58 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKMODULEINFO_H +#define MITKMODULEINFO_H + +#include + +#include + +namespace mitk { + +struct ModuleActivator; + +/** + * This class is not intended to be used directly. It is exported to support + * the MITK module system. + */ +struct MITK_CORE_EXPORT ModuleInfo +{ + ModuleInfo(const std::string& name, const std::string& libName, const std::string& moduleDeps, + const std::string& packageDeps, const std::string& version, bool qtModule); + + typedef ModuleActivator*(*ModuleActivatorHook)(void); + + std::string name; + std::string libName; + std::string moduleDeps; + std::string packageDeps; + std::string version; + + std::string location; + + bool qtModule; + + long id; + + ModuleActivatorHook activatorHook; +}; + +} + +#endif // MITKMODULEINFO_H diff --git a/Core/Code/Service/mitkModulePrivate.cpp b/Core/Code/Service/mitkModulePrivate.cpp new file mode 100644 index 0000000000..edc5ccbd7b --- /dev/null +++ b/Core/Code/Service/mitkModulePrivate.cpp @@ -0,0 +1,143 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkModulePrivate.h" + +#include "mitkModule.h" +#include "mitkCoreModuleContext_p.h" +#include "mitkServiceRegistration.h" +#include "mitkServiceReferencePrivate.h" + +namespace mitk { + +AtomicInt ModulePrivate::idCounter; + +ModulePrivate::ModulePrivate(Module* qq, CoreModuleContext* coreCtx, + ModuleInfo* info) + : coreCtx(coreCtx), info(*info), moduleContext(0), moduleActivator(0), q(qq) +{ + + std::stringstream propId; + propId << this->info.id; + properties[Module::PROP_ID()] = propId.str(); + + std::stringstream propModuleDepends; + std::stringstream propLibDepends; + std::stringstream propPackageDepends; + + int counter = 0; + int counter2 = 0; + std::stringstream ss(this->info.moduleDeps); + while (ss) + { + std::string moduleDep; + ss >> moduleDep; + if (!moduleDep.empty()) + { + Module* dep = ModuleRegistry::GetModule(moduleDep); + if (dep) + { + requiresIds.push_back(dep->GetModuleId()); + if (counter > 0) propModuleDepends << ", "; + propModuleDepends << moduleDep; + ++counter; + } + else + { + requiresLibs.push_back(moduleDep); + if (counter2 > 0) propLibDepends << ", "; + propLibDepends << moduleDep; + ++counter2; + } + } + } + + properties[Module::PROP_MODULE_DEPENDS()] = propModuleDepends.str(); + properties[Module::PROP_LIB_DEPENDS()] = propLibDepends.str(); + + counter = 0; + ss.clear(); + ss.str(this->info.packageDeps); + while (ss) + { + std::string packageDep; + ss >> packageDep; + if (!packageDep.empty()) + { + requiresPackages.push_back(packageDep); + if (counter > 0) propPackageDepends << ", "; + propPackageDepends << packageDep; + ++counter; + } + } + + properties[Module::PROP_PACKAGE_DEPENDS()] = propPackageDepends.str(); + + if (!this->info.version.empty()) + { + try + { + version = mitk::ModuleVersion(this->info.version); + properties[Module::PROP_VERSION()] = this->info.version; + } + catch (const std::exception& e) + { + throw std::invalid_argument(std::string("MITK module does not specify a valid version identifier. Got exception: ") + e.what()); + } + } + + properties[Module::PROP_LOCATION()] = this->info.location; + properties[Module::PROP_NAME()] = this->info.name; + properties[Module::PROP_QT()] = this->info.qtModule ? "true" : "false"; +} + +ModulePrivate::~ModulePrivate() +{ +} + +void ModulePrivate::RemoveModuleResources() +{ + coreCtx->listeners.RemoveAllListeners(moduleContext); + + std::list srs; + coreCtx->services.GetRegisteredByModule(this, srs); + for (std::list::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::list::const_iterator i = srs.begin(); + i != srs.end(); ++i) + { + i->GetReference().d->UngetService(q, false); + } +} + +} + diff --git a/Core/Code/Service/mitkModulePrivate.h b/Core/Code/Service/mitkModulePrivate.h new file mode 100644 index 0000000000..5dc6fc35fe --- /dev/null +++ b/Core/Code/Service/mitkModulePrivate.h @@ -0,0 +1,82 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKMODULEPRIVATE_H +#define MITKMODULEPRIVATE_H + +#include "mitkModuleRegistry.h" +#include "mitkModuleVersion.h" +#include "mitkModuleInfo.h" + +#include "mitkAtomicInt.h" + +namespace mitk { + +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(); + + CoreModuleContext* const coreCtx; + + std::vector requiresIds; + + std::vector requiresLibs; + std::vector requiresPackages; + + /** + * Module version + */ + ModuleVersion version; + + ModuleInfo info; + + /** + * ModuleContext for the module + */ + ModuleContext* moduleContext; + + ModuleActivator* moduleActivator; + + std::map properties; + + Module* const q; + +private: + + static AtomicInt idCounter; + +}; + +} + +#endif // MITKMODULEPRIVATE_H diff --git a/Core/Code/Service/mitkModuleRegistry.cpp b/Core/Code/Service/mitkModuleRegistry.cpp new file mode 100644 index 0000000000..6d00646ed2 --- /dev/null +++ b/Core/Code/Service/mitkModuleRegistry.cpp @@ -0,0 +1,179 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkModuleRegistry.h" + +#include "mitkModule.h" +#include "mitkModuleInfo.h" +#include "mitkModuleContext.h" +#include "mitkCoreModuleContext_p.h" +#include "mitkStaticInit.h" + +#include +#include + +namespace mitk { + +#ifdef MITK_HAS_UNORDERED_MAP_H +typedef std::unordered_map ModuleMap; +#else +typedef itk::hash_map ModuleMap; +#endif + +MITK_GLOBAL_STATIC(CoreModuleContext, coreModuleContext) + +/** + * Table of all installed modules in this framework. + * Key is the module location. + */ +MITK_GLOBAL_STATIC(ModuleMap, modules) + + +typedef itk::SimpleFastMutexLock MutexType; +typedef itk::MutexLockHolder MutexLocker; + +/** + * Lock for protecting the modules object + */ +MITK_GLOBAL_STATIC(MutexType, modulesLock) + +/** + * Lock for protecting the register count + */ +MITK_GLOBAL_STATIC(MutexType, countLock) + + +void ModuleRegistry::Register(ModuleInfo* info) +{ + static long regCount = 0; + if (info->id > 0) + { + // The module was already registered + MutexLocker lock(*modulesLock()); + Module* module = modules()->operator[](info->id); + module->Start(); + } + else + { + Module* module = 0; + // check if the module is reloaded + { + MutexLocker lock(*modulesLock()); + ModuleMap* map = modules(); + for (ModuleMap::const_iterator i = map->begin(); + i != map->end(); ++i) + { + if (i->second->GetLocation() == info->location) + { + module = i->second; + info->id = module->GetModuleId(); + } + } + } + + if (!module) + { + module = new Module(); + countLock()->Lock(); + info->id = ++regCount; + countLock()->Unlock(); + + module->Init(coreModuleContext(), info); + + MutexLocker lock(*modulesLock()); + ModuleMap* map = modules(); + map->insert(std::make_pair(info->id, module)); + } + else + { + module->Init(coreModuleContext(), info); + } + + module->Start(); + } +} + +void ModuleRegistry::UnRegister(const ModuleInfo* info) +{ + // If we are unregistering the mitkCore module, there is + // nothing to do. + if (info->id == 1) return; + + MutexLocker lock(*modulesLock()); + Module* curr = modules()->operator[](info->id); + curr->Stop(); + delete curr->GetModuleContext(); +} + +Module* ModuleRegistry::GetModule(long id) +{ + MutexLocker lock(*modulesLock()); + + ModuleMap::const_iterator iter = modules()->find(id); + if (iter != modules()->end()) + { + return iter->second; + } + return 0; +} + +Module* ModuleRegistry::GetModule(const std::string& name) +{ + MutexLocker lock(*modulesLock()); + + ModuleMap::const_iterator iter = modules()->begin(); + ModuleMap::const_iterator iterEnd = modules()->end(); + for (; iter != iterEnd; ++iter) + { + if (iter->second->GetName() == name) + { + return iter->second; + } + } + + return 0; +} + +void ModuleRegistry::GetModules(std::vector& m) +{ + MutexLocker lock(*modulesLock()); + + ModuleMap* map = modules(); + ModuleMap::const_iterator iter = map->begin(); + ModuleMap::const_iterator iterEnd = map->end(); + for (; iter != iterEnd; ++iter) + { + m.push_back(iter->second); + } +} + +void ModuleRegistry::GetLoadedModules(std::vector& m) +{ + MutexLocker lock(*modulesLock()); + + ModuleMap::const_iterator iter = modules()->begin(); + ModuleMap::const_iterator iterEnd = modules()->end(); + for (; iter != iterEnd; ++iter) + { + if (iter->second->IsLoaded()) + { + m.push_back(iter->second); + } + } +} + +} diff --git a/Core/Code/Service/mitkModuleRegistry.h b/Core/Code/Service/mitkModuleRegistry.h new file mode 100644 index 0000000000..0159036bb5 --- /dev/null +++ b/Core/Code/Service/mitkModuleRegistry.h @@ -0,0 +1,87 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKMODULEREGISTRY_H +#define MITKMODULEREGISTRY_H + +#include +#include + +#include + +namespace mitk { + +class Module; +class ModuleInfo; + +/** + * \ingroup MicroServices + * + * Here we handle all the modules that are loaded in the framework. + */ +class MITK_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 Module list with modules. + */ + static void GetModules(std::vector& modules); + + /** + * Get all modules currently in module state LOADED. + * + * @return A List of Modules. + */ + static void GetLoadedModules(std::vector& modules); + +private: + + friend class ModuleInitializer; + + // disabled + ModuleRegistry(); + + static void Register(ModuleInfo* info); + + static void UnRegister(const ModuleInfo* info); + +}; + +} + + +#endif // MITKMODULEREGISTRY_H diff --git a/Core/Code/Service/mitkModuleUtils.cpp b/Core/Code/Service/mitkModuleUtils.cpp new file mode 100644 index 0000000000..4cd893e881 --- /dev/null +++ b/Core/Code/Service/mitkModuleUtils.cpp @@ -0,0 +1,154 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkModuleUtils.h" + +namespace mitk { + +#ifdef __GNUC__ + +#define _GNU_SOURCE +#include + +std::string GetLibraryPath_impl(const std::string& /*libName*/, const void* symbol) +{ + Dl_info info; + if (dladdr(symbol, &info)) + { + return info.dli_fname; + } + return ""; +} + +void* GetSymbol_impl(const std::string& libName, const char* symbol) +{ + void* selfHandle = dlopen(libName.c_str(), RTLD_LAZY); + if (selfHandle) + { + void* addr = dlsym(selfHandle, symbol); + dlclose(selfHandle); + return addr; + } + return 0; +} + +#elif _WIN32 + +#include + +void PrintLastError_impl(const std::string& context) +{ + // Retrieve the system error message for the last-error code + LPVOID lpMsgBuf; + LPVOID lpDisplayBuf; + 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 ); + + // Display the error message and exit the process + + lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, + (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)context.c_str()) + 50) * sizeof(TCHAR)); + StringCchPrintf((LPTSTR)lpDisplayBuf, + LocalSize(lpDisplayBuf) / sizeof(TCHAR), + TEXT("Error in context %s (%d): %s"), + context.c_str(), dw, lpMsgBuf); + + std::string errMsg((LPCTSTR)lpDisplayBuf); + + LocalFree(lpMsgBuf); + LocalFree(lpDisplayBuf); + + MITK_DEBUG(true) << errMsg; +} + +std::string GetLibraryPath_impl(const std::string& libName, const void *symbol) +{ + HMODULE handle = 0; + if (libName.empty()) + { + // get the handle for the executable + handle = GetModuleHandle(0); + } + else + { + handle = GetModuleHandle(libName.c_str()); + } + if (!handle) + { + PrintLastError_impl("GetLibraryPath_impl():GetModuleHandle()"); + return ""; + } + + char modulePath[512]; + if (GetModuleFileName(handle, modulePath, 512)) + { + return modulePath; + } + + PrintLastError_impl("GetLibraryPath_impl():GetModuleFileName()"); + return ""; +} + +void* GetSymbol_impl(const std::string& libName, const char* symbol) +{ + HMODULE handle = GetModuleHandle(libName.c_str()); + if (!handle) + { + PrintLastError_impl("GetSymbol_impl():GetModuleHandle()"); + return 0; + } + + void* addr = (void*)GetProcAddress(handle, symbol); + if (!addr) + { + PrintLastError_impl(std::string("GetSymbol_impl():GetProcAddress(handle,") + std::string(symbol) + ")"); + } + return addr; +} +#else +std::string GetLibraryPath_impl(const std::string& libName, const void* symbol) +{ + return ""; +} + +void* GetSymbol_impl(const std::string& libName, const char* symbol) +{ + return 0; +} +#endif + +std::string ModuleUtils::GetLibraryPath(const std::string& libName, const void* symbol) +{ + return GetLibraryPath_impl(libName, symbol); +} + +void* ModuleUtils::GetSymbol(const std::string& libName, const char* symbol) +{ + return GetSymbol_impl(libName, symbol); +} + +} diff --git a/Core/Code/Service/mitkModuleUtils.h b/Core/Code/Service/mitkModuleUtils.h new file mode 100644 index 0000000000..9e54679790 --- /dev/null +++ b/Core/Code/Service/mitkModuleUtils.h @@ -0,0 +1,41 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKMODULEUTILS_H +#define MITKMODULEUTILS_H + +#include + +#include + +namespace mitk { + +/** + * This class is not intended to be used directly. It is exported to support + * the MITK module system. + */ +struct MITK_CORE_EXPORT ModuleUtils +{ + static std::string GetLibraryPath(const std::string& libName, const void* symbol); + + static void* GetSymbol(const std::string& libName, const char* symbol); +}; + +} + +#endif // MITKMODULEUTILS_H diff --git a/Core/Code/Service/mitkModuleVersion.cpp b/Core/Code/Service/mitkModuleVersion.cpp new file mode 100644 index 0000000000..4bf6a2fe00 --- /dev/null +++ b/Core/Code/Service/mitkModuleVersion.cpp @@ -0,0 +1,270 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkModuleVersion.h" + +#include +#include +#include +#include +#include + +namespace mitk { + +const char ModuleVersion::SEPARATOR = '.'; + +bool IsInvalidQualifier(char c) +{ + return !(std::isalnum(c) || c == '_' || c == '-'); +} + +ModuleVersion ModuleVersion::EmptyVersion() +{ + static ModuleVersion emptyV(false); + return emptyV; +} + +ModuleVersion ModuleVersion::UndefinedVersion() +{ + static ModuleVersion undefinedV(true); + return undefinedV; +} + +ModuleVersion& ModuleVersion::operator=(const ModuleVersion& v) +{ + majorVersion = v.majorVersion; + minorVersion = v.minorVersion; + microVersion = v.microVersion; + qualifier = v.qualifier; + undefined = v.undefined; + return *this; +} + +ModuleVersion::ModuleVersion(bool undefined) + : majorVersion(0), minorVersion(0), microVersion(0), qualifier(""), undefined(undefined) +{ + +} + +void ModuleVersion::Validate() +{ + if (std::find_if(qualifier.begin(), qualifier.end(), IsInvalidQualifier) != qualifier.end()) + throw std::invalid_argument(std::string("invalid qualifier: ") + qualifier); + + undefined = false; +} + +ModuleVersion::ModuleVersion(unsigned int majorVersion, unsigned int minorVersion, unsigned int microVersion) + : majorVersion(majorVersion), minorVersion(minorVersion), microVersion(microVersion), qualifier(""), + undefined(false) +{ + +} + +ModuleVersion::ModuleVersion(unsigned int majorVersion, unsigned int minorVersion, unsigned int microVersion, const std::string& qualifier) + : majorVersion(majorVersion), minorVersion(minorVersion), microVersion(microVersion), qualifier(qualifier), + undefined(true) +{ + this->Validate(); +} + +ModuleVersion::ModuleVersion(const std::string& version) + : majorVersion(0), minorVersion(0), microVersion(0), undefined(true) +{ + unsigned int maj = 0; + unsigned int min = 0; + unsigned int mic = 0; + std::string qual(""); + + std::vector st; + std::stringstream ss(version); + std::string token; + while(std::getline(ss, token, SEPARATOR)) + { + st.push_back(token); + } + + if (st.empty()) return; + + bool ok = true; + ss.clear(); + ss.str(st[0]); + ss >> maj; + ok = !ss.fail(); + + if (st.size() > 1) + { + ss.clear(); + ss.str(st[1]); + ss >> min; + ok = !ss.fail(); + if (st.size() > 2) + { + ss.clear(); + ss.str(st[2]); + ss >> mic; + ok = !ss.fail(); + if (st.size() > 3) + { + qual = st[3]; + if (st.size() > 4) + { + ok = false; + } + } + } + } + + if (!ok) throw std::invalid_argument("invalid format"); + + majorVersion = maj; + minorVersion = min; + microVersion = mic; + qualifier = qual; + this->Validate(); +} + +ModuleVersion::ModuleVersion(const ModuleVersion& version) +: majorVersion(version.majorVersion), minorVersion(version.minorVersion), + microVersion(version.microVersion), qualifier(version.qualifier), + undefined(version.undefined) +{ + +} + +ModuleVersion ModuleVersion::ParseVersion(const std::string& version) +{ + if (version.empty()) + { + return EmptyVersion(); + } + + std::string version2(version); + version2.erase(0, version2.find_first_not_of(' ')); + version2.erase(version2.find_last_not_of(' ')+1); + if (version2.empty()) + { + return EmptyVersion(); + } + + return ModuleVersion(version2); +} + +bool ModuleVersion::IsUndefined() const +{ + return undefined; +} + +unsigned int ModuleVersion::GetMajor() const +{ + if (undefined) throw std::logic_error("Version undefined"); + return majorVersion; +} + +unsigned int ModuleVersion::GetMinor() const +{ + if (undefined) throw std::logic_error("Version undefined"); + return minorVersion; +} + +unsigned int ModuleVersion::GetMicro() const +{ + if (undefined) throw std::logic_error("Version undefined"); + return microVersion; +} + +std::string ModuleVersion::GetQualifier() const +{ + if (undefined) throw std::logic_error("Version undefined"); + return qualifier; +} + +std::string ModuleVersion::ToString() const +{ + if (undefined) return "undefined"; + + std::string result; + std::stringstream ss(result); + ss << majorVersion << SEPARATOR << minorVersion << SEPARATOR << microVersion; + if (!qualifier.empty()) + { + ss << SEPARATOR << qualifier; + } + return result; +} + +bool ModuleVersion::operator==(const ModuleVersion& other) const +{ + if (&other == this) + { // quicktest + return true; + } + + if (other.undefined && this->undefined) return true; + if (this->undefined) throw std::logic_error("Version undefined"); + if (other.undefined) return false; + + return (majorVersion == other.majorVersion) && (minorVersion == other.minorVersion) && (microVersion + == other.microVersion) && qualifier == other.qualifier; +} + +int ModuleVersion::Compare(const ModuleVersion& other) const +{ + if (&other == this) + { // quicktest + return 0; + } + + if (this->undefined || other.undefined) + throw std::logic_error("Cannot compare undefined version"); + + if (majorVersion < other.majorVersion) + { + return -1; + } + + if (majorVersion == other.majorVersion) + { + + if (minorVersion < other.minorVersion) + { + return -1; + } + + if (minorVersion == other.minorVersion) + { + + if (microVersion < other.microVersion) + { + return -1; + } + + if (microVersion == other.microVersion) + { + return qualifier.compare(other.qualifier); + } + } + } + return 1; +} + +} + +std::ostream& operator<<(std::ostream& os, const mitk::ModuleVersion& v) +{ + return os << v.ToString(); +} diff --git a/Core/Code/Service/mitkModuleVersion.h b/Core/Code/Service/mitkModuleVersion.h new file mode 100644 index 0000000000..9594597cb4 --- /dev/null +++ b/Core/Code/Service/mitkModuleVersion.h @@ -0,0 +1,250 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKMODULEVERSION_H +#define MITKMODULEVERSION_H + +#include + +#include + +namespace mitk { + +/** + * \ingroup MicroServices + * + * Version identifier for MITK modules. + * + *

+ * Version identifiers have four components. + *

    + *
  1. Major version. A non-negative integer.
  2. + *
  3. Minor version. A non-negative integer.
  4. + *
  5. Micro version. A non-negative integer.
  6. + *
  7. Qualifier. A text string. See ModuleVersion(const std::string&) for the + * format of the qualifier string.
  8. + *
+ * + *

+ * ModuleVersion objects are immutable. + */ +class MITK_CORE_EXPORT ModuleVersion { + +private: + + friend class ModulePrivate; + + unsigned int majorVersion; + unsigned int minorVersion; + unsigned int microVersion; + std::string qualifier; + + static const char SEPARATOR; // = "." + + bool undefined; + + + /** + * Called by the ModuleVersion constructors to validate the version components. + * + * @return true if the validation was successfull, false otherwise. + */ + void Validate(); + + ModuleVersion& operator=(const ModuleVersion& v); + + explicit ModuleVersion(bool undefined = false); + +public: + + /** + * The empty version "0.0.0". + */ + static ModuleVersion EmptyVersion(); + + /** + * Creates an undefined version identifier, representing either + * infinity or minus infinity. + */ + static ModuleVersion UndefinedVersion(); + + /** + * Creates a version identifier from the specified numerical components. + * + *

+ * The qualifier is set to the empty string. + * + * @param majorVersion Major component of the version identifier. + * @param minorVersion Minor component of the version identifier. + * @param microVersion Micro component of the version identifier. + * + */ + ModuleVersion(unsigned int majorVersion, unsigned int minorVersion, unsigned int microVersion); + + /** + * Creates a version identifier from the specified components. + * + * @param majorVersion Major component of the version identifier. + * @param minorVersion Minor component of the version identifier. + * @param microVersion Micro component of the version identifier. + * @param qualifier Qualifier component of the version identifier. + */ + ModuleVersion(unsigned int majorVersion, unsigned int minorVersion, unsigned int microVersion, const std::string& qualifier); + + /** + * Created a version identifier from the specified string. + * + *

+ * Here is the grammar for version strings. + * + *

+   * version ::= majorVersion('.'minorVersion('.'microVersion('.'qualifier)?)?)?
+   * majorVersion ::= digit+
+   * minorVersion ::= digit+
+   * microVersion ::= digit+
+   * qualifier ::= (alpha|digit|'_'|'-')+
+   * digit ::= [0..9]
+   * alpha ::= [a..zA..Z]
+   * 
+ * + * There must be no whitespace in version. + * + * @param version string representation of the version identifier. + */ + ModuleVersion(const std::string& version); + + /** + * Create a version identifier from another. + * + * @param version Another version identifier + */ + ModuleVersion(const ModuleVersion& version); + + + /** + * Parses a version identifier from the specified string. + * + *

+ * See ModuleVersion(const std::string&) for the format of the version string. + * + * @param version string representation of the version identifier. Leading + * and trailing whitespace will be ignored. + * @return A ModuleVersion object representing the version + * identifier. If version is the empty string + * then EmptyVersion will be + * returned. + */ + static ModuleVersion ParseVersion(const std::string& version); + + /** + * Returns the undefined state of this version identifier. + * + * @return true if this version identifier is undefined, + * false otherwise. + */ + bool IsUndefined() const; + + /** + * Returns the majorVersion component of this version identifier. + * + * @return The majorVersion component. + */ + unsigned int GetMajor() const; + + /** + * Returns the minorVersion component of this version identifier. + * + * @return The minorVersion component. + */ + unsigned int GetMinor() const; + + /** + * Returns the microVersion component of this version identifier. + * + * @return The microVersion component. + */ + unsigned int GetMicro() const; + + /** + * Returns the qualifier component of this version identifier. + * + * @return The qualifier component. + */ + std::string GetQualifier() const; + + /** + * Returns the string representation of this version identifier. + * + *

+ * The format of the version string will be majorVersion.minorVersion.microVersion + * if qualifier is the empty string or + * majorVersion.minorVersion.microVersion.qualifier otherwise. + * + * @return The string representation of this version identifier. + */ + std::string ToString() const; + + /** + * Compares this ModuleVersion object to another object. + * + *

+ * A version is considered to be equal to another version if the + * majorVersion, minorVersion and microVersion components are equal and the qualifier component + * is equal. + * + * @param object The ModuleVersion object to be compared. + * @return true if object is a + * ModuleVersion and is equal to this object; + * false otherwise. + */ + bool operator==(const ModuleVersion& object) const; + + /** + * Compares this ModuleVersion object to another object. + * + *

+ * A version is considered to be less than another version if its + * majorVersion component is less than the other version's majorVersion component, or the + * majorVersion components are equal and its minorVersion component is less than the other + * version's minorVersion component, or the majorVersion and minorVersion components are equal + * and its microVersion component is less than the other version's microVersion component, + * or the majorVersion, minorVersion and microVersion components are equal and it's qualifier + * component is less than the other version's qualifier component (using + * std::string::operator<()). + * + *

+ * A version is considered to be equal to another version if the + * majorVersion, minorVersion and microVersion components are equal and the qualifier component + * is equal. + * + * @param object The ModuleVersion object to be compared. + * @return A negative integer, zero, or a positive integer if this object is + * less than, equal to, or greater than the specified + * ModuleVersion object. + */ + int Compare(const ModuleVersion& object) const; + +}; + +} + +/** + * \ingroup MicroServices + */ +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::ModuleVersion& v); + +#endif // MITKMODULEVERSION_H diff --git a/Core/Code/Service/mitkServiceEvent.cpp b/Core/Code/Service/mitkServiceEvent.cpp new file mode 100644 index 0000000000..62dd2269c8 --- /dev/null +++ b/Core/Code/Service/mitkServiceEvent.cpp @@ -0,0 +1,121 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkServiceEvent.h" + +#include "mitkServiceProperties.h" + +namespace mitk { + +class ServiceEventData : public SharedData +{ +public: + + ServiceEventData(const ServiceEvent::Type& type, const ServiceReference& reference) + : type(type), reference(reference) + { + + } + + ServiceEventData(const ServiceEventData& other) + : SharedData(other), type(other.type), reference(other.reference) + { + + } + + const ServiceEvent::Type type; + const ServiceReference reference; +}; + +ServiceEvent::ServiceEvent() + : d(0) +{ + +} + +ServiceEvent::~ServiceEvent() +{ + +} + +bool ServiceEvent::IsNull() const +{ + return !d; +} + +ServiceEvent::ServiceEvent(Type type, const ServiceReference& 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; +} + +ServiceReference ServiceEvent::GetServiceReference() const +{ + return d->reference; +} + +ServiceEvent::Type ServiceEvent::GetType() const +{ + return d->type; +} + +} + +std::ostream& operator<<(std::ostream& os, const mitk::ServiceEvent::Type& type) +{ + switch(type) + { + case mitk::ServiceEvent::MODIFIED: return os << "MODIFIED"; + case mitk::ServiceEvent::MODIFIED_ENDMATCH: return os << "MODIFIED_ENDMATCH"; + case mitk::ServiceEvent::REGISTERED: return os << "REGISTERED"; + case mitk::ServiceEvent::UNREGISTERING: return os << "UNREGISTERING"; + + default: return os << "unknown service event type (" << static_cast(type) << ")"; + } +} + +std::ostream& operator<<(std::ostream& os, const mitk::ServiceEvent& event) +{ + if (event.IsNull()) return os << "NONE"; + + os << event.GetType(); + + mitk::ServiceReference sr = event.GetServiceReference(); + if (sr) + { + // Some events will not have a service reference + long int sid = mitk::any_cast(sr.GetProperty(mitk::ServiceConstants::SERVICE_ID())); + os << " " << sid; + + mitk::Any classes = sr.GetProperty(mitk::ServiceConstants::OBJECTCLASS()); + os << " objectClass=" << classes << ")"; + } + + return os; +} diff --git a/Core/Code/Service/mitkServiceEvent.h b/Core/Code/Service/mitkServiceEvent.h new file mode 100644 index 0000000000..620c79cef1 --- /dev/null +++ b/Core/Code/Service/mitkServiceEvent.h @@ -0,0 +1,166 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKSERVICEEVENT_H +#define MITKSERVICEEVENT_H + +#include "mitkSharedData.h" + +#include "mitkServiceReference.h" + +namespace mitk { + +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 MITK_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 ServiceReference& 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. + */ + ServiceReference GetServiceReference() const; + + /** + * 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; + +}; + +} + +/** + * \ingroup MicroServices + * @{ + */ +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::ServiceEvent::Type& type); +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::ServiceEvent& event); +/** @}*/ + +#endif // MITKSERVICEEVENT_H diff --git a/Core/Code/Service/mitkServiceException.cpp b/Core/Code/Service/mitkServiceException.cpp new file mode 100644 index 0000000000..7d2b86f75c --- /dev/null +++ b/Core/Code/Service/mitkServiceException.cpp @@ -0,0 +1,54 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkServiceException.h" + +#include + +namespace mitk +{ + +ServiceException::ServiceException(const std::string& msg, const Type& type) + : std::runtime_error(msg), type(type) +{ + +} + +ServiceException::ServiceException(const ServiceException& o) + : std::runtime_error(o), type(o.type) +{ + +} + +ServiceException& ServiceException::operator=(const ServiceException& o) +{ + std::runtime_error::operator=(o); + this->type = o.type; + return *this; +} + +ServiceException::Type ServiceException::GetType() const +{ + return type; +} + +} + +std::ostream& operator<<(std::ostream& os, const mitk::ServiceException& exc) +{ + return os << "mitk::ServiceException: " << exc.what(); +} diff --git a/Core/Code/Service/mitkServiceException.h b/Core/Code/Service/mitkServiceException.h new file mode 100644 index 0000000000..2afb2090d3 --- /dev/null +++ b/Core/Code/Service/mitkServiceException.h @@ -0,0 +1,114 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICEEXCEPTION_H +#define MITKSERVICEEXCEPTION_H + +#include + +#include + +namespace mitk { + +/** + * \ingroup MicroServices + * + * A service exception used to indicate that a service problem occurred. + * + *

+ * A ServiceException object is created by the framework or + * to denote an exception condition in the service. An enum + * type is used to identify the exception type for future extendability. + * + *

+ * This exception conforms to the general purpose exception chaining mechanism. + */ +class MITK_CORE_EXPORT ServiceException : public std::runtime_error +{ +public: + + enum Type { + /** + * No exception type is unspecified. + */ + UNSPECIFIED = 0, + /** + * The service has been unregistered. + */ + UNREGISTERED = 1, + /** + * The service factory produced an invalid service object. + */ + FACTORY_ERROR = 2, + /** + * The service factory threw an exception. + */ + FACTORY_EXCEPTION = 3, + /** + * An error occurred invoking a remote service. + */ + REMOTE = 5, + /** + * The service factory resulted in a recursive call to itself for the + * requesting module. + */ + FACTORY_RECURSION = 6 + }; + + /** + * Creates a ServiceException with the specified message, + * type and exception cause. + * + * @param msg The associated message. + * @param type The type for this exception. + * @param cause The cause of this exception. + */ + ServiceException(const std::string& msg, const Type& type = UNSPECIFIED); + + ServiceException(const ServiceException& o); + ServiceException& operator=(const ServiceException& o); + + ~ServiceException() throw() { } + + /** + * Returns the type for this exception or UNSPECIFIED if the + * type was unspecified or unknown. + * + * @return The type of this exception. + */ + Type GetType() const; + +private: + + /** + * Type of service exception. + */ + Type type; + +}; + +} + +/** + * \ingroup MicroServices + * @{ + */ +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::ServiceException& exc); +/** @}*/ + +#endif // MITKSERVICEEXCEPTION_H diff --git a/Core/Code/Service/mitkServiceFactory.h b/Core/Code/Service/mitkServiceFactory.h new file mode 100644 index 0000000000..afb0a895cb --- /dev/null +++ b/Core/Code/Service/mitkServiceFactory.h @@ -0,0 +1,106 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkServiceRegistration.h" + +namespace mitk { + +/** + * \ingroup MicroServices + * + * Allows services to provide customized service objects in the module + * environment. + * + *

+ * When registering a service, a ServiceFactory object can be + * used instead of a service object, so that the module developer can gain + * control of the specific service object granted to a module that is using the + * service. + * + *

+ * When this happens, the + * ModuleContext::GetService(const ServiceReference&) method calls the + * ServiceFactory::GetService method to create a service object + * specifically for the requesting module. The service object returned by the + * ServiceFactory is cached by the framework until the module + * releases its use of the service. + * + *

+ * When the module's use count for the service equals zero (including the module + * unloading or the service being unregistered), the + * ServiceFactory::UngetService method is called. + * + *

+ * ServiceFactory objects are only used by the framework and are + * not made available to other modules in the module environment. The framework + * may concurrently call a ServiceFactory. + * + * @see ModuleContext#GetService + * @remarks This class is thread safe. + */ +class ServiceFactory +{ + +public: + + /** + * Creates a new service object. + * + *

+ * The Framework invokes this method the first time the specified + * module requests a service object using the + * ModuleContext::GetService(const ServiceReference&) method. The + * service factory can then return a specific service object for each + * module. + * + *

+ * The framework caches the value returned (unless it is 0), + * and will return the same service object on any future call to + * ModuleContext::GetService for the same modules. This means the + * framework must not allow this method to be concurrently called for the + * same module. + * + * @param module The module using the service. + * @param registration The ServiceRegistration object for the + * service. + * @return A service object that must be an instance of all + * the classes named when the service was registered. + * @see ModuleContext#GetService + */ + virtual itk::LightObject* GetService(Module* module, const ServiceRegistration& registration) = 0; + + /** + * Releases a service object. + * + *

+ * The framework invokes this method when a service has been released by a + * module. The service object may then be destroyed. + * + * @param module The Module releasing the service. + * @param registration The ServiceRegistration object for the + * service. + * @param service The service object returned by a previous call to the + * ServiceFactory::getService method. + * @see ModuleContext#UngetService + */ + virtual void UngetService(Module* module, const ServiceRegistration& registration, + itk::LightObject* service) = 0; +}; + +} + diff --git a/Core/Code/Service/mitkServiceInterface.h b/Core/Code/Service/mitkServiceInterface.h new file mode 100644 index 0000000000..725c61495e --- /dev/null +++ b/Core/Code/Service/mitkServiceInterface.h @@ -0,0 +1,50 @@ +/*============================================================================= + + Library: CTK + + 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 MITKSERVICEINTERFACE_H +#define MITKSERVICEINTERFACE_H + +template inline const char* mitk_service_interface_iid() +{ return 0; } + +#if defined(QT_DEBUG) || defined(QT_NODEBUG) +#include + +#define MITK_DECLARE_SERVICE_INTERFACE(IFace, IId) \ + template <> inline const char* qobject_interface_iid() \ + { return IId; } \ + template <> inline const char* mitk_service_interface_iid() \ + { return IId; } \ + template <> inline IFace *qobject_cast(QObject *object) \ + { return reinterpret_cast((object ? object->qt_metacast(IId) : 0)); } \ + template <> inline IFace *qobject_cast(const QObject *object) \ + { return reinterpret_cast((object ? const_cast(object)->qt_metacast(IId) : 0)); } + +#else + +#define MITK_DECLARE_SERVICE_INTERFACE(IFace, IId) \ + template <> inline const char* mitk_service_interface_iid() \ + { return IId; } \ + +#endif + +#endif // MITKSERVICEINTERFACE_H diff --git a/Core/Code/Service/mitkServiceListenerEntry.cpp b/Core/Code/Service/mitkServiceListenerEntry.cpp new file mode 100644 index 0000000000..0b3bc26c7c --- /dev/null +++ b/Core/Code/Service/mitkServiceListenerEntry.cpp @@ -0,0 +1,137 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkServiceListenerEntry_p.h" + +namespace mitk { + +class ServiceListenerEntryData : public SharedData +{ +public: + + ServiceListenerEntryData(Module* mc, const ServiceListenerDelegate& l, const std::string& filter) + : mc(mc), listener(l.Clone()), bRemoved(false), ldap() + { + if (!filter.empty()) + { + ldap = LDAPExpr(filter); + } + } + + ~ServiceListenerEntryData() + { + delete listener; + } + + Module* const mc; + const ServiceListenerDelegate* const listener; + bool bRemoved; + LDAPExpr ldap; + + /** + * The elements of "simple" filters are cached, for easy lookup. + * + * The grammar for simple filters is as follows: + * + *

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

+ * The index of the vector determines which key the cache is for + * (see {@link ServiceListenerState#hashedKeys}). For each key, there is + * a vector pointing out the values which are accepted by this + * ServiceListenerEntry's filter. This cache is maintained to make + * it easy to remove this service listener. + */ + LDAPExpr::LocalCache local_cache; +}; + +ServiceListenerEntry::ServiceListenerEntry(const ServiceListenerEntry& other) + : d(other.d) +{ + +} + +ServiceListenerEntry::~ServiceListenerEntry() +{ + +} + +ServiceListenerEntry& ServiceListenerEntry::operator=(const ServiceListenerEntry& other) +{ + d = other.d; + return *this; +} + +bool ServiceListenerEntry::operator==(const ServiceListenerEntry& other) const +{ + return ((d->mc == 0 || other.d->mc == 0) || d->mc == other.d->mc) && + (d->listener->operator ==(other.d->listener)); +} + +bool ServiceListenerEntry::operator<(const ServiceListenerEntry& other) const +{ + return d->mc < other.d->mc; +} + +void ServiceListenerEntry::SetRemoved(bool removed) const +{ + d->bRemoved = removed; +} + +bool ServiceListenerEntry::IsRemoved() const +{ + return d->bRemoved; +} + +ServiceListenerEntry::ServiceListenerEntry(Module* mc, const ServiceListenerDelegate& l, const std::string& filter) + : d(new ServiceListenerEntryData(mc, l, filter)) +{ + +} + +Module* ServiceListenerEntry::GetModule() const +{ + return d->mc; +} + +std::string ServiceListenerEntry::GetFilter() const +{ + return d->ldap.IsNull() ? std::string() : d->ldap.ToString(); +} + +LDAPExpr ServiceListenerEntry::GetLDAPExpr() const +{ + return d->ldap; +} + +LDAPExpr::LocalCache& ServiceListenerEntry::GetLocalCache() const +{ + return d->local_cache; +} + +void ServiceListenerEntry::CallDelegate(const ServiceEvent& event) const +{ + d->listener->Execute(event); +} + +} diff --git a/Core/Code/Service/mitkServiceListenerEntry_p.h b/Core/Code/Service/mitkServiceListenerEntry_p.h new file mode 100644 index 0000000000..0ac8790317 --- /dev/null +++ b/Core/Code/Service/mitkServiceListenerEntry_p.h @@ -0,0 +1,111 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICELISTENERENTRY_H +#define MITKSERVICELISTENERENTRY_H + +#include "mitkLDAPExpr_p.h" + +#include "mitkModuleContext.h" + +namespace mitk { + +class Module; +class ServiceListenerEntryData; + +/** + * Data structure for saving service listener info. Contains + * the optional service listener filter, in addition to the info + * in ListenerEntry. + */ +class ServiceListenerEntry +{ + +public: + + ServiceListenerEntry(const ServiceListenerEntry& other); + ~ServiceListenerEntry(); + ServiceListenerEntry& operator=(const ServiceListenerEntry& other); + + bool operator==(const ServiceListenerEntry& other) const; + + bool operator<(const ServiceListenerEntry& other) const; + + void SetRemoved(bool removed) const; + bool IsRemoved() const; + + ServiceListenerEntry(Module* mc, const ServiceListenerDelegate& l, const std::string& filter = ""); + + Module* GetModule() const; + + std::string GetFilter() const; + + LDAPExpr GetLDAPExpr() const; + + LDAPExpr::LocalCache& GetLocalCache() const; + + void CallDelegate(const ServiceEvent& event) const; + +private: + +#ifdef MITK_HAS_UNORDERED_MAP_H + friend class std::hash; +#elif defined(__GNUC__) + friend class __gnu_cxx::hash; +#else + friend struct itk::hash; +#endif + + ExplicitlySharedDataPointer d; +}; + +} + +#ifdef MITK_HAS_UNORDERED_MAP_H +namespace std { +#elif defined(__GNUC__) +namespace __gnu_cxx { +#else +namespace itk { +#endif + +template<> +class hash : public std::unary_function +{ +public: + size_t operator()(const mitk::ServiceListenerEntry& sle) const + { +#ifdef MITK_HAS_HASH_SIZE_T + return hash()(reinterpret_cast(sle.d.ConstData())); +#else + unsigned long long key = reinterpret_cast(sle.d.ConstData()); + if (sizeof(unsigned long long) > sizeof(std::size_t)) + { + return std::size_t(((key >> (8 * sizeof(std::size_t) - 1)) ^ key) & (~0U)); + } + else + { + return std::size_t(key & (~0U)); + } +#endif + } +}; + +} + +#endif // MITKSERVICELISTENERENTRY_H diff --git a/Core/Code/Service/mitkServiceListeners.cpp b/Core/Code/Service/mitkServiceListeners.cpp new file mode 100644 index 0000000000..0aa6c24523 --- /dev/null +++ b/Core/Code/Service/mitkServiceListeners.cpp @@ -0,0 +1,268 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkServiceListeners_p.h" +#include "mitkServiceReferencePrivate.h" + +#include "mitkModule.h" + +namespace mitk { + +const int ServiceListeners::OBJECTCLASS_IX = 0; +const int ServiceListeners::SERVICE_ID_IX = 1; + +ServiceListeners::ServiceListeners() +{ + hashedServiceKeys.push_back(ServiceConstants::OBJECTCLASS()); + hashedServiceKeys.push_back(ServiceConstants::SERVICE_ID()); +} + +void ServiceListeners::AddServiceListener(ModuleContext* mc, const ServiceListenerDelegate& listener, + const std::string& filter) +{ + MutexLocker lock(mutex); + ServiceListenerEntry sle(mc->GetModule(), listener, filter); + if (serviceSet.find(sle) != serviceSet.end()) + { + RemoveServiceListener_unlocked(sle); + } + serviceSet.insert(sle); + CheckSimple(sle); +} + +void ServiceListeners::RemoveServiceListener(ModuleContext* mc, const ServiceListenerDelegate& listener) +{ + ServiceListenerEntry entryToRemove(mc->GetModule(), listener); + + MutexLocker lock(mutex); + RemoveServiceListener_unlocked(entryToRemove); +} + +void ServiceListeners::RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove) +{ + for (ServiceListenerEntries::iterator it = serviceSet.begin(); + it != serviceSet.end(); ++it) + { + if (it->operator ==(entryToRemove)) + { + it->SetRemoved(true); + RemoveFromCache(*it); + serviceSet.erase(it); + break; + } + } +} + +void ServiceListeners::AddModuleListener(ModuleContext* mc, const ModuleListenerDelegate& listener) +{ + MutexLocker lock(moduleListenerMapMutex); + moduleListenerMap[mc] += listener; +} + +void ServiceListeners::RemoveModuleListener(ModuleContext* mc, const ModuleListenerDelegate& listener) +{ + MutexLocker lock(moduleListenerMapMutex); + moduleListenerMap[mc] -= listener; +} + +void ServiceListeners::RemoveAllListeners(ModuleContext* mc) +{ + { + MutexLocker lock(mutex); + for (ServiceListenerEntries::iterator it = serviceSet.begin(); + it != serviceSet.end(); ) + { + if (it->GetModule() == mc->GetModule()) + { + RemoveFromCache(*it); + serviceSet.erase(it++); + } + else + { + ++it; + } + } + } + + { + MutexLocker lock(moduleListenerMapMutex); + moduleListenerMap.erase(mc); + } +} + +void ServiceListeners::ServiceChanged(const ServiceListenerEntries& receivers, + const ServiceEvent& evt) +{ + ServiceListenerEntries matchBefore; + ServiceChanged(receivers, evt, matchBefore); +} + +void ServiceListeners::ServiceChanged(const ServiceListenerEntries& receivers, + const ServiceEvent& evt, + ServiceListenerEntries& matchBefore) +{ + ServiceReference sr = evt.GetServiceReference(); + int n = 0; + + for (ServiceListenerEntries::const_iterator l = receivers.begin(); + l != receivers.end(); ++l) + { + if (!matchBefore.empty()) + { + matchBefore.erase(*l); + } + + if (!l->IsRemoved()) + { + try + { + ++n; + l->CallDelegate(evt); + } + catch (...) + { + MITK_ERROR << "Service listener in " << l->GetModule()->GetName() + << " threw an exception!"; + } + } + } + + MITK_INFO << "Notified " << n << " listeners"; +} + +void ServiceListeners::GetMatchingServiceListeners(const ServiceReference& sr, ServiceListenerEntries& set) +{ + MutexLocker lock(mutex); + + // Check complicated or empty listener filters + int n = 0; + for (std::list::const_iterator sse = complicatedListeners.begin(); + sse != complicatedListeners.end(); ++sse) + { + ++n; + if (sse->GetLDAPExpr().IsNull() || + sse->GetLDAPExpr().Evaluate(sr.d->GetProperties(), false)) + { + set.insert(*sse); + } + } + + MITK_INFO << "Added " << set.size() << " out of " << n + << " listeners with complicated filters"; + + // Check the cache + const std::list c(any_cast > + (sr.GetProperty(ServiceConstants::OBJECTCLASS()))); + for (std::list::const_iterator objClass = c.begin(); + objClass != c.end(); ++objClass) + { + AddToSet(set, OBJECTCLASS_IX, *objClass); + } + + long service_id = any_cast(sr.GetProperty(ServiceConstants::SERVICE_ID())); + std::stringstream ss; + ss << service_id; + AddToSet(set, SERVICE_ID_IX, ss.str()); +} + +void ServiceListeners::ModuleChanged(const ModuleEvent& evt) +{ + MutexLocker lock(moduleListenerMapMutex); + for(ModuleListenerMap::iterator i = moduleListenerMap.begin(); + i != moduleListenerMap.end(); ++i) + { + i->second.Send(evt); + } +} + +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 + { + MITK_INFO << "Too complicated filter: " << sle.GetFilter(); + complicatedListeners.push_back(sle); + } + } + } + +void ServiceListeners::AddToSet(ServiceListenerEntries& set, + int cache_ix, const std::string& val) +{ + std::list& l = cache[cache_ix][val]; + if (!l.empty()) + { + MITK_INFO << hashedServiceKeys[cache_ix] << " matches " << l.size(); + + for (std::list::const_iterator entry = l.begin(); + entry != l.end(); ++entry) + { + set.insert(*entry); + } + } + else + { + MITK_INFO << hashedServiceKeys[cache_ix] << " matches none"; + } +} + +} diff --git a/Core/Code/Service/mitkServiceListeners_p.h b/Core/Code/Service/mitkServiceListeners_p.h new file mode 100644 index 0000000000..e6b2270950 --- /dev/null +++ b/Core/Code/Service/mitkServiceListeners_p.h @@ -0,0 +1,191 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICELISTENERS_H +#define MITKSERVICELISTENERS_H + +#include +#include +#include + +#include + +#ifdef MITK_HAS_UNORDERED_MAP_H +#include +#else +#include "mitkItkHashMap.h" +#endif + +#ifdef MITK_HAS_UNORDERED_SET_H +#include +#else +#include "mitkItkHashSet.h" +#endif + +#include + +#include "mitkServiceUtils.h" +#include "mitkServiceListenerEntry_p.h" + +namespace mitk { + +class CoreModuleContext; +class ModuleContext; + +/** + * Here we handle all listeners that modules have registered. + * + */ +class ServiceListeners { + +public: + + typedef Message1 ModuleMessage; + +#ifdef MITK_HAS_UNORDERED_MAP_H + typedef std::unordered_map > CacheType; + typedef std::unordered_map ModuleListenerMap; +#else + typedef itk::hash_map > CacheType; + typedef itk::hash_map ModuleListenerMap; +#endif + +#ifdef MITK_HAS_UNORDERED_SET_H + typedef std::unordered_set ServiceListenerEntries; +#else + typedef itk::hash_set ServiceListenerEntries; +#endif + +private: + + std::vector hashedServiceKeys; + static const int OBJECTCLASS_IX; // = 0; + static const int SERVICE_ID_IX; // = 1; + + /* Service listeners with complicated or empty filters */ + std::list complicatedListeners; + + /* Service listeners with "simple" filters are cached. */ + CacheType cache[2]; + + ServiceListenerEntries serviceSet; + ModuleListenerMap moduleListenerMap; + + typedef itk::SimpleFastMutexLock MutexType; + typedef itk::MutexLockHolder MutexLocker; + + MutexType mutex; + MutexType moduleListenerMapMutex; + +public: + + ServiceListeners(); + + /** + * Add a new service listener. If an old one exists, and it has the + * same owning module, the old listener is removed first. + * + * @param mc The module context adding this listener. + * @param listener The service listener to add. + * @param filter An LDAP filter string to check when a service is modified. + * @exception org.osgi.framework.InvalidSyntaxException + * If the filter is not a correct LDAP expression. + */ + void AddServiceListener(ModuleContext* mc, const ServiceListenerDelegate& listener, + const std::string& filter); + + /** + * Remove service listener from current framework. Silently ignore + * if listener doesn't exist. If listener is registered more than + * once remove all instances. + * + * @param mc The module context who wants to remove listener. + * @param listener Object to remove. + */ + void RemoveServiceListener(ModuleContext* mc, const ServiceListenerDelegate& listener); + + /** + * Add a new service listener. + * + * @param mc The module context adding this listener. + * @param listener The service listener to add. + * @param filter An LDAP filter string to check when a service is modified. + * @exception org.osgi.framework.InvalidSyntaxException + * If the filter is not a correct LDAP expression. + */ + void AddModuleListener(ModuleContext* mc, const ModuleListenerDelegate& listener); + + /** + * Remove service listener from current framework. Silently ignore + * if listener doesn't exist. + * + * @param mc The module context who wants to remove listener. + * @param listener Object to remove. + */ + void RemoveModuleListener(ModuleContext* mc, const ModuleListenerDelegate& listener); + + /** + * Remove all listener registered by a module in the current framework. + * + * @param mc Module context which listeners we want to remove. + */ + void RemoveAllListeners(ModuleContext* mc); + + /** + * Receive notification that a service has had a change occur in its lifecycle. + * + * @see org.osgi.framework.ServiceListener#serviceChanged + */ + void ServiceChanged(const ServiceListenerEntries& receivers, + const ServiceEvent& evt, + ServiceListenerEntries& matchBefore); + + void ServiceChanged(const ServiceListenerEntries& receivers, + const ServiceEvent& evt); + + /** + * + * + */ + void GetMatchingServiceListeners(const ServiceReference& sr, ServiceListenerEntries& listeners); + + void ModuleChanged(const ModuleEvent& evt); + +private: + + void RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove); + + /** + * Remove all references to a service listener from the service listener + * cache. + */ + void RemoveFromCache(const ServiceListenerEntry& sle); + + /** + * Checks if the specified service listener's filter is simple enough + * to cache. + */ + void CheckSimple(const ServiceListenerEntry& sle); + + void AddToSet(ServiceListenerEntries& set, int cache_ix, const std::string& val); + +}; + +} + +#endif // MITKSERVICELISTENERS_H diff --git a/Core/Code/Service/mitkServiceProperties.cpp b/Core/Code/Service/mitkServiceProperties.cpp new file mode 100644 index 0000000000..271a4b58e3 --- /dev/null +++ b/Core/Code/Service/mitkServiceProperties.cpp @@ -0,0 +1,57 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include + +#include "mitkServiceProperties.h" +#include "mitkServiceUtils.h" + +const std::string& mitk::ServiceConstants::OBJECTCLASS() +{ + static const std::string s("objectclass"); + return s; +} + +const std::string& mitk::ServiceConstants::SERVICE_ID() +{ + static const std::string s("service.id"); + return s; +} + +const std::string& mitk::ServiceConstants::SERVICE_RANKING() +{ + static const std::string s("service.ranking"); + return s; +} + +namespace mitk { + +std::size_t hash_ci_string::operator()(const ci_string& s) const +{ + ci_string ls(s); + std::transform(ls.begin(), ls.end(), ls.begin(), tolower); + +#ifdef MITK_HAS_UNORDERED_MAP_H + using namespace std; +#else + using namespace itk; +#endif + return hash()(ls); +} + +} + diff --git a/Core/Code/Service/mitkServiceProperties.h b/Core/Code/Service/mitkServiceProperties.h new file mode 100644 index 0000000000..f68ff790eb --- /dev/null +++ b/Core/Code/Service/mitkServiceProperties.h @@ -0,0 +1,191 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITK_SERVICE_PROPERTIES_H +#define MITK_SERVICE_PROPERTIES_H + +#include + +#include + +#ifdef MITK_HAS_UNORDERED_MAP_H +#include +#else +#include "mitkItkHashMap.h" +#endif + +#include +#include "mitkAny.h" + +namespace mitk { + +struct ci_char_traits : public std::char_traits + // just inherit all the other functions + // that we don't need to override +{ + + static bool eq(char c1, char c2) + { + return std::toupper(c1) == std::toupper(c2); + } + + static bool ne(char c1, char c2) + { + return std::toupper(c1) != std::toupper(c2); + } + + static bool lt(char c1, char c2) + { + return std::toupper(c1) < std::toupper(c2); + } + + static bool gt(char c1, char c2) + { + return std::toupper(c1) > std::toupper(c2); + } + + static int compare(const char* s1, const char* s2, std::size_t n) + { + while (n-- > 0) + { + if (lt(*s1, *s2)) return -1; + if (gt(*s1, *s2)) return 1; + ++s1; ++s2; + } + return 0; + } + + static const char* find(const char* s, int n, char a) + { + while (n-- > 0 && std::toupper(*s) != std::toupper(a)) + { + ++s; + } + return s; + } + +}; + +class ci_string : public std::basic_string +{ +private: + + typedef std::basic_string Super; + +public: + + inline ci_string() : Super() {} + inline ci_string(const ci_string& cistr) : Super(cistr) {} + inline ci_string(const ci_string& cistr, size_t pos, size_t n) : Super(cistr, pos, n) {} + inline ci_string(const char* s, size_t n) : Super(s, n) {} + inline ci_string(const char* s) : Super(s) {} + inline ci_string(size_t n, char c) : Super(n, c) {} + + inline ci_string(const std::string& str) : Super(str.begin(), str.end()) {} + + template ci_string(InputIterator begin, InputIterator end) + : Super(begin, end) + {} + + inline operator std::string () const + { + return std::string(begin(), end()); + } +}; + +struct MITK_CORE_EXPORT hash_ci_string +{ + std::size_t operator()(const ci_string& s) const; +}; + +/** + * \ingroup MicroServices + * + * A hash table based map class with case-insensitive keys. This class + * uses ci_string as key type and Any as values. Due + * to the conversion capabilities of ci_string, std::string objects + * can be used transparantly to insert or retrieve key-value pairs. + * + *

+ * Note that the case of the keys will be preserved. + */ +#ifdef MITK_HAS_UNORDERED_MAP_H +typedef std::unordered_map ServiceProperties; +#else +typedef itk::hash_map ServiceProperties; +#endif + +/** + * \ingroup MicroServices + */ +namespace ServiceConstants { + +/** + * Service property identifying all of the class names under which a service + * was registered in the framework. The value of this property must be of + * type std::list<std::string>. + * + *

+ * This property is set by the framework when a service is registered. + */ +MITK_CORE_EXPORT const std::string& OBJECTCLASS(); // = "objectclass" + +/** + * Service property identifying a service's registration number. The value + * of this property must be of type long int. + * + *

+ * The value of this property is assigned by the framework when a service is + * registered. The framework assigns a unique value that is larger than all + * previously assigned values since the framework was started. These values + * are NOT persistent across restarts of the framework. + */ +MITK_CORE_EXPORT const std::string& SERVICE_ID(); // = "service.id" + +/** + * Service property identifying a service's ranking number. + * + *

+ * This property may be supplied in the + * ServiceProperties object passed to the + * ModuleContext::RegisterService method. The value of this + * property must be of type int. + * + *

+ * The service ranking is used by the framework to determine the natural + * order of services, see ServiceReference::operator<(const ServiceReference&), + * and the default service to be returned from a call to the + * {@link ModuleContext::GetServiceReference} method. + * + *

+ * The default ranking is zero (0). A service with a ranking of + * std::numeric_limits::max() is very likely to be returned as the + * default service, whereas a service with a ranking of + * std::numeric_limits::min() is very unlikely to be returned. + * + *

+ * If the supplied property value is not of type int, it is + * deemed to have a ranking value of zero. + */ +MITK_CORE_EXPORT const std::string& SERVICE_RANKING(); // = "service.ranking" + +} + +} + +#endif // MITK_SERVICE_PROPERTIES_H diff --git a/Core/Code/Service/mitkServiceReference.cpp b/Core/Code/Service/mitkServiceReference.cpp new file mode 100644 index 0000000000..e6dda32d33 --- /dev/null +++ b/Core/Code/Service/mitkServiceReference.cpp @@ -0,0 +1,197 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkServiceReference.h" +#include "mitkServiceReferencePrivate.h" +#include "mitkServiceRegistrationPrivate.h" + +#include "mitkModule.h" +#include "mitkModulePrivate.h" + +#include + +namespace mitk { + +typedef ServiceRegistrationPrivate::MutexType MutexType; +typedef itk::MutexLockHolder MutexLocker; + +ServiceReference::ServiceReference() + : d(new ServiceReferencePrivate(0)) +{ + +} + +ServiceReference::ServiceReference(const ServiceReference& ref) + : d(ref.d) +{ + d->ref.Ref(); +} + +ServiceReference::ServiceReference(ServiceRegistrationPrivate* reg) + : d(new ServiceReferencePrivate(reg)) +{ + +} + +ServiceReference::operator bool() const +{ + return GetModule() != 0; +} + +ServiceReference& ServiceReference::operator=(int null) +{ + if (null == 0) + { + if (d && !d->ref.Deref()) + delete d; + d = new ServiceReferencePrivate(0); + } + return *this; +} + +ServiceReference::~ServiceReference() +{ + if (!d->ref.Deref()) + delete d; +} + +Any ServiceReference::GetProperty(const std::string& key) const +{ + MutexLocker lock(d->registration->propsLock); + + ServiceProperties::const_iterator iter = d->registration->properties.find(key); + if (iter != d->registration->properties.end()) + return iter->second; + return Any(); +} + +void ServiceReference::GetPropertyKeys(std::vector& keys) const +{ + MutexLocker lock(d->registration->propsLock); + + ServiceProperties::const_iterator iterEnd = d->registration->properties.end(); + for (ServiceProperties::const_iterator iter = d->registration->properties.begin(); + iter != iterEnd; ++iter) + { + keys.push_back(iter->first); + } +} + +Module* ServiceReference::GetModule() const +{ + if (d->registration == 0 || d->registration->module == 0) + { + return 0; + } + + return d->registration->module->q; +} + +void ServiceReference::GetUsingModules(std::vector& modules) const +{ + MutexLocker lock(d->registration->propsLock); + + ServiceRegistrationPrivate::ModuleToRefsMap::const_iterator end = d->registration->dependents.end(); + for (ServiceRegistrationPrivate::ModuleToRefsMap::const_iterator iter = d->registration->dependents.begin(); + iter != end; ++iter) + { + modules.push_back(iter->first); + } +} + +bool ServiceReference::operator<(const ServiceReference& reference) const +{ + int r1 = 0; + int r2 = 0; + + mitk::Any anyR1 = GetProperty(ServiceConstants::SERVICE_RANKING()); + mitk::Any anyR2 = reference.GetProperty(ServiceConstants::SERVICE_RANKING()); + if (anyR1.Type() == typeid(int)) r1 = any_cast(anyR1); + if (anyR2.Type() == typeid(int)) r2 = any_cast(anyR2); + + if (r1 != r2) + { + // use ranking if ranking differs + return r1 < r2; + } + else + { + long int id1 = any_cast(GetProperty(ServiceConstants::SERVICE_ID())); + long int id2 = any_cast(reference.GetProperty(ServiceConstants::SERVICE_ID())); + + // otherwise compare using IDs, + // is less than if it has a higher ID. + return id2 < id1; + } +} + +bool ServiceReference::operator==(const ServiceReference& reference) const +{ + return d->registration == reference.d->registration; +} + +ServiceReference& ServiceReference::operator=(const ServiceReference& reference) +{ + ServiceReferencePrivate* curr_d = d; + d = reference.d; + d->ref.Ref(); + + if (!curr_d->ref.Deref()) + delete curr_d; + + return *this; +} + +} + +std::ostream& operator<<(std::ostream& os, const mitk::ServiceReference& serviceRef) +{ + os << "Reference for service object registered from " + << serviceRef.GetModule()->GetName() << " " << serviceRef.GetModule()->GetVersion() + << " ("; + std::vector keys; + serviceRef.GetPropertyKeys(keys); + int keySize = keys.size(); + for(int i = 0; i < keySize; ++i) + { + os << keys[i] << "=" << serviceRef.GetProperty(keys[i]); + if (i < keySize-1) os << ","; + } + os << ")"; + + return os; +} + +#ifdef MITK_HAS_UNORDERED_MAP_H +namespace std { +#elif defined(__GNUC__) +namespace __gnu_cxx { +#else +namespace itk { +#endif + +std::size_t hash::operator()(const mitk::ServiceReference& sr) const +{ +#ifdef MITK_HAS_HASH_SIZE_T + return hash()(reinterpret_cast(sr.d->registration)); +#else + std::size_t key = reinterpret_cast(sr.d->registration); + return std::size_t(key & (~0U)); +#endif +} + +} diff --git a/Core/Code/Service/mitkServiceReference.h b/Core/Code/Service/mitkServiceReference.h new file mode 100644 index 0000000000..2bb504c8db --- /dev/null +++ b/Core/Code/Service/mitkServiceReference.h @@ -0,0 +1,239 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKSERVICEREFERENCE_H +#define MITKSERVICEREFERENCE_H + +#include +#include + +#ifdef MITK_HAS_UNORDERED_MAP_H +namespace std { +#elif defined(__GNUC__) +namespace __gnu_cxx { +#else +namespace itk { +#endif + +template class hash; + +} + +namespace mitk { + +class Module; +class ServiceRegistrationPrivate; +class ServiceReferencePrivate; + +/** + * \ingroup MicroServices + * + * A reference to a service. + * + *

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

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

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

+ * If the same service object is registered multiple times, + * ServiceReference objects associated with different + * ServiceRegistration objects are not equal. + * + * @see ModuleContext::GetServiceReference + * @see ModuleContext::GetServiceReferences + * @see ModuleContext::GetService + * @remarks This class is thread safe. + */ +class MITK_CORE_EXPORT ServiceReference { + +public: + + /** + * Creates an invalid ServiceReference object. You can use + * this object in boolean expressions and it will evaluate to + * false. + */ + ServiceReference(); + + ServiceReference(const ServiceReference& ref); + + /** + * Converts this ServiceReference instance into a boolean + * expression. If this instance was default constructed or + * the service it references has been unregistered, the conversion + * returns false, otherwise it returns true. + */ + operator bool() const; + + /** + * Releases any resources held or locked by this + * ServiceReference and renders it invalid. + */ + ServiceReference& operator=(int null); + + ~ServiceReference(); + + /** + * Returns the property value to which the specified property key is mapped + * in the properties ServiceProperties object of the service + * referenced by this ServiceReference object. + * + *

+ * Property keys are case-insensitive. + * + *

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

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

+ * This method must return 0 when the service has been + * unregistered. This can be used to determine if the service has been + * unregistered. + * + * @return The module that registered the service referenced by this + * ServiceReference object; 0 if that + * service has already been unregistered. + * @see ModuleContext::RegisterService(const std::vector&, itk::LightObject*, const ServiceProperties&) + */ + Module* GetModule() const; + + /** + * Returns the modules that are using the service referenced by this + * ServiceReference object. Specifically, this method returns + * the modules whose usage count for that service is greater than zero. + * + * @param modules A list of modules whose usage count for the service referenced + * by this ServiceReference object is greater than + * zero. + */ + void GetUsingModules(std::vector& modules) const; + + /** + * Compares this ServiceReference with the specified + * ServiceReference for order. + * + *

+ * If this ServiceReference and the specified + * ServiceReference have the same {@link ServiceProperties::SERVICE_ID + * service id} they are equal. This ServiceReference is less + * than the specified ServiceReference if it has a lower + * {@link ServiceProperties::SERVICE_RANKING service ranking} and greater if it has a + * higher service ranking. Otherwise, if this ServiceReference + * and the specified ServiceReference have the same + * {@link ServiceProperties::SERVICE_RANKING service ranking}, this + * ServiceReference is less than the specified + * ServiceReference if it has a higher + * {@link ServiceProperties::SERVICE_ID service id} and greater if it has a lower + * service id. + * + * @param reference The ServiceReference to be compared. + * @return Returns a false or true if this + * ServiceReference is less than or greater + * than the specified ServiceReference. + */ + bool operator<(const ServiceReference& reference) const; + + bool operator==(const ServiceReference& reference) const; + + ServiceReference& operator=(const ServiceReference& reference); + + +protected: + + friend class ModulePrivate; + friend class ModuleContext; + friend class ServiceFilter; + friend class ServiceRegistrationPrivate; + friend class ServiceListeners; + friend class LDAPFilter; + + template friend class ServiceTracker; + template friend class ServiceTrackerPrivate; + template friend class ModuleAbstractTracked; + +#ifdef MITK_HAS_UNORDERED_MAP_H + friend class std::hash; +#elif defined(__GNUC__) + friend class __gnu_cxx::hash; +#else + friend struct itk::hash; +#endif + + + ServiceReference(ServiceRegistrationPrivate* reg); + + ServiceReferencePrivate* d; + +}; + +} + +MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::ServiceReference& serviceRef); + +#ifdef MITK_HAS_UNORDERED_MAP_H +namespace std { +#elif defined(__GNUC__) +namespace __gnu_cxx { +#else +namespace itk { +#endif + +template<> struct MITK_CORE_EXPORT hash +{ + std::size_t operator()(const mitk::ServiceReference& sr) const; +}; + +} + +#endif // MITKSERVICEREFERENCE_H diff --git a/Core/Code/Service/mitkServiceReferencePrivate.cpp b/Core/Code/Service/mitkServiceReferencePrivate.cpp new file mode 100644 index 0000000000..c778e50734 --- /dev/null +++ b/Core/Code/Service/mitkServiceReferencePrivate.cpp @@ -0,0 +1,157 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkServiceReferencePrivate.h" + +#include "mitkServiceFactory.h" +#include "mitkServiceException.h" +#include "mitkServiceRegistry_p.h" +#include "mitkServiceRegistrationPrivate.h" + +#include "mitkModule.h" +#include "mitkModulePrivate.h" +#include "mitkCoreModuleContext_p.h" + +#include + +namespace mitk { + +typedef ServiceRegistrationPrivate::MutexLocker MutexLocker; + +ServiceReferencePrivate::ServiceReferencePrivate(ServiceRegistrationPrivate* reg) + : ref(1), registration(reg) +{ +} + +itk::LightObject* ServiceReferencePrivate::GetService(Module* module) +{ + itk::LightObject* s = 0; + { + MutexLocker lock(registration->propsLock); + if (registration->available) + { + int count = registration->dependents[module]; + if (count == 0) + { + const std::list& classes = + ref_any_cast >(registration->properties[ServiceConstants::OBJECTCLASS()]); + registration->dependents[module] = 1; + if (ServiceFactory* serviceFactory = dynamic_cast(registration->GetService())) + { + try + { + s = serviceFactory->GetService(module, ServiceRegistration(registration)); + } + catch (...) + { + MITK_WARN << "mitk::ServiceFactory threw an exception"; + return 0; + } + if (s == 0) { + MITK_WARN << "mitk::ServiceFactory produced null"; + return 0; + } + for (std::list::const_iterator i = classes.begin(); + i != classes.end(); ++i) + { + if (!registration->module->coreCtx->services.CheckServiceClass(s, *i)) + { + MITK_WARN << "mitk::ServiceFactory produced an object " + "that did not implement: " << (*i); + return 0; + } + } + registration->serviceInstances.insert(std::make_pair(module, s)); + } + else + { + s = registration->GetService(); + } + } + else + { + registration->dependents.insert(std::make_pair(module, count + 1)); + if (dynamic_cast(registration->GetService())) + { + s = registration->serviceInstances[module]; + } + else + { + s = registration->GetService(); + } + } + } + } + return s; +} + +bool ServiceReferencePrivate::UngetService(Module* module, bool checkRefCounter) +{ + MutexLocker lock(registration->propsLock); + bool hadReferences = false; + bool removeService = false; + + int count= registration->dependents[module]; + if (count > 0) + { + hadReferences = true; + } + + if(checkRefCounter) + { + if (count > 1) + { + registration->dependents[module] = count - 1; + } + else if(count == 1) + { + removeService = true; + } + } + else + { + removeService = true; + } + + if (removeService) + { + itk::LightObject* sfi = registration->serviceInstances[module]; + registration->serviceInstances.erase(module); + if (sfi != 0) + { + try + { + dynamic_cast( + registration->GetService())->UngetService(module, ServiceRegistration(registration), sfi); + } + catch (const std::exception& /*e*/) + { + MITK_WARN << "mitk::ServiceFactory threw an exception"; + } + } + registration->dependents.erase(module); + } + + return hadReferences; +} + +ServiceProperties ServiceReferencePrivate::GetProperties() const +{ + return registration->properties; +} + +} diff --git a/Core/Code/Service/mitkServiceReferencePrivate.h b/Core/Code/Service/mitkServiceReferencePrivate.h new file mode 100644 index 0000000000..830baf39c9 --- /dev/null +++ b/Core/Code/Service/mitkServiceReferencePrivate.h @@ -0,0 +1,89 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICEREFERENCEPRIVATE_H +#define MITKSERVICEREFERENCEPRIVATE_H + +#include "mitkAtomicInt.h" + +#include "mitkServiceProperties.h" + +namespace itk { + class LightObject; +} + +namespace mitk { + +class Module; +class ServiceRegistrationPrivate; +class ServiceReferencePrivate; + + +/** + * \ingroup MicroServices + */ +class ServiceReferencePrivate +{ +public: + + ServiceReferencePrivate(ServiceRegistrationPrivate* reg); + + virtual ~ServiceReferencePrivate() {} + + /** + * Get the service object. + * + * @param module requester of service. + * @return Service requested or null in case of failure. + */ + itk::LightObject* GetService(Module* module); + + /** + * Unget the service object. + * + * @param module Module who wants remove service. + * @param checkRefCounter If true decrement refence counter and remove service + * if we reach zero. If false remove service without + * checking refence counter. + * @return True if service was remove or false if only refence counter was + * decremented. + */ + bool UngetService(Module* module, bool checkRefCounter); + + /** + * Get all properties registered with this service. + * + * @return A ServiceProperties object containing properties or being empty + * if service has been removed. + */ + ServiceProperties GetProperties() const; + + /** + * Reference count for implicitly shared private implementation. + */ + AtomicInt ref; + + /** + * Link to registration object for this reference. + */ + ServiceRegistrationPrivate* const registration; +}; + +} + +#endif // MITKSERVICEREFERENCEPRIVATE_H diff --git a/Core/Code/Service/mitkServiceRegistration.cpp b/Core/Code/Service/mitkServiceRegistration.cpp new file mode 100644 index 0000000000..7974483638 --- /dev/null +++ b/Core/Code/Service/mitkServiceRegistration.cpp @@ -0,0 +1,220 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkServiceRegistration.h" +#include "mitkServiceRegistrationPrivate.h" +#include "mitkServiceListenerEntry_p.h" +#include "mitkServiceRegistry_p.h" +#include "mitkServiceFactory.h" + +#include "mitkModulePrivate.h" +#include "mitkCoreModuleContext_p.h" + +#include + +namespace mitk { + +typedef ServiceRegistrationPrivate::MutexLocker MutexLocker; + +ServiceRegistration::ServiceRegistration() + : d(0) +{ + +} + +ServiceRegistration::ServiceRegistration(const ServiceRegistration& reg) + : d(reg.d) +{ + d->ref.Ref(); +} + +ServiceRegistration::ServiceRegistration(ServiceRegistrationPrivate* registrationPrivate) + : d(registrationPrivate) +{ + d->ref.Ref(); +} + +ServiceRegistration::ServiceRegistration(ModulePrivate* module, itk::LightObject* service, + const ServiceProperties& props) + : d(new ServiceRegistrationPrivate(module, service, props)) +{ + +} + +ServiceRegistration::operator bool() const +{ + return d != 0; +} + +ServiceRegistration& ServiceRegistration::operator=(int null) +{ + if (null == 0) + { + if (d && !d->ref.Deref()) + { + delete d; + } + d = 0; + } + return *this; +} + +ServiceRegistration::~ServiceRegistration() +{ + if (d && !d->ref.Deref()) + delete d; +} + +ServiceReference ServiceRegistration::GetReference() const +{ + if (!d) throw std::logic_error("ServiceRegistration object invalid"); + if (!d->available) throw std::logic_error("Service is unregistered"); + + return d->reference; +} + +void ServiceRegistration::SetProperties(const ServiceProperties& props) +{ + if (!d) throw std::logic_error("ServiceRegistration object invalid"); + + MutexLocker lock(d->eventLock); + + ServiceListeners::ServiceListenerEntries before; + // TBD, optimize the locking of services + { + //MutexLocker lock2(d->module->coreCtx->globalFwLock); + MutexLocker lock3(d->propsLock); + + if (d->available) + { + // NYI! Optimize the MODIFIED_ENDMATCH code + int old_rank = any_cast(d->properties[ServiceConstants::SERVICE_RANKING()]); + d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, before); + const std::list& classes = ref_any_cast >(d->properties[ServiceConstants::OBJECTCLASS()]); + long int sid = any_cast(d->properties[ServiceConstants::SERVICE_ID()]); + d->properties = ServiceRegistry::CreateServiceProperties(props, classes, sid); + int new_rank = any_cast(d->properties[ServiceConstants::SERVICE_RANKING()]); + if (old_rank != new_rank) + { + d->module->coreCtx->services.UpdateServiceRegistrationOrder(*this, classes); + } + } + else + { + throw std::logic_error("Service is unregistered"); + } + } + ServiceListeners::ServiceListenerEntries matchingListeners; + d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, matchingListeners); + d->module->coreCtx->listeners.ServiceChanged(matchingListeners, + ServiceEvent(ServiceEvent::MODIFIED, d->reference), + before); + + d->module->coreCtx->listeners.ServiceChanged(before, + ServiceEvent(ServiceEvent::MODIFIED_ENDMATCH, d->reference)); +} + +void ServiceRegistration::Unregister() +{ + if (!d) throw std::logic_error("ServiceRegistration object invalid"); + + if (d->unregistering) return; // Silently ignore redundant unregistration. + { + MutexLocker lock(d->eventLock); + if (d->unregistering) return; + d->unregistering = true; + + if (d->available) + { + if (d->module) + { + d->module->coreCtx->services.RemoveServiceRegistration(*this); + } + } + else + { + throw std::logic_error("Service is unregistered"); + } + } + + if (d->module) + { + ServiceListeners::ServiceListenerEntries listeners; + d->module->coreCtx->listeners.GetMatchingServiceListeners(d->reference, listeners); + d->module->coreCtx->listeners.ServiceChanged( + listeners, + ServiceEvent(ServiceEvent::UNREGISTERING, d->reference)); + } + + { + MutexLocker lock(d->eventLock); + { + MutexLocker lock2(d->propsLock); + d->available = false; + if (d->module) + { + ServiceRegistrationPrivate::ModuleToServicesMap::const_iterator end = d->serviceInstances.end(); + for (ServiceRegistrationPrivate::ModuleToServicesMap::const_iterator i = d->serviceInstances.begin(); + i != end; ++i) + { + itk::LightObject* obj = i->second; + try + { + // NYI, don't call inside lock + dynamic_cast(d->service)->UngetService(i->first, + *this, + obj); + } + catch (const std::exception& /*ue*/) + { + MITK_WARN << "mitk::ServiceFactory UngetService implementation threw an exception"; + } + } + } + d->module = 0; + d->dependents.clear(); + d->service = 0; + d->serviceInstances.clear();; + d->unregistering = false; + } + } +} + +bool ServiceRegistration::operator<(const ServiceRegistration& o) const +{ + if (!d) return true; + return d->reference <(o.d->reference); +} + +bool ServiceRegistration::operator==(const ServiceRegistration& registration) const +{ + return d == registration.d; +} + +ServiceRegistration& ServiceRegistration::operator=(const ServiceRegistration& registration) +{ + ServiceRegistrationPrivate* curr_d = d; + d = registration.d; + d->ref.Ref(); + + if (curr_d && !curr_d->ref.Deref()) + delete curr_d; + + return *this; +} + +} diff --git a/Core/Code/Service/mitkServiceRegistration.h b/Core/Code/Service/mitkServiceRegistration.h new file mode 100644 index 0000000000..e41630bbb2 --- /dev/null +++ b/Core/Code/Service/mitkServiceRegistration.h @@ -0,0 +1,171 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef MITKSERVICEREGISTRATION_H +#define MITKSERVICEREGISTRATION_H + +#include "mitkServiceProperties.h" +#include "mitkServiceReference.h" + +namespace mitk { + +class ModulePrivate; + +/** + * \ingroup MicroServices + * + * A registered service. + * + *

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

+ * The ServiceRegistration object may be used to update the + * properties of the service or to unregister the service. + * + * @see ModuleContext#RegisterService() + * @remarks This class is thread safe. + */ +class MITK_CORE_EXPORT ServiceRegistration { + +public: + + /** + * Creates an invalid ServiceRegistration object. You can use + * this object in boolean expressions and it will evaluate to + * false. + */ + ServiceRegistration(); + + ServiceRegistration(const ServiceRegistration& reg); + + operator bool() const; + + /** + * Releases any resources held or locked by this + * ServiceRegistration and renders it invalid. + */ + ServiceRegistration& operator=(int null); + + ~ServiceRegistration(); + + /** + * Returns a ServiceReference object for a service being + * registered. + *

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

+ * The {@link ServiceProperties#OBJECTCLASS} and {@link ServiceProperties#SERVICE_ID} keys + * cannot be modified by this method. These values are set by the framework + * when the service is registered in the environment. + * + *

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

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

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

    + *
  1. The service is removed from the framework service registry so that + * it can no longer be obtained. + *
  2. A service event of type {@link ServiceEvent#UNREGISTERING} is fired + * so that modules using this service can release their use of the service. + * Once delivery of the service event is complete, the + * ServiceRegistration objects for the service may no longer be + * used to get a service object for the service. + *
  3. For each module whose use count for this service is greater than + * zero:
    + * The module's use count for this service is set to zero.
    + * If the service was registered with a {@link ServiceFactory} object, the + * ServiceFactory#UngetService method is called to release + * the service object for the module. + *
+ * + * @throws std::logic_error If this + * ServiceRegistration object has already been + * unregistered or if it is invalid. + * @see ModuleContext#UngetService + * @see ServiceFactory#UngetService + */ + virtual void Unregister(); + + bool operator<(const ServiceRegistration& o) const; + + bool operator==(const ServiceRegistration& registration) const; + + ServiceRegistration& operator=(const ServiceRegistration& registration); + + +protected: + + friend class ServiceRegistry; + friend class ServiceReferencePrivate; + friend struct HashServiceRegistration; + + ServiceRegistration(ServiceRegistrationPrivate* registrationPrivate); + + ServiceRegistration(ModulePrivate* module, itk::LightObject* service, + const ServiceProperties& props); + + ServiceRegistrationPrivate* d; + +}; + +} + +inline std::ostream& operator<<(std::ostream& os, const mitk::ServiceRegistration& /*reg*/) +{ + return os << "mitk::ServiceRegistration object"; +} + +#endif // MITKSERVICEREGISTRATION_H diff --git a/Core/Code/Service/mitkServiceRegistrationPrivate.cpp b/Core/Code/Service/mitkServiceRegistrationPrivate.cpp new file mode 100644 index 0000000000..26d12eb3ca --- /dev/null +++ b/Core/Code/Service/mitkServiceRegistrationPrivate.cpp @@ -0,0 +1,46 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkServiceRegistrationPrivate.h" + +namespace mitk { + +ServiceRegistrationPrivate::ServiceRegistrationPrivate( + ModulePrivate* module, itk::LightObject* service, + const ServiceProperties& props) + : ref(1), service(service), module(module), reference(this), + properties(props), available(true), unregistering(false) +{ + +} + +ServiceRegistrationPrivate::~ServiceRegistrationPrivate() +{ + +} + +bool ServiceRegistrationPrivate::IsUsedByModule(Module* p) +{ + return dependents.find(p) != dependents.end(); +} + +itk::LightObject* ServiceRegistrationPrivate::GetService() +{ + return service; +} + +} diff --git a/Core/Code/Service/mitkServiceRegistrationPrivate.h b/Core/Code/Service/mitkServiceRegistrationPrivate.h new file mode 100644 index 0000000000..7d3b4400ca --- /dev/null +++ b/Core/Code/Service/mitkServiceRegistrationPrivate.h @@ -0,0 +1,134 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICEREGISTRATIONPRIVATE_H +#define MITKSERVICEREGISTRATIONPRIVATE_H + +#include "mitkModule.h" +#include "mitkServiceReference.h" +#include "mitkServiceProperties.h" +#include "mitkAtomicInt.h" + +#include + +namespace mitk { + +class ModulePrivate; +class ServiceRegistration; + +/** + * \ingroup MicroServices + */ +class ServiceRegistrationPrivate +{ + +protected: + + friend class ServiceRegistration; + + /** + * Reference count for implicitly shared private implementation. + */ + AtomicInt ref; + + /** + * Service or ServiceFactory object. + */ + itk::LightObject* service; + +public: + + typedef itk::SimpleFastMutexLock MutexType; + typedef itk::MutexLockHolder MutexLocker; + +#ifdef MITK_HAS_UNORDERED_MAP_H + typedef std::unordered_map ModuleToRefsMap; + typedef std::unordered_map ModuleToServicesMap; +#else + typedef itk::hash_map ModuleToRefsMap; + typedef itk::hash_map ModuleToServicesMap; +#endif + + /** + * Module registering this service. + */ + ModulePrivate* module; + + /** + * Reference object to this service registration. + */ + ServiceReference reference; + + /** + * Service properties. + */ + ServiceProperties properties; + + /** + * Modules dependent on this service. Integer is used as + * reference counter, counting number of unbalanced getService(). + */ + ModuleToRefsMap dependents; + + /** + * Object instances that factory has produced. + */ + ModuleToServicesMap serviceInstances; + + /** + * Is service available. I.e., if true then holders + * of a ServiceReference for the service are allowed to get it. + */ + volatile bool available; + + /** + * Avoid recursive unregistrations. I.e., if true then + * unregistration of this service has started but is not yet + * finished. + */ + volatile bool unregistering; + + /** + * Lock object for synchronous event delivery. + */ + MutexType eventLock; + + // needs to be recursive + MutexType propsLock; + + ServiceRegistrationPrivate(ModulePrivate* module, itk::LightObject* service, + const ServiceProperties& props); + + virtual ~ServiceRegistrationPrivate(); + + /** + * Check if a module uses this service + * + * @param p Module to check + * @return true if module uses this service + */ + bool IsUsedByModule(Module* m); + + virtual itk::LightObject* GetService(); + +}; + +} + + +#endif // MITKSERVICEREGISTRATIONPRIVATE_H diff --git a/Core/Code/Service/mitkServiceRegistry.cpp b/Core/Code/Service/mitkServiceRegistry.cpp new file mode 100644 index 0000000000..3f6644f91f --- /dev/null +++ b/Core/Code/Service/mitkServiceRegistry.cpp @@ -0,0 +1,329 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include + +#include "mitkServiceRegistry_p.h" +#include "mitkServiceFactory.h" +#include "mitkServiceRegistry_p.h" +#include "mitkServiceRegistrationPrivate.h" +#include "mitkModulePrivate.h" +#include "mitkCoreModuleContext_p.h" + +#include "itkMutexLockHolder.h" + + +namespace mitk { + +typedef itk::MutexLockHolder MutexLocker; + +std::size_t HashServiceRegistration::operator()(const ServiceRegistration& s) const +{ + return reinterpret_cast(s.d); +} + + +struct ServiceRegistrationComparator +{ + bool operator()(const ServiceRegistration& a, const ServiceRegistration& b) const + { + return a < b; + } +}; + +ServiceProperties ServiceRegistry::CreateServiceProperties(const ServiceProperties& in, + const std::list& classes, + 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++)); + + return props; +} + +ServiceRegistry::ServiceRegistry(CoreModuleContext* coreCtx) + : core(coreCtx) +{ + +} + +ServiceRegistry::~ServiceRegistry() +{ + Clear(); +} + +void ServiceRegistry::Clear() +{ + services.clear(); + serviceRegistrations.clear(); + classServices.clear(); + core = 0; +} + +ServiceRegistration ServiceRegistry::RegisterService(ModulePrivate* module, + const std::list& classes, + itk::LightObject* service, + const ServiceProperties& properties) +{ + if (service == 0) + { + throw std::invalid_argument("Can't register 0 as a service"); + } + + // Check if service implements claimed classes and that they exist. + for (std::list::const_iterator i = classes.begin(); + i != classes.end(); ++i) + { + if (i->empty()) + { + throw std::invalid_argument("Can't register as null class"); + } + + if (!(dynamic_cast(service))) + { + if (!CheckServiceClass(service, *i)) + { + std::string msg; + std::stringstream ss(msg); + ss << "Service class " << service->GetNameOfClass() << " is not an instance of " + << (*i) << ". Maybe you forgot to export the RTTI information for the interface."; + throw std::invalid_argument(msg); + } + } + } + + ServiceRegistration res(module, service, + CreateServiceProperties(properties, classes)); + { + MutexLocker lock(mutex); + services.insert(std::make_pair(res, classes)); + serviceRegistrations.push_back(res); + for (std::list::const_iterator i = classes.begin(); + i != classes.end(); ++i) + { + std::list& s = classServices[*i]; + std::list::iterator ip = + std::lower_bound(s.begin(), s.end(), res, ServiceRegistrationComparator()); + s.insert(ip, res); + } + } + + ServiceReference r = res.GetReference(); + ServiceListeners::ServiceListenerEntries listeners; + module->coreCtx->listeners.GetMatchingServiceListeners(r, listeners); + module->coreCtx->listeners.ServiceChanged(listeners, + ServiceEvent(ServiceEvent::REGISTERED, r)); + return res; +} + +void ServiceRegistry::UpdateServiceRegistrationOrder(const ServiceRegistration& sr, + const std::list& classes) +{ + MutexLocker lock(mutex); + for (std::list::const_iterator i = classes.begin(); + i != classes.end(); ++i) + { + std::list& s = classServices[*i]; + std::remove(s.begin(), s.end(), sr); + s.insert(std::lower_bound(s.begin(), s.end(), sr, ServiceRegistrationComparator()), sr); + } +} + +bool ServiceRegistry::CheckServiceClass(itk::LightObject* , const std::string& ) const +{ + //return service->inherits(cls.toAscii()); + // No possibility to check inheritance based on string literals. + return true; +} + +void ServiceRegistry::Get(const std::string& clazz, + std::list& serviceRegs) const +{ + MutexLocker lock(mutex); + MapClassServices::const_iterator i = classServices.find(clazz); + if (i != classServices.end()) + { + serviceRegs = i->second; + } +} + +ServiceReference ServiceRegistry::Get(ModulePrivate* module, const std::string& clazz) const +{ + MutexLocker lock(mutex); + try + { + std::list srs; + Get_Unlocked(clazz, "", module, srs); + MITK_INFO << "get service ref " << clazz << " for module " + << module->info.name << " = " << srs.size() << " refs"; + + if (!srs.empty()) + { + return srs.front(); + } + } + catch (const std::invalid_argument& ) + { } + + return ServiceReference(); +} + +void ServiceRegistry::Get(const std::string& clazz, const std::string& filter, + ModulePrivate* module, std::list& res) const +{ + MutexLocker lock(mutex); + Get_Unlocked(clazz, filter, module, res); +} + +void ServiceRegistry::Get_Unlocked(const std::string& clazz, const std::string& filter, + ModulePrivate* /*module*/, std::list& res) const +{ + std::list::const_iterator s; + std::list::const_iterator send; + std::list 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) + { + ServiceReference sri = s->GetReference(); + + if (filter.empty() || ldap.Evaluate(s->d->properties, false)) + { + res.push_back(sri); + } + } +} + +void ServiceRegistry::RemoveServiceRegistration(const ServiceRegistration& sr) +{ + MutexLocker lock(mutex); + + const std::list& classes = ref_any_cast >( + sr.d->properties[ServiceConstants::OBJECTCLASS()]); + services.erase(sr); + serviceRegistrations.remove(sr); + for (std::list::const_iterator i = classes.begin(); + i != classes.end(); ++i) + { + std::list& s = classServices[*i]; + if (s.size() > 1) + { + std::remove(s.begin(), s.end(), sr); + } + else + { + classServices.erase(*i); + } + } +} + +void ServiceRegistry::GetRegisteredByModule(ModulePrivate* p, + std::list& res) const +{ + MutexLocker lock(mutex); + + for (std::list::const_iterator i = serviceRegistrations.begin(); + i != serviceRegistrations.end(); ++i) + { + if (i->d->module == p) + { + res.push_back(*i); + } + } +} + +void ServiceRegistry::GetUsedByModule(Module* p, + std::list& res) const +{ + MutexLocker lock(mutex); + + for (std::list::const_iterator i = serviceRegistrations.begin(); + i != serviceRegistrations.end(); ++i) + { + if (i->d->IsUsedByModule(p)) + { + res.push_back(*i); + } + } +} + +} // end namespace mitk + diff --git a/Core/Code/Service/mitkServiceRegistry_p.h b/Core/Code/Service/mitkServiceRegistry_p.h new file mode 100644 index 0000000000..34c7938797 --- /dev/null +++ b/Core/Code/Service/mitkServiceRegistry_p.h @@ -0,0 +1,198 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICEREGISTRY_H +#define MITKSERVICEREGISTRY_H + +#include + +#include + +#include "mitkServiceRegistration.h" +#include "mitkServiceProperties.h" +#include "mitkServiceUtils.h" + +namespace mitk { + +class CoreModuleContext; +class ModulePrivate; + +struct HashServiceRegistration +{ + std::size_t operator()(const ServiceRegistration& s) const; +}; + +/** + * Here we handle all the MITK services that are registered. + */ +class ServiceRegistry +{ + +public: + + typedef itk::SimpleFastMutexLock MutexType; + + mutable MutexType mutex; + + /** + * Creates a new ServiceProperties object containing in + * with the keys converted to lower case. + * + * @param classes A list of class names which will be added to the + * created ServiceProperties object under the key + * ModuleConstants::OBJECTCLASS. + * @param sid A service id which will be used instead of a default one. + */ + static ServiceProperties CreateServiceProperties(const ServiceProperties& in, + const std::list& classes = std::list(), + long sid = -1); + +#ifdef MITK_HAS_UNORDERED_MAP_H + typedef std::unordered_map, HashServiceRegistration> MapServiceClasses; + typedef std::unordered_map > MapClassServices; +#else + typedef itk::hash_map, HashServiceRegistration> MapServiceClasses; + typedef itk::hash_map > MapClassServices; +#endif + + /** + * All registered services in the current framework. + * Mapping of registered service to class names under which + * the service is registerd. + */ + MapServiceClasses services; + + std::list serviceRegistrations; + + /** + * Mapping of classname to registered service. + * The List of registered services are ordered with the highest + * ranked service first. + */ + MapClassServices classServices; + + CoreModuleContext* core; + + ServiceRegistry(CoreModuleContext* coreCtx); + + ~ServiceRegistry(); + + void Clear(); + + /** + * Register a service in the framework wide register. + * + * @param module The module registering the service. + * @param classes The class names under which the service can be located. + * @param service The service object. + * @param properties The properties for this service. + * @return A ServiceRegistration object. + * @exception std::invalid_argument If one of the following is true: + *
    + *
  • The service object is 0.
  • + *
  • The service parameter is not a ServiceFactory or an + * instance of all the named classes in the classes parameter.
  • + *
+ */ + ServiceRegistration RegisterService(ModulePrivate* module, + const std::list& clazzes, + itk::LightObject* service, + const ServiceProperties& properties); + + /** + * Service ranking changed, reorder registered services + * according to ranking. + * + * @param serviceRegistration The ServiceRegistrationPrivate object. + * @param rank New rank of object. + */ + void UpdateServiceRegistrationOrder(const ServiceRegistration& sr, + const std::list& classes); + + /** + * Checks that a given service object is an instance of the given + * class name. + * + * @param service The service object to check. + * @param cls The class name to check for. + */ + bool CheckServiceClass(itk::LightObject* service, const std::string& cls) const; + + /** + * Get all services implementing a certain class. + * Only used internally by the framework. + * + * @param clazz The class name of the requested service. + * @return A sorted list of {@link ServiceRegistrationPrivate} objects. + */ + void Get(const std::string& clazz, std::list& serviceRegs) const; + + /** + * Get a service implementing a certain class. + * + * @param module The module requesting reference + * @param clazz The class name of the requested service. + * @return A {@link ServiceReference} object. + */ + ServiceReference Get(ModulePrivate* module, const std::string& clazz) const; + + /** + * Get all services implementing a certain class and then + * filter these with a property filter. + * + * @param clazz The class name of requested service. + * @param filter The property filter. + * @param module The module requesting reference. + * @return A list of {@link ServiceReference} object. + */ + void Get(const std::string& clazz, const std::string& filter, + ModulePrivate* module, std::list& serviceRefs) const; + + /** + * Remove a registered service. + * + * @param sr The ServiceRegistration object that is registered. + */ + void RemoveServiceRegistration(const ServiceRegistration& sr) ; + + /** + * Get all services that a module has registered. + * + * @param p The module + * @return A set of {@link ServiceRegistration} objects + */ + void GetRegisteredByModule(ModulePrivate* m, std::list& serviceRegs) const; + + /** + * Get all services that a module uses. + * + * @param p The module + * @return A set of {@link ServiceRegistration} objects + */ + void GetUsedByModule(Module* m, std::list& serviceRegs) const; + +private: + + void Get_Unlocked(const std::string& clazz, const std::string& filter, + ModulePrivate* module, std::list& serviceRefs) const; + +}; + +} + +#endif // MITKSERVICEREGISTRY_H diff --git a/Core/Code/Service/mitkServiceTracker.h b/Core/Code/Service/mitkServiceTracker.h new file mode 100644 index 0000000000..88efdc10f1 --- /dev/null +++ b/Core/Code/Service/mitkServiceTracker.h @@ -0,0 +1,429 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICETRACKER_H +#define MITKSERVICETRACKER_H + +#include "mitkCommon.h" + +#include "mitkServiceReference.h" +#include "mitkServiceTrackerCustomizer.h" +#include "mitkLDAPFilter.h" + +namespace mitk { + +template class TrackedService; +template class ServiceTrackerPrivate; +class ModuleContext; + +/** + * \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. + *

+ * The ServiceTracker class is thread-safe. It does not call a + * ServiceTrackerCustomizer while holding any locks. + * ServiceTrackerCustomizer implementations must also be + * thread-safe. + * + * \tparam S The type of the service being tracked. The type must be an + * assignable datatype. Further, if the + * ServiceTracker(ModuleContext*, ServiceTrackerCustomizer*) + * constructor is used, the type must have an associated interface id via + * MITK_DECLARE_SERVICE_INTERFACE. + * \tparam T The type of the tracked object. The type must be an assignable + * datatype, provide a boolean conversion function, and provide + * a constructor and an assignment operator which can handle 0 as an argument. + * \remarks This class is thread safe. + */ +template +class ServiceTracker : protected ServiceTrackerCustomizer +{ +public: + + typedef std::map 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 ServiceReference& 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(); + + /** + * Return a list of ServiceReferences for all services being + * tracked by this ServiceTracker. + * + * @param refs List of ServiceReferences. + */ + virtual void GetServiceReferences(std::list& refs) 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 ServiceReference 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 ServiceReference& 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. + * + * @param services A list of service objects or an empty list if no services + * are being tracked. + */ + virtual void GetServices(std::list& services) 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 ServiceReference& 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 ServiceReference&, 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 ServiceReference& 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&, itk::LighObject*) + */ + void ModifiedService(const ServiceReference& 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 ServiceReference&) 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 ServiceReference&, itk::LighObject*) + */ + void RemovedService(const ServiceReference& 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; +}; + +} + +#include "mitkServiceTracker.tpp" + +#endif // MITKSERVICETRACKER_H diff --git a/Core/Code/Service/mitkServiceTracker.tpp b/Core/Code/Service/mitkServiceTracker.tpp new file mode 100644 index 0000000000..54871059f7 --- /dev/null +++ b/Core/Code/Service/mitkServiceTracker.tpp @@ -0,0 +1,436 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkServiceTrackerPrivate.h" +#include "mitkTrackedService.h" +#include "mitkServiceException.h" +#include "mitkModuleContext.h" + +#include +#include + +namespace mitk { + +template +ServiceTracker::~ServiceTracker() +{ + delete d; +} + +template +ServiceTracker::ServiceTracker(ModuleContext* context, + const ServiceReference& 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, mitk_service_interface_iid(), customizer)) +{ + const char* clazz = mitk_service_interface_iid(); + if (clazz == 0) throw ServiceException("The service interface class has no MITK_DECLARE_SERVICE_INTERFACE macro"); +} + +template +void ServiceTracker::Open() +{ + itk::SmartPointer<_TrackedService> t; + { + MutexLocker lock(d->mutex); + if (d->trackedService) + { + return; + } + + MITK_DEBUG(d->DEBUG) << "ServiceTracker::Open: " << d->filter; + + t = itk::SmartPointer<_TrackedService>( + new _TrackedService(this, d->customizer)); + { + itk::MutexLockHolder lockT(*t); + try { + d->context->AddServiceListener(t.GetPointer(), &_TrackedService::ServiceChanged, d->listenerFilter); + std::list 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() +{ + itk::SmartPointer<_TrackedService> outgoing; + std::list references; + { + MutexLocker lock(d->mutex); + outgoing = d->trackedService; + if (outgoing.IsNull()) + { + return; + } + MITK_DEBUG(d->DEBUG) << "ServiceTracker::close:" << d->filter; + outgoing->Close(); + GetServiceReferences(references); + d->trackedService = 0; + try + { + d->context->RemoveServiceListener(outgoing.GetPointer(), &_TrackedService::ServiceChanged); + } + catch (const std::logic_error& /*e*/) + { + /* In case the context was stopped. */ + } + } + d->Modified(); /* clear the cache */ + { + itk::MutexLockHolder lockT(*outgoing); + outgoing->WakeAll(); /* wake up any waiters */ + } + for(std::list::const_iterator ref = references.begin(); + ref != references.end(); ++ref) + { + outgoing->Untrack(*ref, ServiceEvent()); + } + + if (d->DEBUG) + { + MutexLocker lock(d->mutex); + if ((d->cachedReference.GetModule() == 0) && (d->cachedService == 0)) + { + MITK_DEBUG(true) << "ServiceTracker::close[cached cleared]:" + << d->filter; + } + } +} + +template +T ServiceTracker::WaitForService() +{ + T object = GetService(); + while (object == 0) + { + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return 0; + } + { + itk::MutexLockHolder lockT(*t); + if (t->Size() == 0) + { + t->Wait(); + } + } + object = GetService(); + } + return object; +} + +template +void ServiceTracker::GetServiceReferences(std::list& refs) const +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return; + } + { + itk::MutexLockHolder lockT(*t); + if (t->Size() == 0) + { + return; + } + t->GetTracked(refs); + } +} + +template +ServiceReference ServiceTracker::GetServiceReference() const +{ + ServiceReference reference(0); + { + MutexLocker lock(d->mutex); + reference = d->cachedReference; + } + if (reference.GetModule() != 0) + { + MITK_DEBUG(d->DEBUG) << "ServiceTracker::getServiceReference[cached]:" + << d->filter; + return reference; + } + MITK_DEBUG(d->DEBUG) << "ServiceTracker::getServiceReference:" << d->filter; + std::list references; + GetServiceReferences(references); + int length = references.size(); + if (length == 0) + { /* if no service is being tracked */ + throw ServiceException("No service is being tracked"); + } + std::list::const_iterator selectedRef; + if (length > 1) + { /* if more than one service, select highest ranking */ + std::vector rankings(length); + int count = 0; + int maxRanking = std::numeric_limits::min(); + std::list::const_iterator refIter = references.begin(); + for (int i = 0; i < length; i++) + { + bool ok = false; + Any rankingAny = refIter->GetProperty(ServiceConstants::SERVICE_RANKING()); + int ranking = 0; + if (rankingAny.Type() == typeid(int)) + { + ranking = any_cast(rankingAny); + ok = true; + } + + rankings[i] = ranking; + if (ranking > maxRanking) + { + selectedRef = refIter; + maxRanking = ranking; + count = 1; + } + else + { + if (ranking == maxRanking) + { + count++; + } + } + } + if (count > 1) + { /* if still more than one service, select lowest id */ + long int minId = std::numeric_limits::max(); + for (int 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; + } + + { + MutexLocker lock(d->mutex); + d->cachedReference = *selectedRef; + return d->cachedReference; + } +} + +template +T ServiceTracker::GetService(const ServiceReference& reference) const +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return 0; + } + { + itk::MutexLockHolder lockT(*t); + return t->GetCustomizedObject(reference); + } +} + +template +void ServiceTracker::GetServices(std::list& services) const +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return; + } + { + itk::MutexLockHolder lockT(*t); + std::list references; + GetServiceReferences(references); + for(std::list::const_iterator ref = references.begin(); + ref != references.end(); ++ref) + { + services.push_back(GetService(*ref)); + } + } +} + +template +T ServiceTracker::GetService() const +{ + T service = d->cachedService; + if (service != 0) + { + MITK_DEBUG(d->DEBUG) << "ServiceTracker::getService[cached]:" + << d->filter; + return service; + } + MITK_DEBUG(d->DEBUG) << "ServiceTracker::getService:" << d->filter; + + try + { + ServiceReference reference = GetServiceReference(); + if (reference.GetModule() == 0) + { + return 0; + } + return d->cachedService = GetService(reference); + } + catch (const ServiceException&) + { + return 0; + } +} + +template +void ServiceTracker::Remove(const ServiceReference& reference) +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return; + } + t->Untrack(reference, ServiceEvent()); +} + +template +int ServiceTracker::Size() const +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return 0; + } + { + itk::MutexLockHolder lockT(*t); + return t->Size(); + } +} + +template +int ServiceTracker::GetTrackingCount() const +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return -1; + } + { + itk::MutexLockHolder lockT(*t); + return t->GetTrackingCount(); + } +} + +template +void ServiceTracker::GetTracked(TrackingMap& map) const +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return; + } + { + itk::MutexLockHolder lockT(*t); + t->CopyEntries(map); + } +} + +template +bool ServiceTracker::IsEmpty() const +{ + itk::SmartPointer<_TrackedService> t = d->Tracked(); + if (t.IsNull()) + { /* if ServiceTracker is not open */ + return true; + } + { + itk::MutexLockHolder lockT(*t); + return t->IsEmpty(); + } +} + +template +T ServiceTracker::AddingService(const ServiceReference& reference) +{ + return dynamic_cast(d->context->GetService(reference)); +} + +template +void ServiceTracker::ModifiedService(const ServiceReference& /*reference*/, T /*service*/) +{ + /* do nothing */ +} + +template +void ServiceTracker::RemovedService(const ServiceReference& reference, T /*service*/) +{ + d->context->UngetService(reference); +} + +} // end namespace mitk diff --git a/Core/Code/Service/mitkServiceTrackerCustomizer.h b/Core/Code/Service/mitkServiceTrackerCustomizer.h new file mode 100644 index 0000000000..8d055dc0db --- /dev/null +++ b/Core/Code/Service/mitkServiceTrackerCustomizer.h @@ -0,0 +1,109 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICETRACKERCUSTOMIZER_H +#define MITKSERVICETRACKERCUSTOMIZER_H + +#include "mitkServiceReference.h" + +namespace mitk { + +/** + * \ingroup MicroServices + * + * The ServiceTrackerCustomizer interface allows a + * ServiceTracker to customize the service objects that are + * tracked. A ServiceTrackerCustomizer is called when a service is + * being added to a ServiceTracker. The + * ServiceTrackerCustomizer can then return an object for the + * tracked service. A ServiceTrackerCustomizer is also called when + * a tracked service is modified or has been removed from a + * ServiceTracker. + * + *

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

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

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

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

+ * This method is called after a service is no longer being tracked by the + * ServiceTracker. + * + * @param reference The reference to the service that has been removed. + * @param service The service object for the specified referenced service. + */ + virtual void RemovedService(const ServiceReference& reference, T service) = 0; +}; + +} + +#endif // MITKSERVICETRACKERCUSTOMIZER_H diff --git a/Core/Code/Service/mitkServiceTrackerPrivate.h b/Core/Code/Service/mitkServiceTrackerPrivate.h new file mode 100644 index 0000000000..a4ccf33b03 --- /dev/null +++ b/Core/Code/Service/mitkServiceTrackerPrivate.h @@ -0,0 +1,170 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICETRACKERPRIVATE_H +#define MITKSERVICETRACKERPRIVATE_H + +#include "mitkServiceReference.h" +#include "mitkLDAPFilter.h" + +#include + +namespace mitk { + +/** + * \ingroup MicroServices + */ +template +class ServiceTrackerPrivate +{ + +public: + + typedef itk::SimpleFastMutexLock MutexType; + + ServiceTrackerPrivate(ServiceTracker* st, + ModuleContext* context, + const ServiceReference& reference, + ServiceTrackerCustomizer* customizer); + + ServiceTrackerPrivate(ServiceTracker* st, + ModuleContext* context, const std::string& clazz, + ServiceTrackerCustomizer* customizer); + + ServiceTrackerPrivate(ServiceTracker* st, + ModuleContext* context, const LDAPFilter& filter, + ServiceTrackerCustomizer* customizer); + + ~ServiceTrackerPrivate(); + + /** + * Returns the list of initial ServiceReferences that will be + * tracked by this ServiceTracker. + * + * @param className The class name with which the service was registered, or + * null for all services. + * @param filterString The filter criteria or null for all + * services. + * @return The list of initial ServiceReferences. + * @throws std::invalid_argument If the specified filterString has an + * invalid syntax. + */ + std::list GetInitialReferences(const std::string& className, + const std::string& filterString); + + /* set this to true to compile in debug messages */ + static const bool DEBUG; // = false; + + /** + * The Module Context used by this ServiceTracker. + */ + ModuleContext* const context; + + /** + * The filter used by this ServiceTracker which specifies the + * search criteria for the services to track. + */ + LDAPFilter filter; + + /** + * The ServiceTrackerCustomizer for this tracker. + */ + ServiceTrackerCustomizer* customizer; + + /** + * Filter string for use when adding the ServiceListener. If this field is + * set, then certain optimizations can be taken since we don't have a user + * supplied filter. + */ + std::string listenerFilter; + + /** + * Class name to be tracked. If this field is set, then we are tracking by + * class name. + */ + std::string trackClass; + + /** + * Reference to be tracked. If this field is set, then we are tracking a + * single ServiceReference. + */ + ServiceReference trackReference; + + /** + * Tracked services: ServiceReference -> customized Object and + * ServiceListenerEntry object + */ + itk::SmartPointer > trackedService; + + /** + * Accessor method for the current TrackedService object. This method is only + * intended to be used by the unsynchronized methods which do not modify the + * trackedService field. + * + * @return The current Tracked object. + */ + itk::SmartPointer > Tracked() const; + + /** + * Called by the TrackedService object whenever the set of tracked services is + * modified. Clears the cache. + */ + /* + * This method must not be synchronized since it is called by TrackedService while + * TrackedService is synchronized. We don't want synchronization interactions + * between the listener thread and the user thread. + */ + void Modified(); + + /** + * Cached ServiceReference for getServiceReference. + */ + mutable ServiceReference cachedReference; + + /** + * Cached service object for GetService. + * + * This field is volatile since it is accessed by multiple threads. + */ + mutable T volatile cachedService; + + mutable MutexType mutex; + +private: + + inline ServiceTracker* q_func() + { + return static_cast *>(q_ptr); + } + + inline const ServiceTracker* q_func() const + { + return static_cast *>(q_ptr); + } + + friend class ServiceTracker; + + ServiceTracker * const q_ptr; + +}; + +} + +#include "mitkServiceTrackerPrivate.tpp" + +#endif // MITKSERVICETRACKERPRIVATE_H diff --git a/Core/Code/Service/mitkServiceTrackerPrivate.tpp b/Core/Code/Service/mitkServiceTrackerPrivate.tpp new file mode 100644 index 0000000000..bc56586828 --- /dev/null +++ b/Core/Code/Service/mitkServiceTrackerPrivate.tpp @@ -0,0 +1,128 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "mitkTrackedService.h" + +#include "mitkModuleContext.h" +#include "mitkLDAPFilter.h" + +#include + +namespace mitk { + +template +const bool ServiceTrackerPrivate::DEBUG = true; + +template +ServiceTrackerPrivate::ServiceTrackerPrivate( + ServiceTracker* st, ModuleContext* context, + const ServiceReference& reference, + ServiceTrackerCustomizer* customizer) + : context(context), customizer(customizer), trackReference(reference), + trackedService(0), cachedReference(0), cachedService(0), q_ptr(st) +{ + this->customizer = customizer ? customizer : q_func(); + this->listenerFilter = std::string("(") + ServiceConstants::SERVICE_ID() + + "=" + any_cast(reference.GetProperty(ServiceConstants::SERVICE_ID())) + ")"; + try + { + this->filter = LDAPFilter(listenerFilter); + } + catch (const std::invalid_argument& e) + { + /* + * we could only get this exception if the ServiceReference was + * invalid + */ + std::invalid_argument ia(std::string("unexpected std::invalid_argument exception: ") + e.what()); + throw ia; + } +} + +template +ServiceTrackerPrivate::ServiceTrackerPrivate( + ServiceTracker* st, + ModuleContext* context, const std::string& clazz, + ServiceTrackerCustomizer* customizer) + : context(context), customizer(customizer), trackClass(clazz), + trackReference(0), trackedService(0), cachedReference(0), + cachedService(0), q_ptr(st) +{ + this->customizer = customizer ? customizer : q_func(); + this->listenerFilter = std::string("(") + mitk::ServiceConstants::OBJECTCLASS() + "=" + + clazz + ")"; + try + { + this->filter = LDAPFilter(listenerFilter); + } + catch (const std::invalid_argument& e) + { + /* + * we could only get this exception if the clazz argument was + * malformed + */ + std::invalid_argument ia( + std::string("unexpected std::invalid_argument exception: ") + e.what()); + throw ia; + } +} + +template +ServiceTrackerPrivate::ServiceTrackerPrivate( + ServiceTracker* st, + ModuleContext* context, const LDAPFilter& filter, + ServiceTrackerCustomizer* customizer) + : context(context), filter(filter), customizer(customizer), + listenerFilter(filter.ToString()), trackReference(0), + trackedService(0), cachedReference(0), cachedService(0), q_ptr(st) +{ + this->customizer = customizer ? customizer : q_func(); + if (context == 0) + { + throw std::invalid_argument("The module context cannot be null."); + } +} + +template +ServiceTrackerPrivate::~ServiceTrackerPrivate() +{ + +} + +template +std::list ServiceTrackerPrivate::GetInitialReferences( + const std::string& className, const std::string& filterString) +{ + return context->GetServiceReferences(className, filterString); +} + +template +itk::SmartPointer > ServiceTrackerPrivate::Tracked() const +{ + return trackedService; +} + +template +void ServiceTrackerPrivate::Modified() +{ + cachedReference = 0; /* clear cached value */ + cachedService = 0; /* clear cached value */ + MITK_DEBUG(DEBUG) << "ServiceTracker::Modified(): " << filter; +} + +} // end namespace mitk diff --git a/Core/Code/Service/mitkServiceUtils.h b/Core/Code/Service/mitkServiceUtils.h new file mode 100644 index 0000000000..9701f9506f --- /dev/null +++ b/Core/Code/Service/mitkServiceUtils.h @@ -0,0 +1,51 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKSERVICEUTILS_H +#define MITKSERVICEUTILS_H + +#ifndef MITK_HAS_HASH_STRING + +#ifdef MITK_HAS_UNORDERED_MAP_H +#include +namespace std { +#else + +#include "mitkItkHashMap.h" +#if defined(__GNUC__) +namespace __gnu_cxx { +#else +namespace itk { +#endif + +#endif // MITK_HAS_UNORDERED_MAP_H + +template<> +struct hash +{ + std::size_t operator()(const std::string& str) const + { + return hash()(str.c_str()); + } +}; + +} + +#endif // MITK_HAS_HASH_STRING + +#endif // MITKSERVICEUTILS_H diff --git a/Core/Code/Service/mitkSharedData.h b/Core/Code/Service/mitkSharedData.h new file mode 100644 index 0000000000..f4f81e5bae --- /dev/null +++ b/Core/Code/Service/mitkSharedData.h @@ -0,0 +1,262 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +Modified version of qshareddata.h from Qt 4.7.3 for MITK. +Original copyright (c) Nokia Corporation. Usage covered by the +GNU Lesser General Public License version 2.1 +(http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and the Nokia Qt +LGPL Exception version 1.1 (file LGPL_EXCEPTION.txt in Qt 4.7.3 package). + +=========================================================================*/ + +#ifndef MITKSHAREDDATA_H +#define MITKSHAREDDATA_H + +#include +#include + +#include +#include "mitkAtomicInt.h" + +namespace mitk { + +template class SharedDataPointer; + +class MITK_CORE_EXPORT SharedData +{ +public: + mutable AtomicInt ref; + + inline SharedData() : ref(0) { } + inline SharedData(const SharedData&) : ref(0) { } + +private: + // using the assignment operator would lead to corruption in the ref-counting + SharedData& operator=(const SharedData&); +}; + +template class SharedDataPointer +{ +public: + typedef T Type; + typedef T* pointer; + + inline void Detach() { if (d && d->ref != 1) Detach_helper(); } + inline T& operator*() { Detach(); return *d; } + inline const T& operator*() const { return *d; } + inline T* operator->() { Detach(); return d; } + inline const T* operator->() const { return d; } + inline operator T*() { Detach(); return d; } + inline operator const T*() const { return d; } + inline T* Data() { Detach(); return d; } + inline const T* Data() const { return d; } + inline const T* ConstData() const { return d; } + + inline bool operator==(const SharedDataPointer& other) const { return d == other.d; } + inline bool operator!=(const SharedDataPointer& other) const { return d != other.d; } + + inline SharedDataPointer() { d = 0; } + inline ~SharedDataPointer() { if (d && !d->ref.Deref()) delete d; } + + explicit SharedDataPointer(T* data); + inline SharedDataPointer(const SharedDataPointer& o) : d(o.d) { if (d) d->ref.Ref(); } + + inline SharedDataPointer & operator=(const SharedDataPointer& o) + { + if (o.d != d) + { + if (o.d) + o.d->ref.Ref(); + T *old = d; + d = o.d; + if (old && !old->ref.Deref()) + delete old; + } + return *this; + } + + inline SharedDataPointer &operator=(T *o) + { + if (o != d) + { + if (o) + o->ref.Ref(); + T *old = d; + d = o; + if (old && !old->ref.Deref()) + delete old; + } + return *this; + } + + inline bool operator!() const { return !d; } + + inline void Swap(SharedDataPointer& other) + { + using std::swap; + swap(d, other.d); + } + +protected: + T* Clone(); + +private: + void Detach_helper(); + + T *d; +}; + +template class ExplicitlySharedDataPointer +{ +public: + typedef T Type; + typedef T* pointer; + + inline T& operator*() const { return *d; } + inline T* operator->() { return d; } + inline T* operator->() const { return d; } + inline T* Data() const { return d; } + inline const T* ConstData() const { return d; } + + inline void Detach() { if (d && d->ref != 1) Detach_helper(); } + + inline void Reset() + { + if(d && !d->ref.Deref()) + delete d; + + d = 0; + } + + inline operator bool () const { return d != 0; } + + inline bool operator==(const ExplicitlySharedDataPointer& other) const { return d == other.d; } + inline bool operator!=(const ExplicitlySharedDataPointer& other) const { return d != other.d; } + inline bool operator==(const T* ptr) const { return d == ptr; } + inline bool operator!=(const T* ptr) const { return d != ptr; } + + inline ExplicitlySharedDataPointer() { d = 0; } + inline ~ExplicitlySharedDataPointer() { if (d && !d->ref.Deref()) delete d; } + + explicit ExplicitlySharedDataPointer(T* data); + inline ExplicitlySharedDataPointer(const ExplicitlySharedDataPointer &o) + : d(o.d) { if (d) d->ref.Ref(); } + + template + inline ExplicitlySharedDataPointer(const ExplicitlySharedDataPointer& o) + : d(static_cast(o.Data())) + { + if(d) + d->ref.Ref(); + } + + inline ExplicitlySharedDataPointer& operator=(const ExplicitlySharedDataPointer& o) + { + if (o.d != d) + { + if (o.d) + o.d->ref.Ref(); + T *old = d; + d = o.d; + if (old && !old->ref.Deref()) + delete old; + } + return *this; + } + + inline ExplicitlySharedDataPointer& operator=(T* o) + { + if (o != d) + { + if (o) + o->ref.Ref(); + T *old = d; + d = o; + if (old && !old->ref.Deref()) + delete old; + } + return *this; + } + + inline bool operator!() const { return !d; } + + inline void Swap(ExplicitlySharedDataPointer& other) + { + using std::swap; + swap(d, other.d); + } + +protected: + T* Clone(); + +private: + void Detach_helper(); + + T *d; +}; + + +template +SharedDataPointer::SharedDataPointer(T* adata) : d(adata) +{ if (d) d->ref.Ref(); } + +template +T* SharedDataPointer::Clone() +{ + return new T(*d); +} + +template +void SharedDataPointer::Detach_helper() +{ + T *x = Clone(); + x->ref.Ref(); + if (!d->ref.Deref()) + delete d; + d = x; +} + +template +T* ExplicitlySharedDataPointer::Clone() +{ + return new T(*d); +} + +template +void ExplicitlySharedDataPointer::Detach_helper() +{ + T *x = Clone(); + x->ref.Ref(); + if (!d->ref.Deref()) + delete d; + d = x; +} + +template +ExplicitlySharedDataPointer::ExplicitlySharedDataPointer(T* adata) + : d(adata) +{ if (d) d->ref.Ref(); } + +template +void swap(mitk::SharedDataPointer& p1, mitk::SharedDataPointer& p2) +{ p1.Swap(p2); } + +template +void swap(mitk::ExplicitlySharedDataPointer& p1, mitk::ExplicitlySharedDataPointer& p2) +{ p1.Swap(p2); } + +} + +#endif // MITKSHAREDDATA_H diff --git a/Core/Code/Service/mitkStaticInit.h b/Core/Code/Service/mitkStaticInit.h new file mode 100644 index 0000000000..86b1634786 --- /dev/null +++ b/Core/Code/Service/mitkStaticInit.h @@ -0,0 +1,123 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +Extracted from qglobal.h from Qt 4.7.3 and adapted for MITK. +Original copyright (c) Nokia Corporation. Usage covered by the +GNU Lesser General Public License version 2.1 +(http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and the Nokia Qt +LGPL Exception version 1.1 (file LGPL_EXCEPTION.txt in Qt 4.7.3 package). + +=========================================================================*/ + +#ifndef MITK_STATIC_INIT_H +#define MITK_STATIC_INIT_H + +#include + +namespace mitk { + +// POD for MITK_GLOBAL_STATIC +template +class GlobalStatic +{ +public: + T* pointer; + bool destroyed; + + // Guards acces to "pointer". If a "atomic pointer" class is available, + // this should be used instead of an explicit mutex. + itk::SimpleFastMutexLock mutex; +}; + +// Created as a function-local static to delete a GlobalStatic +template +class GlobalStaticDeleter +{ +public: + GlobalStatic &globalStatic; + + GlobalStaticDeleter(GlobalStatic &_globalStatic) + : globalStatic(_globalStatic) + { } + + inline ~GlobalStaticDeleter() + { + delete globalStatic.pointer; + globalStatic.pointer = 0; + globalStatic.destroyed = true; + } +}; + +} // namespace mitk + +#define MITK_GLOBAL_STATIC_INIT(TYPE, NAME) \ + static ::mitk::GlobalStatic& this_##NAME() \ + { \ + static ::mitk::GlobalStatic l = \ + { 0, false, itk::SimpleFastMutexLock() }; \ + return l; \ + } + +#define MITK_GLOBAL_STATIC(TYPE, NAME) \ + MITK_GLOBAL_STATIC_INIT(TYPE, NAME) \ + static TYPE *NAME() \ + { \ + if (!this_##NAME().pointer && !this_##NAME().destroyed) \ + { \ + TYPE *x = new TYPE; \ + bool ok = false; \ + { \ + this_##NAME().mutex.Lock(); \ + if (!this_##NAME().pointer) \ + { \ + this_##NAME().pointer = x; \ + ok = true; \ + } \ + this_##NAME().mutex.Unlock(); \ + } \ + if (!ok) \ + delete x; \ + else \ + static ::mitk::GlobalStaticDeleter cleanup(this_##NAME());\ + } \ + return this_##NAME().pointer; \ + } + +#define MITK_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ + MITK_GLOBAL_STATIC_INIT(TYPE, NAME) \ + static TYPE *NAME() \ + { \ + if (!this_##NAME().pointer && !this_##NAME().destroyed) \ + { \ + TYPE *x = new TYPE ARGS; \ + bool ok = false; \ + { \ + this_##NAME().mutex.Lock(); \ + if (!this_##NAME().pointer) \ + { \ + this_##NAME().pointer = x; \ + ok = true; \ + } \ + this_##NAME().mutex.Unlock(); \ + } \ + if (!ok) \ + delete x; \ + else \ + static ::mitk::GlobalStaticDeleter cleanup(this_##NAME());\ + } \ + return this_##NAME().pointer; \ + } + +#endif // MITK_STATIC_INIT_H diff --git a/Core/Code/Service/mitkTrackedService.h b/Core/Code/Service/mitkTrackedService.h new file mode 100644 index 0000000000..56acf94ee3 --- /dev/null +++ b/Core/Code/Service/mitkTrackedService.h @@ -0,0 +1,103 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKTRACKEDSERVICE_H +#define MITKTRACKEDSERVICE_H + +#include "mitkTrackedServiceListener.h" +#include "mitkModuleAbstractTracked.h" +#include "mitkServiceEvent.h" + +namespace mitk { + +/** + * This class is not intended to be used directly. It is exported to support + * the MITK module system. + */ +template +class TrackedService : public TrackedServiceListener, + public ModuleAbstractTracked +{ + +public: + TrackedService(ServiceTracker* serviceTracker, + ServiceTrackerCustomizer* customizer); + + /** + * Method connected to service events for the + * ServiceTracker class. This method must NOT be + * synchronized to avoid deadlock potential. + * + * @param event ServiceEvent object from the framework. + */ + void ServiceChanged(const ServiceEvent& event); + +private: + + typedef ModuleAbstractTracked Superclass; + + ServiceTracker* serviceTracker; + ServiceTrackerCustomizer* customizer; + + /** + * Increment the tracking count and tell the tracker there was a + * modification. + * + * @GuardedBy this + */ + void Modified(); + + /** + * Call the specific customizer adding method. This method must not be + * called while synchronized on this object. + * + * @param item Item to be tracked. + * @param related Action related object. + * @return Customized object for the tracked item or null + * if the item is not to be tracked. + */ + T CustomizerAdding(ServiceReference item, const ServiceEvent& related); + + /** + * Call the specific customizer modified method. This method must not be + * called while synchronized on this object. + * + * @param item Tracked item. + * @param related Action related object. + * @param object Customized object for the tracked item. + */ + void CustomizerModified(ServiceReference item, + const ServiceEvent& related, T object) ; + + /** + * Call the specific customizer removed method. This method must not be + * called while synchronized on this object. + * + * @param item Tracked item. + * @param related Action related object. + * @param object Customized object for the tracked item. + */ + void CustomizerRemoved(ServiceReference item, + const ServiceEvent& related, T object) ; +}; + +} + +#include "mitkTrackedService.tpp" + +#endif // MITKTRACKEDSERVICE_H diff --git a/Core/Code/Service/mitkTrackedService.tpp b/Core/Code/Service/mitkTrackedService.tpp new file mode 100644 index 0000000000..00c46426bd --- /dev/null +++ b/Core/Code/Service/mitkTrackedService.tpp @@ -0,0 +1,119 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +namespace mitk { + +template +TrackedService::TrackedService(ServiceTracker* serviceTracker, + ServiceTrackerCustomizer* customizer) + : serviceTracker(serviceTracker), customizer(customizer) +{ + +} + +template +void TrackedService::ServiceChanged(const ServiceEvent& event) +{ + /* + * Check if we had a delayed call (which could happen when we + * close). + */ + if (this->closed) + { + return; + } + + ServiceReference reference = event.GetServiceReference(); + MITK_DEBUG(serviceTracker->d->DEBUG) << "TrackedService::ServiceChanged[" + << event.GetType() << "]: " << reference; + + switch (event.GetType()) + { + case ServiceEvent::REGISTERED : + case ServiceEvent::MODIFIED : + { + if (!serviceTracker->d->listenerFilter.empty()) + { // service listener added with filter + this->Track(reference, event); + /* + * If the customizer throws an unchecked exception, it + * is safe to let it propagate + */ + } + else + { // service listener added without filter + if (serviceTracker->d->filter.Match(reference)) + { + this->Track(reference, event); + /* + * If the customizer throws an unchecked exception, + * it is safe to let it propagate + */ + } + else + { + this->Untrack(reference, event); + /* + * If the customizer throws an unchecked exception, + * it is safe to let it propagate + */ + } + } + break; + } + case ServiceEvent::MODIFIED_ENDMATCH : + case ServiceEvent::UNREGISTERING : + this->Untrack(reference, event); + /* + * If the customizer throws an unchecked exception, it is + * safe to let it propagate + */ + break; + } +} + +template +void TrackedService::Modified() +{ + Superclass::Modified(); /* increment the modification count */ + serviceTracker->d->Modified(); +} + +template +T TrackedService::CustomizerAdding(ServiceReference item, + const ServiceEvent& /*related*/) +{ + return customizer->AddingService(item); +} + +template +void TrackedService::CustomizerModified(ServiceReference item, + const ServiceEvent& /*related*/, + T object) +{ + customizer->ModifiedService(item, object); +} + +template +void TrackedService::CustomizerRemoved(ServiceReference item, + const ServiceEvent& /*related*/, + T object) +{ + customizer->RemovedService(item, object); +} + +} // end namespace mitk diff --git a/Core/Code/Service/mitkTrackedServiceListener.h b/Core/Code/Service/mitkTrackedServiceListener.h new file mode 100644 index 0000000000..d88d942fc1 --- /dev/null +++ b/Core/Code/Service/mitkTrackedServiceListener.h @@ -0,0 +1,48 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKTRACKEDSERVICELISTENER_H +#define MITKTRACKEDSERVICELISTENER_H + +#include + +#include "mitkServiceEvent.h" + +namespace mitk { + +/** + * This class is not intended to be used directly. It is exported to support + * the MITK module system. + */ +struct TrackedServiceListener : public itk::LightObject +{ + + /** + * Slot connected to service events for the + * ServiceTracker class. This method must NOT be + * synchronized to avoid deadlock potential. + * + * @param event ServiceEvent object from the framework. + */ + virtual void ServiceChanged(const ServiceEvent& event) = 0; + +}; + +} + +#endif // MITKTRACKEDSERVICELISTENER_H diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index baf13522b7..0b705254e3 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,36 +1,38 @@ + MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) # MITK_INSTALL_TARGETS(EXECUTABLES MitkTestDriver) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyGzipFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_CT mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_MR mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_SC mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkEventMapperTest_Test1And2 mitkEventMapperTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.pic.gz) mitkAddCustomModuleTest(mitkStateMachineFactoryTest_TestStateMachine1_2 mitkStateMachineFactoryTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkDicomSeriesReaderTest_CTImage mitkDicomSeriesReaderTest ${MITK_DATA_DIR}/TinyCTAbdomen) ADD_TEST(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) SET_PROPERTY(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) ADD_TEST(mitkPicFileReaderTest_emptyGzipFile ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) SET_PROPERTY(TEST mitkPicFileReaderTest_emptyGzipFile PROPERTY LABELS MITK-Core) ADD_TEST(mitkImageTest_brainImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageTest ${MITK_DATA_DIR}/brain.mhd) SET_PROPERTY(TEST mitkImageTest_brainImage PROPERTY LABELS MITK-Core) # ADD_TEST(mitkImageTest_4DImageData ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageTest ${MITK_DATA_DIR}/US4DCyl.pic.gz) # SET_PROPERTY(TEST mitkImageTest_4DImageData PROPERTY LABELS MITK-Core) ADD_TEST(mitkImageWriterTest_nrrdImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) SET_PROPERTY(TEST mitkImageWriterTest_nrrdImage PROPERTY LABELS MITK-Core) add_subdirectory(DICOMTesting) +add_subdirectory(TestModules) diff --git a/Core/Code/Testing/TestModules/CMakeLists.txt b/Core/Code/Testing/TestModules/CMakeLists.txt new file mode 100644 index 0000000000..4364c60eeb --- /dev/null +++ b/Core/Code/Testing/TestModules/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(libA) +add_subdirectory(libA2) +add_subdirectory(libSL1) +add_subdirectory(libSL3) +add_subdirectory(libSL4) diff --git a/Core/Code/Testing/TestModules/libA/CMakeLists.txt b/Core/Code/Testing/TestModules/libA/CMakeLists.txt new file mode 100644 index 0000000000..45b499309a --- /dev/null +++ b/Core/Code/Testing/TestModules/libA/CMakeLists.txt @@ -0,0 +1,5 @@ + +MITK_CREATE_MODULE(TestModuleA + DEPENDS Mitk) + +add_dependencies(${TESTDRIVER} TestModuleA) diff --git a/Core/Code/Testing/TestModules/libA/files.cmake b/Core/Code/Testing/TestModules/libA/files.cmake new file mode 100644 index 0000000000..1ca4954517 --- /dev/null +++ b/Core/Code/Testing/TestModules/libA/files.cmake @@ -0,0 +1,5 @@ +set(H_FILES ) + +set(CPP_FILES + mitkTestModuleA.cpp +) diff --git a/Core/Code/Testing/TestModules/libA/mitkTestModuleA.cpp b/Core/Code/Testing/TestModules/libA/mitkTestModuleA.cpp new file mode 100644 index 0000000000..a9baa930c1 --- /dev/null +++ b/Core/Code/Testing/TestModules/libA/mitkTestModuleA.cpp @@ -0,0 +1,60 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkTestModuleAService.h" + +#include + +#include +#include + +namespace mitk { + +struct TestModuleA : public itk::LightObject, public TestModuleAService +{ + + TestModuleA(ModuleContext* mc) + { + MITK_INFO << "Registering TestModuleAService"; + mc->RegisterService(this); + } + +}; + +class TestModuleAActivator : public ModuleActivator +{ +public: + + void Load(ModuleContext* context) + { + s = new TestModuleA(context); + } + + void Unload(ModuleContext*) + { + + } + +private: + + itk::SmartPointer s; +}; + +} + +MITK_EXPORT_MODULE_ACTIVATOR(TestModuleA, mitk::TestModuleAActivator) + diff --git a/Core/Code/Testing/TestModules/libA/mitkTestModuleAService.h b/Core/Code/Testing/TestModules/libA/mitkTestModuleAService.h new file mode 100644 index 0000000000..3df74eaf90 --- /dev/null +++ b/Core/Code/Testing/TestModules/libA/mitkTestModuleAService.h @@ -0,0 +1,35 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKTESTMODULEASERVICE_H +#define MITKTESTMODULEASERVICE_H + +#include + +namespace mitk { + +struct TestModuleAService +{ + virtual ~TestModuleAService() {} +}; + +} + +MITK_DECLARE_SERVICE_INTERFACE(mitk::TestModuleAService, "org.mitk.TestModuleAService") + +#endif // MITKTESTMODULEASERVICE_H diff --git a/Core/Code/Testing/TestModules/libA2/CMakeLists.txt b/Core/Code/Testing/TestModules/libA2/CMakeLists.txt new file mode 100644 index 0000000000..56fbd7af24 --- /dev/null +++ b/Core/Code/Testing/TestModules/libA2/CMakeLists.txt @@ -0,0 +1,5 @@ + +MITK_CREATE_MODULE(TestModuleA2 + DEPENDS Mitk) + +add_dependencies(${TESTDRIVER} TestModuleA2) diff --git a/Core/Code/Testing/TestModules/libA2/files.cmake b/Core/Code/Testing/TestModules/libA2/files.cmake new file mode 100644 index 0000000000..6cd482f4cb --- /dev/null +++ b/Core/Code/Testing/TestModules/libA2/files.cmake @@ -0,0 +1,5 @@ +set(H_FILES ) + +set(CPP_FILES + mitkTestModuleA2.cpp +) diff --git a/Core/Code/Testing/TestModules/libA2/mitkTestModuleA2.cpp b/Core/Code/Testing/TestModules/libA2/mitkTestModuleA2.cpp new file mode 100644 index 0000000000..8e9f778b4d --- /dev/null +++ b/Core/Code/Testing/TestModules/libA2/mitkTestModuleA2.cpp @@ -0,0 +1,71 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkTestModuleA2Service.h" + +#include + +#include +#include + +namespace mitk { + +struct TestModuleA2 : public itk::LightObject, public TestModuleA2Service +{ + + TestModuleA2(ModuleContext* mc) + { + MITK_INFO << "Registering TestModuleA2Service"; + sr = mc->RegisterService(this); + } + + void Unregister() + { + if (sr) + { + sr.Unregister(); + } + } + +private: + + ServiceRegistration sr; +}; + +class TestModuleA2Activator : public ModuleActivator +{ +public: + + void Load(ModuleContext* context) + { + s = new TestModuleA2(context); + } + + void Unload(ModuleContext* /*context*/) + { + s->Unregister(); + } + +private: + + itk::SmartPointer s; +}; + +} + +MITK_EXPORT_MODULE_ACTIVATOR(TestModuleA2, mitk::TestModuleA2Activator) + diff --git a/Core/Code/Testing/TestModules/libA2/mitkTestModuleA2Service.h b/Core/Code/Testing/TestModules/libA2/mitkTestModuleA2Service.h new file mode 100644 index 0000000000..5249cf31e2 --- /dev/null +++ b/Core/Code/Testing/TestModules/libA2/mitkTestModuleA2Service.h @@ -0,0 +1,35 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKTESTMODULEA2SERVICE_H +#define MITKTESTMODULEA2SERVICE_H + +#include + +namespace mitk { + +struct TestModuleA2Service +{ + virtual ~TestModuleA2Service() {} +}; + +} + +MITK_DECLARE_SERVICE_INTERFACE(mitk::TestModuleA2Service, "org.mitk.TestModuleA2Service") + +#endif // MITKTESTMODULEA2SERVICE_H diff --git a/Core/Code/Testing/TestModules/libSL1/CMakeLists.txt b/Core/Code/Testing/TestModules/libSL1/CMakeLists.txt new file mode 100644 index 0000000000..284f7811e1 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL1/CMakeLists.txt @@ -0,0 +1,4 @@ +MITK_CREATE_MODULE(TestModuleSL1 + DEPENDS Mitk) + +add_dependencies(${TESTDRIVER} TestModuleSL1) diff --git a/Core/Code/Testing/TestModules/libSL1/files.cmake b/Core/Code/Testing/TestModules/libSL1/files.cmake new file mode 100644 index 0000000000..b2c1639489 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL1/files.cmake @@ -0,0 +1,7 @@ +set(H_FILES + mitkFooService.h +) + +set(CPP_FILES + mitkActivatorSL1.cpp +) diff --git a/Core/Code/Testing/TestModules/libSL1/mitkActivatorSL1.cpp b/Core/Code/Testing/TestModules/libSL1/mitkActivatorSL1.cpp new file mode 100644 index 0000000000..85eadda1c9 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL1/mitkActivatorSL1.cpp @@ -0,0 +1,103 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include + +#include +#include + +#include +#include + +#include "mitkFooService.h" + +namespace mitk { + +class ActivatorSL1 : + public itk::LightObject, public ModuleActivator, public ModulePropsInterface, + public ServiceTrackerCustomizer +{ + +public: + + ActivatorSL1() + : tracker(0), context(0) + { + + } + + ~ActivatorSL1() + { + delete tracker; + --m_ReferenceCount; + } + + void Load(ModuleContext* context) + { + this->context = context; + + context->RegisterService("mitk::ActivatorSL1", this); + + delete tracker; + tracker = new FooTracker(context, this); + tracker->Open(); + } + + void Unload(ModuleContext* /*context*/) + { + tracker->Close(); + } + + const Properties& GetProperties() const + { + return props; + } + + FooService* AddingService(const ServiceReference& reference) + { + props["serviceAdded"] = true; + + FooService* fooService = context->GetService(reference); + fooService->foo(); + return fooService; + } + + void ModifiedService(const ServiceReference& /*reference*/, FooService* /*service*/) + {} + + void RemovedService(const ServiceReference& /*reference*/, FooService* /*service*/) + { + props["serviceRemoved"] = true; + } + +private: + + ModulePropsInterface::Properties props; + + typedef ServiceTracker FooTracker; + + FooTracker* tracker; + ModuleContext* context; + +}; // ActivatorSL1 + +} // end namespace mitk + +MITK_EXPORT_MODULE_ACTIVATOR(TestModuleSL1, mitk::ActivatorSL1) + + diff --git a/Core/Code/Testing/TestModules/libSL1/mitkFooService.h b/Core/Code/Testing/TestModules/libSL1/mitkFooService.h new file mode 100644 index 0000000000..20989176d7 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL1/mitkFooService.h @@ -0,0 +1,36 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKFOOSERVICE_H +#define MITKFOOSERVICE_H + +#include + +namespace mitk { + +struct FooService +{ + virtual ~FooService() {} + virtual void foo() = 0; +}; + +} + +MITK_DECLARE_SERVICE_INTERFACE(mitk::FooService, "org.mitk.testing.FooService") + +#endif // MITKFOOSERVICE_H diff --git a/Core/Code/Testing/TestModules/libSL3/CMakeLists.txt b/Core/Code/Testing/TestModules/libSL3/CMakeLists.txt new file mode 100644 index 0000000000..cf106c4916 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL3/CMakeLists.txt @@ -0,0 +1,6 @@ +MITK_CREATE_MODULE(TestModuleSL3 + DEPENDS Mitk + INTERNAL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../libSL1" +) + +add_dependencies(${TESTDRIVER} TestModuleSL3) diff --git a/Core/Code/Testing/TestModules/libSL3/files.cmake b/Core/Code/Testing/TestModules/libSL3/files.cmake new file mode 100644 index 0000000000..6f2bcba46a --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL3/files.cmake @@ -0,0 +1,7 @@ +set(H_FILES + +) + +set(CPP_FILES + mitkActivatorSL3.cpp +) diff --git a/Core/Code/Testing/TestModules/libSL3/mitkActivatorSL3.cpp b/Core/Code/Testing/TestModules/libSL3/mitkActivatorSL3.cpp new file mode 100644 index 0000000000..4e7f960702 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL3/mitkActivatorSL3.cpp @@ -0,0 +1,93 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +namespace mitk { + +class ActivatorSL3 : + public itk::LightObject, public ModuleActivator, public ModulePropsInterface, + public ServiceTrackerCustomizer +{ + +public: + + ActivatorSL3() : tracker(0), context(0) {} + + ~ActivatorSL3() + { delete tracker; --m_ReferenceCount; } + + void Load(ModuleContext* context) + { + this->context = context; + + context->RegisterService("mitk::ActivatorSL3", this); + 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 ServiceReference& reference) + { + props["serviceAdded"] = true; + MITK_INFO << "SL3: Adding reference =" << reference; + + FooService* fooService = context->GetService(reference); + fooService->foo(); + return fooService; + } + + void ModifiedService(const ServiceReference& /*reference*/, FooService* /*service*/) + { + + } + + void RemovedService(const ServiceReference& reference, FooService* /*service*/) + { + props["serviceRemoved"] = true; + MITK_INFO << "SL3: Removing reference =" << reference; + } + +private: + + typedef ServiceTracker FooTracker; + FooTracker* tracker; + ModuleContext* context; + + ModulePropsInterface::Properties props; + +}; + +} + +MITK_EXPORT_MODULE_ACTIVATOR(TestModuleSL3, mitk::ActivatorSL3) + + diff --git a/Core/Code/Testing/TestModules/libSL4/CMakeLists.txt b/Core/Code/Testing/TestModules/libSL4/CMakeLists.txt new file mode 100644 index 0000000000..5ea9355c85 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL4/CMakeLists.txt @@ -0,0 +1,6 @@ +MITK_CREATE_MODULE(TestModuleSL4 + DEPENDS Mitk + INTERNAL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../libSL1" +) + +add_dependencies(${TESTDRIVER} TestModuleSL4) diff --git a/Core/Code/Testing/TestModules/libSL4/files.cmake b/Core/Code/Testing/TestModules/libSL4/files.cmake new file mode 100644 index 0000000000..b10793d5f8 --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL4/files.cmake @@ -0,0 +1,7 @@ +set(H_FILES + +) + +set(CPP_FILES + mitkActivatorSL4.cpp +) diff --git a/Core/Code/Testing/TestModules/libSL4/mitkActivatorSL4.cpp b/Core/Code/Testing/TestModules/libSL4/mitkActivatorSL4.cpp new file mode 100644 index 0000000000..ad45511ece --- /dev/null +++ b/Core/Code/Testing/TestModules/libSL4/mitkActivatorSL4.cpp @@ -0,0 +1,60 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include + +#include +#include +#include + +#include + +namespace mitk { + +class ActivatorSL4 : + public itk::LightObject, public ModuleActivator, public FooService +{ + +public: + + ~ActivatorSL4() + { + --m_ReferenceCount; + } + + void foo() + { + MITK_INFO << "TestModuleSL4: Doing foo"; + } + + void Load(ModuleContext* context) + { + ServiceRegistration registration = + context->RegisterService(this); + MITK_INFO << "TestModuleSL4: Registered" << registration; + } + + void Unload(ModuleContext* /*context*/) + { + //unregister will be done automagically + } + +}; + +} + +MITK_EXPORT_MODULE_ACTIVATOR(TestModuleSL4, mitk::ActivatorSL4) diff --git a/Core/Code/Testing/files.cmake b/Core/Code/Testing/files.cmake index 1d7df8917e..21114146e6 100644 --- a/Core/Code/Testing/files.cmake +++ b/Core/Code/Testing/files.cmake @@ -1,95 +1,117 @@ # tests with no extra command line parameter SET(MODULE_TESTS mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkPointSetWriterTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkEnumerationPropertyTest.cpp mitkEventTest.cpp mitkFocusManagerTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkGlobalInteractionTest.cpp mitkImageDataItemTest.cpp #mitkImageMapper2DTest.cpp mitkImageGeneratorTest.cpp mitkBaseDataTest.cpp #mitkImageToItkTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkInteractorTest.cpp mitkITKThreadingTest.cpp + mitkLDAPFilterTest.cpp # mitkLevelWindowManagerTest.cpp mitkLevelWindowTest.cpp mitkMessageTest.cpp + mitkModuleTest.cpp #mitkPipelineSmartPointerCorrectnessTest.cpp mitkPixelTypeTest.cpp mitkPlaneGeometryTest.cpp mitkPointSetFileIOTest.cpp mitkPointSetTest.cpp mitkPointSetInteractorTest.cpp mitkPropertyListTest.cpp #mitkRegistrationBaseTest.cpp #mitkSegmentationInterpolationTest.cpp + mitkServiceListenerTest.cpp mitkSlicedGeometry3DTest.cpp mitkSliceNavigationControllerTest.cpp mitkStateMachineTest.cpp mitkStateTest.cpp mitkSurfaceTest.cpp mitkSurfaceToSurfaceFilterTest.cpp mitkTimeSlicedGeometryTest.cpp mitkTransitionTest.cpp mitkUndoControllerTest.cpp mitkVtkWidgetRenderingTest.cpp mitkVerboseLimitedLinearUndoTest.cpp mitkWeakPointerTest.cpp mitkTransferFunctionTest.cpp #mitkAbstractTransformGeometryTest.cpp #mitkPicFileIOTest.cpp mitkStepperTest.cpp itkTotalVariationDenoisingImageFilterTest.cpp mitkRenderingManagerTest.cpp vtkMitkThickSlicesFilterTest.cpp mitkNodePredicateSourceTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp ) # test with image filename as an extra command line parameter SET(MODULE_IMAGE_TESTS mitkSurfaceVtkWriterTest.cpp mitkPicFileWriterTest.cpp #mitkImageSliceSelectorTest.cpp mitkImageTimeSelectorTest.cpp mitkPicFileReaderTest.cpp # mitkVtkPropRendererTest.cpp mitkDataNodeFactoryTest.cpp #mitkSTLFileReaderTest.cpp ) # list of images for which the tests are run SET(MODULE_TESTIMAGES US4DCyl.pic.gz Pic3D.pic.gz Pic2DplusT.pic.gz BallBinary30x30x30.pic.gz binary.stl ball.stl ) SET(MODULE_CUSTOM_TESTS #mitkLabeledImageToSurfaceFilterTest.cpp #mitkExternalToolsTest.cpp mitkDataStorageTest.cpp mitkDataNodeTest.cpp mitkDicomSeriesReaderTest.cpp mitkDICOMLocaleTest.cpp mitkEventMapperTest.cpp mitkNodeDependentPointSetInteractorTest.cpp mitkStateMachineFactoryTest.cpp mitkPointSetLocaleTest.cpp mitkImageTest.cpp - mitkImageWriterTest.cpp + mitkImageWriterTest.cpp ) + +# Create an artificial module initializing class for +# the mitkServiceListenerTest.cpp + +SET(module_name_orig ${MODULE_NAME}) +SET(module_libname_orig ${MODULE_LIBNAME}) +SET(MODULE_NAME "${MODULE_NAME}TestDriver") +SET(MODULE_LIBNAME "") +SET(MODULE_DEPENDS_STR "Mitk") +SET(MODULE_PACKAGE_DEPENDS_STR "") +SET(MODULE_VERSION "0.1.0") +SET(MODULE_QT_BOOL "false") + +SET(testdriver_init_file "${CMAKE_CURRENT_BINARY_DIR}/MitkTestDriver_init.cpp") +CONFIGURE_FILE("${MITK_SOURCE_DIR}/CMake/mitkModuleInit.cpp" ${testdriver_init_file} @ONLY) +SET(TEST_CPP_FILES ${testdriver_init_file}) + +SET(MODULE_NAME ${module_name_orig}) +SET(MODULE_LIBNAME ${module_libname_orig}) diff --git a/Core/Code/Testing/mitkLDAPFilterTest.cpp b/Core/Code/Testing/mitkLDAPFilterTest.cpp new file mode 100644 index 0000000000..70f729c9ec --- /dev/null +++ b/Core/Code/Testing/mitkLDAPFilterTest.cpp @@ -0,0 +1,142 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include + +#include + +int TestParsing() +{ + // WELL FORMED Expr + try + { + MITK_TEST_OUTPUT(<< "Parsing (cn=Babs Jensen)") + mitk::LDAPFilter ldap( "(cn=Babs Jensen)" ); + MITK_TEST_OUTPUT(<< "Parsing (!(cn=Tim Howes))") + ldap = mitk::LDAPFilter( "(!(cn=Tim Howes))" ); + MITK_TEST_OUTPUT(<< "Parsing " << std::string("(&(") + mitk::ServiceConstants::OBJECTCLASS() + "=Person)(|(sn=Jensen)(cn=Babs J*)))") + ldap = mitk::LDAPFilter( std::string("(&(") + mitk::ServiceConstants::OBJECTCLASS() + "=Person)(|(sn=Jensen)(cn=Babs J*)))" ); + MITK_TEST_OUTPUT(<< "Parsing (o=univ*of*mich*)") + ldap = mitk::LDAPFilter( "(o=univ*of*mich*)" ); + } + catch (const std::invalid_argument& e) + { + MITK_TEST_OUTPUT(<< e.what()); + return EXIT_FAILURE; + } + + + // MALFORMED Expr + try + { + MITK_TEST_OUTPUT( << "Parsing malformed expr: cn=Babs Jensen)") + mitk::LDAPFilter ldap( "cn=Babs Jensen)" ); + return EXIT_FAILURE; + } + catch (const std::invalid_argument&) + { + } + + return EXIT_SUCCESS; +} + + +int TestEvaluate() +{ + // EVALUATE + try + { + mitk::LDAPFilter ldap( "(Cn=Babs Jensen)" ); + mitk::ServiceProperties props; + bool eval = false; + + // Several values + props["cn"] = std::string("Babs Jensen"); + props["unused"] = std::string("Jansen"); + MITK_TEST_OUTPUT(<< "Evaluating expr: " << ldap.ToString()) + eval = ldap.Match(props); + if (!eval) + { + return EXIT_FAILURE; + } + + // WILDCARD + ldap = mitk::LDAPFilter( "(cn=Babs *)" ); + props.clear(); + props["cn"] = std::string("Babs Jensen"); + MITK_TEST_OUTPUT(<< "Evaluating wildcard expr: " << ldap.ToString()) + eval = ldap.Match(props); + if ( !eval ) + { + return EXIT_FAILURE; + } + + // NOT FOUND + ldap = mitk::LDAPFilter( "(cn=Babs *)" ); + props.clear(); + props["unused"] = std::string("New"); + MITK_TEST_OUTPUT(<< "Expr not found test: " << ldap.ToString()) + eval = ldap.Match(props); + if ( eval ) + { + return EXIT_FAILURE; + } + + // std::vector with integer values + ldap = mitk::LDAPFilter( " ( |(cn=Babs *)(sn=1) )" ); + props.clear(); + std::vector list; + list.push_back(std::string("Babs Jensen")); + list.push_back(std::string("1")); + props["sn"] = list; + MITK_TEST_OUTPUT(<< "Evaluating vector expr: " << ldap.ToString()) + eval = ldap.Match(props); + if (!eval) + { + return EXIT_FAILURE; + } + + // wrong case + ldap = mitk::LDAPFilter( "(cN=Babs *)" ); + props.clear(); + props["cn"] = std::string("Babs Jensen"); + MITK_TEST_OUTPUT(<< "Evaluating case sensitive expr: " << ldap.ToString()) + eval = ldap.MatchCase(props); + if (eval) + { + return EXIT_FAILURE; + } + } + catch (const std::invalid_argument& e) + { + MITK_TEST_OUTPUT( << e.what() ) + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int mitkLDAPFilterTest(int /*argc*/, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("LDAPFilterTest"); + + MITK_TEST_CONDITION(TestParsing() == EXIT_SUCCESS, "Parsing LDAP expressions: ") + MITK_TEST_CONDITION(TestEvaluate() == EXIT_SUCCESS, "Evaluating LDAP expressions: ") + + MITK_TEST_END() +} + diff --git a/Core/Code/Testing/mitkModulePropsInterface.h b/Core/Code/Testing/mitkModulePropsInterface.h new file mode 100644 index 0000000000..befb63f090 --- /dev/null +++ b/Core/Code/Testing/mitkModulePropsInterface.h @@ -0,0 +1,40 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef MITKMODULEPROPSINTERFACE_H +#define MITKMODULEPROPSINTERFACE_H + +#include +#include + +namespace mitk { + +struct ModulePropsInterface +{ + typedef ServiceProperties Properties; + + virtual ~ModulePropsInterface() {} + + virtual const Properties& GetProperties() const = 0; +}; + +} + +MITK_DECLARE_SERVICE_INTERFACE(mitk::ModulePropsInterface, "org.mitk.testing.ModulePropsInterface") + +#endif // MITKMODULEPROPSINTERFACE_H diff --git a/Core/Code/Testing/mitkModuleTest.cpp b/Core/Code/Testing/mitkModuleTest.cpp new file mode 100644 index 0000000000..e8b7d68bad --- /dev/null +++ b/Core/Code/Testing/mitkModuleTest.cpp @@ -0,0 +1,353 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include "mitkTestUtilSharedLibrary.cpp" + +#include + +class ModuleListener { + +public: + + ModuleListener(mitk::ModuleContext* mc) : mc(mc) + {} + + void ModuleChanged(const mitk::ModuleEvent& event) + { + moduleEvents.push_back(event); + MITK_DEBUG << "ModuleEvent:" << event; + } + + void ServiceChanged(const mitk::ServiceEvent& event) + { + serviceEvents.push_back(event); + MITK_DEBUG << "ServiceEvent:" << event; + } + + mitk::ModuleEvent GetModuleEvent() const + { + if (moduleEvents.empty()) + { + return mitk::ModuleEvent(); + } + return moduleEvents.back(); + } + + mitk::ServiceEvent GetServiceEvent() const + { + if (serviceEvents.empty()) + { + return mitk::ServiceEvent(); + } + return serviceEvents.back(); + } + + bool CheckListenerEvents( + bool pexp, mitk::ModuleEvent::Type ptype, + bool sexp, mitk::ServiceEvent::Type stype, + mitk::Module* moduleX, mitk::ServiceReference* servX) + { + std::vector pEvts; + std::vector seEvts; + + if (pexp) pEvts.push_back(mitk::ModuleEvent(ptype, moduleX)); + if (sexp) seEvts.push_back(mitk::ServiceEvent(stype, *servX)); + + return CheckListenerEvents(pEvts, seEvts); + } + + bool CheckListenerEvents( + const std::vector& pEvts, + const std::vector& seEvts) + { + bool listenState = true; // assume everything will work + + if (pEvts.size() != moduleEvents.size()) + { + listenState = false; + MITK_DEBUG << "*** Module event mismatch: expected " + << pEvts.size() << " event(s), found " + << moduleEvents.size() << " event(s)."; + + const std::size_t max = pEvts.size() > moduleEvents.size() ? pEvts.size() : moduleEvents.size(); + for (std::size_t i = 0; i < max; ++i) + { + const mitk::ModuleEvent& pE = i < pEvts.size() ? pEvts[i] : mitk::ModuleEvent(); + const mitk::ModuleEvent& pR = i < moduleEvents.size() ? moduleEvents[i] : mitk::ModuleEvent(); + MITK_DEBUG << " " << pE << " - " << pR; + } + } + else + { + for (std::size_t i = 0; i < pEvts.size(); ++i) + { + const mitk::ModuleEvent& pE = pEvts[i]; + const mitk::ModuleEvent& pR = moduleEvents[i]; + if (pE.GetType() != pR.GetType() + || pE.GetModule() != pR.GetModule()) + { + listenState = false; + MITK_DEBUG << "*** Wrong module event: " << pR << " expected " << pE; + } + } + } + + if (seEvts.size() != serviceEvents.size()) + { + listenState = false; + MITK_DEBUG << "*** Service event mismatch: expected " + << seEvts.size() << " event(s), found " + << serviceEvents.size() << " event(s)."; + + const std::size_t max = seEvts.size() > serviceEvents.size() + ? seEvts.size() : serviceEvents.size(); + for (std::size_t i = 0; i < max; ++i) + { + const mitk::ServiceEvent& seE = i < seEvts.size() ? seEvts[i] : mitk::ServiceEvent(); + const mitk::ServiceEvent& seR = i < serviceEvents.size() ? serviceEvents[i] : mitk::ServiceEvent(); + MITK_DEBUG << " " << seE << " - " << seR; + } + } + else + { + for (std::size_t i = 0; i < seEvts.size(); ++i) + { + const mitk::ServiceEvent& seE = seEvts[i]; + const mitk::ServiceEvent& seR = serviceEvents[i]; + if (seE.GetType() != seR.GetType() + || (!(seE.GetServiceReference() == seR.GetServiceReference()))) + { + listenState = false; + MITK_DEBUG << "*** Wrong service event: " << seR << " expected " << seE; + } + } + } + + moduleEvents.clear(); + serviceEvents.clear(); + return listenState; + } + +private: + + mitk::ModuleContext* const mc; + + std::vector serviceEvents; + std::vector moduleEvents; +}; + +// Verify information from the ModuleInfo struct +void frame005a(mitk::ModuleContext* mc) +{ + mitk::Module* m = mc->GetModule(); + + // check expected headers + + MITK_TEST_CONDITION("MitkTestDriver" == m->GetName(), "Test module name"); +// MITK_DEBUG << "Version: " << m->GetVersion(); + MITK_TEST_CONDITION(mitk::ModuleVersion(0,1,0) == m->GetVersion(), "Test module version") +} + +// Get context id, location and status of the module +void frame010a(mitk::ModuleContext* mc) +{ + mitk::Module* m = mc->GetModule(); + + long int contextid = m->GetModuleId(); + MITK_DEBUG << "CONTEXT ID:" << contextid; + + std::string location = m->GetLocation(); + MITK_DEBUG << "LOCATION:" << location; + MITK_TEST_CONDITION(!location.empty(), "Test for non-empty module location") + + MITK_TEST_CONDITION(m->IsLoaded(), "Test for loaded flag") +} + +//---------------------------------------------------------------------------- +//Test result of GetService(mitk::ServiceReference()). Should throw std::invalid_argument +void frame018a(mitk::ModuleContext* mc) +{ + try + { + itk::LightObject* obj = mc->GetService(mitk::ServiceReference()); + MITK_DEBUG << "Got service object = " << obj->GetNameOfClass() << ", excpected std::invalid_argument exception"; + MITK_TEST_FAILED_MSG(<< "Got service object, excpected std::invalid_argument exception") + } + catch (const std::invalid_argument& ) + {} + catch (...) + { + MITK_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 +void frame020a(mitk::ModuleContext* mc, ModuleListener& listener, mitk::SharedLibraryHandle& libA) +{ + try + { + libA.Load(); + } + catch (const std::exception& e) + { + MITK_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) + } + + mitk::Module* moduleA = mitk::ModuleRegistry::GetModule("TestModuleA"); + MITK_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for existing moudle TestModuleA") + + MITK_TEST_CONDITION(moduleA->GetName() == "TestModuleA", "Test module name") + + // Check if libA registered the expected service + try + { + mitk::ServiceReference sr1 = mc->GetServiceReference("org.mitk.TestModuleAService"); + itk::LightObject* o1 = mc->GetService(sr1); + MITK_TEST_CONDITION(o1 != 0, "Test if service object found"); + + try + { + MITK_TEST_CONDITION(mc->UngetService(sr1), "Test if Service UnGet returns true"); + } + catch (const std::logic_error le) + { + MITK_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) + } + + // check the listeners for events + std::vector pEvts; + pEvts.push_back(mitk::ModuleEvent(mitk::ModuleEvent::LOADING, moduleA)); + pEvts.push_back(mitk::ModuleEvent(mitk::ModuleEvent::LOADED, moduleA)); + + std::vector seEvts; + seEvts.push_back(mitk::ServiceEvent(mitk::ServiceEvent::REGISTERED, sr1)); + + MITK_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); + + } + catch (const mitk::ServiceException& /*se*/) + { + MITK_TEST_FAILED_MSG(<< "test moudle, expected service not found"); + } + + MITK_TEST_CONDITION(moduleA->IsLoaded() == true, "Test if loaded correctly"); +} + + +// Unload libA and check for correct events +void frame030b(mitk::ModuleContext* mc, ModuleListener& listener, mitk::SharedLibraryHandle& libA) +{ + mitk::Module* moduleA = mitk::ModuleRegistry::GetModule("TestModuleA"); + MITK_TEST_CONDITION_REQUIRED(moduleA != 0, "Test for non-null module") + + mitk::ServiceReference sr1 + = mc->GetServiceReference("org.mitk.TestModuleAService"); + MITK_TEST_CONDITION(sr1, "Test for valid service reference") + + try + { + libA.Unload(); + MITK_TEST_CONDITION(moduleA->IsLoaded() == false, "Test for unloaded state") + } + catch (const std::exception& e) + { + MITK_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) + } + + std::vector pEvts; + pEvts.push_back(mitk::ModuleEvent(mitk::ModuleEvent::UNLOADING, moduleA)); + pEvts.push_back(mitk::ModuleEvent(mitk::ModuleEvent::UNLOADED, moduleA)); + + std::vector seEvts; + seEvts.push_back(mitk::ServiceEvent(mitk::ServiceEvent::UNREGISTERING, sr1)); + + MITK_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); +} + + +struct LocalListener { + void ServiceChanged(const mitk::ServiceEvent&) {} +}; + +// Add a service listener with a broken LDAP filter to Get an exception +void frame045a(mitk::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 (...) + { + MITK_TEST_FAILED_MSG(<< "test module, wrong exception on broken LDAP filter:"); + } +} + + +int mitkModuleTest(int /*argc*/, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("ModuleTest"); + + mitk::ModuleContext* mc = mitk::GetModuleContext(); + ModuleListener listener(mc); + + try + { + mc->AddModuleListener(&listener, &ModuleListener::ModuleChanged); + } + catch (const std::logic_error& ise) + { + MITK_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); + throw; + } + + try + { + mc->AddServiceListener(&listener, &ModuleListener::ServiceChanged); + } + catch (const std::logic_error& ise) + { + MITK_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); + throw; + } + + frame005a(mc); + frame010a(mc); + frame018a(mc); + + mitk::SharedLibraryHandle libA("TestModuleA"); + frame020a(mc, listener, libA); + frame030b(mc, listener, libA); + + frame045a(mc); + + mc->RemoveModuleListener(&listener, &ModuleListener::ModuleChanged); + mc->RemoveServiceListener(&listener, &ModuleListener::ServiceChanged); + + MITK_TEST_END() +} diff --git a/Core/Code/Testing/mitkServiceListenerTest.cpp b/Core/Code/Testing/mitkServiceListenerTest.cpp new file mode 100644 index 0000000000..91cf2b197e --- /dev/null +++ b/Core/Code/Testing/mitkServiceListenerTest.cpp @@ -0,0 +1,506 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include + +#include +#include +#include + +#include + +#include "mitkTestUtilSharedLibrary.cpp" + + +class ServiceListener +{ + +private: + + friend bool runLoadUnloadTest(const std::string&, int cnt, mitk::SharedLibraryHandle&, + const std::vector&); + + const bool checkUsingModules; + std::vector events; + + bool teststatus; + + mitk::ModuleContext* mc; + +public: + + ServiceListener(mitk::ModuleContext* mc, bool checkUsingModules = true) + : checkUsingModules(checkUsingModules), teststatus(true), mc(mc) + {} + + bool getTestStatus() const + { + return teststatus; + } + + void clearEvents() + { + events.clear(); + } + + bool checkEvents(const std::vector& eventTypes) + { + if (events.size() != eventTypes.size()) + { + dumpEvents(eventTypes); + return false; + } + + for (std::size_t i=0; i < eventTypes.size(); ++i) + { + if (eventTypes[i] != events[i].GetType()) + { + dumpEvents(eventTypes); + return false; + } + } + return true; + } + + void serviceChanged(const mitk::ServiceEvent& evt) + { + events.push_back(evt); + MITK_TEST_OUTPUT( << "ServiceEvent: " << evt ); + if (mitk::ServiceEvent::UNREGISTERING == evt.GetType()) + { + mitk::ServiceReference sr = evt.GetServiceReference(); + + // Validate that no module is marked as using the service + std::vector usingModules; + sr.GetUsingModules(usingModules); + if (checkUsingModules && !usingModules.empty()) + { + teststatus = false; + printUsingModules(sr, "*** Using modules (unreg) should be empty but is: "); + } + + // Check if the service can be fetched + itk::LightObject* service = mc->GetService(sr); + sr.GetUsingModules(usingModules); + // if (UNREGISTERSERVICE_VALID_DURING_UNREGISTERING) { + // In this mode the service shall be obtainable during + // unregistration. + if (service == 0) + { + teststatus = false; + MITK_TEST_OUTPUT( << "*** Service should be available to ServiceListener " + << "while handling unregistering event." ); + } + MITK_TEST_OUTPUT( << "Service (unreg): " << service->GetNameOfClass() ); + if (checkUsingModules && usingModules.size() != 1) + { + teststatus = false; + printUsingModules(sr, "*** One using module expected " + "(unreg, after getService), found: "); + } + else + { + printUsingModules(sr, "Using modules (unreg, after getService): "); + } + // } else { + // // In this mode the service shall NOT be obtainable during + // // unregistration. + // if (null!=service) { + // teststatus = false; + // out.print("*** Service should not be available to ServiceListener " + // +"while handling unregistering event."); + // } + // if (checkUsingBundles && null!=usingBundles) { + // teststatus = false; + // printUsingBundles(sr, + // "*** Using bundles (unreg, after getService), " + // +"should be null but is: "); + // } else { + // printUsingBundles(sr, + // "Using bundles (unreg, after getService): null"); + // } + // } + mc->UngetService(sr); + + // Check that the UNREGISTERING service can not be looked up + // using the service registry. + try + { + long sid = mitk::any_cast(sr.GetProperty(mitk::ServiceConstants::SERVICE_ID())); + std::stringstream ss; + ss << "(" << mitk::ServiceConstants::SERVICE_ID() << "=" << sid << ")"; + std::list srs = mc->GetServiceReferences("", ss.str()); + if (srs.empty()) + { + MITK_TEST_OUTPUT( << "mitk::ServiceReference for UNREGISTERING service is not" + " found in the service registry; ok." ); + } + else + { + teststatus = false; + MITK_TEST_OUTPUT( << "*** mitk::ServiceReference for UNREGISTERING service," + << sr << ", not found in the service registry; fail." ); + MITK_TEST_OUTPUT( << "Found the following Service references:") ; + for(std::list::const_iterator sr = srs.begin(); + sr != srs.end(); ++sr) + { + MITK_TEST_OUTPUT( << (*sr) ); + } + } + } + catch (const std::exception& e) + { + teststatus = false; + MITK_TEST_OUTPUT( << "*** Unexpected excpetion when trying to lookup a" + " service while it is in state UNREGISTERING: " + << e.what() ); + } + } + } + + void printUsingModules(const mitk::ServiceReference& sr, const std::string& caption) + { + std::vector usingModules; + sr.GetUsingModules(usingModules); + + MITK_TEST_OUTPUT( << (caption.empty() ? "Using modules: " : caption) ); + for(std::vector::const_iterator module = usingModules.begin(); + module != usingModules.end(); ++module) + { + MITK_TEST_OUTPUT( << " -" << (*module) ); + } + } + + // Print expected and actual service events. + void dumpEvents(const std::vector& eventTypes) + { + std::size_t max = events.size() > eventTypes.size() ? events.size() : eventTypes.size(); + MITK_TEST_OUTPUT( << "Expected event type -- Actual event" ); + for (std::size_t i=0; i < max; ++i) + { + mitk::ServiceEvent evt = i < events.size() ? events[i] : mitk::ServiceEvent(); + if (i < eventTypes.size()) + { + MITK_TEST_OUTPUT( << " " << eventTypes[i] << "--" << evt ); + } + else + { + MITK_TEST_OUTPUT( << " " << "- NONE - " << "--" << evt ); + } + } + } + +}; // end of class ServiceListener + +bool runLoadUnloadTest(const std::string& name, int cnt, mitk::SharedLibraryHandle& target, + const std::vector& events) +{ + bool teststatus = true; + + mitk::ModuleContext* mc = mitk::GetModuleContext(); + + for (int i = 0; i < cnt && teststatus; ++i) + { + ServiceListener sListen(mc); + try + { + mc->AddServiceListener(&sListen, &ServiceListener::serviceChanged); + //mc->AddServiceListener(mitk::MessageDelegate1(&sListen, &ServiceListener::serviceChanged)); + } + catch (const std::logic_error& ise) + { + teststatus = false; + MITK_TEST_OUTPUT( << "service listener registration failed " << ise.what() + << " :" << name << ":FAIL" ); + } + + // Start the test target to get a service published. + try + { + target.Load(); + } + catch (const std::exception& e) + { + teststatus = false; + MITK_TEST_OUTPUT( << "Failed to load module, got exception: " + << e.what() << " + in " << name << ":FAIL" ); + } + + // Stop the test target to get a service unpublished. + try + { + target.Unload(); + } + catch (const std::exception& e) + { + teststatus = false; + MITK_TEST_OUTPUT( << "Failed to unload module, got exception: " + << e.what() << " + in " << name << ":FAIL" ); + } + + if (teststatus && !sListen.checkEvents(events)) + { + teststatus = false; + MITK_TEST_OUTPUT( << "Service listener event notification error :" + << name << ":FAIL" ); + } + + try + { + mc->RemoveServiceListener(&sListen, &ServiceListener::serviceChanged); + teststatus &= sListen.teststatus; + sListen.clearEvents(); + } + catch (const std::logic_error& ise) + { + teststatus = false; + MITK_TEST_OUTPUT( << "service listener removal failed " << ise.what() + << " :" << name << ":FAIL" ); + } + } + return teststatus; +} + +void frameSL05a() +{ + std::vector events; + events.push_back(mitk::ServiceEvent::REGISTERED); + events.push_back(mitk::ServiceEvent::UNREGISTERING); + mitk::SharedLibraryHandle libA("TestModuleA"); + bool testStatus = runLoadUnloadTest("FrameSL05a", 1, libA, events); + MITK_TEST_CONDITION(testStatus, "FrameSL05a") +} + +void frameSL10a() +{ + std::vector events; + events.push_back(mitk::ServiceEvent::REGISTERED); + events.push_back(mitk::ServiceEvent::UNREGISTERING); + mitk::SharedLibraryHandle libA2("TestModuleA2"); + bool testStatus = runLoadUnloadTest("FrameSL10a", 1, libA2, events); + MITK_TEST_CONDITION(testStatus, "FrameSL10a") +} + +void frameSL25a() +{ + mitk::ModuleContext* mc = mitk::GetModuleContext(); + + ServiceListener sListen(mc, false); + try + { + mc->AddServiceListener(&sListen, &ServiceListener::serviceChanged); + } + catch (const std::logic_error& ise) + { + MITK_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); + throw; + } + + mitk::SharedLibraryHandle libSL1("TestModuleSL1"); + mitk::SharedLibraryHandle libSL3("TestModuleSL3"); + mitk::SharedLibraryHandle libSL4("TestModuleSL4"); + + std::vector expectedServiceEventTypes; + + // Startup + expectedServiceEventTypes.push_back(mitk::ServiceEvent::REGISTERED); // at start of libSL1 + expectedServiceEventTypes.push_back(mitk::ServiceEvent::REGISTERED); // mitk::FooService at start of libSL4 + expectedServiceEventTypes.push_back(mitk::ServiceEvent::REGISTERED); // at start of libSL3 + + // Stop libSL4 + expectedServiceEventTypes.push_back(mitk::ServiceEvent::UNREGISTERING); // mitk::FooService at first stop of libSL4 + + // Shutdown + expectedServiceEventTypes.push_back(mitk::ServiceEvent::UNREGISTERING); // at stop of libSL1 + expectedServiceEventTypes.push_back(mitk::ServiceEvent::UNREGISTERING); // at stop of libSL3 + + + // Start libModuleTestSL1 to ensure that the Service interface is available. + try + { + MITK_TEST_OUTPUT( << "Starting libModuleTestSL1: " << libSL1.GetAbsolutePath() ); + libSL1.Load(); + } + catch (const std::exception& e) + { + MITK_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); + throw; + } + + // Start libModuleTestSL4 that will require the serivce interface and publish + // ctkFooService + try + { + MITK_TEST_OUTPUT( << "Starting libModuleTestSL4: " << libSL4.GetAbsolutePath() ); + libSL4.Load(); + } + catch (const std::exception& e) + { + MITK_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); + throw; + } + + // Start libModuleTestSL3 that will require the serivce interface and get the service + try + { + MITK_TEST_OUTPUT( << "Starting libModuleTestSL3: " << libSL3.GetAbsolutePath() ); + libSL3.Load(); + } + catch (const std::exception& e) + { + MITK_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); + throw; + } + + // Check that libSL3 has been notified about the mitk::FooService. + MITK_TEST_OUTPUT( << "Check that mitk::FooService is added to service tracker in libSL3" ); + try + { + mitk::ServiceReference libSL3SR = mc->GetServiceReference("mitk::ActivatorSL3"); + itk::LightObject* libSL3Activator = mc->GetService(libSL3SR); + MITK_TEST_CONDITION_REQUIRED(libSL3Activator, "mitk::ActivatorSL3 service != 0"); + + mitk::ModulePropsInterface* propsInterface = dynamic_cast(libSL3Activator); + MITK_TEST_CONDITION_REQUIRED(propsInterface, "Cast to mitk::ModulePropsInterface"); + + mitk::ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceAdded"); + MITK_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceAdded"); + mitk::Any serviceAddedField3 = i->second; + MITK_TEST_CONDITION_REQUIRED(!serviceAddedField3.Empty() && mitk::any_cast(serviceAddedField3), + "libSL3 notified about presence of mitk::FooService"); + mc->UngetService(libSL3SR); + } + catch (const mitk::ServiceException& se) + { + MITK_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); + } + + // Check that libSL1 has been notified about the mitk::FooService. + MITK_TEST_OUTPUT( << "Check that mitk::FooService is added to service tracker in libSL1" ); + try + { + mitk::ServiceReference libSL1SR = mc->GetServiceReference("mitk::ActivatorSL1"); + itk::LightObject* libSL1Activator = mc->GetService(libSL1SR); + MITK_TEST_CONDITION_REQUIRED(libSL1Activator, "mitk::ActivatorSL1 service != 0"); + + mitk::ModulePropsInterface* propsInterface = dynamic_cast(libSL1Activator); + MITK_TEST_CONDITION_REQUIRED(propsInterface, "Cast to mitk::ModulePropsInterface"); + + mitk::ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceAdded"); + MITK_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceAdded"); + mitk::Any serviceAddedField1 = i->second; + MITK_TEST_CONDITION_REQUIRED(!serviceAddedField1.Empty() && mitk::any_cast(serviceAddedField1), + "libSL1 notified about presence of mitk::FooService"); + mc->UngetService(libSL1SR); + } + catch (const mitk::ServiceException& se) + { + MITK_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); + } + + // Stop the service provider: libSL4 + try + { + MITK_TEST_OUTPUT( << "Stop libSL4: " << libSL4.GetAbsolutePath() ); + libSL4.Unload(); + } + catch (const std::exception& e) + { + MITK_TEST_OUTPUT( << "Failed to unload module, got exception:" << e.what() ); + throw; + } + + // Check that libSL3 has been notified about the removal of mitk::FooService. + MITK_TEST_OUTPUT( << "Check that mitk::FooService is removed from service tracker in libSL3" ); + try + { + mitk::ServiceReference libSL3SR = mc->GetServiceReference("mitk::ActivatorSL3"); + itk::LightObject* libSL3Activator = mc->GetService(libSL3SR); + MITK_TEST_CONDITION_REQUIRED(libSL3Activator, "mitk::ActivatorSL3 service != 0"); + + mitk::ModulePropsInterface* propsInterface = dynamic_cast(libSL3Activator); + MITK_TEST_CONDITION_REQUIRED(propsInterface, "Cast to mitk::ModulePropsInterface"); + + mitk::ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceRemoved"); + MITK_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceRemoved"); + + mitk::Any serviceRemovedField3 = i->second; + MITK_TEST_CONDITION(!serviceRemovedField3.Empty() && mitk::any_cast(serviceRemovedField3), + "libSL3 notified about removal of mitk::FooService"); + mc->UngetService(libSL3SR); + } + catch (const mitk::ServiceException& se) + { + MITK_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); + } + + // Stop libSL1 + try + { + MITK_TEST_OUTPUT( << "Stop libSL1:" << libSL1.GetAbsolutePath() ); + libSL1.Unload(); + } + catch (const std::exception& e) + { + MITK_TEST_OUTPUT( << "Failed to unload module got exception" << e.what() ); + throw; + } + + // Stop pSL3 + try + { + MITK_TEST_OUTPUT( << "Stop libSL3:" << libSL3.GetAbsolutePath() ); + libSL3.Unload(); + } + catch (const std::exception& e) + { + MITK_TEST_OUTPUT( << "Failed to unload module got exception" << e.what() ); + throw; + } + + // Check service events seen by this class + MITK_TEST_OUTPUT( << "Checking ServiceEvents(ServiceListener):" ); + if (!sListen.checkEvents(expectedServiceEventTypes)) + { + MITK_TEST_FAILED_MSG( << "Service listener event notification error" ); + } + + MITK_TEST_CONDITION_REQUIRED(sListen.getTestStatus(), "Service listener checks"); + try + { + mc->RemoveServiceListener(&sListen, &ServiceListener::serviceChanged); + sListen.clearEvents(); + } + catch (const std::logic_error& ise) + { + MITK_TEST_FAILED_MSG( << "service listener removal failed: " << ise.what() ); + } + +} + +int mitkServiceListenerTest(int /*argc*/, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("ServiceListenerTest"); + + frameSL05a(); + frameSL10a(); + frameSL25a(); + + MITK_TEST_END() +} + diff --git a/Core/Code/Testing/mitkTestUtilSharedLibrary.cpp b/Core/Code/Testing/mitkTestUtilSharedLibrary.cpp new file mode 100644 index 0000000000..5e48b10b60 --- /dev/null +++ b/Core/Code/Testing/mitkTestUtilSharedLibrary.cpp @@ -0,0 +1,168 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "mitkTestingConfig.h" + +#if defined(__APPLE__) + #define PLATFORM_APPLE +#endif + +#if defined(unix) || defined(__unix) || defined(__APPLE__) + #include + #define PLATFORM_UNIX +#elif defined(_WIN32) + #include + #include + #define PLATFORM_WINDOWS +#else + #error Unsupported platform +#endif + + +namespace mitk { + +class SharedLibraryHandle +{ +public: + + SharedLibraryHandle() : m_Handle(0) {} + + SharedLibraryHandle(const std::string& name) + : m_Name(name), m_Handle(0) + {} + + virtual ~SharedLibraryHandle() {} + + void Load() + { + Load(m_Name); + } + + void Load(const std::string& name) + { + if (m_Handle) throw std::logic_error(std::string("Library already loaded: ") + name); + std::string libPath = GetAbsolutePath(name); +#ifdef PLATFORM_UNIX + m_Handle = dlopen(libPath.c_str(), RTLD_LAZY | RTLD_GLOBAL); + if (!m_Handle) + { + const char* err = dlerror(); + throw std::runtime_error(err ? std::string(err) : libPath); + } +#else + m_Handle = LoadLibrary(libPath.c_str()); + if (!m_Handle) + { + // Retrieve the system error message for the last-error code + LPVOID lpMsgBuf; + LPVOID lpDisplayBuf; + 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 ); + + // Display the error message and exit the process + + lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, + (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)libPath.c_str()) + 50) * sizeof(TCHAR)); + StringCchPrintf((LPTSTR)lpDisplayBuf, + LocalSize(lpDisplayBuf) / sizeof(TCHAR), + TEXT("Loading %s failed with error %d: %s"), + libPath.c_str(), dw, lpMsgBuf); + + std::string errMsg((LPCTSTR)lpDisplayBuf); + + LocalFree(lpMsgBuf); + LocalFree(lpDisplayBuf); + + throw std::runtime_error(errMsg); + } +#endif + + m_Name = name; + } + + void Unload() + { + if (m_Handle) + { +#ifdef PLATFORM_UNIX + dlclose(m_Handle); +#else + FreeLibrary((HMODULE)m_Handle); +#endif + m_Handle = 0; + } + } + + std::string GetAbsolutePath(const std::string& name) + { + return GetLibraryPath() + "/" + Prefix() + name + Suffix(); + } + + std::string GetAbsolutePath() + { + return GetLibraryPath() + "/" + Prefix() + m_Name + Suffix(); + } + + static std::string GetLibraryPath() + { + return std::string(MITK_RUNTIME_OUTPUT_DIR); + } + + static std::string Suffix() + { +#ifdef PLATFORM_WINDOWS + return ".dll"; +#elif defined(PLATFORM_APPLE) + return ".dylib"; +#else + return ".so"; +#endif + } + + static std::string Prefix() + { +#if defined(PLATFORM_UNIX) + return "lib"; +#else + return ""; +#endif + } + +private: + + SharedLibraryHandle(const SharedLibraryHandle&); + SharedLibraryHandle& operator = (const SharedLibraryHandle&); + + std::string m_Name; + void* m_Handle; +}; + + +} // namespace mitk + diff --git a/Core/Code/files.cmake b/Core/Code/files.cmake index 24abc1d0c4..7329086108 100644 --- a/Core/Code/files.cmake +++ b/Core/Code/files.cmake @@ -1,278 +1,324 @@ SET(H_FILES Algorithms/itkImportMitkImageContainer.h Algorithms/itkImportMitkImageContainer.txx Algorithms/itkLocalVariationImageFilter.h Algorithms/itkLocalVariationImageFilter.txx Algorithms/itkMITKScalarImageToHistogramGenerator.h Algorithms/itkMITKScalarImageToHistogramGenerator.txx Algorithms/itkTotalVariationDenoisingImageFilter.h Algorithms/itkTotalVariationDenoisingImageFilter.txx Algorithms/itkTotalVariationSingleIterationImageFilter.h Algorithms/itkTotalVariationSingleIterationImageFilter.txx Algorithms/mitkImageAccessByItk.h Algorithms/mitkImageCast.h Algorithms/mitkImageToItk.h Algorithms/mitkImageToItk.txx Algorithms/mitkInstantiateAccessFunctions.h Algorithms/mitkITKImageImport.h Algorithms/mitkITKImageImport.txx Algorithms/mitkPixelTypeList.h # Preprocessor macros taken from Boost Algorithms/mitkPPArithmeticDec.h Algorithms/mitkPPArgCount.h Algorithms/mitkPPCat.h Algorithms/mitkPPConfig.h Algorithms/mitkPPControlExprIIf.h Algorithms/mitkPPControlIf.h Algorithms/mitkPPControlIIf.h Algorithms/mitkPPDebugError.h Algorithms/mitkPPDetailAutoRec.h Algorithms/mitkPPDetailDMCAutoRec.h Algorithms/mitkPPExpand.h Algorithms/mitkPPFacilitiesEmpty.h Algorithms/mitkPPFacilitiesExpand.h Algorithms/mitkPPLogicalBool.h Algorithms/mitkPPRepetitionDetailDMCFor.h Algorithms/mitkPPRepetitionDetailEDGFor.h Algorithms/mitkPPRepetitionDetailFor.h Algorithms/mitkPPRepetitionDetailMSVCFor.h Algorithms/mitkPPRepetitionFor.h Algorithms/mitkPPSeqElem.h Algorithms/mitkPPSeqForEach.h Algorithms/mitkPPSeqForEachProduct.h Algorithms/mitkPPSeq.h Algorithms/mitkPPSeqEnum.h Algorithms/mitkPPSeqSize.h Algorithms/mitkPPSeqToTuple.h Algorithms/mitkPPStringize.h Algorithms/mitkPPTupleEat.h Algorithms/mitkPPTupleElem.h Algorithms/mitkPPTupleRem.h Algorithms/mitkClippedSurfaceBoundsCalculator.h DataManagement/mitkCommon.h Interactions/mitkEventMapperAddOn.h + + Service/mitkAny.h + Service/mitkGetModuleContext.h + Service/mitkItkHashMap.h + Service/mitkItkHashSet.h + Service/mitkItkHashTable.h + Service/mitkModuleAbstractTracked.h + Service/mitkModuleAbstractTracked.tpp + Service/mitkModuleActivator.h + Service/mitkServiceFactory.h + Service/mitkServiceTracker.h + Service/mitkServiceTracker.tpp + Service/mitkServiceTrackerCustomizer.h + Service/mitkServiceTrackerPrivate.h + Service/mitkServiceTrackerPrivate.tpp + Service/mitkServiceUtils.h + Service/mitkSharedData.h + Service/mitkStaticInit.h + Service/mitkTrackedService.h + Service/mitkTrackedService.tpp + Service/mitkTrackedServiceListener.h ) SET(CPP_FILES Algorithms/mitkBaseDataSource.cpp Algorithms/mitkBaseProcess.cpp Algorithms/mitkCoreObjectFactoryBase.cpp Algorithms/mitkCoreObjectFactory.cpp Algorithms/mitkDataNodeFactory.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkGeometry2DDataToSurfaceFilter.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageCaster.cpp Algorithms/mitkImageCastPart1.cpp Algorithms/mitkImageCastPart2.cpp Algorithms/mitkImageCastPart3.cpp Algorithms/mitkImageCastPart4.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkFocusManager.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkSlicesRotator.cpp Controllers/mitkSlicesSwiveller.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkInteractorCameraController.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataStorage.cpp #DataManagement/mitkDataTree.cpp DataManagement/mitkDataNode.cpp #DataManagement/mitkDataTreeStorage.cpp DataManagement/mitkDisplayGeometry.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkGeometry2D.cpp DataManagement/mitkGeometry2DData.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkLandmarkBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModeOperation.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStateTransitionOperation.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeSlicedGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkVector.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkShaderProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkMaterial.cpp Interactions/mitkAction.cpp Interactions/mitkAffineInteractor.cpp Interactions/mitkCoordinateSupplier.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkDisplayPositionEvent.cpp Interactions/mitkDisplayVectorInteractor.cpp Interactions/mitkDisplayVectorInteractorLevelWindow.cpp Interactions/mitkDisplayVectorInteractorScroll.cpp Interactions/mitkEvent.cpp Interactions/mitkEventDescription.cpp Interactions/mitkEventMapper.cpp Interactions/mitkGlobalInteraction.cpp Interactions/mitkInteractor.cpp Interactions/mitkMouseMovePointSetInteractor.cpp Interactions/mitkMoveSurfaceInteractor.cpp Interactions/mitkNodeDepententPointSetInteractor.cpp Interactions/mitkPointSetInteractor.cpp Interactions/mitkPositionEvent.cpp Interactions/mitkPositionTracker.cpp Interactions/mitkState.cpp Interactions/mitkStateEvent.cpp Interactions/mitkStateMachine.cpp Interactions/mitkStateMachineFactory.cpp Interactions/mitkTransition.cpp Interactions/mitkWheelEvent.cpp Interactions/mitkKeyEvent.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkCrosshairPositionEvent.cpp IO/mitkBaseDataIOFactory.cpp IO/mitkDicomSeriesReader.cpp IO/mitkFileReader.cpp IO/mitkFileSeriesReader.cpp IO/mitkFileWriter.cpp IO/mitkIpPicGet.c IO/mitkImageGenerator.cpp IO/mitkImageWriter.cpp IO/mitkImageWriterFactory.cpp IO/mitkItkImageFileIOFactory.cpp IO/mitkItkImageFileReader.cpp IO/mitkItkPictureWrite.cpp IO/mitkLookupTableProperty.cpp IO/mitkOperation.cpp IO/mitkPicFileIOFactory.cpp IO/mitkPicFileReader.cpp IO/mitkPicFileWriter.cpp IO/mitkPicHelper.cpp IO/mitkPicVolumeTimeSeriesIOFactory.cpp IO/mitkPicVolumeTimeSeriesReader.cpp IO/mitkPixelType.cpp IO/mitkPointSetIOFactory.cpp IO/mitkPointSetReader.cpp IO/mitkPointSetWriter.cpp IO/mitkPointSetWriterFactory.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSTLFileIOFactory.cpp IO/mitkSTLFileReader.cpp IO/mitkSurfaceVtkWriter.cpp IO/mitkSurfaceVtkWriterFactory.cpp IO/mitkVtiFileIOFactory.cpp IO/mitkVtiFileReader.cpp IO/mitkVtkImageIOFactory.cpp IO/mitkVtkImageReader.cpp IO/mitkVtkSurfaceIOFactory.cpp IO/mitkVtkSurfaceReader.cpp IO/vtkPointSetXMLParser.cpp IO/mitkLog.cpp Rendering/mitkBaseRenderer.cpp Rendering/mitkVtkMapper2D.cpp Rendering/mitkVtkMapper3D.cpp Rendering/mitkRenderWindowFrame.cpp Rendering/mitkGeometry2DDataMapper2D.cpp Rendering/mitkGeometry2DDataVtkMapper3D.cpp Rendering/mitkGLMapper2D.cpp Rendering/mitkGradientBackground.cpp Rendering/mitkManufacturerLogo.cpp Rendering/mitkMapper2D.cpp Rendering/mitkMapper3D.cpp Rendering/mitkMapper.cpp Rendering/mitkPointSetGLMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkPolyDataGLMapper2D.cpp Rendering/mitkSurfaceGLMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVolumeDataVtkMapper3D.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkShaderRepository.cpp Rendering/mitkImageMapperGL2D.cpp Rendering/vtkMitkThickSlicesFilter.cpp + + Service/mitkAny.cpp + Service/mitkAtomicInt.cpp + Service/mitkCoreActivator.cpp + Service/mitkCoreModuleContext.cpp + Service/mitkModule.cpp + Service/mitkModuleContext.cpp + Service/mitkModuleEvent.cpp + Service/mitkModuleInfo.cpp + Service/mitkModulePrivate.cpp + Service/mitkModuleRegistry.cpp + Service/mitkModuleUtils.cpp + Service/mitkModuleVersion.cpp + Service/mitkLDAPExpr.cpp + Service/mitkLDAPFilter.cpp + Service/mitkServiceEvent.cpp + Service/mitkServiceException.cpp + Service/mitkServiceListenerEntry.cpp + Service/mitkServiceListeners.cpp + Service/mitkServiceProperties.cpp + Service/mitkServiceReference.cpp + Service/mitkServiceReferencePrivate.cpp + Service/mitkServiceRegistration.cpp + Service/mitkServiceRegistrationPrivate.cpp + Service/mitkServiceRegistry.cpp ) diff --git a/Documentation/Doxygen/Modules/ModuleMicroServices.dox b/Documentation/Doxygen/Modules/ModuleMicroServices.dox new file mode 100644 index 0000000000..dd8176c71d --- /dev/null +++ b/Documentation/Doxygen/Modules/ModuleMicroServices.dox @@ -0,0 +1,10 @@ + +/** + +\defgroup MicroServices Micro Services Classes +\ingroup Core + +\brief This category includes classes related to the MITK Micro Services component. + + +*/ diff --git a/Documentation/Snippets/uServices-activator/main.cpp b/Documentation/Snippets/uServices-activator/main.cpp new file mode 100644 index 0000000000..2c92be2050 --- /dev/null +++ b/Documentation/Snippets/uServices-activator/main.cpp @@ -0,0 +1,26 @@ +//! [0] +#include +#include + +class MyActivator : public mitk::ModuleActivator +{ + +public: + + void Load(mitk::ModuleContext* context) + { /* register stuff */ } + + + void Unload(mitk::ModuleContext* context) + { /* cleanup */ } + +}; + +MITK_EXPORT_MODULE_ACTIVATOR(mylibname, MyActivator) +//![0] + +int main(int argc, char* argv[]) +{ + MyActivator ma; + return 0; +} diff --git a/Utilities/glew/CMakeLists.txt b/Utilities/glew/CMakeLists.txt index 718039e4b7..d366020a1a 100644 --- a/Utilities/glew/CMakeLists.txt +++ b/Utilities/glew/CMakeLists.txt @@ -1,6 +1,7 @@ MITK_CREATE_MODULE(glew INCLUDE_DIRS external/include INTERNAL_INCLUDE_DIRS external/include PACKAGE_DEPENDS VTK GCC_DEFAULT_VISIBILITY + NO_INIT ) diff --git a/mitkTestingConfig.h.in b/mitkTestingConfig.h.in index 930ea5992c..02b0b416ec 100644 --- a/mitkTestingConfig.h.in +++ b/mitkTestingConfig.h.in @@ -1,8 +1,13 @@ /* mitkTestingConfig.h this file is generated. Do not change! */ #cmakedefine BUILD_TESTING #cmakedefine MITK_FAST_TESTING #define MITK_TEST_OUTPUT_DIR "@MITK_TEST_OUTPUT_DIR@" +#ifdef CMAKE_INTDIR +#define MITK_RUNTIME_OUTPUT_DIR "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/" ## CMAKE_INTDIR +#else +#define MITK_RUNTIME_OUTPUT_DIR "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@" +#endif