diff --git a/Applications/PluginGenerator/PluginGenerator.cpp b/Applications/PluginGenerator/PluginGenerator.cpp index 6bfa50e1f8..3f13d8aebf 100644 --- a/Applications/PluginGenerator/PluginGenerator.cpp +++ b/Applications/PluginGenerator/PluginGenerator.cpp @@ -1,547 +1,547 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "ctkCommandLineParser.h" #include #include #include #include #include #include #include //#include //#include #include #include #include #include int compareVersions(const QString &v1, const QString &v2) { QList t1; foreach (QString t, v1.split('.')) { t1.append(t.toInt()); } QList t2; foreach (QString t, v2.split('.')) { t2.append(t.toInt()); } // pad with 0 if (t1.size() < t2.size()) { for (int i = 0; i < t2.size() - t1.size(); ++i) t1.append(0); } else { for (int i = 0; i < t1.size() - t2.size(); ++i) t2.append(0); } for (int i = 0; i < t1.size(); ++i) { if (t1.at(i) < t2.at(i)) return -1; else if (t1.at(i) > t2.at(i)) return 1; } return 0; } /*int checkUpdates(QTextStream &out) { out << "Checking for updates... "; out.flush(); QNetworkAccessManager manager; QNetworkReply *reply = - manager.get(QNetworkRequest(QUrl("http://www.mitk.org/wiki/PluginGeneratorUpdate?action=raw"))); + manager.get(QNetworkRequest(QUrl("https://www.mitk.org/wiki/PluginGeneratorUpdate?action=raw"))); QEventLoop eventLoop; reply->connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit())); eventLoop.exec(); QByteArray data = reply->readAll(); if (data.isEmpty()) { qCritical() << "A network error occured:" << reply->errorString(); return EXIT_FAILURE; } delete reply; QBuffer buffer(&data); buffer.open(QIODevice::ReadOnly); bool versionFound = false; while (buffer.canReadLine()) { QString line = buffer.readLine(); if (!versionFound) { line = line.trimmed(); if (line.isEmpty()) continue; if (compareVersions(PLUGIN_GENERATOR_VERSION, line) < 0) { versionFound = true; out << "New version " << line << " available.\n"; } else { // no update available out << "No update available.\n"; out.flush(); return EXIT_SUCCESS; } } else { out << line; } } if (!versionFound) { qCritical() << "Update information not readable."; return EXIT_FAILURE; } out << '\n'; out.flush(); return EXIT_SUCCESS; }*/ bool readAnswer(char defaultAnswer) { std::string line; std::cin >> std::noskipws >> line; // consume the new line character std::cin.clear(); std::cin.ignore(std::numeric_limits::max(), '\n'); char answer = defaultAnswer; if (!line.empty() && line[0] != '\n') { answer = std::tolower(line[0]); } if (answer == 'y') return true; if (answer == 'n') return false; if (defaultAnswer == 'y') return true; return false; } void createFilePathMapping(const QString &templateName, const QString &baseInDir, const QString &baseOutDir, QHash &fileNameMapping) { QFileInfo info(templateName); if (info.isDir()) { QStringList subEntries = QDir(templateName).entryList(); foreach (QString subEntry, subEntries) { createFilePathMapping(templateName + "/" + subEntry, baseInDir, baseOutDir, fileNameMapping); } return; } fileNameMapping[templateName] = QString(templateName).replace(baseInDir, baseOutDir); } QHash createTemplateFileMapping(const QString &qrcBase, const QString &baseOutDir, const QHash &fileNameMapping) { QHash filePathMapping; createFilePathMapping(qrcBase, qrcBase, baseOutDir, filePathMapping); QMutableHashIterator i(filePathMapping); while (i.hasNext()) { i.next(); QHashIterator j(fileNameMapping); while (j.hasNext()) { j.next(); i.setValue(i.value().replace(j.key(), j.value())); } } return filePathMapping; } bool generateFiles(const QHash ¶meters, const QHash &filePathMapping) { QHashIterator paths(filePathMapping); while (paths.hasNext()) { paths.next(); QFile templ(paths.key()); templ.open(QIODevice::ReadOnly); QByteArray templContent = templ.readAll(); QHashIterator i(parameters); while (i.hasNext()) { i.next(); templContent.replace(i.key(), QByteArray(i.value().toLatin1())); } QFile outTempl(paths.value()); QDir dir(QFileInfo(outTempl).dir()); if (!dir.exists()) { if (!dir.mkpath(dir.absolutePath())) { qCritical() << "Could not create directory" << dir.absolutePath(); return EXIT_FAILURE; } } if (!outTempl.open(QIODevice::WriteOnly)) { qCritical() << outTempl.errorString(); return false; } outTempl.write(templContent); } return true; } int main(int argc, char **argv) { QString appName("MitkPluginGenerator"); QCoreApplication app(argc, argv); app.setApplicationName(appName); app.setOrganizationName("DKFZ"); ctkCommandLineParser parser; // Use Unix-style argument names parser.setArgumentPrefix("--", "-"); parser.setStrictModeEnabled(true); // Add command line argument names parser.addArgument("help", "h", QVariant::Bool, " Show this help text"); parser.addArgument("out-dir", "o", QVariant::String, " Output directory", QDir::tempPath()); parser.addArgument( "license", "l", QVariant::String, " Path to a file containing license information", ":/COPYRIGHT_HEADER"); parser.addArgument("vendor", "v", QVariant::String, " The vendor of the generated code", "German Cancer Research Center (DKFZ)"); parser.addArgument("quiet", "q", QVariant::Bool, " Do not print additional information"); parser.addArgument("confirm-all", "y", QVariant::Bool, " Answer all questions with 'yes'"); //parser.addArgument("check-update", "u", QVariant::Bool, " Check for updates and exit"); //parser.addArgument("no-networking", "n", QVariant::Bool, " Disable all network requests"); parser.beginGroup("Plug-in options"); parser.addArgument("plugin-symbolic-name", "ps", QVariant::String, "* The plugin's symbolic name"); parser.setExactMatchRegularExpression("-ps", "^[a-zA-Z]+\\.[a-zA-Z0-9._]+[^\\.]$", "Symbolic name invalid"); parser.addArgument("plugin-name", "pn", QVariant::String, " The plug-in's human readable name"); parser.beginGroup("Plug-in View options"); parser.addArgument("view-class", "vc", QVariant::String, " The View's' class name"); parser.addArgument("view-name", "vn", QVariant::String, "* The View's human readable name"); parser.beginGroup("Project options"); parser.addArgument( "project-copyright", "", QVariant::String, " Path to a file containing copyright information", ":/LICENSE"); parser.addArgument("project-name", "", QVariant::String, " The project name"); parser.setExactMatchRegularExpression("--project-name", "^[a-zA-Z_\\-]+$", "Project name invalid"); parser.addArgument("project-app-name", "", QVariant::String, " The application name"); parser.setExactMatchRegularExpression("--project-app-name", "^[a-zA-Z_\\-]+$", "Project application name invalid"); parser.endGroup(); // Parse the command line arguments bool ok = false; QHash parsedArgs = parser.parseArguments(QCoreApplication::arguments(), &ok); if (!ok) { QTextStream(stderr, QIODevice::WriteOnly) << "Error parsing arguments: " << parser.errorString() << "\nType '" << appName << " -h' for help\n"; return EXIT_FAILURE; } QTextStream out(stdout, QIODevice::WriteOnly); // Show a help message if (parsedArgs.contains("help")) { out << "A CTK plug-in generator for MITK (version " PLUGIN_GENERATOR_VERSION ")\n\n" << parser.helpText() << "\n[* - options are required]\n"; return EXIT_SUCCESS; } /*bool noNetwork = parsedArgs.contains("no-networking"); if (parsedArgs.contains("check-update")) { if (noNetwork) { out << "Network support disabled. Cannot check for updates.\n"; out.flush(); } else { return checkUpdates(out); } } else { // always check for updates if no-networking is not given if (!noNetwork) { checkUpdates(out); } }*/ // Check arguments // Project options QString projectName = parsedArgs["project-name"].toString(); QString projectAppName = parsedArgs["project-app-name"].toString(); QString copyrightPath = QDir::fromNativeSeparators(parsedArgs["project-copyright"].toString()); bool createProject = !projectName.isEmpty(); if (createProject && projectAppName.isEmpty()) { projectAppName = projectName; } QString pluginSymbolicName = parsedArgs["plugin-symbolic-name"].toString(); if (pluginSymbolicName.isEmpty()) { qCritical() << "Required argument 'plugin-symbolic-name' missing."; qCritical("%s%s%s", "Type '", qPrintable(appName), " -h' for help"); return EXIT_FAILURE; } QString pluginTarget(pluginSymbolicName); pluginTarget.replace('.', '_'); QString activatorClass = pluginTarget + "_Activator"; QString outDir = QDir::fromNativeSeparators(parsedArgs["out-dir"].toString()); QString licensePath = QDir::fromNativeSeparators(parsedArgs["license"].toString()); QString pluginExportDirective = pluginSymbolicName.split('.').last().toUpper() + "_EXPORT"; QString pluginName = parsedArgs["plugin-name"].toString(); if (pluginName.isEmpty()) { QStringList toks = pluginSymbolicName.split('.'); pluginName = toks.last(); pluginName[0] = pluginName[0].toUpper(); } QString vendor = parsedArgs["vendor"].toString(); QString viewName = parsedArgs["view-name"].toString(); if (viewName.isEmpty()) { qCritical() << "Required argument 'view-name' missing."; qCritical("%s%s%s", "Type '", qPrintable(appName), " -h' for help"); return EXIT_FAILURE; } QStringList toks = viewName.split(QRegExp("\\s"), QString::SkipEmptyParts); QString viewClass = parsedArgs["view-class"].toString(); if (viewClass.isEmpty()) { foreach (QString tok, toks) { QString tmp = tok; tmp[0] = tmp[0].toUpper(); viewClass += tmp; } } QString viewId; if (viewId.isEmpty()) { viewId = "org.mitk.views."; foreach (QString tok, toks) { viewId += tok.toLower(); } } bool quiet = parsedArgs.contains("quiet"); bool autoConfirm = parsedArgs.contains("confirm-all"); if (!outDir.endsWith('/')) outDir += '/'; if (createProject) outDir += projectName; else outDir += pluginSymbolicName; // Print the collected information if (!quiet) { if (createProject) { out << "Using the following information to create a project:\n\n" << " Project Name: " << projectName << '\n' << " Application Name: " << projectAppName << '\n' << " Copyright File: " << QDir::toNativeSeparators(copyrightPath) << '\n'; } else { out << "Using the following information to create a plug-in:\n\n"; } out << " License File: " << QDir::toNativeSeparators(licensePath) << '\n' << " Plugin-SymbolicName: " << pluginSymbolicName << '\n' << " Plugin-Name: " << pluginName << '\n' << " Plugin-Vendor: " << vendor << '\n' << " View Name: " << viewName << '\n' << " View Id: " << viewId << '\n' << " View Class: " << viewClass << '\n' << '\n' << "Create in: " << outDir << '\n' << '\n'; if (!autoConfirm) out << "Continue [Y/n]? "; out.flush(); if (!autoConfirm && !readAnswer('y')) { out << "Aborting.\n"; return EXIT_SUCCESS; } } // Check the output directory if (!QDir(outDir).exists()) { if (!autoConfirm) { out << "Directory '" << outDir << "' does not exist. Create it [Y/n]? "; out.flush(); } if (autoConfirm || readAnswer('y')) { if (!QDir().mkpath(outDir)) { qCritical() << "Could not create directory:" << outDir; return EXIT_FAILURE; } } else { out << "Aborting.\n"; return EXIT_SUCCESS; } } if (!QDir(outDir).entryList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) { if (!autoConfirm) { out << "Directory '" << outDir << "' is not empty. Continue [y/N]? "; out.flush(); } if (!autoConfirm && !readAnswer('n')) { out << "Aborting.\n"; return EXIT_SUCCESS; } } // Extract the license text QFile licenseFile(licensePath); if (!licenseFile.open(QIODevice::ReadOnly)) { qCritical() << "Cannot open file" << licenseFile.fileName(); return EXIT_FAILURE; } QString licenseText = licenseFile.readAll(); licenseFile.close(); QHash parameters; if (createProject) { // Extract the copyright QFile copyrightFile(copyrightPath); if (!copyrightFile.open(QIODevice::ReadOnly)) { qCritical() << "Cannot open file" << copyrightFile.fileName(); return EXIT_FAILURE; } QString copyrighText = copyrightFile.readAll(); copyrightFile.close(); parameters["$(copyright)"] = copyrighText; parameters["$(project-name)"] = projectName; parameters["$(project-app-name)"] = projectAppName; parameters["$(project-plugins)"] = QString("Plugins/") + pluginSymbolicName + ":ON"; QStringList toks = pluginTarget.split("_"); QString projectPluginBase = toks[0] + "_" + toks[1]; parameters["$(project-plugin-base)"] = projectPluginBase; } parameters["$(license)"] = licenseText; parameters["$(plugin-name)"] = pluginName; parameters["$(plugin-symbolic-name)"] = pluginSymbolicName; parameters["$(vendor)"] = vendor; parameters["$(plugin-target)"] = pluginTarget; parameters["$(plugin-export-directive)"] = pluginExportDirective; parameters["$(view-id)"] = viewId; parameters["$(view-name)"] = viewName; parameters["$(view-file-name)"] = viewClass; parameters["$(view-class-name)"] = viewClass; parameters["$(activator-file-name)"] = activatorClass; parameters["$(activator-class-name)"] = activatorClass; if (createProject) { QHash projectFileNameMapping; projectFileNameMapping["TemplateApp"] = projectAppName; QHash filePathMapping = createTemplateFileMapping(":/ProjectTemplate", outDir, projectFileNameMapping); generateFiles(parameters, filePathMapping); } QHash pluginFileNameMapping; pluginFileNameMapping["QmitkTemplateView"] = viewClass; pluginFileNameMapping["mitkPluginActivator"] = activatorClass; if (createProject) { if (!outDir.endsWith('/')) outDir += '/'; outDir += "Plugins/" + pluginSymbolicName; } QHash filePathMapping = createTemplateFileMapping(":/PluginTemplate", outDir, pluginFileNameMapping); generateFiles(parameters, filePathMapping); return EXIT_SUCCESS; } diff --git a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt index f7afae7f5f..162805f0d2 100644 --- a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt +++ b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt @@ -1,329 +1,325 @@ cmake_minimum_required(VERSION 3.18 FATAL_ERROR) # Change project and application name to your own set(MY_PROJECT_NAME $(project-name)) set(MY_APP_NAME $(project-app-name)) #----------------------------------------------------------------------------- # Set the language standard (MITK requires C++17) #----------------------------------------------------------------------------- set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED 1) set(CMAKE_CXX_EXTENSIONS 0) #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(${MY_PROJECT_NAME}_USE_SUPERBUILD "Build ${MY_PROJECT_NAME} and the projects it depends on via SuperBuild.cmake." ON) if(${MY_PROJECT_NAME}_USE_SUPERBUILD) project(${MY_PROJECT_NAME}-superbuild) set(${MY_PROJECT_NAME}_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(${MY_PROJECT_NAME}_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(${MY_PROJECT_NAME}) endif() -#----------------------------------------------------------------------------- -# See http://cmake.org/cmake/help/cmake-2-8-docs.html#section_Policies for details -#----------------------------------------------------------------------------- - set(project_policies CMP0001 # NEW: CMAKE_BACKWARDS_COMPATIBILITY should no longer be used. CMP0002 # NEW: Logical target names must be globally unique. CMP0003 # NEW: Libraries linked via full path no longer produce linker search paths. CMP0004 # NEW: Libraries linked may NOT have leading or trailing whitespace. CMP0005 # NEW: Preprocessor definition values are now escaped automatically. CMP0006 # NEW: Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION. CMP0007 # NEW: List command no longer ignores empty elements. CMP0008 # NEW: Libraries linked by full-path must have a valid library file name. CMP0009 # NEW: FILE GLOB_RECURSE calls should not follow symlinks by default. CMP0010 # NEW: Bad variable reference syntax is an error. CMP0011 # NEW: Included scripts do automatic cmake_policy PUSH and POP. CMP0012 # NEW: if() recognizes numbers and boolean constants. CMP0013 # NEW: Duplicate binary directories are not allowed. CMP0014 # NEW: Input directories must have CMakeLists.txt CMP0020 # NEW: Automatically link Qt executables to qtmain target on Windows. CMP0028 # NEW: Double colon in target name means ALIAS or IMPORTED target. ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${${MY_PROJECT_NAME}_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- include(CTest) include(MacroEmptyExternalProject) #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- foreach(type LIBRARY RUNTIME ARCHIVE) set(output_dir ${${MY_PROJECT_NAME}_BINARY_DIR}/bin) set(CMAKE_${type}_OUTPUT_DIRECTORY ${output_dir} CACHE INTERNAL "Single output directory for building all libraries.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Additional Options (also shown during superbuild) #----------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build ${MY_PROJECT_NAME} with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS "Build all ${MY_PROJECT_NAME} plugins" OFF) mark_as_advanced(${MY_PROJECT_NAME}_INSTALL_RPATH_RELATIVE ${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS ) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(${MY_PROJECT_NAME}_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # Prerequesites #----------------------------------------------------------------------------- set(${PROJECT_NAME}_MODULES_PACKAGE_DEPENDS_DIR "${PROJECT_SOURCE_DIR}/CMake/PackageDepends") set(MODULES_PACKAGE_DEPENDS_DIRS ${${PROJECT_NAME}_MODULES_PACKAGE_DEPENDS_DIR}) find_package(MITK 2018.04.99 REQUIRED) if(COMMAND mitkFunctionCheckMitkCompatibility) mitkFunctionCheckMitkCompatibility(VERSIONS MITK_VERSION_PLUGIN_SYSTEM 1 REQUIRED) else() message(SEND_ERROR "Your MITK version is too old. Please use Git hash b86bf28 or newer") endif() link_directories(${MITK_LINK_DIRECTORIES}) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionGetGccVersion) include(mitkFunctionGetVersion) #----------------------------------------------------------------------------- # Set project specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- set(${PROJECT_NAME}_VERSION_MAJOR "0") set(${PROJECT_NAME}_VERSION_MINOR "1") set(${PROJECT_NAME}_VERSION_PATCH "1") set(${PROJECT_NAME}_VERSION_STRING "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}") # Ask the user if a console window should be shown with the applications option(${PROJECT_NAME}_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting GUI Applications" ON) mark_as_advanced(${PROJECT_NAME}_SHOW_CONSOLE_WINDOW) if(NOT UNIX) set(MITK_WIN32_FORCE_STATIC "STATIC") endif() #----------------------------------------------------------------------------- # Get project version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${PROJECT_SOURCE_DIR} ${PROJECT_NAME}) #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on macOS all CTK plugins get copied into every # application bundle (.app directory) specified here set(MACOSX_BUNDLE_NAMES) if(APPLE) list(APPEND MACOSX_BUNDLE_NAMES ${MY_APP_NAME}) endif(APPLE) #----------------------------------------------------------------------------- # Set symbol visibility Flags #----------------------------------------------------------------------------- if(CMAKE_COMPILER_IS_GNUCXX) # The MITK module build system does not yet support default hidden visibility set(VISIBILITY_CXX_FLAGS ) # "-fvisibility=hidden -fvisibility-inlines-hidden") endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if(CMAKE_COMPILER_IS_GNUCXX) set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # Project C/CXX Flags #----------------------------------------------------------------------------- set(${PROJECT_NAME}_C_FLAGS "${MITK_C_FLAGS} ${COVERAGE_C_FLAGS}") set(${PROJECT_NAME}_C_FLAGS_DEBUG ${MITK_C_FLAGS_DEBUG}) set(${PROJECT_NAME}_C_FLAGS_RELEASE ${MITK_C_FLAGS_RELEASE}) set(${PROJECT_NAME}_CXX_FLAGS "${MITK_CXX_FLAGS} ${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS}") set(${PROJECT_NAME}_CXX_FLAGS_DEBUG ${MITK_CXX_FLAGS_DEBUG}) set(${PROJECT_NAME}_CXX_FLAGS_RELEASE ${MITK_CXX_FLAGS_RELEASE}) set(${PROJECT_NAME}_EXE_LINKER_FLAGS ${MITK_EXE_LINKER_FLAGS}) set(${PROJECT_NAME}_SHARED_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(${PROJECT_NAME}_MODULE_LINKER_FLAGS ${MITK_MODULE_LINKER_FLAGS}) #----------------------------------------------------------------------------- # Set C/CXX Flags #----------------------------------------------------------------------------- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${${PROJECT_NAME}_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${${PROJECT_NAME}_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${${PROJECT_NAME}_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${PROJECT_NAME}_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${${PROJECT_NAME}_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${${PROJECT_NAME}_CXX_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS ${${PROJECT_NAME}_EXE_LINKER_FLAGS}) set(CMAKE_SHARED_LINKER_FLAGS ${${PROJECT_NAME}_SHARED_LINKER_FLAGS}) set(CMAKE_MODULE_LINKER_FLAGS ${${PROJECT_NAME}_MODULE_LINKER_FLAGS}) #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch (const std::exception& e) { fprintf(stderr, \"%s\\n\", e.what()); return EXIT_FAILURE; } catch (...) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; }") endif() #----------------------------------------------------------------------------- # ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR isn't defined, it means this project is # *NOT* build using Superbuild. In that specific case, ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR # should default to PROJECT_BINARY_DIR if(NOT DEFINED ${PROJECT_NAME}_SUPERBUILD_BINARY_DIR) set(${PROJECT_NAME}_SUPERBUILD_BINARY_DIR ${PROJECT_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK modules #----------------------------------------------------------------------------- #add_subdirectory(Modules) #----------------------------------------------------------------------------- # CTK plugins #----------------------------------------------------------------------------- # The CMake code in this section *must* be in the top-level CMakeLists.txt file macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin "^$(project-plugin-base)_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin OUTPUT_VARIABLE ${varname}) endmacro() include(${CMAKE_CURRENT_SOURCE_DIR}/Plugins/Plugins.cmake) ctkMacroSetupPlugins(${PROJECT_PLUGINS} BUILD_OPTION_PREFIX ${MY_PROJECT_NAME}_ BUILD_ALL ${${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS}) #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Apps/$(project-app-name)) #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables include(mitkSetupCPack) # Customize CPack variables for this project include(CPackSetup) list(APPEND CPACK_CREATE_DESKTOP_LINKS "${MY_APP_NAME}") configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake") # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- diff --git a/Applications/PluginGenerator/ctkCommandLineParser.cpp b/Applications/PluginGenerator/ctkCommandLineParser.cpp index d8214ea76d..52d3c45068 100644 --- a/Applications/PluginGenerator/ctkCommandLineParser.cpp +++ b/Applications/PluginGenerator/ctkCommandLineParser.cpp @@ -1,874 +1,874 @@ /*========================================================================= Library: CTK Copyright (c) Kitware Inc. 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.txt + https://www.apache.org/licenses/LICENSE-2.0.txt 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. =========================================================================*/ // STL includes #include // Qt includes #include #include #include #include #include #include // CTK includes #include "ctkCommandLineParser.h" namespace { // -------------------------------------------------------------------------- class CommandLineParserArgumentDescription { public: CommandLineParserArgumentDescription(const QString &longArg, const QString &longArgPrefix, const QString &shortArg, const QString &shortArgPrefix, QVariant::Type type, const QString &argHelp, const QVariant &defaultValue, bool ignoreRest, bool deprecated) : LongArg(longArg), LongArgPrefix(longArgPrefix), ShortArg(shortArg), ShortArgPrefix(shortArgPrefix), ArgHelp(argHelp), IgnoreRest(ignoreRest), NumberOfParametersToProcess(0), Deprecated(deprecated), DefaultValue(defaultValue), Value(type), ValueType(type) { if (defaultValue.isValid()) { Value = defaultValue; } switch (type) { case QVariant::String: { NumberOfParametersToProcess = 1; RegularExpression = ".*"; } break; case QVariant::Bool: { NumberOfParametersToProcess = 0; RegularExpression = ""; } break; case QVariant::StringList: { NumberOfParametersToProcess = -1; RegularExpression = ".*"; } break; case QVariant::Int: { NumberOfParametersToProcess = 1; RegularExpression = "-?[0-9]+"; ExactMatchFailedMessage = "A negative or positive integer is expected."; } break; default: ExactMatchFailedMessage = QString("Type %1 not supported.").arg(static_cast(type)); } } ~CommandLineParserArgumentDescription() {} bool addParameter(const QString &value); QString helpText(int fieldWidth, const char charPad, const QString &settingsValue = ""); QString LongArg; QString LongArgPrefix; QString ShortArg; QString ShortArgPrefix; QString ArgHelp; bool IgnoreRest; int NumberOfParametersToProcess; QString RegularExpression; QString ExactMatchFailedMessage; bool Deprecated; QVariant DefaultValue; QVariant Value; QVariant::Type ValueType; }; // -------------------------------------------------------------------------- bool CommandLineParserArgumentDescription::addParameter(const QString &value) { if (!RegularExpression.isEmpty()) { // Validate value QRegExp regexp(this->RegularExpression); if (!regexp.exactMatch(value)) { return false; } } switch (Value.type()) { case QVariant::String: { Value.setValue(value); } break; case QVariant::Bool: { Value.setValue(!QString::compare(value, "true", Qt::CaseInsensitive)); } break; case QVariant::StringList: { if (Value.isNull()) { QStringList list; list << value; Value.setValue(list); } else { QStringList list = Value.toStringList(); list << value; Value.setValue(list); } } break; case QVariant::Int: { Value.setValue(value.toInt()); } break; default: return false; } return true; } // -------------------------------------------------------------------------- QString CommandLineParserArgumentDescription::helpText(int fieldWidth, const char charPad, const QString &settingsValue) { QString text; QTextStream stream(&text); stream.setFieldAlignment(QTextStream::AlignLeft); stream.setPadChar(charPad); QString shortAndLongArg; if (!this->ShortArg.isEmpty()) { shortAndLongArg += QString(" %1%2").arg(this->ShortArgPrefix).arg(this->ShortArg); } if (!this->LongArg.isEmpty()) { if (this->ShortArg.isEmpty()) { shortAndLongArg.append(" "); } else { shortAndLongArg.append(", "); } shortAndLongArg += QString("%1%2").arg(this->LongArgPrefix).arg(this->LongArg); } if (!this->ArgHelp.isEmpty()) { stream.setFieldWidth(fieldWidth); } stream << shortAndLongArg; stream.setFieldWidth(0); stream << this->ArgHelp; if (!settingsValue.isNull()) { stream << " (default: " << settingsValue << ")"; } else if (!this->DefaultValue.isNull()) { stream << " (default: " << this->DefaultValue.toString() << ")"; } stream << "\n"; return text; } } // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal class // -------------------------------------------------------------------------- class ctkCommandLineParser::ctkInternal { public: ctkInternal(QSettings *settings) : Debug(false), FieldWidth(0), UseQSettings(false), Settings(settings), MergeSettings(true), StrictMode(false) { } ~ctkInternal() { qDeleteAll(ArgumentDescriptionList); } CommandLineParserArgumentDescription *argumentDescription(const QString &argument); QList ArgumentDescriptionList; QHash ArgNameToArgumentDescriptionMap; QMap> GroupToArgumentDescriptionListMap; QStringList UnparsedArguments; QStringList ProcessedArguments; QString ErrorString; bool Debug; int FieldWidth; QString LongPrefix; QString ShortPrefix; QString CurrentGroup; bool UseQSettings; QPointer Settings; QString DisableQSettingsLongArg; QString DisableQSettingsShortArg; bool MergeSettings; bool StrictMode; }; // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal methods // -------------------------------------------------------------------------- CommandLineParserArgumentDescription *ctkCommandLineParser::ctkInternal::argumentDescription(const QString &argument) { QString unprefixedArg = argument; if (!LongPrefix.isEmpty() && argument.startsWith(LongPrefix)) { // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix if (argument == LongPrefix && !ShortPrefix.isEmpty() && argument.startsWith(ShortPrefix)) { unprefixedArg = argument.mid(ShortPrefix.length()); } else { unprefixedArg = argument.mid(LongPrefix.length()); } } else if (!ShortPrefix.isEmpty() && argument.startsWith(ShortPrefix)) { unprefixedArg = argument.mid(ShortPrefix.length()); } else if (!LongPrefix.isEmpty() && !ShortPrefix.isEmpty()) { return nullptr; } if (this->ArgNameToArgumentDescriptionMap.contains(unprefixedArg)) { return this->ArgNameToArgumentDescriptionMap[unprefixedArg]; } return nullptr; } // -------------------------------------------------------------------------- // ctkCommandLineParser methods // -------------------------------------------------------------------------- ctkCommandLineParser::ctkCommandLineParser(QObject *newParent) : Superclass(newParent) { this->Internal = new ctkInternal(nullptr); } // -------------------------------------------------------------------------- ctkCommandLineParser::ctkCommandLineParser(QSettings *settings, QObject *newParent) : Superclass(newParent) { this->Internal = new ctkInternal(settings); } // -------------------------------------------------------------------------- ctkCommandLineParser::~ctkCommandLineParser() { delete this->Internal; } // -------------------------------------------------------------------------- QHash ctkCommandLineParser::parseArguments(const QStringList &arguments, bool *ok) { // Reset this->Internal->UnparsedArguments.clear(); this->Internal->ProcessedArguments.clear(); this->Internal->ErrorString.clear(); foreach (CommandLineParserArgumentDescription *desc, this->Internal->ArgumentDescriptionList) { desc->Value = QVariant(desc->ValueType); if (desc->DefaultValue.isValid()) { desc->Value = desc->DefaultValue; } } bool error = false; bool ignoreRest = false; bool useSettings = this->Internal->UseQSettings; CommandLineParserArgumentDescription *currentArgDesc = nullptr; QList parsedArgDescriptions; for (int i = 1; i < arguments.size(); ++i) { QString argument = arguments.at(i); if (this->Internal->Debug) { qDebug() << "Processing" << argument; } // should argument be ignored ? if (ignoreRest) { if (this->Internal->Debug) { qDebug() << " Skipping: IgnoreRest flag was been set"; } this->Internal->UnparsedArguments << argument; continue; } // Skip if the argument does not start with the defined prefix if (!(argument.startsWith(this->Internal->LongPrefix) || argument.startsWith(this->Internal->ShortPrefix))) { if (this->Internal->StrictMode) { this->Internal->ErrorString = QString("Unknown argument %1").arg(argument); error = true; break; } if (this->Internal->Debug) { qDebug() << " Skipping: It does not start with the defined prefix"; } this->Internal->UnparsedArguments << argument; continue; } // Skip if argument has already been parsed ... if (this->Internal->ProcessedArguments.contains(argument)) { if (this->Internal->StrictMode) { this->Internal->ErrorString = QString("Argument %1 already processed !").arg(argument); error = true; break; } if (this->Internal->Debug) { qDebug() << " Skipping: Already processed !"; } continue; } // Retrieve corresponding argument description currentArgDesc = this->Internal->argumentDescription(argument); // Is there a corresponding argument description ? if (currentArgDesc) { // If the argument is deprecated, print the help text but continue processing if (currentArgDesc->Deprecated) { qWarning().nospace() << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp; } else { parsedArgDescriptions.push_back(currentArgDesc); } // Is the argument the special "disable QSettings" argument? if ((!currentArgDesc->LongArg.isEmpty() && currentArgDesc->LongArg == this->Internal->DisableQSettingsLongArg) || (!currentArgDesc->ShortArg.isEmpty() && currentArgDesc->ShortArg == this->Internal->DisableQSettingsShortArg)) { useSettings = false; } this->Internal->ProcessedArguments << currentArgDesc->ShortArg << currentArgDesc->LongArg; int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess; ignoreRest = currentArgDesc->IgnoreRest; if (this->Internal->Debug && ignoreRest) { qDebug() << " IgnoreRest flag is True"; } // Is the number of parameters associated with the argument being processed known ? if (numberOfParametersToProcess == 0) { currentArgDesc->addParameter("true"); } else if (numberOfParametersToProcess > 0) { QString missingParameterError = "Argument %1 has %2 value(s) associated whereas exacly %3 are expected."; for (int j = 1; j <= numberOfParametersToProcess; ++j) { if (i + j >= arguments.size()) { this->Internal->ErrorString = missingParameterError.arg(argument).arg(j - 1).arg(numberOfParametersToProcess); if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; } if (ok) { *ok = false; } return QHash(); } QString parameter = arguments.at(i + j); if (this->Internal->Debug) { qDebug() << " Processing parameter" << j << ", value:" << parameter; } if (this->argumentAdded(parameter)) { this->Internal->ErrorString = missingParameterError.arg(argument).arg(j - 1).arg(numberOfParametersToProcess); if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; } if (ok) { *ok = false; } return QHash(); } if (!currentArgDesc->addParameter(parameter)) { this->Internal->ErrorString = QString("Value(s) associated with argument %1 are incorrect. %2") .arg(argument) .arg(currentArgDesc->ExactMatchFailedMessage); if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; } if (ok) { *ok = false; } return QHash(); } } // Update main loop increment i = i + numberOfParametersToProcess; } else if (numberOfParametersToProcess == -1) { if (this->Internal->Debug) { qDebug() << " Proccessing StringList ..."; } int j = 1; while (j + i < arguments.size()) { if (this->argumentAdded(arguments.at(j + i))) { if (this->Internal->Debug) { qDebug() << " No more parameter for" << argument; } break; } QString parameter = arguments.at(j + i); if (this->Internal->Debug) { qDebug() << " Processing parameter" << j << ", value:" << parameter; } if (!currentArgDesc->addParameter(parameter)) { this->Internal->ErrorString = QString("Value(s) associated with argument %1 are incorrect. %2") .arg(argument) .arg(currentArgDesc->ExactMatchFailedMessage); if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; } if (ok) { *ok = false; } return QHash(); } j++; } // Update main loop increment i = i + j; } } else { if (this->Internal->StrictMode) { this->Internal->ErrorString = QString("Unknown argument %1").arg(argument); error = true; break; } if (this->Internal->Debug) { qDebug() << " Skipping: Unknown argument"; } this->Internal->UnparsedArguments << argument; } } if (ok) { *ok = !error; } QSettings *settings = nullptr; if (this->Internal->UseQSettings && useSettings) { if (this->Internal->Settings) { settings = this->Internal->Settings; } else { // Use a default constructed QSettings instance settings = new QSettings(); } } QHash parsedArguments; QListIterator it(this->Internal->ArgumentDescriptionList); while (it.hasNext()) { QString key; CommandLineParserArgumentDescription *desc = it.next(); if (!desc->LongArg.isEmpty()) { key = desc->LongArg; } else { key = desc->ShortArg; } if (parsedArgDescriptions.contains(desc)) { // The argument was supplied on the command line, so use the given value if (this->Internal->MergeSettings && settings) { // Merge with QSettings QVariant settingsVal = settings->value(key); if (desc->ValueType == QVariant::StringList && settingsVal.canConvert(QVariant::StringList)) { QStringList stringList = desc->Value.toStringList(); stringList.append(settingsVal.toStringList()); parsedArguments.insert(key, stringList); } else { // do a normal insert parsedArguments.insert(key, desc->Value); } } else { // No merging, just insert all user values parsedArguments.insert(key, desc->Value); } } else { if (settings) { // If there is a valid QSettings entry for the argument, use the value QVariant settingsVal = settings->value(key, desc->Value); if (!settingsVal.isNull()) { parsedArguments.insert(key, settingsVal); } } else { // Just insert the arguments with valid default values if (!desc->Value.isNull()) { parsedArguments.insert(key, desc->Value); } } } } // If we created a default QSettings instance, delete it if (settings && !this->Internal->Settings) { delete settings; } return parsedArguments; } // ------------------------------------------------------------------------- QHash ctkCommandLineParser::parseArguments(int argc, char **argv, bool *ok) { QStringList arguments; // Create a QStringList of arguments for (int i = 0; i < argc; ++i) { arguments << argv[i]; } return this->parseArguments(arguments, ok); } // ------------------------------------------------------------------------- QString ctkCommandLineParser::errorString() const { return this->Internal->ErrorString; } // ------------------------------------------------------------------------- const QStringList &ctkCommandLineParser::unparsedArguments() const { return this->Internal->UnparsedArguments; } // -------------------------------------------------------------------------- void ctkCommandLineParser::addArgument(const QString &longarg, const QString &shortarg, QVariant::Type type, const QString &argHelp, const QVariant &defaultValue, bool ignoreRest, bool deprecated) { Q_ASSERT_X(!(longarg.isEmpty() && shortarg.isEmpty()), "addArgument", "both long and short argument names are empty"); if (longarg.isEmpty() && shortarg.isEmpty()) { return; } Q_ASSERT_X(!defaultValue.isValid() || defaultValue.type() == type, "addArgument", "defaultValue type does not match"); if (defaultValue.isValid() && defaultValue.type() != type) throw std::logic_error("The QVariant type of defaultValue does not match the specified type"); /* Make sure it's not already added */ bool added = this->Internal->ArgNameToArgumentDescriptionMap.contains(longarg); Q_ASSERT_X(!added, "addArgument", "long argument already added"); if (added) { return; } added = this->Internal->ArgNameToArgumentDescriptionMap.contains(shortarg); Q_ASSERT_X(!added, "addArgument", "short argument already added"); if (added) { return; } auto argDesc = new CommandLineParserArgumentDescription(longarg, this->Internal->LongPrefix, shortarg, this->Internal->ShortPrefix, type, argHelp, defaultValue, ignoreRest, deprecated); int argWidth = 0; if (!longarg.isEmpty()) { this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc; argWidth += longarg.length() + this->Internal->LongPrefix.length(); } if (!shortarg.isEmpty()) { this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc; argWidth += shortarg.length() + this->Internal->ShortPrefix.length() + 2; } argWidth += 5; // Set the field width for the arguments if (argWidth > this->Internal->FieldWidth) { this->Internal->FieldWidth = argWidth; } this->Internal->ArgumentDescriptionList << argDesc; this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup] << argDesc; } // -------------------------------------------------------------------------- void ctkCommandLineParser::addDeprecatedArgument(const QString &longarg, const QString &shortarg, const QString &argHelp) { addArgument(longarg, shortarg, QVariant::StringList, argHelp, QVariant(), false, true); } // -------------------------------------------------------------------------- bool ctkCommandLineParser::setExactMatchRegularExpression(const QString &argument, const QString &expression, const QString &exactMatchFailedMessage) { CommandLineParserArgumentDescription *argDesc = this->Internal->argumentDescription(argument); if (!argDesc) { return false; } if (argDesc->Value.type() == QVariant::Bool) { return false; } argDesc->RegularExpression = expression; argDesc->ExactMatchFailedMessage = exactMatchFailedMessage; return true; } // -------------------------------------------------------------------------- int ctkCommandLineParser::fieldWidth() const { return this->Internal->FieldWidth; } // -------------------------------------------------------------------------- void ctkCommandLineParser::beginGroup(const QString &description) { this->Internal->CurrentGroup = description; } // -------------------------------------------------------------------------- void ctkCommandLineParser::endGroup() { this->Internal->CurrentGroup.clear(); } // -------------------------------------------------------------------------- void ctkCommandLineParser::enableSettings(const QString &disableLongArg, const QString &disableShortArg) { this->Internal->UseQSettings = true; this->Internal->DisableQSettingsLongArg = disableLongArg; this->Internal->DisableQSettingsShortArg = disableShortArg; } // -------------------------------------------------------------------------- void ctkCommandLineParser::mergeSettings(bool merge) { this->Internal->MergeSettings = merge; } // -------------------------------------------------------------------------- bool ctkCommandLineParser::settingsEnabled() const { return this->Internal->UseQSettings; } // -------------------------------------------------------------------------- QString ctkCommandLineParser::helpText(const char charPad) const { QString text; QTextStream stream(&text); QList deprecatedArgs; // Loop over grouped argument descriptions QMapIterator> it( this->Internal->GroupToArgumentDescriptionListMap); while (it.hasNext()) { it.next(); if (!it.key().isEmpty()) { stream << "\n" << it.key() << "\n"; } foreach (CommandLineParserArgumentDescription *argDesc, it.value()) { if (argDesc->Deprecated) { deprecatedArgs << argDesc; } else { // Extract associated value from settings if any QString settingsValue; if (this->Internal->Settings) { QString key; if (!argDesc->LongArg.isEmpty()) { key = argDesc->LongArg; } else { key = argDesc->ShortArg; } settingsValue = this->Internal->Settings->value(key).toString(); } stream << argDesc->helpText(this->Internal->FieldWidth, charPad, settingsValue); } } } if (!deprecatedArgs.empty()) { stream << "\nDeprecated arguments:\n"; foreach (CommandLineParserArgumentDescription *argDesc, deprecatedArgs) { stream << argDesc->helpText(this->Internal->FieldWidth, charPad); } } return text; } // -------------------------------------------------------------------------- bool ctkCommandLineParser::argumentAdded(const QString &argument) const { return this->Internal->ArgNameToArgumentDescriptionMap.contains(argument); } // -------------------------------------------------------------------------- bool ctkCommandLineParser::argumentParsed(const QString &argument) const { return this->Internal->ProcessedArguments.contains(argument); } // -------------------------------------------------------------------------- void ctkCommandLineParser::setArgumentPrefix(const QString &longPrefix, const QString &shortPrefix) { this->Internal->LongPrefix = longPrefix; this->Internal->ShortPrefix = shortPrefix; } // -------------------------------------------------------------------------- void ctkCommandLineParser::setStrictModeEnabled(bool strictMode) { this->Internal->StrictMode = strictMode; } diff --git a/Applications/PluginGenerator/ctkCommandLineParser.h b/Applications/PluginGenerator/ctkCommandLineParser.h index daee3816fe..da1de78e8f 100644 --- a/Applications/PluginGenerator/ctkCommandLineParser.h +++ b/Applications/PluginGenerator/ctkCommandLineParser.h @@ -1,418 +1,418 @@ /*========================================================================= Library: CTK Copyright (c) Kitware Inc. 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.txt + https://www.apache.org/licenses/LICENSE-2.0.txt 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 __ctkCommandLineParser_h #define __ctkCommandLineParser_h // Qt includes #include #include #include class QSettings; /** * \ingroup Core * * The CTK command line parser. * * Use this class to add information about the command line arguments * your program understands and to easily parse them from a given list * of strings. * * This parser provides the following features: * *
    *
  • Add arguments by supplying a long name and/or a short name. * Arguments are validated using a regular expression. They can have * a default value and a help string.
  • *
  • Deprecated arguments.
  • *
  • Custom regular expressions for argument validation.
  • *
  • Set different argument name prefixes for native platform look and feel.
  • *
  • QSettings support. Default values for arguments can be read from * a QSettings object.
  • *
  • Create a help text for the command line arguments with support for * grouping arguments.
  • *
* * Here is an example how to use this class inside a main function: * * \code * #include * #include * #include * * int main(int argc, char** argv) * { * QCoreApplication app(argc, argv); * // This is used by QSettings * QCoreApplication::setOrganizationName("MyOrg"); * QCoreApplication::setApplicationName("MyApp"); * * ctkCommandLineParser parser; * // Use Unix-style argument names * parser.setArgumentPrefix("--", "-"); * // Enable QSettings support * parser.enableSettings("disable-settings"); * * // Add command line argument names * parser.addArgument("disable-settings", "", QVariant::Bool, "Do not use QSettings"); * parser.addArgument("help", "h", QVariant::Bool, "Show this help text"); * parser.addArgument("search-paths", "s", QVariant::StringList, "A list of paths to search"); * * // Parse the command line arguments * bool ok = false; * QHash parsedArgs = parser.parseArguments(QCoreApplication::arguments(), &ok); * if (!ok) * { * QTextStream(stderr, QIODevice::WriteOnly) << "Error parsing arguments: " * << parser.errorString() << "\n"; * return EXIT_FAILURE; * } * * // Show a help message * if (parsedArgs.contains("help") || parsedArgs.contains("h")) * { * QTextStream(stdout, QIODevice::WriteOnly) << parser.helpText(); * return EXIT_SUCCESS; * } * * // Do something * * return EXIT_SUCCESS; * } * \endcode */ class ctkCommandLineParser : public QObject { Q_OBJECT Q_PROPERTY(QString errorString READ errorString) Q_PROPERTY(QStringList unparsedArguments READ unparsedArguments) Q_PROPERTY(bool settingsEnabled READ settingsEnabled) public: typedef QObject Superclass; /** * Constructs a parser instance. * * If QSettings support is enabled by a call to enableSettings() * a default constructed QSettings instance will be used when parsing * the command line arguments. Make sure to call QCoreApplication::setOrganizationName() * and QCoreApplication::setApplicationName() before using default * constructed QSettings objects. * * @param newParent The QObject parent. */ ctkCommandLineParser(QObject *newParent = nullptr); /** * Constructs a parser instance. * * If QSettings support is enabled by a call to enableSettings() * the provided QSettings instance will be used. If the QSettings instance is * zero, a default constructed QSettings instance will be used when parsing * the command line arguments. Using a default constructed instance is usually * what you want, if you have called QCoreApplication::setOrganizationName() * and QCoreApplication::setApplicationName(). * * @param settings A QSettings instance which should be used. * @param newParent The QObject parent. * * */ ctkCommandLineParser(QSettings *settings, QObject *newParent = nullptr); ~ctkCommandLineParser() override; /** * Parse a given list of command line arguments. * * This method parses a list of QString elements considering the known arguments * added by calls to addArgument(). If any one of the argument * values does not match the corresponding regular expression, * ok is set to false and an empty QHash object is returned. * * The keys in the returned QHash object correspond to the long argument string, * if it is not empty. Otherwise, the short argument string is used as key. The * QVariant values can safely be converted to the type specified in the * addArgument() method call. * * @param arguments A QStringList containing command line arguments. Usually * given by QCoreApplication::arguments(). * @param ok A pointer to a boolean variable. Will be set to true * if all regular expressions matched, false otherwise. * @return A QHash object mapping the long argument (if empty, the short one) * to a QVariant containing the value. */ QHash parseArguments(const QStringList &arguments, bool *ok = nullptr); /** * Convenient method allowing to parse a given list of command line arguments. * @see parseArguments(const QStringList &, bool*) */ QHash parseArguments(int argc, char **argv, bool *ok = nullptr); /** * Returns a detailed error description if a call to parseArguments() * failed. * * @return The error description, empty if no error occured. * @see parseArguments(const QStringList&, bool*) */ QString errorString() const; /** * This method returns all unparsed arguments, i.e. all arguments * for which no long or short name has been registered via a call * to addArgument(). * * @see addArgument() * * @return A list containing unparsed arguments. */ const QStringList &unparsedArguments() const; /** * Checks if the given argument has been added via a call * to addArgument(). * * @see addArgument() * * @param argument The argument to be checked. * @return true if the argument was added, false * otherwise. */ Q_INVOKABLE bool argumentAdded(const QString &argument) const; /** * Checks if the given argument has been parsed successfully by a previous * call to parseArguments(). * * @param argument The argument to be checked. * @return true if the argument was parsed, false * otherwise. */ Q_INVOKABLE bool argumentParsed(const QString &argument) const; /** * Adds a command line argument. An argument can have a long name * (like --long-argument-name), a short name (like -l), or both. The type * of the argument can be specified by using the type parameter. * The following types are supported: * * * * * * * * *
Type# of parametersDefault regular exprExample
QVariant::String1.*--test-string StringParameter
QVariant::Bool0does not apply--enable-something
QVariant::StringList-1.*--test-list string1 string2
QVariant::Int1-?[0-9]+--test-int -5
* * The regular expressions are used to validate the parameters of command line * arguments. You can restrict the valid set of parameters by calling * setExactMatchRegularExpression() for your argument. * * Optionally, a help string and a default value can be provided for the argument. If * the QVariant type of the default value does not match type, an * exception is thrown. Arguments with default values are always returned by * parseArguments(). * * You can also declare an argument deprecated, by setting deprecated * to true. Alternatively you can add a deprecated argument by calling * addDeprecatedArgument(). * * If the long or short argument has already been added, or if both are empty strings, * the method call has no effect. * * @param longarg The long argument name. * @param shortarg The short argument name. * @param type The argument type (see the list above for supported types). * @param argHelp A help string describing the argument. * @param defaultValue A default value for the argument. * @param ignoreRest All arguments after the current one will be ignored. * @param deprecated Declares the argument deprecated. * * @see setExactMatchRegularExpression() * @see addDeprecatedArgument() * @throws std::logic_error If the QVariant type of defaultValue * does not match type, a std::logic_error is thrown. */ void addArgument(const QString &longarg, const QString &shortarg, QVariant::Type type, const QString &argHelp = QString(), const QVariant &defaultValue = QVariant(), bool ignoreRest = false, bool deprecated = false); /** * Adds a deprecated command line argument. If a deprecated argument is provided * on the command line, argHelp is displayed in the console and * processing continues with the next argument. * * Deprecated arguments are grouped separately at the end of the help text * returned by helpText(). * * @param longarg The long argument name. * @param shortarg The short argument name. * @param argHelp A help string describing alternatives to the deprecated argument. */ void addDeprecatedArgument(const QString &longarg, const QString &shortarg, const QString &argHelp); /** * Sets a custom regular expression for validating argument parameters. The method * errorString() can be used the get the last error description. * * @param argument The previously added long or short argument name. * @param expression A regular expression which the arugment parameters must match. * @param exactMatchFailedMessage An error message explaining why the parameter did * not match. * * @return true if the argument was found and the regular expression was set, * false otherwise. * * @see errorString() */ bool setExactMatchRegularExpression(const QString &argument, const QString &expression, const QString &exactMatchFailedMessage); /** * The field width for the argument names without the help text. * * @return The argument names field width in the help text. */ int fieldWidth() const; /** * Creates a help text containing properly formatted argument names and help strings * provided by calls to addArgument(). The arguments can be grouped by * using beginGroup() and endGroup(). * * @param charPad The padding character. * @return The formatted help text. */ QString helpText(const char charPad = ' ') const; /** * Sets the argument prefix for long and short argument names. This can be used * to create native command line arguments without changing the calls to * addArgument(). For example on Unix-based systems, long argument * names start with "--" and short names with "-", while on Windows argument names * always start with "/". * * Note that all methods in ctkCommandLineParser which take an argument name * expect the name as it was supplied to addArgument. * * Example usage: * * \code * ctkCommandLineParser parser; * parser.setArgumentPrefix("--", "-"); * parser.addArgument("long-argument", "l", QVariant::String); * QStringList args; * args << "program name" << "--long-argument Hi"; * parser.parseArguments(args); * \endcode * * @param longPrefix The prefix for long argument names. * @param shortPrefix The prefix for short argument names. */ void setArgumentPrefix(const QString &longPrefix, const QString &shortPrefix); /** * Begins a new group for documenting arguments. All newly added arguments via * addArgument() will be put in the new group. You can close the * current group by calling endGroup() or be opening a new group. * * Note that groups cannot be nested and all arguments which do not belong to * a group will be listed at the top of the text created by helpText(). * * @param description The description of the group */ void beginGroup(const QString &description); /** * Ends the current group. * * @see beginGroup(const QString&) */ void endGroup(); /** * Enables QSettings support in ctkCommandLineParser. If an argument name is found * in the QSettings instance with a valid QVariant, the value is considered as * a default value and overwrites default values registered with * addArgument(). User supplied values on the command line overwrite * values in the QSettings instance, except for arguments with multiple parameters * which are merged with QSettings values. Call mergeSettings(false) * to disable merging. * * See ctkCommandLineParser(QSettings*) for information about how to * supply a QSettings instance. * * Additionally, a long and short argument name can be specified which will disable * QSettings support if supplied on the command line. The argument name must be * registered as a regular argument via addArgument(). * * @param disableLongArg Long argument name. * @param disableShortArg Short argument name. * * @see ctkCommandLineParser(QSettings*) */ void enableSettings(const QString &disableLongArg = "", const QString &disableShortArg = ""); /** * Controlls the merging behavior of user values and QSettings values. * * If merging is on (the default), user supplied values for an argument * which can take more than one parameter are merged with values stored * in the QSettings instance. If merging is off, the user values overwrite * the QSettings values. * * @param merge true enables QSettings merging, false * disables it. */ void mergeSettings(bool merge); /** * Can be used to check if QSettings support has been enabled by a call to * enableSettings(). * * @return true if QSettings support is enabled, false * otherwise. */ bool settingsEnabled() const; /** * Can be used to teach the parser to stop parsing the arguments and return False when * an unknown argument is encountered. By default StrictMode is disabled. * * @see parseArguments(const QStringList &, bool*) */ void setStrictModeEnabled(bool strictMode); private: class ctkInternal; ctkInternal *Internal; }; #endif diff --git a/CMake/MacroParseArguments.cmake b/CMake/MacroParseArguments.cmake index aed343d65f..fc8ee579af 100644 --- a/CMake/MacroParseArguments.cmake +++ b/CMake/MacroParseArguments.cmake @@ -1,81 +1,81 @@ # macro(MACRO_PARSE_ARGUMENTS prefix arg_names option_names) # -# From http://www.cmake.org/Wiki/CMakeMacroParseArguments: +# From https://gitlab.kitware.com/cmake/community/-/wikis/contrib/macros/ParseArguments: # # The MACRO_PARSE_ARGUMENTS macro will take the arguments of another macro and # define several variables: # # 1) The first argument to is a prefix to put on all variables it creates. # 2) The second argument is a quoted list of names, # 3) and the third argument is a quoted list of options. # # The rest of MACRO_PARSE_ARGUMENTS are arguments from another macro to be # parsed. # # MACRO_PARSE_ARGUMENTS(prefix arg_names options arg1 arg2...) # # For each item in options, MACRO_PARSE_ARGUMENTS will create a variable # with that name, prefixed with prefix_. So, for example, if prefix is # MY_MACRO and options is OPTION1;OPTION2, then PARSE_ARGUMENTS will create # the variables MY_MACRO_OPTION1 and MY_MACRO_OPTION2. These variables will # be set to true if the option exists in the command line or false otherwise. # # For each item in arg_names, MACRO_PARSE_ARGUMENTS will create a variable # with that name, prefixed with prefix_. Each variable will be filled with the # arguments that occur after the given arg_name is encountered up to the next # arg_name or the end of the arguments. All options are removed from these # lists. # # MACRO_PARSE_ARGUMENTS also creates a prefix_DEFAULT_ARGS variable containing # the list of all arguments up to the first arg_name encountered. if(NOT COMMAND MACRO_PARSE_ARGUMENTS) macro(MACRO_PARSE_ARGUMENTS prefix arg_names option_names) message(WARNING "The MACRO_PARSE_ARGUMENTS macro is deprecated. Use cmake_parse_arguments instead.") set(DEFAULT_ARGS) foreach(arg_name ${arg_names}) set(${prefix}_${arg_name}) endforeach(arg_name) foreach(option ${option_names}) set(${prefix}_${option} FALSE) endforeach(option) set(current_arg_name DEFAULT_ARGS) set(current_arg_list) foreach(arg ${ARGN}) set(larg_names ${arg_names}) list(FIND larg_names "${arg}" is_arg_name) if(is_arg_name GREATER -1) set(${prefix}_${current_arg_name} ${current_arg_list}) set(current_arg_name "${arg}") set(current_arg_list) else(is_arg_name GREATER -1) set(loption_names ${option_names}) list(FIND loption_names "${arg}" is_option) if(is_option GREATER -1) set(${prefix}_${arg} TRUE) else(is_option GREATER -1) set(current_arg_list ${current_arg_list} "${arg}") endif(is_option GREATER -1) endif(is_arg_name GREATER -1) endforeach(arg ${ARGN}) set(${prefix}_${current_arg_name} ${current_arg_list}) endmacro(MACRO_PARSE_ARGUMENTS) endif(NOT COMMAND MACRO_PARSE_ARGUMENTS) diff --git a/CMake/NSIS.template.in b/CMake/NSIS.template.in index 47f5d675ff..619bfcd3f8 100644 --- a/CMake/NSIS.template.in +++ b/CMake/NSIS.template.in @@ -1,1014 +1,1014 @@ ; CPack install script designed for a nmake build ;-------------------------------- ; You must define these values !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" ;-------------------------------- ;Variables Var MUI_TEMP Var STARTMENU_FOLDER Var SV_ALLUSERS Var START_MENU Var DO_NOT_ADD_TO_PATH Var ADD_TO_PATH_ALL_USERS Var ADD_TO_PATH_CURRENT_USER Var INSTALL_DESKTOP Var IS_DEFAULT_INSTALLDIR ;-------------------------------- ;Include Modern UI !include "MUI.nsh" ;Default installation folder InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ;Allow for very long title on the welcome page !define MUI_WELCOMEPAGE_TITLE_3LINES ;-------------------------------- ;General ;Name and file Name "@CPACK_NSIS_PACKAGE_NAME@" OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" ;Set compression SetCompressor @CPACK_NSIS_COMPRESSOR@ RequestExecutionLevel user @CPACK_NSIS_DEFINES@ !include Sections.nsh ;--- Component support macros: --- ; The code for the add/remove functionality is from: -; http://nsis.sourceforge.net/Add/Remove_Functionality +; https://nsis.sourceforge.io/Add/Remove_Functionality ; It has been modified slightly and extended to provide ; inter-component dependencies. Var AR_SecFlags Var AR_RegFlags @CPACK_NSIS_SECTION_SELECTED_VARS@ ; Loads the "selected" flag for the section named SecName into the ; variable VarName. !macro LoadSectionSelectedIntoVar SecName VarName SectionGetFlags ${${SecName}} $${VarName} IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits !macroend ; Loads the value of a variable... can we get around this? !macro LoadVar VarName IntOp $R0 0 + $${VarName} !macroend ; Sets the value of a variable !macro StoreVar VarName IntValue IntOp $${VarName} 0 + ${IntValue} !macroend !macro InitSection SecName ; This macro reads component installed flag from the registry and ;changes checked state of the section on the components page. ;Input: section index constant name specified in Section command. ClearErrors ;Reading component status from registry ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" "Installed" IfErrors "default_${SecName}" ;Status will stay default if registry value not found ;(component was never installed) IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit ; Note whether this component was installed before !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags IntOp $R0 $AR_RegFlags & $AR_RegFlags ;Writing modified flags SectionSetFlags ${${SecName}} $AR_SecFlags "default_${SecName}:" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected !macroend !macro FinishSection SecName ; This macro reads section flag set by user and removes the section ;if it is not selected. ;Then it writes component installed flag to registry ;Input: section index constant name specified in Section command. SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags ;Checking lowest bit: IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} IntCmp $AR_SecFlags 1 "leave_${SecName}" ;Section is not selected: ;Calling Section uninstall macro and writing zero installed flag !insertmacro "Remove_${${SecName}}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" \ "Installed" 0 Goto "exit_${SecName}" "leave_${SecName}:" ;Section is selected: WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" \ "Installed" 1 "exit_${SecName}:" !macroend ; NSIS example code to only include some code if a file exists at compile time (whereas IfFileExists works at runtime) -; See http://nsis.sourceforge.net/Check_if_a_file_exists_at_compile_time for documentation +; See https://nsis.sourceforge.io/Check_if_a_file_exists_at_compile_time for documentation !macro !defineifexist _VAR_NAME _FILE_NAME !tempfile _TEMPFILE !system 'if exist "${_FILE_NAME}" echo !define ${_VAR_NAME} > "${_TEMPFILE}"' !include '${_TEMPFILE}' !delfile '${_TEMPFILE}' !undef _TEMPFILE !macroend !define !defineifexist "!insertmacro !defineifexist" ; Determine whether the selection of SecName changed !macro MaybeSelectionChanged SecName !insertmacro LoadVar ${SecName}_selected SectionGetFlags ${${SecName}} $R1 IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits ; See if the status has changed: IntCmp $R0 $R1 "${SecName}_unchanged" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" !insertmacro "Deselect_required_by_${SecName}" goto "${SecName}_unchanged" "${SecName}_was_selected:" !insertmacro "Select_${SecName}_depends" "${SecName}_unchanged:" !macroend ;--- End of Add/Remove macros --- ;-------------------------------- ;Interface Settings !define MUI_HEADERIMAGE !define MUI_ABORTWARNING ;-------------------------------- ; path functions !verbose 3 !include "WinMessages.NSH" !verbose 4 ;---------------------------------------- ; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" ;---------------------------------------- !verbose 3 !include "WinMessages.NSH" !verbose 4 ;==================================================== ; get_NT_environment ; Returns: the selected environment ; Output : head of the stack ;==================================================== !macro select_NT_profile UN Function ${UN}select_NT_profile StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single DetailPrint "Selected environment for all users" Push "all" Return environment_single: DetailPrint "Selected environment for current user only." Push "current" Return FunctionEnd !macroend !insertmacro select_NT_profile "" !insertmacro select_NT_profile "un." ;---------------------------------------------------- !define NT_current_env 'HKCU "Environment"' !define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !ifndef WriteEnvStr_RegKey !ifdef ALL_USERS !define WriteEnvStr_RegKey \ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !else !define WriteEnvStr_RegKey 'HKCU "Environment"' !endif !endif ; AddToPath - Adds the given dir to the search path. ; Input - head of the stack ; Note - Win9x systems requires reboot Function AddToPath Exch $0 Push $1 Push $2 Push $3 # don't add if the path doesn't exist IfFileExists "$0\*.*" "" AddToPath_done ReadEnvStr $1 PATH ; if the path is too long for a NSIS variable NSIS will return a 0 ; length string. If we find that, then warn and skip any path ; modification as it will trash the existing path. StrLen $2 $1 IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done CheckPathLength_ShowPathWarning: DetailPrint "Warning: Could not modify PATH variable - current PATH is too long.\n\ This does not impact the functionality of MITK itself, but you will not be able to start\ it from anywhere via command line." ; The message box is probably too much of an escalation, most users won't care or notice ;Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" Goto AddToPath_done CheckPathLength_Done: Push "$1;" Push "$0;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$0\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done GetFullPathName /SHORT $3 $0 Push "$1;" Push "$3;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$3\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Call IsNT Pop $1 StrCmp $1 1 AddToPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" a FileSeek $1 -1 END FileReadByte $1 $2 IntCmp $2 26 0 +2 +2 # DOS EOF FileSeek $1 -1 END # write over EOF FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" FileClose $1 SetRebootFlag true Goto AddToPath_done AddToPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto DoTrim ReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" DoTrim: StrCmp $1 "" AddToPath_NTdoIt Push $1 Call Trim Pop $1 StrCpy $0 "$1;$0" AddToPath_NTdoIt: StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $0 Goto DoSend WriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $0 DoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 AddToPath_done: Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; RemoveFromPath - Remove a given dir from the path ; Input: head of the stack Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $6 IntFmt $6 "%c" 26 # DOS EOF Call un.IsNT Pop $1 StrCmp $1 1 unRemoveFromPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" r GetTempFileName $4 FileOpen $2 $4 w GetFullPathName /SHORT $0 $0 StrCpy $0 "SET PATH=%PATH%;$0" Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoop: FileRead $1 $3 StrCpy $5 $3 1 -1 # read last char StrCmp $5 $6 0 +2 # if DOS EOF StrCpy $3 $3 -1 # remove DOS EOF so we can compare StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "" unRemoveFromPath_dosLoopEnd FileWrite $2 $3 Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopRemoveLine: SetRebootFlag true Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopEnd: FileClose $2 FileClose $1 StrCpy $1 $WINDIR 2 Delete "$1\autoexec.bat" CopyFiles /SILENT $4 "$1\autoexec.bat" Delete $4 Goto unRemoveFromPath_done unRemoveFromPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto unDoTrim unReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" unDoTrim: StrCpy $5 $1 1 -1 # copy last char StrCmp $5 ";" +2 # if last char != ; StrCpy $1 "$1;" # append ; Push $1 Push "$0;" Call un.StrStr ; Find `$0;` in $1 Pop $2 ; pos of our dir StrCmp $2 "" unRemoveFromPath_done ; else, it is in path # $0 - path to add # $1 - path var StrLen $3 "$0;" StrLen $4 $2 StrCpy $5 $1 -$4 # $5 is now the part before the path to remove StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove StrCpy $3 $5$6 StrCpy $5 $3 1 -1 # copy last char StrCmp $5 ";" 0 +2 # if last char == ; StrCpy $3 $3 -1 # remove last char StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $3 Goto unDoSend unWriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $3 unDoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 unRemoveFromPath_done: Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Uninstall stuff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ########################################### # Utility Functions # ########################################### ;==================================================== ; IsNT - Returns 1 if the current system is NT, 0 ; otherwise. ; Output: head of the stack ;==================================================== ; IsNT ; no input ; output, top of the stack = 1 if NT or 0 if not ; ; Usage: ; Call IsNT ; Pop $R0 ; ($R0 at this point is 1 or 0) !macro IsNT un Function ${un}IsNT Push $0 ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion StrCmp $0 "" 0 IsNT_yes ; we are not NT. Pop $0 Push 0 Return IsNT_yes: ; NT!!! Pop $0 Push 1 FunctionEnd !macroend !insertmacro IsNT "" !insertmacro IsNT "un." ; StrStr ; input, top of stack = string to search for ; top of stack-1 = string to search in ; output, top of stack (replaces with the portion of the string remaining) ; modifies no other variables. ; ; Usage: ; Push "this is a long ass string" ; Push "ass" ; Call StrStr ; Pop $R0 ; ($R0 at this point is "ass string") !macro StrStr un Function ${un}StrStr Exch $R1 ; st=haystack,old$R1, $R1=needle Exch ; st=old$R1,haystack Exch $R2 ; st=old$R1,old$R2, $R2=haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ; $R1=needle ; $R2=haystack ; $R3=len(needle) ; $R4=cnt ; $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un." Function Trim ; Added by Pelaca Exch $R1 Push $R2 Loop: StrCpy $R2 "$R1" 1 -1 StrCmp "$R2" " " RTrim StrCmp "$R2" "$\n" RTrim StrCmp "$R2" "$\r" RTrim StrCmp "$R2" ";" RTrim GoTo Done RTrim: StrCpy $R1 "$R1" -1 Goto Loop Done: Pop $R2 Exch $R1 FunctionEnd Function ConditionalAddToRegisty Pop $0 Pop $1 StrCmp "$0" "" ConditionalAddToRegisty_EmptyString WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" \ "$1" "$0" ;MessageBox MB_OK "Set Registry: '$1' to '$0'" DetailPrint "Set install registry entry: '$1' to '$0'" ConditionalAddToRegisty_EmptyString: FunctionEnd ;-------------------------------- !ifdef CPACK_USES_DOWNLOAD Function DownloadFile IfFileExists $INSTDIR\* +2 CreateDirectory $INSTDIR Pop $0 ; Skip if already downloaded IfFileExists $INSTDIR\$0 0 +2 Return StrCpy $1 "@CPACK_DOWNLOAD_SITE@" try_again: NSISdl::download "$1/$0" "$INSTDIR\$0" Pop $1 StrCmp $1 "success" success StrCmp $1 "Cancelled" cancel MessageBox MB_OK "Download failed: $1" cancel: Return success: FunctionEnd !endif ;-------------------------------- ; Installation types @CPACK_NSIS_INSTALLATION_TYPES@ ;-------------------------------- ; Component sections @CPACK_NSIS_COMPONENT_SECTIONS@ ;-------------------------------- ; Define some macro setting for the gui @CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ @CPACK_NSIS_INSTALLER_ICON_CODE@ @CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ @CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ ;-------------------------------- ;Pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" Page custom InstallOptionsPage !insertmacro MUI_PAGE_DIRECTORY ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER @CPACK_NSIS_PAGE_COMPONENTS@ !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;first language is the default language !insertmacro MUI_LANGUAGE "Albanian" !insertmacro MUI_LANGUAGE "Arabic" !insertmacro MUI_LANGUAGE "Basque" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Bosnian" !insertmacro MUI_LANGUAGE "Breton" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Farsi" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Hebrew" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Icelandic" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Irish" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Korean" !insertmacro MUI_LANGUAGE "Kurdish" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Luxembourgish" !insertmacro MUI_LANGUAGE "Macedonian" !insertmacro MUI_LANGUAGE "Malay" !insertmacro MUI_LANGUAGE "Mongolian" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Serbian" !insertmacro MUI_LANGUAGE "SerbianLatin" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Thai" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Ukrainian" !insertmacro MUI_LANGUAGE "Welsh" ;-------------------------------- ;Reserve Files ;These files should be inserted before other files in the data block ;Keep these lines before any File command ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) ReserveFile "NSIS.InstallOptions.ini" !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ;-------------------------------- ;Installer Sections Section "-Core installation" ;Use the entire tree produced by the INSTALL target. Keep the ;list of directories here in sync with the RMDir commands below. SetOutPath "$INSTDIR" @CPACK_NSIS_FULL_INSTALL@ ;Store installation folder WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" Push "DisplayName" Push "@CPACK_NSIS_DISPLAY_NAME@" Call ConditionalAddToRegisty Push "DisplayVersion" Push "@CPACK_PACKAGE_VERSION@" Call ConditionalAddToRegisty Push "Publisher" Push "@CPACK_PACKAGE_VENDOR@" Call ConditionalAddToRegisty Push "UninstallString" Push "$INSTDIR\Uninstall.exe" Call ConditionalAddToRegisty Push "NoRepair" Push "1" Call ConditionalAddToRegisty !ifdef CPACK_NSIS_ADD_REMOVE ;Create add/remove functionality Push "ModifyPath" Push "$INSTDIR\AddRemove.exe" Call ConditionalAddToRegisty !else Push "NoModify" Push "1" Call ConditionalAddToRegisty !endif ; Optional registration Push "DisplayIcon" Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" Call ConditionalAddToRegisty Push "HelpLink" Push "@CPACK_NSIS_HELP_LINK@" Call ConditionalAddToRegisty Push "URLInfoAbout" Push "@CPACK_NSIS_URL_INFO_ABOUT@" Call ConditionalAddToRegisty Push "Contact" Push "@CPACK_NSIS_CONTACT@" Call ConditionalAddToRegisty !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" @CPACK_NSIS_CREATE_ICONS@ @CPACK_NSIS_CREATE_ICONS_EXTRA@ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" ;Read a value from an InstallOptions INI file !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" ; Write special uninstall registry entries Push "StartMenu" Push "$STARTMENU_FOLDER" Call ConditionalAddToRegisty Push "DoNotAddToPath" Push "$DO_NOT_ADD_TO_PATH" Call ConditionalAddToRegisty Push "AddToPathAllUsers" Push "$ADD_TO_PATH_ALL_USERS" Call ConditionalAddToRegisty Push "AddToPathCurrentUser" Push "$ADD_TO_PATH_CURRENT_USER" Call ConditionalAddToRegisty Push "InstallToDesktop" Push "$INSTALL_DESKTOP" Call ConditionalAddToRegisty !insertmacro MUI_STARTMENU_WRITE_END @CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ SectionEnd Section "-Add to path" Push $INSTDIR\bin StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 Call AddToPath doNotAddToPath: SectionEnd ;-------------------------------- ; Create custom pages Function InstallOptionsPage !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" FunctionEnd ; Author: Lilla (lilla@earthlink.net) 2003-06-13 ; function IsUserAdmin uses plugin \NSIS\PlusgIns\UserInfo.dll ; This function is based upon code in \NSIS\Contrib\UserInfo\UserInfo.nsi ; This function was tested under NSIS 2 beta 4 (latest CVS as of this writing). ; ; Usage: ; Call IsUserAdmin ; Pop $R0 ; at this point $R0 is "true" or "false" ; Function IsUserAdmin Push $R0 Push $R1 Push $R2 ClearErrors UserInfo::GetName IfErrors Win9x Pop $R1 UserInfo::GetAccountType Pop $R2 StrCmp $R2 "Admin" 0 Continue ; Observation: I get here when running Win98SE. (Lilla) ; The functions UserInfo.dll looks for are there on Win98 too, ; but just don't work. So UserInfo.dll, knowing that admin isn't required ; on Win98, returns admin anyway. (per kichik) ; MessageBox MB_OK 'User "$R1" is in the Administrators group' StrCpy $R0 "true" Goto Done Continue: ; You should still check for an empty string because the functions ; UserInfo.dll looks for may not be present on Windows 95. (per kichik) StrCmp $R2 "" Win9x StrCpy $R0 "false" ;MessageBox MB_OK 'User "$R1" is in the "$R2" group' Goto Done Win9x: ; comment/message below is by UserInfo.nsi author: ; This one means you don't need to care about admin or ; not admin because Windows 9x doesn't either ;MessageBox MB_OK "Error! This DLL can't run under Windows 9x!" StrCpy $R0 "true" Done: ;MessageBox MB_OK 'User= "$R1" AccountType= "$R2" IsUserAdmin= "$R0"' Pop $R2 Pop $R1 Exch $R0 FunctionEnd ;-------------------------------- ; determine admin versus local install Function un.onInit ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' Goto done StrCmp $1 "Power" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' Goto done noLM: ;Get installation folder from registry if available done: FunctionEnd ;--- Add/Remove callback functions: --- !macro SectionList MacroName ;This macro used to perform operation on multiple sections. ;List all of your components in following manner here. @CPACK_NSIS_COMPONENT_SECTION_LIST@ !macroend Section -FinishComponents ;Removes unselected components and writes component status to registry !insertmacro SectionList "FinishSection" !ifdef CPACK_NSIS_ADD_REMOVE ; Get the name of the installer executable System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' StrCpy $R3 $R0 ; Strip off the last 13 characters, to see if we have AddRemove.exe StrLen $R1 $R0 IntOp $R1 $R0 - 13 StrCpy $R2 $R0 13 $R1 StrCmp $R2 "AddRemove.exe" addremove_installed ; We're not running AddRemove.exe, so install it CopyFiles $R3 $INSTDIR\AddRemove.exe addremove_installed: !endif SectionEnd ;--- End of Add/Remove callback functions --- ;-------------------------------- ; Component dependencies Function .onSelChange !insertmacro SectionList MaybeSelectionChanged FunctionEnd ;-------------------------------- ;Uninstaller Section Section "Uninstall" ReadRegStr $START_MENU SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "StartMenu" ;MessageBox MB_OK "Start menu is in: $START_MENU" ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "DoNotAddToPath" ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "AddToPathAllUsers" ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "AddToPathCurrentUser" ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" ReadRegStr $INSTALL_DESKTOP SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "InstallToDesktop" ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " @CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ ;Remove files we installed. ;Keep the list of directories here in sync with the File commands above. @CPACK_NSIS_DELETE_FILES@ @CPACK_NSIS_DELETE_DIRECTORIES@ !ifdef CPACK_NSIS_ADD_REMOVE ;Remove the add/remove program Delete "$INSTDIR\AddRemove.exe" !endif ;Remove the uninstaller itself. Delete "$INSTDIR\Uninstall.exe" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" ;Remove the installation directory if it is empty. RMDir "$INSTDIR" ; Remove the registry entries. DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ; Removes all optional components !insertmacro SectionList "RemoveSection" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" startMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors startMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop startMenuDeleteLoopDone: ; If the user changed the shortcut, then untinstall may not work. This should ; try to fix it. StrCpy $MUI_TEMP "$START_MENU" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" secondStartMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors secondStartMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop secondStartMenuDeleteLoopDone: DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" Push $INSTDIR\bin StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 Call un.RemoveFromPath doNotRemoveFromPath: SectionEnd ;-------------------------------- ; determine admin versus local install ; Is install for "AllUsers" or "JustMe"? ; Default to "JustMe" - set to "AllUsers" if admin or on Win9x ; This function is used for the very first "custom page" of the installer. ; This custom page does not show up visibly, but it executes prior to the ; first visible page and sets up $INSTDIR properly... ; Choose different default installation folder based on SV_ALLUSERS... ; "Program Files" for AllUsers, "My Documents" for JustMe... Function .onInit ; Reads components status for registry !insertmacro SectionList "InitSection" ; check to see if /D has been used to change ; the install directory by comparing it to the ; install directory that is expected to be the ; default StrCpy $IS_DEFAULT_INSTALLDIR 0 StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 StrCpy $IS_DEFAULT_INSTALLDIR 1 StrCpy $SV_ALLUSERS "JustMe" ; if default install dir then change the default ; if it is installed for JustMe StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' StrCpy $SV_ALLUSERS "AllUsers" Goto done StrCmp $1 "Power" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' StrCpy $SV_ALLUSERS "AllUsers" Goto done noLM: StrCpy $SV_ALLUSERS "AllUsers" ;Get installation folder from registry if available done: StrCmp $SV_ALLUSERS "AllUsers" 0 +3 StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" noOptionsPage: FunctionEnd diff --git a/CMake/mitkFunctionCMakeDoxygenFilterCompile.cmake b/CMake/mitkFunctionCMakeDoxygenFilterCompile.cmake index 373f666f94..fc8e691b55 100644 --- a/CMake/mitkFunctionCMakeDoxygenFilterCompile.cmake +++ b/CMake/mitkFunctionCMakeDoxygenFilterCompile.cmake @@ -1,87 +1,87 @@ #! #! \brief Download and compile a CMake doxygen input filter #! #! \param OUT (optional) Supply an absolute filename for #! the generated executable. #! \param NAMESPACE (optional) Supply a C++ namespace in #! which the generated function declrarations #! should be wrapped. #! #! \return This function sets the CMakeDoxygenFilter_EXECUTABLE #! variable to the absolute path of the generated input filter executable #! in the parent scope. If is specified, they will be the same. #! -#! This CMake function compiles the http://github.com/saschazelzer/CMakeDoxygenFilter +#! This CMake function compiles the https://github.com/saschazelzer/CMakeDoxygenFilter #! project into a doxygen input filter executable. See -#! http://github.com/saschazelzer/CMakeDoxygenFilter/blob/master/README for more details. +#! https://github.com/saschazelzer/CMakeDoxygenFilter/blob/master/README for more details. #! function(mitkFunctionCMakeDoxygenFilterCompile) #-------------------- parse function arguments ------------------- set(DEFAULT_ARGS) set(prefix "FILTER") set(arg_names "OUT;NAMESPACE") set(option_names "") foreach(arg_name ${arg_names}) set(${prefix}_${arg_name}) endforeach(arg_name) foreach(option ${option_names}) set(${prefix}_${option} FALSE) endforeach(option) set(current_arg_name DEFAULT_ARGS) set(current_arg_list) foreach(arg ${ARGN}) set(larg_names ${arg_names}) list(FIND larg_names "${arg}" is_arg_name) if(is_arg_name GREATER -1) set(${prefix}_${current_arg_name} ${current_arg_list}) set(current_arg_name "${arg}") set(current_arg_list) else(is_arg_name GREATER -1) set(loption_names ${option_names}) list(FIND loption_names "${arg}" is_option) if(is_option GREATER -1) set(${prefix}_${arg} TRUE) else(is_option GREATER -1) set(current_arg_list ${current_arg_list} "${arg}") endif(is_option GREATER -1) endif(is_arg_name GREATER -1) endforeach(arg ${ARGN}) set(${prefix}_${current_arg_name} ${current_arg_list}) #------------------- finished parsing arguments ---------------------- if(FILTER_OUT) set(copy_file "${FILTER_OUT}") else() set(copy_file "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CMakeDoxygenFilter${CMAKE_EXECUTABLE_SUFFIX}") endif() set(compile_defs "") if(FILTER_NAMESPACE) set(compile_defs "${compile_defs} -DUSE_NAMESPACE=${FILTER_NAMESPACE}") endif() set(cmake_doxygen_filter_src "${CMAKE_CURRENT_SOURCE_DIR}/CMakeDoxygenFilter.cpp") try_compile(result_var "${CMAKE_CURRENT_BINARY_DIR}" "${cmake_doxygen_filter_src}" COMPILE_DEFINITIONS ${compile_defs} OUTPUT_VARIABLE compile_output COPY_FILE ${copy_file} ) if(NOT result_var) message(FATAL_ERROR "error: Faild to compile ${cmake_doxygen_filter_src} (result: ${result_var})\n${compile_output}") endif() set(CMakeDoxygenFilter_EXECUTABLE "${copy_file}" PARENT_SCOPE) endfunction() diff --git a/CMake/mitkFunctionCreateModule.cmake b/CMake/mitkFunctionCreateModule.cmake index 40e48ef56e..b0a777b921 100644 --- a/CMake/mitkFunctionCreateModule.cmake +++ b/CMake/mitkFunctionCreateModule.cmake @@ -1,650 +1,647 @@ ################################################################## # # mitk_create_module # #! Creates a module for the automatic module dependency system within MITK. #! #! Example: #! #! \code #! mitk_create_module( #! DEPENDS PUBLIC MitkCore #! PACKAGE_DEPENDS #! PRIVATE Qt5|Xml+Networking #! PUBLIC ITK|Watersheds #! \endcode #! #! The parameter specifies the name of the module which is used #! to create a logical target name. The parameter is optional in case the #! MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME variable evaluates to TRUE. The #! module name will then be derived from the directory name in which this #! function is called. #! #! If set, the following variables will be used to validate the module name: #! #! MITK_MODULE_NAME_REGEX_MATCH The module name must match this regular expression. #! MITK_MODULE_NAME_REGEX_NOT_MATCH The module name must not match this regular expression. #! #! If the MITK_MODULE_NAME_PREFIX variable is set, the module name will be prefixed #! with its contents. #! #! A modules source files are specified in a separate CMake file usually #! called files.cmake, located in the module root directory. The #! mitk_create_module() macro evaluates the following CMake variables #! from the files.cmake file: #! #! - CPP_FILES A list of .cpp files #! - H_FILES A list of .h files without a corresponding .cpp file #! - TXX_FILES A list of .txx files #! - RESOURCE_FILES A list of files (resources) which are embedded into the module #! - MOC_H_FILES A list of Qt header files which should be processed by the MOC #! - UI_FILES A list of .ui Qt UI files #! - QRC_FILES A list of .qrc Qt resource files #! - DOX_FILES A list of .dox Doxygen files #! #! List of variables available after the function is called: #! - MODULE_NAME #! - MODULE_TARGET #! - MODULE_IS_ENABLED #! #! \sa mitk_create_executable #! #! Parameters (all optional): #! #! \param The module name (also used as target name) #! \param FILES_CMAKE File name of a CMake file setting source list variables #! (defaults to files.cmake) #! \param VERSION Module version number, e.g. "1.2.0" #! \param AUTOLOAD_WITH A module target name identifying the module which will #! trigger the automatic loading of this module #! \param DEPRECATED_SINCE Marks this modules as deprecated since #! \param DESCRIPTION A description for this module #! #! Multi-value Parameters (all optional): #! #! \param INCLUDE_DIRS Include directories for this module: #! \verbatim #! [[PUBLIC|PRIVATE|INTERFACE] ...]... #! \endverbatim #! The default scope for include directories is PUBLIC. #! \param DEPENDS List of module dependencies: #! \verbatim #! [[PUBLIC|PRIVATE|INTERFACE] ...]... #! \endverbatim #! The default scope for module dependencies is PUBLIC. #! \param PACKAGE_DEPENDS List of public packages dependencies (e.g. Qt, VTK, etc.). #! Package dependencies have the following syntax: #! \verbatim #! [PUBLIC|PRIVATE|INTERFACE] PACKAGE[|COMPONENT1[+COMPONENT2]...] #! \endverbatim #! The default scope for package dependencies is PRIVATE. #! \param ADDITIONAL_LIBS List of additional private libraries linked to this module. #! The folder containing the library will be added to the global list of library search paths. #! \param CPP_FILES List of source files for this module. If the list is non-empty, #! the module does not need to provide a files.cmake file or FILES_CMAKE argument. #! \param H_FILES List of public header files for this module. It is recommended to use #! a files.cmake file instead. #! #! Options (optional) #! #! \param FORCE_STATIC Force building this module as a static library #! \param GCC_DEFAULT_VISIBILITY Do not use gcc visibility flags - all #! symbols will be exported #! \param NO_INIT Do not create CppMicroServices initialization code #! \param NO_FEATURE_INFO Do not create a feature info by calling add_feature_info() #! \param WARNINGS_NO_ERRORS Do not treat compiler warnings as errors # ################################################################## function(mitk_create_module) set(_macro_params VERSION # module version number, e.g. "1.2.0" EXPORT_DEFINE # export macro name for public symbols of this module (DEPRECATED) AUTOLOAD_WITH # a module target name identifying the module which will trigger the # automatic loading of this module FILES_CMAKE # file name of a CMake file setting source list variables # (defaults to files.cmake) DEPRECATED_SINCE # marks this modules as deprecated DESCRIPTION # a description for this module ) set(_macro_multiparams SUBPROJECTS # list of CDash labels (deprecated) INCLUDE_DIRS # include directories: [PUBLIC|PRIVATE|INTERFACE] INTERNAL_INCLUDE_DIRS # include dirs internal to this module (DEPRECATED) DEPENDS # list of modules this module depends on: [PUBLIC|PRIVATE|INTERFACE] DEPENDS_INTERNAL # list of modules this module internally depends on (DEPRECATED) PACKAGE_DEPENDS # list of "packages this module depends on (e.g. Qt, VTK, etc.): [PUBLIC|PRIVATE|INTERFACE] TARGET_DEPENDS # list of CMake targets this module should depend on: [PUBLIC|PRIVATE|INTERFACE] ADDITIONAL_LIBS # list of addidtional private libraries linked to this module. CPP_FILES # list of cpp files H_FILES # list of header files: [PUBLIC|PRIVATE] ) set(_macro_options FORCE_STATIC # force building this module as a static library HEADERS_ONLY # this module is a headers-only library GCC_DEFAULT_VISIBILITY # do not use gcc visibility flags - all symbols will be exported NO_DEFAULT_INCLUDE_DIRS # do not add default include directories like "include" or "." NO_INIT # do not create CppMicroServices initialization code NO_FEATURE_INFO # do not create a feature info by calling add_feature_info() WARNINGS_NO_ERRORS # do not treat compiler warnings as errors EXECUTABLE # create an executable; do not use directly, use mitk_create_executable() instead C_MODULE # compile all source files as C sources CXX_MODULE # compile all source files as C++ sources ) cmake_parse_arguments(MODULE "${_macro_options}" "${_macro_params}" "${_macro_multiparams}" ${ARGN}) set(MODULE_NAME ${MODULE_UNPARSED_ARGUMENTS}) # ----------------------------------------------------------------- # Sanity checks if(NOT MODULE_NAME) if(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME) get_filename_component(MODULE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) else() message(SEND_ERROR "The module name must not be empty") endif() endif() set(_deprecated_args INTERNAL_INCLUDE_DIRS DEPENDS_INTERNAL EXPORT_DEFINE HEADERS_ONLY) foreach(_deprecated_arg ${_deprecated_args}) if(MODULE_${_deprecated_arg}) message(WARNING "The ${_deprecated_arg} argument is deprecated") endif() endforeach() set(_module_type module) set(_Module_type Module) if(MODULE_EXECUTABLE) set(_module_type executable) set(_Module_type Executable) endif() if(MITK_MODULE_NAME_REGEX_MATCH) if(NOT ${MODULE_NAME} MATCHES ${MITK_MODULE_NAME_REGEX_MATCH}) message(SEND_ERROR "The ${_module_type} name \"${MODULE_NAME}\" does not match the regular expression \"${MITK_MODULE_NAME_REGEX_MATCH}\".") endif() endif() if(MITK_MODULE_NAME_REGEX_NOT_MATCH) if(${MODULE_NAME} MATCHES ${MITK_MODULE_NAME_REGEX_NOT_MATCH}) message(SEND_ERROR "The ${_module_type} name \"${MODULE_NAME}\" must not match the regular expression \"${MITK_MODULE_NAME_REGEX_NOT_MATCH}\".") endif() endif() if(MITK_MODULE_NAME_PREFIX AND NOT MODULE_NAME MATCHES "^${MITK_MODULE_NAME_PREFIX}.*$") set(MODULE_NAME "${MITK_MODULE_NAME_PREFIX}${MODULE_NAME}") endif() if(NOT MODULE_FILES_CMAKE) set(MODULE_FILES_CMAKE files.cmake) endif() if(NOT IS_ABSOLUTE ${MODULE_FILES_CMAKE}) set(MODULE_FILES_CMAKE ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_FILES_CMAKE}) endif() # ----------------------------------------------------------------- # Check if module should be build set(MODULE_TARGET ${MODULE_NAME}) # 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_parse_package_args(${MODULE_PACKAGE_DEPENDS}) mitk_check_module_dependencies(MODULES ${MODULE_DEPENDS} PACKAGES ${PACKAGE_NAMES} MISSING_DEPENDENCIES_VAR _MISSING_DEP PACKAGE_DEPENDENCIES_VAR PACKAGE_NAMES) if(_MISSING_DEP) if(MODULE_NO_FEATURE_INFO) message("${_Module_type} ${MODULE_NAME} won't be built, missing dependency: ${_MISSING_DEP}") endif() set(MODULE_IS_ENABLED 0) else() foreach(dep ${MODULE_DEPENDS}) if(TARGET ${dep}) get_target_property(AUTLOAD_DEP ${dep} MITK_AUTOLOAD_DIRECTORY) if (AUTLOAD_DEP) message(SEND_ERROR "Module \"${MODULE_NAME}\" has an invalid dependency on autoload module \"${dep}\". Check MITK_CREATE_MODULE usage for \"${MODULE_NAME}\".") endif() endif() endforeach(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 ${PACKAGE_NAMES}) if((DEFINED MITK_USE_${_package}) AND NOT (MITK_USE_${_package})) message("${_Module_type} ${MODULE_NAME} won't be built. Turn on MITK_USE_${_package} if you want to use it.") set(MODULE_IS_ENABLED 0) break() endif() endforeach() endif() endif() # ----------------------------------------------------------------- # Start creating the module if(MODULE_IS_ENABLED) # clear variables defined in files.cmake set(RESOURCE_FILES ) set(CPP_FILES ) set(H_FILES ) set(TXX_FILES ) set(DOX_FILES ) set(UI_FILES ) set(MOC_H_FILES ) set(QRC_FILES ) # clear other variables set(Q${KITNAME}_GENERATED_CPP ) set(Q${KITNAME}_GENERATED_MOC_CPP ) set(Q${KITNAME}_GENERATED_QRC_CPP ) set(Q${KITNAME}_GENERATED_UI_CPP ) # check and set-up auto-loading if(MODULE_AUTOLOAD_WITH) if(NOT TARGET "${MODULE_AUTOLOAD_WITH}") message(SEND_ERROR "The module target \"${MODULE_AUTOLOAD_WITH}\" specified as the auto-loading module for \"${MODULE_NAME}\" does not exist") endif() endif() set(_module_autoload_meta_target "${CMAKE_PROJECT_NAME}-autoload") # create a meta-target if it does not already exist if(NOT TARGET ${_module_autoload_meta_target}) add_custom_target(${_module_autoload_meta_target}) set_property(TARGET ${_module_autoload_meta_target} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Autoload") endif() if(NOT MODULE_EXPORT_DEFINE) set(MODULE_EXPORT_DEFINE ${MODULE_NAME}_EXPORT) endif() 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 (EXISTS ${MODULE_FILES_CMAKE}) include(${MODULE_FILES_CMAKE}) endif() if(MODULE_CPP_FILES) list(APPEND CPP_FILES ${MODULE_CPP_FILES}) endif() if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src") # Preprend the "src" directory to the cpp file list set(_cpp_files ${CPP_FILES}) set(CPP_FILES ) foreach(_cpp_file ${_cpp_files}) list(APPEND CPP_FILES "src/${_cpp_file}") endforeach() endif() if(CPP_FILES OR RESOURCE_FILES OR UI_FILES OR MOC_H_FILES OR QRC_FILES) set(MODULE_HEADERS_ONLY 0) if(MODULE_C_MODULE) set_source_files_properties(${CPP_FILES} PROPERTIES LANGUAGE C) elseif(MODULE_CXX_MODULE) set_source_files_properties(${CPP_FILES} PROPERTIES LANGUAGE CXX) endif() else() set(MODULE_HEADERS_ONLY 1) if(MODULE_AUTOLOAD_WITH) message(SEND_ERROR "A headers only module cannot be auto-loaded") endif() endif() set(module_c_flags ) set(module_c_flags_debug ) set(module_c_flags_release ) set(module_cxx_flags ) set(module_cxx_flags_debug ) set(module_cxx_flags_release ) if(MODULE_GCC_DEFAULT_VISIBILITY OR NOT CMAKE_COMPILER_IS_GNUCXX) # We only support hidden visibility for gcc for now. Clang still has troubles with # correctly marking template declarations and explicit template instantiations as exported. - # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 - # and http://llvm.org/bugs/show_bug.cgi?id=10113 set(CMAKE_CXX_VISIBILITY_PRESET default) set(CMAKE_VISIBILITY_INLINES_HIDDEN 0) else() set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) endif() if(NOT MODULE_WARNINGS_NO_ERRORS) if(MSVC_VERSION) mitkFunctionCheckCAndCXXCompilerFlags("/WX" module_c_flags module_cxx_flags) # this would turn on unused parameter warnings, but unfortunately MSVC cannot # distinguish yet between internal and external headers so this would be triggered # a lot by external code. There is support for it on the way so this line could be # reactivated after https://gitlab.kitware.com/cmake/cmake/issues/17904 has been fixed. # mitkFunctionCheckCAndCXXCompilerFlags("/w34100" module_c_flags module_cxx_flags) else() mitkFunctionCheckCAndCXXCompilerFlags(-Werror module_c_flags module_cxx_flags) # The flag "c++0x-static-nonintegral-init" has been renamed in newer Clang - # versions to "static-member-init", see - # http://clang-developers.42468.n3.nabble.com/Wc-0x-static-nonintegral-init-gone-td3999651.html + # versions to "static-member-init" # # Also, older Clang and seemingly all gcc versions do not warn if unknown # "-no-*" flags are used, so CMake will happily append any -Wno-* flag to the # command line. This may get confusing if unrelated compiler errors happen and # the error output then additionally contains errors about unknown flags (which # is not the case if there were no compile errors). # # So instead of using -Wno-* we use -Wno-error=*, which will be properly rejected by # the compiler and if applicable, prints the specific warning as a real warning and # not as an error (although -Werror was given). mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=static-member-init" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=unknown-warning" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=gnu" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=class-memaccess" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-copy" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=cast-function-type" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-declarations" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=type-limits" module_c_flags module_cxx_flags) endif() endif() if(MODULE_FORCE_STATIC) set(_STATIC STATIC) else() set(_STATIC ) endif(MODULE_FORCE_STATIC) if(NOT MODULE_HEADERS_ONLY) if(NOT MODULE_NO_INIT OR RESOURCE_FILES) find_package(CppMicroServices QUIET NO_MODULE REQUIRED) endif() if(NOT MODULE_NO_INIT) usFunctionGenerateModuleInit(CPP_FILES) endif() set(binary_res_files ) set(source_res_files ) if(RESOURCE_FILES) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/resource") set(res_dir resource) elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Resources") set(res_dir Resources) else() message(SEND_ERROR "Resources specified but ${CMAKE_CURRENT_SOURCE_DIR}/resource directory not found.") endif() foreach(res_file ${RESOURCE_FILES}) if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${res_dir}/${res_file}) list(APPEND binary_res_files "${res_file}") else() list(APPEND source_res_files "${res_file}") endif() endforeach() # Add a source level dependencies on resource files usFunctionGetResourceSource(TARGET ${MODULE_TARGET} OUT CPP_FILES) endif() endif() if(MITK_USE_Qt5) if(UI_FILES) qt5_wrap_ui(Q${KITNAME}_GENERATED_UI_CPP ${UI_FILES}) endif() if(MOC_H_FILES) qt5_wrap_cpp(Q${KITNAME}_GENERATED_MOC_CPP ${MOC_H_FILES} OPTIONS -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) endif() if(QRC_FILES) qt5_add_resources(Q${KITNAME}_GENERATED_QRC_CPP ${QRC_FILES}) endif() endif() set(Q${KITNAME}_GENERATED_CPP ${Q${KITNAME}_GENERATED_CPP} ${Q${KITNAME}_GENERATED_UI_CPP} ${Q${KITNAME}_GENERATED_MOC_CPP} ${Q${KITNAME}_GENERATED_QRC_CPP}) mitkFunctionOrganizeSources( 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} ) set(coverage_sources ${CPP_FILES} ${H_FILES} ${GLOBBED__H_FILES} ${CORRESPONDING__H_FILES} ${TXX_FILES} ${TOOL_CPPS} ${TOOL_GUI_CPPS}) # --------------------------------------------------------------- # Create the actual module target if(MODULE_HEADERS_ONLY) add_library(${MODULE_TARGET} INTERFACE) # INTERFACE_LIBRARY targets may only have whitelisted properties. The property "FOLDER" is not allowed. # set_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules") else() if(MODULE_EXECUTABLE) if(MITK_SHOW_CONSOLE_WINDOW) set(_SHOW_CONSOLE_OPTION "") else() set(_SHOW_CONSOLE_OPTION WIN32) endif() add_executable(${MODULE_TARGET} ${_SHOW_CONSOLE_OPTION} ${MODULE_CPP_FILES} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES} ${WINDOWS_ICON_RESOURCE_FILE}) if(WIN32 AND MITK_UTF8) mitk_add_manifest(${MODULE_TARGET}) endif() set_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Executables") set(_us_module_name main) else() add_library(${MODULE_TARGET} ${_STATIC} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) set_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules") set(_us_module_name ${MODULE_TARGET}) endif() # Apply properties to the module target. target_compile_definitions(${MODULE_TARGET} PRIVATE US_MODULE_NAME=${_us_module_name}) if(MODULE_C_MODULE) if(module_c_flags) string(REPLACE " " ";" module_c_flags "${module_c_flags}") target_compile_options(${MODULE_TARGET} PRIVATE ${module_c_flags}) endif() if(module_c_flags_debug) string(REPLACE " " ";" module_c_flags_debug "${module_c_flags_debug}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_c_flags_debug}>) endif() if(module_c_flags_release) string(REPLACE " " ";" module_c_flags_release "${module_c_flags_release}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_c_flags_release}>) endif() else() if(module_cxx_flags) string(REPLACE " " ";" module_cxx_flags "${module_cxx_flags}") target_compile_options(${MODULE_TARGET} PRIVATE ${module_cxx_flags}) endif() if(module_cxx_flags_debug) string(REPLACE " " ";" module_cxx_flags_debug "${module_cxx_flags_debug}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_cxx_flags_debug}>) endif() if(module_cxx_flags_release) string(REPLACE " " ";" module_cxx_flags_release "${module_cxx_flags_release}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_cxx_flags_release}>) endif() endif() set_property(TARGET ${MODULE_TARGET} PROPERTY US_MODULE_NAME ${_us_module_name}) # Add additional library search directories to a global property which # can be evaluated by other CMake macros, e.g. our install scripts. if(MODULE_ADDITIONAL_LIBS) target_link_libraries(${MODULE_TARGET} PRIVATE ${MODULE_ADDITIONAL_LIBS}) get_property(_mitk_additional_library_search_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) foreach(_lib_filepath ${MODULE_ADDITIONAL_LIBS}) get_filename_component(_search_path "${_lib_filepath}" PATH) if(_search_path) list(APPEND _mitk_additional_library_search_paths "${_search_path}") endif() endforeach() if(_mitk_additional_library_search_paths) list(REMOVE_DUPLICATES _mitk_additional_library_search_paths) set_property(GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS ${_mitk_additional_library_search_paths}) endif() endif() # add the target name to a global property which is used in the top-level # CMakeLists.txt file to export the target set_property(GLOBAL APPEND PROPERTY MITK_MODULE_TARGETS ${MODULE_TARGET}) if(MODULE_AUTOLOAD_WITH) # for auto-loaded modules, adapt the output directory add_dependencies(${_module_autoload_meta_target} ${MODULE_TARGET}) if(WIN32) set(_module_output_prop RUNTIME_OUTPUT_DIRECTORY) else() set(_module_output_prop LIBRARY_OUTPUT_DIRECTORY) endif() set(_module_output_dir ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) get_target_property(_module_is_imported ${MODULE_AUTOLOAD_WITH} IMPORTED) if(NOT _module_is_imported) # if the auto-loading module is not imported, get its location # and put the auto-load module relative to it. get_target_property(_module_output_dir ${MODULE_AUTOLOAD_WITH} ${_module_output_prop}) set_target_properties(${MODULE_TARGET} PROPERTIES ${_module_output_prop} ${_module_output_dir}/${MODULE_AUTOLOAD_WITH}) else() set_target_properties(${MODULE_TARGET} PROPERTIES ${_module_output_prop} ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) endif() set_target_properties(${MODULE_TARGET} PROPERTIES MITK_AUTOLOAD_DIRECTORY ${MODULE_AUTOLOAD_WITH}) # add the auto-load module name as a property set_property(TARGET ${MODULE_AUTOLOAD_WITH} APPEND PROPERTY MITK_AUTOLOAD_TARGETS ${MODULE_TARGET}) endif() if(binary_res_files) usFunctionAddResources(TARGET ${MODULE_TARGET} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${res_dir} FILES ${binary_res_files}) endif() if(source_res_files) usFunctionAddResources(TARGET ${MODULE_TARGET} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${res_dir} FILES ${source_res_files}) endif() if(binary_res_files OR source_res_files) usFunctionEmbedResources(TARGET ${MODULE_TARGET}) endif() if(MODULE_DEPRECATED_SINCE) set_property(TARGET ${MODULE_TARGET} PROPERTY MITK_MODULE_DEPRECATED_SINCE ${MODULE_DEPRECATED_SINCE}) endif() # create export macros if (NOT MODULE_EXECUTABLE) set(_export_macro_name ) if(MITK_LEGACY_EXPORT_MACRO_NAME) set(_export_macro_names EXPORT_MACRO_NAME ${MODULE_EXPORT_DEFINE} NO_EXPORT_MACRO_NAME ${MODULE_NAME}_NO_EXPORT DEPRECATED_MACRO_NAME ${MODULE_NAME}_DEPRECATED NO_DEPRECATED_MACRO_NAME ${MODULE_NAME}_NO_DEPRECATED ) endif() generate_export_header(${MODULE_NAME} ${_export_macro_names} EXPORT_FILE_NAME ${MODULE_NAME}Exports.h ) endif() target_include_directories(${MODULE_TARGET} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) endif() # --------------------------------------------------------------- # Properties for both header-only and compiled modules if(MODULE_HEADERS_ONLY) set(_module_property_type INTERFACE) else() set(_module_property_type PUBLIC) endif() if(MODULE_TARGET_DEPENDS) target_link_libraries(${MODULE_TARGET} ${MODULE_TARGET_DEPENDS}) endif() set(DEPENDS "${MODULE_DEPENDS}") if(NOT MODULE_NO_INIT AND NOT MODULE_HEADERS_ONLY) # Add a CppMicroServices dependency implicitly, since it is # needed for the generated "module initialization" code. set(DEPENDS "CppMicroServices;${DEPENDS}") endif() if(DEPENDS OR MODULE_PACKAGE_DEPENDS) mitk_use_modules(TARGET ${MODULE_TARGET} MODULES ${DEPENDS} PACKAGES ${MODULE_PACKAGE_DEPENDS} ) endif() # add include directories if(MODULE_INTERNAL_INCLUDE_DIRS) target_include_directories(${MODULE_TARGET} PRIVATE ${MODULE_INTERNAL_INCLUDE_DIRS}) endif() if(NOT MODULE_NO_DEFAULT_INCLUDE_DIRS) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(${MODULE_TARGET} ${_module_property_type} include) else() target_include_directories(${MODULE_TARGET} ${_module_property_type} .) endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(${MODULE_TARGET} PRIVATE src) endif() endif() target_include_directories(${MODULE_TARGET} ${_module_property_type} ${MODULE_INCLUDE_DIRS}) endif() # ----------------------------------------------------------------- # Record missing dependency information if(_MISSING_DEP) if(MODULE_DESCRIPTION) set(MODULE_DESCRIPTION "${MODULE_DESCRIPTION} (missing dependencies: ${_MISSING_DEP})") else() set(MODULE_DESCRIPTION "(missing dependencies: ${_MISSING_DEP})") endif() endif() if(NOT MODULE_NO_FEATURE_INFO) add_feature_info(${MODULE_NAME} MODULE_IS_ENABLED "${MODULE_DESCRIPTION}") endif() set(MODULE_NAME ${MODULE_NAME} PARENT_SCOPE) set(MODULE_TARGET ${MODULE_TARGET} PARENT_SCOPE) set(MODULE_IS_ENABLED ${MODULE_IS_ENABLED} PARENT_SCOPE) endfunction() diff --git a/CMake/mitkFunctionGetGccVersion.cmake b/CMake/mitkFunctionGetGccVersion.cmake index 381341eac0..972a2596eb 100644 --- a/CMake/mitkFunctionGetGccVersion.cmake +++ b/CMake/mitkFunctionGetGccVersion.cmake @@ -1,38 +1,38 @@ ########################################################################### # # Library: CTK # # Copyright (c) Kitware Inc. # # 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.commontk.org/LICENSE +# https://www.apache.org/licenses/LICENSE-2.0.txt # # 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. # ########################################################################### #! \brief Get the gcc version function(mitkFunctionGetGccVersion path_to_gcc output_var) if(CMAKE_COMPILER_IS_GNUCXX) execute_process( COMMAND ${path_to_gcc} -dumpversion RESULT_VARIABLE result OUTPUT_VARIABLE output ERROR_VARIABLE error OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE ) if(result) message(FATAL_ERROR "Failed to obtain compiler version running [${path_to_gcc} -dumpversion]: ${error}") endif() set(${output_var} ${output} PARENT_SCOPE) endif() endfunction() diff --git a/CMake/mitkTargetLinkLibrariesWithDynamicLookup.cmake b/CMake/mitkTargetLinkLibrariesWithDynamicLookup.cmake index 941d25044e..52eea078a2 100644 --- a/CMake/mitkTargetLinkLibrariesWithDynamicLookup.cmake +++ b/CMake/mitkTargetLinkLibrariesWithDynamicLookup.cmake @@ -1,581 +1,581 @@ #.rst: # # Public Functions # ^^^^^^^^^^^^^^^^ # # The following functions are defined: # # .. cmake:command:: mitk_target_link_libraries_with_dynamic_lookup # # :: # # mitk_target_link_libraries_with_dynamic_lookup( []) # # # Useful to "weakly" link a loadable module. For example, it should be used # when compiling a loadable module when the symbols should be resolve from # the run-time environment where the module is loaded, and not a specific # system library. # # Like proper linking, except that the given ```` are not necessarily # linked. Instead, the ```` is produced in a manner that allows for # symbols unresolved within it to be resolved at runtime, presumably by the # given ````. If such a target can be produced, the provided # ```` are not actually linked. # # It links a library to a target such that the symbols are resolved at # run-time not link-time. # # The linker is checked to see if it supports undefined # symbols when linking a shared library. If it does then the library # is not linked when specified with this function. # # On platforms that do not support weak-linking, this function works just # like ``mitk_target_link_libraries``. # # .. note:: # # For OSX it uses ``undefined dynamic_lookup``. This is similar to using # ``-shared`` on Linux where undefined symbols are ignored. # -# For more details, see `blog `_ +# For more details, see `blog `_ # from Tim D. Smith. # # # .. cmake:command:: mitk_check_dynamic_lookup # # Check if the linker requires a command line flag to allow leaving symbols # unresolved when producing a target of type ```` that is # weakly-linked against a dependency of type ````. # # ```` # can be one of "STATIC", "SHARED", "MODULE", or "EXE". # # ```` # can be one of "STATIC", "SHARED", or "MODULE". # # Long signature: # # :: # # mitk_check_dynamic_lookup( # # # []) # # # Short signature: # # :: # # mitk_check_dynamic_lookup() # set to "MODULE" # # set to "SHARED" # # # The result is cached between invocations and recomputed only when the value # of CMake's linker flag list changes; ``CMAKE_STATIC_LINKER_FLAGS`` if # ```` is "STATIC", and ``CMAKE_SHARED_LINKER_FLAGS`` otherwise. # # # Defined variables: # # ```` # Whether the current C toolchain supports weak-linking for target binaries of # type ```` that are weakly-linked against a dependency target of # type ````. # # ```` # List of flags to add to the linker command to produce a working target # binary of type ```` that is weakly-linked against a dependency # target of type ````. # # ``HAS_DYNAMIC_LOOKUP__`` # Cached, global alias for ```` # # ``DYNAMIC_LOOKUP_FLAGS__`` # Cached, global alias for ```` # # # Private Functions # ^^^^^^^^^^^^^^^^^ # # The following private functions are defined: # # .. warning:: These functions are not part of the scikit-build API. They # exist purely as an implementation detail and may change from version # to version without notice, or even be removed. # # We mean it. # # # .. cmake:command:: _get_target_type # # :: # # _get_target_type( ) # # # Shorthand for querying an abbreviated version of the target type # of the given ````. # # ```` is set to: # # - "STATIC" for a STATIC_LIBRARY, # - "SHARED" for a SHARED_LIBRARY, # - "MODULE" for a MODULE_LIBRARY, # - and "EXE" for an EXECUTABLE. # # Defined variables: # # ```` # The abbreviated version of the ````'s type. # # # .. cmake:command:: _test_weak_link_project # # :: # # _test_weak_link_project( # # # ) # # # Attempt to compile and run a test project where a target of type # ```` is weakly-linked against a dependency of type ````: # # - ```` can be one of "STATIC", "SHARED", "MODULE", or "EXE". # - ```` can be one of "STATIC", "SHARED", or "MODULE". # # Defined variables: # # ```` # Whether the current C toolchain can produce a working target binary of type # ```` that is weakly-linked against a dependency target of type # ````. # # ```` # List of flags to add to the linker command to produce a working target # binary of type ```` that is weakly-linked against a dependency # target of type ````. # function(_get_target_type result_var target) set(target_type "SHARED_LIBRARY") if(TARGET ${target}) get_property(target_type TARGET ${target} PROPERTY TYPE) endif() set(result "STATIC") if(target_type STREQUAL "STATIC_LIBRARY") set(result "STATIC") endif() if(target_type STREQUAL "SHARED_LIBRARY") set(result "SHARED") endif() if(target_type STREQUAL "MODULE_LIBRARY") set(result "MODULE") endif() if(target_type STREQUAL "EXECUTABLE") set(result "EXE") endif() set(${result_var} ${result} PARENT_SCOPE) endfunction() function(_test_weak_link_project target_type lib_type can_weak_link_var project_name) set(gnu_ld_ignore "-Wl,--unresolved-symbols=ignore-all") set(osx_dynamic_lookup "-undefined dynamic_lookup") set(no_flag "") foreach(link_flag_spec gnu_ld_ignore osx_dynamic_lookup no_flag) set(link_flag "${${link_flag_spec}}") set(test_project_dir "${PROJECT_BINARY_DIR}/CMakeTmp") set(test_project_dir "${test_project_dir}/${project_name}") set(test_project_dir "${test_project_dir}/${link_flag_spec}") set(test_project_dir "${test_project_dir}/${target_type}") set(test_project_dir "${test_project_dir}/${lib_type}") set(test_project_src_dir "${test_project_dir}/src") set(test_project_bin_dir "${test_project_dir}/build") file(MAKE_DIRECTORY ${test_project_src_dir}) file(MAKE_DIRECTORY ${test_project_bin_dir}) set(mod_type "STATIC") set(link_mod_lib TRUE) set(link_exe_lib TRUE) set(link_exe_mod FALSE) if("${target_type}" STREQUAL "EXE") set(link_exe_lib FALSE) set(link_exe_mod TRUE) else() set(mod_type "${target_type}") endif() if("${mod_type}" STREQUAL "MODULE") set(link_mod_lib FALSE) endif() file(WRITE "${test_project_src_dir}/CMakeLists.txt" " cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(${project_name} C) include_directories(${test_project_src_dir}) add_library(number ${lib_type} number.c) add_library(counter ${mod_type} counter.c) ") if("${mod_type}" STREQUAL "MODULE") file(APPEND "${test_project_src_dir}/CMakeLists.txt" " set_target_properties(counter PROPERTIES PREFIX \"\") ") endif() if(link_mod_lib) file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(counter number) ") elseif(NOT link_flag STREQUAL "") file(APPEND "${test_project_src_dir}/CMakeLists.txt" " set_target_properties(counter PROPERTIES LINK_FLAGS \"${link_flag}\") ") endif() file(APPEND "${test_project_src_dir}/CMakeLists.txt" " add_executable(main main.c) ") if(link_exe_lib) file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main number) ") elseif(NOT link_flag STREQUAL "") file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main \"${link_flag}\") ") endif() if(link_exe_mod) file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main counter) ") else() file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main \"${CMAKE_DL_LIBS}\") ") endif() file(WRITE "${test_project_src_dir}/number.c" " #include static int _number; void set_number(int number) { _number = number; } int get_number() { return _number; } ") file(WRITE "${test_project_src_dir}/number.h" " #ifndef _NUMBER_H #define _NUMBER_H extern void set_number(int); extern int get_number(void); #endif ") file(WRITE "${test_project_src_dir}/counter.c" " #include int count() { int result = get_number(); set_number(result + 1); return result; } ") file(WRITE "${test_project_src_dir}/counter.h" " #ifndef _COUNTER_H #define _COUNTER_H extern int count(void); #endif ") file(WRITE "${test_project_src_dir}/main.c" " #include #include #include ") if(NOT link_exe_mod) file(APPEND "${test_project_src_dir}/main.c" " #include ") endif() file(APPEND "${test_project_src_dir}/main.c" " int my_count() { int result = get_number(); set_number(result + 1); return result; } int main(int argc, char **argv) { int result; ") if(NOT link_exe_mod) file(APPEND "${test_project_src_dir}/main.c" " void *counter_module; int (*count)(void); counter_module = dlopen(\"./counter.so\", RTLD_LAZY | RTLD_GLOBAL); if(!counter_module) goto error; count = dlsym(counter_module, \"count\"); if(!count) goto error; ") endif() file(APPEND "${test_project_src_dir}/main.c" " result = count() != 0 ? EXIT_FAILURE : my_count() != 1 ? EXIT_FAILURE : my_count() != 2 ? EXIT_FAILURE : count() != 3 ? EXIT_FAILURE : count() != 4 ? EXIT_FAILURE : count() != 5 ? EXIT_FAILURE : my_count() != 6 ? EXIT_FAILURE : EXIT_SUCCESS; ") if(NOT link_exe_mod) file(APPEND "${test_project_src_dir}/main.c" " goto done; error: fprintf(stderr, \"Error occured:\\n %s\\n\", dlerror()); result = 1; done: if(counter_module) dlclose(counter_module); ") endif() file(APPEND "${test_project_src_dir}/main.c" " return result; } ") set(_rpath_arg) if(APPLE AND ${CMAKE_VERSION} VERSION_GREATER 2.8.11) set(_rpath_arg "-DCMAKE_MACOSX_RPATH='${CMAKE_MACOSX_RPATH}'") endif() try_compile(project_compiles "${test_project_bin_dir}" "${test_project_src_dir}" "${project_name}" CMAKE_FLAGS "-DCMAKE_SHARED_LINKER_FLAGS='${CMAKE_SHARED_LINKER_FLAGS}'" "-DCMAKE_ENABLE_EXPORTS=ON" ${_rpath_arg} OUTPUT_VARIABLE compile_output) set(project_works 1) set(run_output) if(project_compiles) execute_process(COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} "${test_project_bin_dir}/main" WORKING_DIRECTORY "${test_project_bin_dir}" RESULT_VARIABLE project_works OUTPUT_VARIABLE run_output ERROR_VARIABLE run_output) endif() set(test_description "Weak Link ${target_type} -> ${lib_type} (${link_flag_spec})") if(project_works EQUAL 0) set(project_works TRUE) message(STATUS "Performing Test ${test_description} - Success") else() set(project_works FALSE) message(STATUS "Performing Test ${test_description} - Failed") file(APPEND ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeError.log "Performing Test ${test_description} failed with the " "following output:\n" "BUILD\n-----\n${compile_output}\nRUN\n---\n${run_output}\n") endif() set(${can_weak_link_var} ${project_works} PARENT_SCOPE) if(project_works) set(${project_name} ${link_flag} PARENT_SCOPE) break() endif() endforeach() endfunction() function(mitk_check_dynamic_lookup) # Two signatures are supported: if(ARGC EQUAL "1") # # mitk_check_dynamic_lookup() # set(target_type "MODULE") set(lib_type "SHARED") set(has_dynamic_lookup_var "${ARGV0}") set(link_flags_var "unused") elseif(ARGC GREATER "2") # # mitk_check_dynamic_lookup( # # # []) # set(target_type "${ARGV0}") set(lib_type "${ARGV1}") set(has_dynamic_lookup_var "${ARGV2}") if(ARGC EQUAL "3") set(link_flags_var "unused") else() set(link_flags_var "${ARGV3}") endif() else() message(FATAL_ERROR "missing arguments") endif() _check_dynamic_lookup( ${target_type} ${lib_type} ${has_dynamic_lookup_var} ${link_flags_var} ) set(${has_dynamic_lookup_var} ${${has_dynamic_lookup_var}} PARENT_SCOPE) if(NOT "x${link_flags_var}x" MATCHES "^xunusedx$") set(${link_flags_var} ${${link_flags_var}} PARENT_SCOPE) endif() endfunction() function(_check_dynamic_lookup target_type lib_type has_dynamic_lookup_var link_flags_var ) # hash the CMAKE_FLAGS passed and check cache to know if we need to rerun if("${target_type}" STREQUAL "STATIC") string(MD5 cmake_flags_hash "${CMAKE_STATIC_LINKER_FLAGS}") else() string(MD5 cmake_flags_hash "${CMAKE_SHARED_LINKER_FLAGS}") endif() set(cache_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}") set(cache_hash_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}_hash") set(result_var "DYNAMIC_LOOKUP_FLAGS_${target_type}_${lib_type}") if( NOT DEFINED ${cache_hash_var} OR NOT "${${cache_hash_var}}" STREQUAL "${cmake_flags_hash}") unset(${cache_var} CACHE) endif() if(NOT DEFINED ${cache_var}) set(skip_test FALSE) if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR) set(skip_test TRUE) endif() if(skip_test) set(has_dynamic_lookup FALSE) set(link_flags) else() _test_weak_link_project(${target_type} ${lib_type} has_dynamic_lookup link_flags) endif() set(caveat " (when linking ${target_type} against ${lib_type})") set(${cache_var} "${has_dynamic_lookup}" CACHE BOOL "linker supports dynamic lookup for undefined symbols${caveat}") mark_as_advanced(${cache_var}) set(${result_var} "${link_flags}" CACHE STRING "linker flags for dynamic lookup${caveat}") mark_as_advanced(${result_var}) set(${cache_hash_var} "${cmake_flags_hash}" CACHE INTERNAL "hashed flags for ${cache_var} check") endif() set(${has_dynamic_lookup_var} "${${cache_var}}" PARENT_SCOPE) set(${link_flags_var} "${${result_var}}" PARENT_SCOPE) endfunction() function(mitk_target_link_libraries_with_dynamic_lookup target) _get_target_type(target_type ${target}) set(link_props) set(link_items) set(link_libs) foreach(lib ${ARGN}) _get_target_type(lib_type ${lib}) mitk_check_dynamic_lookup(${target_type} ${lib_type} has_dynamic_lookup dynamic_lookup_flags) if(has_dynamic_lookup) if(dynamic_lookup_flags) if("${target_type}" STREQUAL "EXE") list(APPEND link_items "${dynamic_lookup_flags}") else() list(APPEND link_props "${dynamic_lookup_flags}") endif() endif() else() list(APPEND link_libs "${lib}") endif() endforeach() if(link_props) list(REMOVE_DUPLICATES link_props) endif() if(link_items) list(REMOVE_DUPLICATES link_items) endif() if(link_libs) list(REMOVE_DUPLICATES link_libs) endif() if(link_props) set_target_properties(${target} PROPERTIES LINK_FLAGS "${link_props}") endif() set(links "${link_items}" "${link_libs}") if(links) target_link_libraries(${target} "${links}") endif() endfunction() diff --git a/CMakeExternals/CppUnitCMakeLists.txt b/CMakeExternals/CppUnitCMakeLists.txt index 14c7590705..34577fe5f0 100644 --- a/CMakeExternals/CppUnitCMakeLists.txt +++ b/CMakeExternals/CppUnitCMakeLists.txt @@ -1,228 +1,223 @@ cmake_minimum_required(VERSION 3.18) project(CppUnit) set(${PROJECT_NAME}_MAJOR_VERSION 1) set(${PROJECT_NAME}_MINOR_VERSION 15) set(${PROJECT_NAME}_PATCH_VERSION 1) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) -# UNICODE support -# See Visual C Unicode Programming Summary -# http://msdn.microsoft.com/en-us/library/dybsewaf%28VS.100%29.aspx -#add_definitions(-DUNICODE -D_UNICODE) - # Generates include/cppunit/config-auto.h # This is originally done by autoconf include(CheckIncludeFile) include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) include(CheckCSourceCompiles) include(CheckLibraryExists) include(CheckFunctionExists) #Not used == not seen in any *.h *.cpp files #Not used FUNC_STRING_COMPARE_STRING_FIRST check_include_file_cxx(sstream CPPUNIT_HAVE_SSTREAM) check_include_file_cxx(strstream CPPUNIT_HAVE_STRSTREAM) set (CMAKE_REQUIRED_DEFINITIONS -DHAVE_STRSTREAM=CPPUNIT_HAVE_STRSTREAM) check_cxx_source_compiles( "#ifdef HAVE_STRSTREAM #include #else #include #endif int main() { std::ostrstream message; message << \"Hello\"; return 0; }" CPPUNIT_HAVE_CLASS_STRSTREAM) check_include_file_cxx(cmath CPPUNIT_HAVE_CMATH) #Not used, dld library is obsolete anyway HAVE_DLD #Not used HAVE_DLERROR check_include_file(dlfcn.h CPPUNIT_HAVE_DLFCN_H) check_c_source_compiles( "#include int main() { return finite(3); }" CPPUNIT_HAVE_FINITE) check_c_source_compiles( "#include int main() { return _finite(3); }" CPPUNIT_HAVE__FINITE) check_include_file_cxx(cxxabi.h CPPUNIT_HAVE_GCC_ABI_DEMANGLE) #Not used HAVE_INTTYPES_H check_c_source_compiles( "#include int main() { return isfinite(3); }" CPPUNIT_HAVE_ISFINITE) check_library_exists(dl dlopen "" CPPUNIT_HAVE_LIBDL) #Not used HAVE_MEMORY_H check_cxx_source_compiles( "namespace Outer { namespace Inner { int i = 0; } } using namespace Outer::Inner; int main() { return i; }" CPPUNIT_HAVE_NAMESPACES) check_cxx_source_compiles( "#include class Base { public: Base() {} virtual int f() { return 0; } }; class Derived : public Base { public: Derived() {} virtual int f() { return 1; } }; int main() { Derived d; Base * ptr = &d; return typeid(*ptr) == typeid(Derived); }" CPPUNIT_HAVE_RTTI) check_library_exists(dl shl_load "" CPPUNIT_HAVE_SHL_LOAD) #Not used HAVE_STDINT_H #Not used HAVE_STDLIB_H #Not used HAVE_STRINGS_H #Not used HAVE_STRING_H #Not used HAVE_SYS_STAT_H #Not used HAVE_SYS_TYPES_H #Not used HAVE_UNISTD_H #Not used PACKAGE #Not used PACKAGE_BUGREPORT #Not used PACKAGE_NAME #Not used PACKAGE_STRING #Not used PACKAGE_TARNAME #Not used PACKAGE_VERSION #Not used STDC_HEADERS check_include_file_cxx(typeinfo CPPUNIT_USE_TYPEINFO_NAME) #CPPUNIT_VERSION ok configure_file(config/config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/include/cppunit/config-auto.h) ## set(cppunit_SRCS src/cppunit/AdditionalMessage.cpp src/cppunit/Asserter.cpp src/cppunit/BriefTestProgressListener.cpp src/cppunit/CompilerOutputter.cpp src/cppunit/DefaultProtector.h src/cppunit/DefaultProtector.cpp src/cppunit/DynamicLibraryManager.cpp src/cppunit/DynamicLibraryManagerException.cpp src/cppunit/Exception.cpp src/cppunit/Message.cpp src/cppunit/PlugInManager.cpp src/cppunit/PlugInParameters.cpp src/cppunit/Protector.cpp src/cppunit/ProtectorChain.h src/cppunit/ProtectorContext.h src/cppunit/ProtectorChain.cpp src/cppunit/RepeatedTest.cpp src/cppunit/ShlDynamicLibraryManager.cpp src/cppunit/SourceLine.cpp src/cppunit/StringTools.cpp src/cppunit/SynchronizedObject.cpp src/cppunit/Test.cpp src/cppunit/TestAssert.cpp src/cppunit/TestCase.cpp src/cppunit/TestCaseDecorator.cpp src/cppunit/TestComposite.cpp src/cppunit/TestDecorator.cpp src/cppunit/TestFactoryRegistry.cpp src/cppunit/TestFailure.cpp src/cppunit/TestLeaf.cpp src/cppunit/TestNamer.cpp src/cppunit/TestPath.cpp src/cppunit/TestPlugInDefaultImpl.cpp src/cppunit/TestResult.cpp src/cppunit/TestResultCollector.cpp src/cppunit/TestRunner.cpp src/cppunit/TestSetUp.cpp src/cppunit/TestSuccessListener.cpp src/cppunit/TestSuite.cpp src/cppunit/TestSuiteBuilderContext.cpp src/cppunit/TextOutputter.cpp src/cppunit/TextTestProgressListener.cpp src/cppunit/TextTestResult.cpp src/cppunit/TextTestRunner.cpp src/cppunit/TypeInfoHelper.cpp src/cppunit/UnixDynamicLibraryManager.cpp src/cppunit/Win32DynamicLibraryManager.cpp src/cppunit/XmlDocument.cpp src/cppunit/XmlElement.cpp src/cppunit/XmlOutputter.cpp src/cppunit/XmlOutputterHook.cpp ) add_library(cppunit SHARED ${cppunit_SRCS}) target_include_directories(cppunit PUBLIC "$" "$" ) target_compile_definitions(cppunit PRIVATE CPPUNIT_BUILD_DLL) set_target_properties(cppunit PROPERTIES VERSION ${${PROJECT_NAME}_VERSION} SOVERSION ${${PROJECT_NAME}_VERSION} ) set(${PROJECT_NAME}_LIBRARIES cppunit) # Install support install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin ) install(DIRECTORY include/cppunit DESTINATION include ) # Config files configure_file( ${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) export(EXPORT ${PROJECT_NAME}_TARGETS FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake ) set(config_package_location lib/cmake/${PROJECT_NAME}) install(EXPORT ${PROJECT_NAME}_TARGETS FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${config_package_location} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${config_package_location} ) diff --git a/Documentation/CMakeDoxygenFilter.cpp b/Documentation/CMakeDoxygenFilter.cpp index 1181e6a20a..a6c54a2dfa 100644 --- a/Documentation/CMakeDoxygenFilter.cpp +++ b/Documentation/CMakeDoxygenFilter.cpp @@ -1,475 +1,475 @@ /*============================================================================ Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include //-------------------------------------- // Utilitiy classes and functions //-------------------------------------- struct ci_char_traits : public std::char_traits // just inherit all the other functions // that we don't need to override { static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); } static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); } static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); } static bool gt(char c1, char c2) { return toupper(c1) > toupper(c2); } static int compare(const char *s1, const char *s2, std::size_t n) { while (n-- > 0) { if (lt(*s1, *s2)) return -1; if (gt(*s1, *s2)) return 1; ++s1; ++s2; } return 0; } static const char *find(const char *s, int n, char a) { while (n-- > 0 && toupper(*s) != toupper(a)) { ++s; } return s; } }; typedef std::basic_string ci_string; //-------------------------------------- // Lexer //-------------------------------------- class CMakeLexer { public: enum Token { TOK_EOF = -1, TOK_EOL = -2, // commands TOK_MACRO = -3, TOK_ENDMACRO = -4, TOK_FUNCTION = -5, TOK_ENDFUNCTION = -6, TOK_DOXYGEN_COMMENT = -7, TOK_SET = -8, TOK_STRING_LITERAL = -100, TOK_NUMBER_LITERAL = -102, // primary TOK_IDENTIFIER = -200 }; CMakeLexer(std::istream &is) : _lastChar(' '), _is(is), _line(1), _col(1) {} int getToken() { // skip whitespace while (isspace(_lastChar) && _lastChar != '\r' && _lastChar != '\n') { _lastChar = getChar(); } if (isalpha(_lastChar) || _lastChar == '_') { _identifier = _lastChar; while (isalnum(_lastChar = getChar()) || _lastChar == '-' || _lastChar == '_') { _identifier += _lastChar; } if (_identifier == "set") return TOK_SET; if (_identifier == "function") return TOK_FUNCTION; if (_identifier == "macro") return TOK_MACRO; if (_identifier == "endfunction") return TOK_ENDFUNCTION; if (_identifier == "endmacro") return TOK_ENDMACRO; return TOK_IDENTIFIER; } if (isdigit(_lastChar)) { // very lax!! number detection _identifier = _lastChar; while (isalnum(_lastChar = getChar()) || _lastChar == '.' || _lastChar == ',') { _identifier += _lastChar; } return TOK_NUMBER_LITERAL; } if (_lastChar == '#') { _lastChar = getChar(); if (_lastChar == '!') { // found a doxygen comment marker _identifier.clear(); _lastChar = getChar(); while (_lastChar != EOF && _lastChar != '\n' && _lastChar != '\r') { _identifier += _lastChar; _lastChar = getChar(); } return TOK_DOXYGEN_COMMENT; } // skip the comment while (_lastChar != EOF && _lastChar != '\n' && _lastChar != '\r') { _lastChar = getChar(); } } if (_lastChar == '"') { _lastChar = getChar(); _identifier.clear(); while (_lastChar != EOF && _lastChar != '"') { _identifier += _lastChar; _lastChar = getChar(); } // eat the closing " _lastChar = getChar(); return TOK_STRING_LITERAL; } // don't eat the EOF if (_lastChar == EOF) return TOK_EOF; // don't eat the EOL if (_lastChar == '\r' || _lastChar == '\n') { if (_lastChar == '\r') _lastChar = getChar(); if (_lastChar == '\n') _lastChar = getChar(); return TOK_EOL; } // return the character as its ascii value int thisChar = _lastChar; _lastChar = getChar(); return thisChar; } std::string getIdentifier() const { return std::string(_identifier.c_str()); } int curLine() const { return _line; } int curCol() const { return _col; } int getChar() { int c = _is.get(); updateLoc(c); return c; } private: void updateLoc(int c) { if (c == '\n' || c == '\r') { ++_line; _col = 1; } else { ++_col; } } ci_string _identifier; int _lastChar; std::istream &_is; int _line; int _col; }; //-------------------------------------- // Parser //-------------------------------------- class CMakeParser { public: CMakeParser(std::istream &is, std::ostream &os) : _is(is), _os(os), _lexer(is), _curToken(CMakeLexer::TOK_EOF), _lastToken(CMakeLexer::TOK_EOF) { } int curToken() { return _curToken; } int nextToken() { _lastToken = _curToken; _curToken = _lexer.getToken(); while (_curToken == CMakeLexer::TOK_EOL) { // Try to preserve lines in output to allow correct line number referencing by doxygen. _os << std::endl; _curToken = _lexer.getToken(); } return _curToken; } void handleMacro() { if (!parseMacro()) { // skip token for error recovery nextToken(); } } void handleFunction() { if (!parseFunction()) { // skip token for error recovery nextToken(); } } void handleSet() { // SET(var ...) following a documentation block is assumed to be a variable declaration. if (_lastToken != CMakeLexer::TOK_DOXYGEN_COMMENT) { // No comment block before nextToken(); } else if (!parseSet()) { // skip token for error recovery nextToken(); } } void handleDoxygenComment() { _os << "///" << _lexer.getIdentifier(); nextToken(); } void handleTopLevelExpression() { // skip token nextToken(); } private: void printError(const char *str) { std::cerr << "Error: " << str << " (at line " << _lexer.curLine() << ", col " << _lexer.curCol() << ")"; } bool parseMacro() { if (nextToken() != '(') { printError("Expected '(' after MACRO"); return false; } nextToken(); std::string macroName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || macroName.empty()) { printError("Expected macro name"); return false; } _os << macroName << '('; if (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << _lexer.getIdentifier(); while (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << ", " << _lexer.getIdentifier(); } } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ");"; } // eat the ')' nextToken(); return true; } bool parseSet() { if (nextToken() != '(') { printError("Expected '(' after SET"); return false; } nextToken(); std::string variableName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || variableName.empty()) { printError("Expected variable name"); return false; } _os << "CMAKE_VARIABLE " << variableName; nextToken(); while ((curToken() == CMakeLexer::TOK_IDENTIFIER) || (curToken() == CMakeLexer::TOK_STRING_LITERAL) || (curToken() == CMakeLexer::TOK_NUMBER_LITERAL)) { nextToken(); } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ";"; } // eat the ')' nextToken(); return true; } bool parseFunction() { if (nextToken() != '(') { printError("Expected '(' after FUNCTION"); return false; } nextToken(); std::string funcName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || funcName.empty()) { printError("Expected function name"); return false; } _os << funcName << '('; if (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << _lexer.getIdentifier(); while (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << ", " << _lexer.getIdentifier(); } } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ");"; } // eat the ')' nextToken(); return true; } std::istream &_is; std::ostream &_os; CMakeLexer _lexer; int _curToken; int _lastToken; }; #define STRINGIFY(a) #a #define DOUBLESTRINGIFY(a) STRINGIFY(a) int main(int argc, char **argv) { assert(argc > 1); for (int i = 1; i < argc; ++i) { std::ifstream ifs(argv[i]); std::ostream &os = std::cout; #ifdef USE_NAMESPACE os << "namespace " << DOUBLESTRINGIFY(USE_NAMESPACE) << " {\n"; #endif CMakeParser parser(ifs, os); parser.nextToken(); while (ifs.good()) { switch (parser.curToken()) { case CMakeLexer::TOK_EOF: return ifs.get(); // eat EOF case CMakeLexer::TOK_MACRO: parser.handleMacro(); break; case CMakeLexer::TOK_FUNCTION: parser.handleFunction(); break; case CMakeLexer::TOK_SET: parser.handleSet(); break; case CMakeLexer::TOK_DOXYGEN_COMMENT: parser.handleDoxygenComment(); break; default: parser.handleTopLevelExpression(); break; } } #ifdef USE_NAMESPACE os << "}\n"; #endif } return EXIT_SUCCESS; } diff --git a/Documentation/CMakeLists.txt b/Documentation/CMakeLists.txt index a25b37f09e..00f7794779 100644 --- a/Documentation/CMakeLists.txt +++ b/Documentation/CMakeLists.txt @@ -1,166 +1,128 @@ # Different doxygen versions produce significantly different behaviour in the MITK documentation # especially in regards to the MITK Qt assistant help files and markdown files. # The HTML documentation is supposed to be build with Doxygen 1.8.7 or newer, the # Qt assistant QCH files are supposed to be generated with Doxygen 1.8.7 or newer. # So we check for 1.8.7 here and QCH generation support is checked in # BlueBerry/CMakeLists.txt set(supported_doxygen_version "1.8.7") if(DOXYGEN_VERSION VERSION_LESS ${supported_doxygen_version}) MESSAGE(WARNING "Unsupported doxygen version ${DOXYGEN_VERSION}. The MITK HTML documentation has been tested to work with doxygen ${supported_doxygen_version} or newer.") endif() option(USE_DOT "Use dot program for generating graphical class diagrams with doxygen, if available" ON) option(MITK_DOXYGEN_BUILD_ALWAYS "Always build the MITK documentation when building the default target" OFF) option(MITK_DOXYGEN_GENERATE_QCH_FILES "Use doxygen to generate Qt compressed help files for MITK docs" OFF) mark_as_advanced(USE_DOT MITK_DOXYGEN_BUILD_ALWAYS MITK_DOXYGEN_GENERATE_QCH_FILES) if (MITK_DOXYGEN_GENERATE_QCH_FILES AND DOXYGEN_VERSION VERSION_LESS "1.8.7") message(WARNING "> Forcing MITK_DOXYGEN_GENERATE_QCH_FILES to OFF because Doxygen version 1.8.7 or newer not found.") set(MITK_DOXYGEN_GENERATE_QCH_FILES OFF CACHE BOOL "Use doxygen to generate Qt compressed help files for MITK docs" FORCE) endif() set(HAVE_DOT "NO") if(DOXYGEN_DOT_EXECUTABLE AND USE_DOT) set(HAVE_DOT "YES") endif() set(MITK_DOXYGEN_TAGFILE_NAME ${MITK_DOXYGEN_OUTPUT_DIR}/MITK.tag CACHE INTERNAL "MITK Doxygen tag file") # This is relative to the working directory of the doxygen command set(MITK_DOXYGEN_STYLESHEET mitk_doxygen_extra.css) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${MITK_DOXYGEN_STYLESHEET} ${CMAKE_CURRENT_BINARY_DIR}/${MITK_DOXYGEN_STYLESHEET} COPYONLY) # Create QCH files for MITK and external projects set(MITK_DOXYGEN_GENERATE_QHP "NO") if(MITK_DOXYGEN_GENERATE_QCH_FILES) find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5 PATHS ${QT_BINARY_DIR} DOC "The location of the the Qt help generator executable" NO_DEFAULT_PATH ) mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE) if(NOT QT_HELPGENERATOR_EXECUTABLE) message(SEND_ERROR "The Qt help generator could not be found. Disabling qch generation") else() set(MITK_DOXYGEN_GENERATE_QHP "YES") endif() # The name of the generated MITK qch file, relative to the # Doxygen HTML output folder set(MITK_DOXYGEN_QCH_FILE "${MITK_BINARY_DIR}/MITK-${MITK_REVISION_ID}.qch") # Generating ITK and VTK docs it not done yet #option(MITK_DOXYGEN_GENERATE_VTK_QCH_FILE "Use doxygen to generate a Qt compressed help file for VTK docs" OFF) #option(MITK_DOXYGEN_GENERATE_ITK_QCH_FILE "Use doxygen to generate a Qt compressed help file for ITK docs" OFF) #mark_as_advanced(MITK_DOXYGEN_GENERATE_VTK_QCH_FILE MITK_DOXYGEN_GENERATE_ITK_QCH_FILE) endif() # Compile a doxygen input filter for processing CMake scripts include(mitkFunctionCMakeDoxygenFilterCompile) mitkFunctionCMakeDoxygenFilterCompile(NAMESPACE "CMake") # Configure some doxygen options if(NOT MITK_DOXYGEN_INTERNAL_DOCS) set(MITK_DOXYGEN_INTERNAL_DOCS "NO") set(MITK_DOXYGEN_HIDE_FRIEND_COMPOUNDS "YES") set(MITK_DOXYGEN_EXCLUDE_PATTERNS "*_p.* *Private.h */internal/*") else() set(MITK_DOXYGEN_HIDE_FRIEND_COMPOUNDS "NO") set(MITK_DOXYGEN_EXCLUDE_PATTERNS "") endif() if(NOT MITK_DOXYGEN_GENERATE_TODOLIST) set(MITK_DOXYGEN_GENERATE_TODOLIST "NO") endif() if(NOT MITK_DOXYGEN_GENERATE_BUGLIST) set(MITK_DOXYGEN_GENERATE_BUGLIST "NO") endif() if(NOT MITK_DOXYGEN_HTML_DYNAMIC_SECTIONS) set(MITK_DOXYGEN_HTML_DYNAMIC_SECTIONS "NO") endif() if(NOT MITK_DOXYGEN_UML_LOOK) set(MITK_DOXYGEN_UML_LOOK "NO") endif() if(NOT MITK_DOXYGEN_GENERATE_DEPRECATEDLIST) set(MITK_DOXYGEN_GENERATE_DEPRECATEDLIST "YES") endif() if(NOT DEFINED MITK_DOXYGEN_DOT_NUM_THREADS) set(MITK_DOXYGEN_DOT_NUM_THREADS 0) endif() if(NOT DEFINED US_PLATFORM) if(UNIX) if(APPLE) set(US_PLATFORM "US_PLATFORM_APPLE=1") else() set(US_PLATFORM "US_PLATFORM_LINUX=1") endif() set(US_PLATFORM "${US_PLATFORM} \\\nUS_PLATFORM_POSIX=1") else() set(US_PLATFORM "US_PLATFORM_WINDOWS=1") endif() endif() -#[[ parse which plug-in documentation to activate -set(USERS_GUIDE_INPUT "${MITK_SOURCE_DIR}/Documentation/Doxygen/UserManual/") -if(MITK_USE_BLUEBERRY) - if(MITK_BUILD_ALL_PLUGINS) - set(USERS_GUIDE_INPUT "${USERS_GUIDE_INPUT} \\ - ${MITK_SOURCE_DIR}/Plugins/") - else() - foreach(mitk_plugin ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES}) - # we want each line to end in " \" and each directory be on a separate line - set(USERS_GUIDE_INPUT "${USERS_GUIDE_INPUT} \\ - ${${mitk_plugin}_SOURCE_DIR}/") - endforeach() - endif() - - if(MITK_BUILD_EXAMPLES) - set(USERS_GUIDE_INPUT "${USERS_GUIDE_INPUT} \\ - ${MITK_SOURCE_DIR}/Examples/Plugins/") - endif() -endif()]] - -#[[ create output directories for the guides -file(MAKE_DIRECTORY ${MITK_DOXYGEN_OUTPUT_DIR}/Guides/Users_Guide/) -file(MAKE_DIRECTORY ${MITK_DOXYGEN_OUTPUT_DIR}/Guides/Developers_Guide/)]] - configure_file(doxygen.conf.in ${CMAKE_CURRENT_BINARY_DIR}/doxygen.conf) -#[[configure_file(doxygen_users_guide.conf.in - ${CMAKE_CURRENT_BINARY_DIR}/doxygen_users_guide.conf) -configure_file(doxygen_developers_guide.conf.in - ${CMAKE_CURRENT_BINARY_DIR}/doxygen_developers_guide.conf)]] if(MITK_DOXYGEN_BUILD_ALWAYS) set(_doc_in_all "ALL") else() set(_doc_in_all "") endif() add_custom_target(doc ${_doc_in_all} ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.conf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) -#[[add_custom_target(doc_usersguide - ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/doxygen_users_guide.conf - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ) - -add_custom_target(doc_developersguide - ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/doxygen_developers_guide.conf - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - )]] - -set_property(TARGET doc #[[doc_usersguide doc_developersguide]] PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Documentation") +set_property(TARGET doc PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Documentation") diff --git a/Documentation/Doxygen/3-DeveloperManual/Concepts/ReaderWriterPage.md b/Documentation/Doxygen/3-DeveloperManual/Concepts/ReaderWriterPage.md index 9076717513..74c6e26447 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Concepts/ReaderWriterPage.md +++ b/Documentation/Doxygen/3-DeveloperManual/Concepts/ReaderWriterPage.md @@ -1,176 +1,176 @@ Reader and Writer {#ReaderWriterPage} ================= This page is work in progress and will introduce you to the IO-System of MITK. [TOC] ## Introductory slides Several Talks have been given on the IO-System. The following list should provide you with a good starting point. -- Introduction to MimeTypes: http://www.mitk.org/images/e/e8/MimeTypes.pdf (by Caspar J. Goch) -- Introduction to the IO-System: http://www.mitk.org/images/0/0b/Newio.pdf (by Keno März) -- IO-Streams and the new IO System: http://www.mitk.org/images/9/95/Streams.pdf (by Keno März) +- Introduction to MimeTypes: https://www.mitk.org/images/e/e8/MimeTypes.pdf (by Caspar J. Goch) +- Introduction to the IO-System: https://www.mitk.org/images/0/0b/Newio.pdf (by Keno März) +- IO-Streams and the new IO System: https://www.mitk.org/images/9/95/Streams.pdf (by Keno März) ## Quick start: Reading and writing files using IOUtil mitk::IOUtil class provides convenience methods for loading data into a data storage or just returning BaseData objects without user interaction. The mitk::IOUtil::Save() and mitk::IOUtil::Load() methods cover the typical use cases and automatically select the best matching mitk::IFileReader and mitk::IFileWriter instance. In most cases, this is the easiest way to read or write a file. // load files directly into datastorage mitk::IOUtil::Load("/path/to/my/file.nrrd",*ds); // load basedata into local vector std::vector< mitk::Basedata::Pointer > basedatas; basedatas = mitk::IOUtil::Load("/path/to/my/file.nrrd"); // write basedata to file (here: surface as PLY mitk::IOUtil::Save(mySurface, "/Save/surface/here.ply"); // write basedata to file (here: surface as STL mitk::IOUtil::Save(mySurface, "/Save/surface/here.stl"); When reading a file using IOUtil, the IO-Framework first determines the mime-type of the given file. Afterwards, the best reader is selected internally, instantiated, and executed. The resulting BaseData Objects are returned to the developer as the method result. ## Quick start: Creating your own reader or writer If you implement a new BaseData, usually matching readers and writers are required. The following guide will help you to quickly set up these up and get them working in MITK. Create new classes for reader and writers. Optimally, place them in an extra IO-Module that is configured as autoload. This way, they are available to the application from the start. If you are working with common data, the appropriate module is MitkIOExt. You can either extend mitk::AbstractFileIO, which will allow you to implement a class with reader and writer abilities, or you can extend mitk::AbstractFileReader or mitk::AbstractFileWriter specifically. \imageMacro{reader_writer_classes.png,"",16} Implement the given Methods. A good example on how to write a simple reader and writer is the mitkPointSetReaderService.cpp and mitkPointSetWriterService.cpp class, from which you can take implementation cues. The following is a simplified version of the header file: namespace mitk { class PointSetReaderService: public AbstractFileReader // 2) Extend the Abstract File Reader { public: PointSetReaderService(); // 3) Provide Constructor and Destructor virtual ~PointSetReaderService(); // 4) Overwrite the Read Method as seen here using AbstractFileReader::Read; virtual std::vector< itk::SmartPointer > Read(); private: // 5) Provide a clone method PointSetReaderService(const PointSetReaderService& other); virtual PointSetReaderService* Clone() const; }; } ### Example Follow these steps to implement a new Reader: A) Create a new cpp and h file in an appropriate submodule. Usually, a reader or writer should be located in the same module as the BaseData derivate it reads/writes. B) Extend AbstractFileReader . This is highly recommended because it enables integration of your Reader into the Registery. It will then automatically be used by the application to load this type of files. C) Provide a constructor . It should contain a minimal amount of information and might look like this: mitk::PointSetReaderService::PointSetReaderService() : AbstractFileReader(CustomMimeType(IOMimeTypes::POINTSET_MIMETYPE_NAME()), "MITK Point Set Reader") { RegisterService(); } Note the call to the superclass constructor containing the MIME-type. You can either reuse an existent MIME type here or create your own MIME-type locally . Finally, register the service to make it available to MITK. D) Provide a Clone Method: Readers are clones when the registry requires a new reader. Provide a clone method to accommodate for this. Use the mitkPointSetReaderService.cpp as a reference if necessary. E) Instantiate it in the module activator. Open the module activator and make sure that the new Reader/Writer is instantiated and held somewhere in the code. Also, unregister the reader/writer in the unload function if necessary. ## Reader/Writer Options Options are a powerful concept to modify Reader/Writer behaviour and to automate user interaction with minimal development overhead. In principal, options are represented by a simple map and a few getter and setter functions: typedef std::map Options; virtual Options GetOptions(); virtual void SetOptions(const Options& options); virtual us::Any GetOption(const std::string& name); virtual void SetOptions(const Options& options); In its constructor, a reader or writer can set its options as a number map entries consisting of an human-readable option name and a default value. When a user tries to read/write a file via the interface, an options menu is generate from the map. \imageMacro{io_options.png,"The options dialog shown by the raw reader",5} The user can then modify these options, which are automatically set in the reader/writer. You can use raw-images to see this behaviour in action. ## Mime Types The MimeType class provides meta-data about a specific data format. Every mitk::IFileReader and mitk::IFileWriter instance must be associated with exactly one mime-type via a service property. \imageMacro{mimetypes.png,"",14} Mime-type are used for categorizing data formats and creating filter strings in file open and save dialogs. Hence they effectively control the accessible set of data formats from a graphical user interface. Minimally, mime-types should provide a name and a list of handled extensions in lower case. Additionally, it is highly encouraged to set a category and a comment which will provide user-readable strings for user interaction. It is important to understand the difference between mitk::MimeType and mitk::CustomMimeType. The former is an immutable stack object and can be pulled from mitk::MimeTypeProvider. it should be used for all interaction with MimeTypes. mitk::CustomMimeType is the heap-object pendant which is wrapped by mitk::MimeType and should exclusively be used for registration purposes, i.e. when you register a new MimeType. ## Additional Capabilities You can extend your reader writer with useful capabilities. All of these are optional + Priority: Reader use a ranking with Get- and SetRanking in order to signify how well they are suited to read a file. If several readers are able to read a file, the one with the highest Ranking level will be chosen. + ProgressCallbacks : Readers are executed in a thread automatically. If the reader implements callbacks, the progress bar will be more accurate during loading of files. Note: Progress callbacks are work in progress. ## Ranking strategies Todo. ## Convenience classes Developers usually do not interact with the service registry directly to retrieve and select a matching mitk::IFileReader or mitk::IFileWriter instance. ### %QmitkIOUtil The QmitkIOUtil class is a wrapper around mitk::IOUtil, providing file open and save dialogues for selecting a file name from a within a graphical user interface. ### FileReaderRegistry and FileWriterRegistry Access to mitk::IFileReader and mitk::IFileWriter objects and their service references. ## Integrating external I/O mechanisms The MITK I/O system integrates with several external I/O systems. ### ITK Reader and Writer The I/O classes from ITK are automatically added to the service registry of MITK. They can be transparently used via the mitk::IFileReader and mitk::IFileWriter interfaces or the mitk::IOUtil methods. ### VTK Reader and Writer VTK does not provide a mechanism to enumerate all available I/O classes. Hence MITK provides manual integration of a specific set of VTK readers and writers. ## Error handling and recovery Todo. diff --git a/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox b/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox index 10d3d23308..cb751350a8 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox @@ -1,104 +1,104 @@ /** \page GeneralTests General: Tests in MITK \tableofcontents \section GeneralTestsIntroduction Testing in MITK The basic idea about unit testing is to write a test for every unit (e.g. function) of your software, which automatically checks if the code still returns the expected result for a defined input. The goal is to isolate units as much as possible, in order to be efficient with fixing errors. If this is performed on a low level, this is called unit testing. On higher levels, where various circumstances (such as configuration files, internet connection, hardware, or even input/output) may influence the outcome of the test, this is called integration testing. MITK uses CppUnit, which is a framework for efficient and fast test writing, to support developers in test coding. Furthermore MITK offers currently three types of tests: classic unit tests, rendering tests and interaction tests. Although our unit tests often involve data input (or output), we still consider them to be unit tests. \warning Most of our units tests have been written before adopting CppUnit and have not yet been updated. Therefore we do not recommend to look at a random test for an example of coding a test. This pages gives a general introduction to our test framework. Rendering tests are explained in more detail in the section \ref RenderingTests and interaction tests the section \ref InteractionTestingHowTo. The following sections will explain how to write your own tests with MITK and how to run them. \section GeneralTestsAdding Adding a test to your module Generally, functional code you want to test using unit tests will be located in a module. For an overview of the directory structure see \ref NewModulePageCreateFolder and how to add the files comprising your test compare \ref NewModulePageCreateTestingEnvironment \subsection GeneralTestsAddingFramework Test and test class/suite CppUnit and MITK distinguish between the term test class and test, which is important to understand. A test is simply a call of a single function and a comparison against a reference. The ideal way to write a test is: \code result = myGreatFunction(myParameter); ASSERT_EQUAL(result, reference); \endcode which is just 2 lines of code at the best. Sometimes objects and data may be initialized in a test, but usually this should be done in the setUp() method (see below). If possible, avoid multiple assertions in order to be efficient in error localization and for better readability. For instance, if you instantiate an object and test if its data is not NULL, this is already a complete test and you do not want to repeat this comparison in other tests. All tests check different things and just one at a time. Remember: The goal is to have isolated unit tests and avoid large, confusing tests which are hard to maintain. \note The reference should never be computed and ideally be a distinct and well defined (often hard coded) value. You don't care where you reference comes from, you just want to ensure that your test actually results in the reference value. A test class (also called suite) is a set of tests and often associated to a single functional class in MITK. A test class refers to a TestSuite in CppUnit. These terms are easily confused, so we suggest to use the term test suite for a collection of tests (which is often in a single file), and the term "test" for a single test (usually many per file). In order to create a test class you need to create a new class deriving from mitk::TestFixture. While a purist approach would be to create a new mitk::TestFixture for each method of your class (resulting in as many test source files as your class has methods), we usually follow a more pragmatic approach within MITK. In most cases we suggest having one test source file per class. If your class source file is called mitkGreatClass.cpp we suggest the name mitkGreatClassTest.cpp for your test source file. For very complex and long classes splitting this into several tests may be advisable. Additionally, rendering tests and interaction tests should always get their own test class/suite to mark them as obvious integration tests, because the goal is to isolate unit tests from integration tests. The dashboard for continuous integration will automatically show the results of a test suite and summarize the output. If you run your test manually (e.g. with ctest -VV), you will see the detailed output of all tests of the suite. In order to use CppUnit via MITK you will need to include the corresponding files and register your test: \code #include #include … MITK_TEST_SUITE_REGISTRATION(mitkImageEqual) \endcode \subsection GeneralTestsAddingHow How to structure your test As mentioned before, all test suites derive from mitk::TestFixture. A suggested name for your test suite would be \c \TestSuite . You then create a suite and register your tests. A suggested naming convention for test methods is \c \_\_\ . We suggest not to add the word test, because that is most likely the only thing the reader knows anyway about your test, as he is reading a test suite. An example: \code class mitkImageEqualTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkImageEqualTestSuite); MITK_TEST(Equal_CloneAndOriginal_ReturnsTrue); MITK_TEST(Equal_InputIsNull_ReturnsFalse); MITK_TEST(Equal_DifferentImageGeometry_ReturnsFalse); MITK_TEST(Equal_DifferentPixelTypes_ReturnsFalse); … CPPUNIT_TEST_SUITE_END(); … } \endcode -You also may provide a setUp() and a tearDown() function. These will be called before/after each test and should be used to make sure that each test works independently and on freshly initialized members and memory to maximize isolation. That way you avoid only testing whether a function works after another function has already been called. See CppUnit documentation for more information. For an example test suite including tests see \ref GeneralTestsExample +You also may provide a setUp() and a tearDown() function. These will be called before/after each test and should be used to make sure that each test works independently and on freshly initialized members and memory to maximize isolation. That way you avoid only testing whether a function works after another function has already been called. For an example test suite including tests see \ref GeneralTestsExample \section GeneralTestsRunning Running your test suite The build system of MITK generates a test driver which includes all test suites that have been added to the project. Alternatively you can run MITK test suites by using the program ctest. This is the way all MITK tests run on the continuous dart clients of MITK. The results of these runs can be found at https://cdash.mitk.org/. If you use the test driver, you only need to start the executable. If you start it without parameters, it will then give you an overview of all tests which are included in this test driver and you can choose one by typing a number. Alternatively, you can give your test driver the name of your test suite as parameter. If you want to use ctest instead of the test driver you need to start a command line, go to the binary directory of MITK and call ctest. To avoid errors, check if your path variable contains all relevant paths to start MITK. \section GeneralTestsParameterInput Adding parameters to your test If possible, the setUp() method of the test suite should provide all necessary inputs for the respective tests. MITK provides several helper classes to generate synthetic test data, such as the mitk::ImageGenerator. If you have to load data from the hard disc for your test, you can use the method GetTestDataFilePath(string fileName). For an example of loading data from the MITK_DATA_DIR check the mitkIOUtilTestSuite. \section GeneralTestsPredefinedAssertions Predefined assertions -MITK and CppUnit offer predefined assertions, i.e. helper methods which will help to compare your data against a certain reference. All basic types are covered by CppUnit assertions, such as CPPUNIT_ASSERT. For examples, please check the CppUnit documentation. MITK further offers comparison tools for floating point numbers, vectors, images, surfaces and point sets. A complete list of assertion macros is given in \ref MITKTestingAPI. +MITK and CppUnit offer predefined assertions, i.e. helper methods which will help to compare your data against a certain reference. All basic types are covered by CppUnit assertions, such as CPPUNIT_ASSERT. MITK further offers comparison tools for floating point numbers, vectors, images, surfaces and point sets. A complete list of assertion macros is given in \ref MITKTestingAPI. An example to compare images: \code MITK_ASSERT_EQUAL(image, reference, "Checks if image is equal to a reference"); \endcode By default, the method uses an mitk::eps for floating point comparison, but this can be adapted. It can be necessary to write your own assertion for your own data meeting your special requirements. Recommended examples are all equal test suites for basic data types (mitkImageEqualTest, mitkSurfaceEqualTest and mitkPointSetEqualTest). \section GeneralTestsExample An example \include Examples/FirstSteps/NewModule/test/mitkExampleDataStructureTest.cpp \section GeneralTestsFurtherInfo Further information More examples can be found in the corresponding bugsquashing presentation. */ \section GeneralTestsDeprecatedOldTestingStyle Deprecated macros All tests with MITK_TEST_BEGIN(); and MITK_TEST_END(); use the deprecated old MITK testing style. If possible, they should be replaced with the new CppUnit style as explained before. Most of these test classes contain very unfortunate examples and should not be regarded as reference. diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox index ff4c803e83..b8781ce573 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox @@ -1,115 +1,115 @@ /** \page thirdpartylibs Third-party libraries The following third-party libraries can be used with MITK by default and can, in part, be automatically downloaded during superbuild. \par ACVD https://www.creatis.insa-lyon.fr/~valette/public/project/acvd/ \par ANN https://www.cs.umd.edu/~mount/ANN/ \par Boost https://www.boost.org/ \par C++ REST SDK https://github.com/Microsoft/cpprestsdk/ \par CppUnit https://sourceforge.net/projects/cppunit/ \par CTK https://commontk.org/ \par DCMTK https://dicom.offis.de/dcmtk \par Eigen -http://eigen.tuxfamily.org/index.php?title=Main_Page +https://eigen.tuxfamily.org/index.php?title=Main_Page \par GDCM https://gdcm.sourceforge.net/ \par HDF5 https://support.hdfgroup.org/HDF5/ \par ITK https://itk.org/ \par JSON for Modern C++ https://github.com/nlohmann/json \par lz4 https://github.com/lz4/lz4 \par MatchPoint https://www.dkfz.de/en/sidt/projects/MatchPoint/info.html \par OpenCL https://www.khronos.org/opencl/ \par OpenCV https://opencv.org/ \par OpenIGTLink http://openigtlink.org/ \par PCRE https://www.pcre.org/ \par POCO https://pocoproject.org/ \par Python https://www.python.org/ \par Qt https://www.qt.io/ \par Qwt -http://qwt.sourceforge.net/ +https://qwt.sourceforge.io/ \par SWIG -http://www.swig.org/ +https://www.swig.org/ \par TinyXML-2 -http://www.grinninglizard.com/tinyxml2/ +https://www.grinninglizard.com/tinyxml2/ \par VIGRA https://ukoethe.github.io/vigra/ \par VTK https://vtk.org/ \par zlib https://zlib.net/ For copyright information on any of the above toolkits see the corresponding home page or the corresponding source folder. */ diff --git a/Documentation/MITKDoxygenLayout.xml b/Documentation/MITKDoxygenLayout.xml index da9704a0b3..81f8e2f990 100644 --- a/Documentation/MITKDoxygenLayout.xml +++ b/Documentation/MITKDoxygenLayout.xml @@ -1,197 +1,197 @@ - - + + diff --git a/Documentation/mitk_doxygen_extra.css b/Documentation/mitk_doxygen_extra.css index 2e2cef5271..a8c790b24d 100644 --- a/Documentation/mitk_doxygen_extra.css +++ b/Documentation/mitk_doxygen_extra.css @@ -1,140 +1,140 @@ /* Main Doxygen CSS overrides */ -@import url(http://fonts.googleapis.com/css?family=Open+Sans); +@import url(https://fonts.googleapis.com/css?family=Open+Sans); body, table, div, p, dl { font-family: 'Open Sans', Lucida Grande, Verdana, Geneva, Arial, sans-serif; } a { color: #2d5c88; } #top { border-bottom: 1px solid #e1e1e1; } .navpath ul { background-image:none; color:#dddddd; } .navpath li.navelem a { color: inherit; font-family: inherit; text-shadow: none; } #projectname { visibility: hidden; height: 70px; margin-left: -520px; } #projectbrief { display: none; } #projectnumber { font: inherit; visibility: visible; font-size: 12px; position: relative; top: 17px; left: 80px; } #titlearea table tbody>tr:first-child>td:first-child { background: url(mitkLogo.jpg) 0 0 no-repeat; padding-right: 15px; } /* Doxygen navtree.css overrides */ #nav-tree .label { font: inherit; } #nav-tree { background-color: inherit; } #nav-tree { background-image:none; background-color: inherit; } /* Doxygen tabs.css overrides */ .tabs, .tabs2, .tabs3 { background-image: none; font-family: inherit; } .tabs2 { font-size: 12px; } .tablist { margin: 0 auto; } .tablist li { background-image: none; } .tablist a { background-image:none; color: #808080; transition:all .3s ease-out; border-bottom:2px solid transparent; } .tablist a:hover { background-image:none; text-shadow: none; color: #333333; border-bottom: 2px solid #2d5c88; } .tablist li.current a { background-image:none; text-shadow: none; color: #333333; border-bottom: 2px solid #2d5c88; } /* Search field */ #MSearchBox .left { border-style: solid none solid solid; border-width: 1px; background: none; border-color: #000000; } #MSearchField { margin-top: -1px; border-style: solid none; border-width: 1px; border-color: #000000; background: none; padding-top: 0px; padding-bottom: 0px; } #MSearchBox .right { border-style: solid solid solid none; border-width: 1px; background: none; border-color: #000000; } #MSearchResultsWindow { background-color: #ffffff; } #MSearchSelectWindow { border-color: #000000; background-color: #ffffff; } diff --git a/Examples/BlueBerryExampleLauncher/Configurations/CustomViewer.cmake b/Examples/BlueBerryExampleLauncher/Configurations/CustomViewer.cmake index 8341577b97..1379663bea 100644 --- a/Examples/BlueBerryExampleLauncher/Configurations/CustomViewer.cmake +++ b/Examples/BlueBerryExampleLauncher/Configurations/CustomViewer.cmake @@ -1,23 +1,23 @@ set(REQUIRED_PLUGINS org.mitk.example.gui.customviewer org.mitk.gui.qt.datamanager org.mitk.example.gui.customviewer.views ) set(DESCRIPTION "The Custom Viewer Example is a BlueBerry example plugin, developed to demonstrate customization capabilities provided by the BlueBerry application framework. The example plugin implements a GUI customized viewer application. The developed viewer incorporates simple viewer functionality embedded in a customized graphical user interface.

Spoken in BlueBerry terms, the following features are provided:

  • Hidden Menu-, Tool- and Statusbars
  • Hidden Editor Area
  • Fixed perspectives
  • Customized main window contents
  • Customized perspectives bar based on QTabBar
  • GUI Customization using Qt-Stylesheets
-See the main documentation for details." +See the main documentation for details." ) diff --git a/Examples/BlueBerryExampleLauncher/Configurations/ExtensionPointDefinition.cmake b/Examples/BlueBerryExampleLauncher/Configurations/ExtensionPointDefinition.cmake index aa5691918d..7a2f36ac71 100644 --- a/Examples/BlueBerryExampleLauncher/Configurations/ExtensionPointDefinition.cmake +++ b/Examples/BlueBerryExampleLauncher/Configurations/ExtensionPointDefinition.cmake @@ -1,19 +1,19 @@ set(REQUIRED_PLUGINS org.mitk.example.gui.extensionpointdefinition org.mitk.example.gui.extensionpointcontribution ) set(DESCRIPTION "This BlueBerry example consists of two plugins that demonstrate the use of the extension point concept. The first plugin defines an extension point and holds the GUI. The user can insert a text in a text field. The second plugin contributes an extension in the form of two classes that can change the user text to upper or lower case.

The following features are demonstrated:

  • creating an extension point
  • creating an extension
  • collecting extensions for an extension point
-See the main documentation for details." +See the main documentation for details." ) diff --git a/Examples/BlueBerryExampleLauncher/Configurations/MinimalApplication.cmake b/Examples/BlueBerryExampleLauncher/Configurations/MinimalApplication.cmake index d6d30ed8fd..30d21d369a 100644 --- a/Examples/BlueBerryExampleLauncher/Configurations/MinimalApplication.cmake +++ b/Examples/BlueBerryExampleLauncher/Configurations/MinimalApplication.cmake @@ -1,17 +1,17 @@ set(REQUIRED_PLUGINS org.mitk.example.gui.minimalapplication ) set(DESCRIPTION "This BlueBerry example plugin demonstrates a minimal implementation of an application consisting only of an empty perspective.

The following features are demonstrated:

  • creating a new application
  • creating a perspective
-See the main documentation for details." +See the main documentation for details." ) diff --git a/Examples/BlueBerryExampleLauncher/Configurations/MultiplePerspectives.cmake b/Examples/BlueBerryExampleLauncher/Configurations/MultiplePerspectives.cmake index f7d468bd3c..6e59762bb6 100644 --- a/Examples/BlueBerryExampleLauncher/Configurations/MultiplePerspectives.cmake +++ b/Examples/BlueBerryExampleLauncher/Configurations/MultiplePerspectives.cmake @@ -1,20 +1,20 @@ set(REQUIRED_PLUGINS org.mitk.example.gui.multipleperspectives ) set(DESCRIPTION "This BlueBerry example plugin demonstrates the use of multiple perspectives and the perspective bar. The example plugin implements a minimal application with two perspectives and two empty views. This example is a direct extension of the 'minimal BlueBerry application' example.

The following features are demonstrated:

  • Hidden Editor Area
  • creating a view
  • using more than one perspective
  • use of the perspective bar
  • setting an initial size
-See the main documentation for details." +See the main documentation for details." ) diff --git a/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceMITK.cmake b/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceMITK.cmake index aecc709ce0..5a28f6c257 100644 --- a/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceMITK.cmake +++ b/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceMITK.cmake @@ -1,19 +1,19 @@ set(REQUIRED_PLUGINS org.mitk.example.gui.selectionservicemitk org.mitk.example.gui.selectionservicemitk.views ) set(DESCRIPTION "The Selection Service MITK Example is a BlueBerry example plugin, developed to demonstrate the use and the concept of the selection service provided by MITK. The example plugin implements a selection service based on mitk data nodes. This example is an alternative for the Qt selection service described in the 'Selection Service QT' example.

The following features are demonstrated:

  • manually creating mitk data nodes
  • creating qt list widget items
  • reimplementation of the selection listener method
-See the main documentation for details." +See the main documentation for details." ) diff --git a/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceQT.cmake b/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceQT.cmake index 8ec723b470..8095cf1d8c 100644 --- a/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceQT.cmake +++ b/Examples/BlueBerryExampleLauncher/Configurations/SelectionServiceQT.cmake @@ -1,18 +1,18 @@ set(REQUIRED_PLUGINS org.mitk.example.gui.selectionserviceqt ) set(DESCRIPTION "The Selection Service QT Example is a BlueBerry example plugin, developed to demonstrate the use and the concept of the selection service provided by Qt. The example plugin implements a selection service based on QListWidgetItems. A selection provider is created for a QListWidget and selection listener is used for the selection of two radio buttons. This example is an alternative for the MITK selection service described in the 'Selection Service MITK' example.

The following features are demonstrated:

  • creating a selection provider
  • setting the selection model of the selection provider
  • selection listener implementation
-See the main documentation for details." +See the main documentation for details." ) diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.customviewer.views/manifest_headers.cmake index 9d97d71601..843e7b95ec 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/manifest_headers.cmake @@ -1,8 +1,8 @@ set(Plugin-Name "MITK Example Test Views") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.mitk.gui.qt.common # QmitkAbstractView ) diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake index 7cf2e7837d..058dcf0b91 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake @@ -1,9 +1,9 @@ set(Plugin-Name "MITK Example Custom Viewer") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.mitk.core.ext # Registers file reader factories org.mitk.gui.qt.application # Initializes GlobalInteraction and registers MITK Core factories ) diff --git a/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/manifest_headers.cmake index e45e6ae862..f353dbb990 100644 --- a/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.extensionpointcontribution/manifest_headers.cmake @@ -1,8 +1,8 @@ set(Plugin-Name "MITK Example: Extension Point Contribution") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.blueberry.ui.qt org.mitk.example.gui.extensionpointdefinition ) diff --git a/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/manifest_headers.cmake index cba1e99058..537225e489 100644 --- a/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/manifest_headers.cmake @@ -1,7 +1,7 @@ set(Plugin-Name "MITK Example: Extension Point Definition") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.blueberry.ui.qt ) diff --git a/Examples/Plugins/org.mitk.example.gui.imaging/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.imaging/manifest_headers.cmake index 45e5ae51ff..ad1561e537 100644 --- a/Examples/Plugins/org.mitk.example.gui.imaging/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.imaging/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Examples") set(Plugin-Version "0.1") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Examples/Plugins/org.mitk.example.gui.minimalapplication/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.minimalapplication/manifest_headers.cmake index 8ca4c41380..d0083fc102 100644 --- a/Examples/Plugins/org.mitk.example.gui.minimalapplication/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.minimalapplication/manifest_headers.cmake @@ -1,6 +1,6 @@ set(Plugin-Name "MITK Example Minimal Application") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.blueberry.ui.qt) diff --git a/Examples/Plugins/org.mitk.example.gui.multipleperspectives/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.multipleperspectives/manifest_headers.cmake index d0da20b9dc..053ad0f085 100644 --- a/Examples/Plugins/org.mitk.example.gui.multipleperspectives/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.multipleperspectives/manifest_headers.cmake @@ -1,7 +1,7 @@ set(Plugin-Name "MITK Example: multiple perspectives and views") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.blueberry.ui.qt ) diff --git a/Examples/Plugins/org.mitk.example.gui.opencv/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.opencv/manifest_headers.cmake index 8897e4cfed..4f58c01ac1 100644 --- a/Examples/Plugins/org.mitk.example.gui.opencv/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.opencv/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Examples OpenCV") set(Plugin-Version "1.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/manifest_headers.cmake index dcdb9807c2..b59bf17ec9 100644 --- a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk.views/manifest_headers.cmake @@ -1,7 +1,7 @@ set(Plugin-Name "MITK Example: Seletion service MITK") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.mitk.gui.qt.common ) diff --git a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/manifest_headers.cmake index 2eb89a444a..ddeb405483 100644 --- a/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.selectionservicemitk/manifest_headers.cmake @@ -1,7 +1,7 @@ set(Plugin-Name "MITK Example: Seletion service MITK") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.blueberry.ui.qt ) diff --git a/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/manifest_headers.cmake index 7c800b9b3f..7b788636a4 100644 --- a/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/manifest_headers.cmake +++ b/Examples/Plugins/org.mitk.example.gui.selectionserviceqt/manifest_headers.cmake @@ -1,7 +1,7 @@ set(Plugin-Name "MITK Example: Seletion service QT") set(Plugin-Version "1.0.0") set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "http://www.mitk.org") +set(Plugin-ContactAddress "https://www.mitk.org") set(Require-Plugin org.blueberry.ui.qt ) diff --git a/Licenses/OFL.txt b/Licenses/OFL.txt index 1456c1809d..71cde63e28 100644 --- a/Licenses/OFL.txt +++ b/Licenses/OFL.txt @@ -1,97 +1,97 @@ Copyright (c) , (), with Reserved Font Name . Copyright (c) , (), with Reserved Font Name . Copyright (c) , (). This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL +https://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. "Reserved Font Name" refers to any names specified as such after the copyright statement(s). "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. TERMINATION This license becomes null and void if any of the above conditions are not met. DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/MITKCPackOptions.cmake.in b/MITKCPackOptions.cmake.in index c4aabcee3d..5728c46f84 100644 --- a/MITKCPackOptions.cmake.in +++ b/MITKCPackOptions.cmake.in @@ -1,31 +1,31 @@ if(CPACK_GENERATOR MATCHES "NSIS") # set the package header icon for MUI set(CPACK_PACKAGE_ICON "@MITK_SOURCE_DIR@\\mitk.bmp") # set the install/unistall icon used for the installer itself # There is a bug in NSIS that does not handle full unix paths properly. set(CPACK_NSIS_MUI_ICON "@MITK_SOURCE_DIR@\\mitk.ico") set(CPACK_NSIS_MUI_UNIICON "@MITK_SOURCE_DIR@\\mitk.ico") set(CPACK_NSIS_DISPLAY_NAME "MITK - Medical Imaging and Interaction Toolkit") # tell cpack to create links to the doc files set(CPACK_NSIS_MENU_LINKS - "http://www.mitk.org" "MITK Web Site" + "https://www.mitk.org" "MITK Web Site" ) # tell cpack the executables you want in the start menu as links set(CPACK_PACKAGE_EXECUTABLES "@MITK_CPACK_PACKAGE_EXECUTABLES@") # tell cpack to create a desktop link to MainApp set(CPACK_CREATE_DESKTOP_LINKS "@CPACK_CREATE_DESKTOP_LINKS@") set(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\mitk.ico") set(CPACK_NSIS_HELP_LINK "http:\\\\www.mitk.org") set(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\www.mitk.org") set(CPACK_NSIS_CONTACT mitk@mitk.org) set(CPACK_NSIS_MODIFY_PATH ON) endif(CPACK_GENERATOR MATCHES "NSIS") diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h index 528fd0ebf4..dde9e23548 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h @@ -1,184 +1,184 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter_h #define __itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter_h #include "itkHistogram.h" #include "itkMacro.h" #include "itkProcessObject.h" #include "itkSimpleDataObjectDecorator.h" namespace itk { namespace Statistics { /** \class EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter * \brief This class computes texture feature coefficients from a grey level * Zone-length matrix. * * By default, Zone length features are computed for each spatial * direction and then averaged afterward, so it is possible to access the * standard deviations of the texture features. These values give a clue as * to texture anisotropy. However, doing this is much more work, because it * involved computing one for each offset given. To compute a single matrix * using the first offset, call FastCalculationsOn(). If this is called, * then the texture standard deviations will not be computed (and will be set * to zero), but texture computation will be much faster. * * This class is templated over the input histogram type. * * Print references: * M. M. Galloway. Texture analysis using gray level Zone lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * Zone lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level Zone-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa ScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter * \sa ScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter * \sa EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template< typename THistogram > class EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter : public ProcessObject { public: /** Standard typedefs */ typedef EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Zone-time type information (and related methods). */ itkTypeMacro( EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter, ProcessObject ); /** standard New() method support */ itkNewMacro( Self ); typedef THistogram HistogramType; typedef typename HistogramType::Pointer HistogramPointer; typedef typename HistogramType::ConstPointer HistogramConstPointer; typedef typename HistogramType::MeasurementType MeasurementType; typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; typedef typename HistogramType::IndexType IndexType; typedef typename HistogramType:: TotalAbsoluteFrequencyType FrequencyType; /** Method to Set/Get the input Histogram */ using Superclass::SetInput; void SetInput (const HistogramType * histogram ); const HistogramType * GetInput() const; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef SimpleDataObjectDecorator MeasurementObjectType; /** Methods to return the short Zone emphasis. */ MeasurementType GetCoarseness() const; const MeasurementObjectType* GetCoarsenessOutput() const; /** Methods to return the long Zone emphasis. */ MeasurementType GetContrast() const; const MeasurementObjectType* GetContrastOutput() const; /** Methods to return the grey level nonuniformity. */ MeasurementType GetBusyness() const; const MeasurementObjectType* GetBusynessOutput() const; /** Methods to return the Zone length nonuniformity. */ MeasurementType GetComplexity() const; const MeasurementObjectType* GetComplexityOutput() const; /** Methods to return the low grey level Zone emphasis. */ MeasurementType GetStrength() const; const MeasurementObjectType* GetStrengthOutput() const; itkGetMacro( TotalNumberOfValidVoxels, unsigned long ); itkGetConstMacro(NumberOfVoxels, unsigned long); itkSetMacro(NumberOfVoxels, unsigned long); void SetSiMatrix(double* matrix) { m_siMatrix = matrix; } /** Zone-length feature types */ typedef enum { Coarseness, Contrast, Busyness, Complexity, Strength } NeighbourhoodGreyLevelDifferenceFeatureName; /** convenience method to access the Zone length values */ MeasurementType GetFeature( NeighbourhoodGreyLevelDifferenceFeatureName name ); protected: EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter(); ~EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter() override {}; void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput( DataObjectPointerArraySizeType ) ITK_OVERRIDE; void GenerateData() ITK_OVERRIDE; private: EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented unsigned long m_TotalNumberOfValidVoxels; unsigned long m_NumberOfVoxels; double* m_siMatrix; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx index d4d195f2c4..c2ccadf2b6 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx @@ -1,326 +1,326 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter_hxx #define __itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter_hxx #include "itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h" #include "itkNumericTraits.h" #include "vnl/vnl_math.h" namespace itk { namespace Statistics { //constructor template EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter() : m_NumberOfVoxels(1) { this->ProcessObject::SetNumberOfRequiredInputs( 1 ); // allocate the data objects for the outputs which are // just decorators real types for( unsigned int i = 0; i < 5; i++ ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } } template void EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter< THistogram> ::SetInput(const HistogramType *histogram ) { this->ProcessObject::SetNthInput( 0, const_cast( histogram ) ); } template const typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::HistogramType * EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter< THistogram> ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return itkDynamicCastInDebugMode(this->ProcessObject::GetInput(0) ); } template typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::DataObjectPointer EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return MeasurementObjectType::New().GetPointer(); } template void EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter< THistogram>:: GenerateData( void ) { const HistogramType * inputHistogram = this->GetInput(); //The nis this->m_TotalNumberOfValidVoxels = static_cast ( inputHistogram->GetTotalFrequency() ); MeasurementType coarseness = NumericTraits::ZeroValue(); MeasurementType contrast = NumericTraits::ZeroValue(); MeasurementType busyness = NumericTraits::ZeroValue(); MeasurementType complexity = NumericTraits::ZeroValue(); MeasurementType strength = NumericTraits::ZeroValue(); typedef typename HistogramType::ConstIterator HistogramIterator; long unsigned int Ng = inputHistogram->GetSize(0); std::cout << "No of bins: " << Ng << " total number of valid voxels: " << this->m_TotalNumberOfValidVoxels << std::endl; double sumPiSi = 0.0; double sumSi = 0.0; unsigned int Ngp = 0; unsigned int Nv = 0; //Calculate sum(pi*si). for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { IndexType index = hit.GetIndex(); MeasurementType ni = hit.GetFrequency(); double si = m_siMatrix[index[0]]; if ( ni == 0 ) { continue; } sumPiSi += ni*si; sumSi += si; Ngp++; Nv += ni; } sumPiSi /= (Nv > 0) ? Nv : 1; //Calculate the other features //pi = ni / Nv, so we can simply calculate with ni instead of pi double pipj = 0.0; double ipijpj = 0.0; double complexitySum = 0.0; double strengthSum = 0.0; for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { MeasurementVectorType measurement = hit.GetMeasurementVector(); IndexType index = hit.GetIndex(); //MITK_WARN << "current index " << index; MeasurementType ni = hit.GetFrequency(); double si = m_siMatrix[index[0]]; double i = measurement[0]; for ( HistogramIterator hit2 = inputHistogram->Begin(); hit2 != inputHistogram->End(); ++hit2 ) { MeasurementVectorType measurement2 = hit2.GetMeasurementVector(); IndexType index2 = hit2.GetIndex(); MeasurementType nj= hit2.GetFrequency(); double sj = m_siMatrix[index2[0]]; double j = measurement2[0]; pipj += ni*nj*(i-j)*(i-j); ipijpj += std::abs(i*ni - j*nj); if(ni != 0 && nj != 0) complexitySum += std::abs(i-j) * (ni*si + nj*sj)/(ni+nj); strengthSum += (ni+nj)*(i-j)*(i-j); } } //Calculate Coarseness coarseness = (sumPiSi == 0) ? 1e6 : 1.0 / sumPiSi; contrast = (Ngp <= 1 || Nv == 0) ? 0 : (1.0/(Ngp * (Ngp - 1))*pipj / Nv / Nv) * (sumSi / Nv / Nv); busyness = (Ngp <= 1 || ipijpj == 0) ? 0 : sumPiSi / ipijpj / Nv; complexity = (Nv == 0) ? 0: complexitySum / Nv / Nv; strength = (sumSi == 0 || Nv == 0) ? 0 : strengthSum / Nv / sumSi; //Calculate the other features. MeasurementObjectType* CoarsenessOutputObject = static_cast( this->ProcessObject::GetOutput( 0 ) ); CoarsenessOutputObject->Set( coarseness ); MeasurementObjectType* ContrastOutputObject = static_cast( this->ProcessObject::GetOutput( 1 ) ); ContrastOutputObject->Set( contrast ); MeasurementObjectType* BusynessOutputObject = static_cast( this->ProcessObject::GetOutput( 2 ) ); BusynessOutputObject->Set( busyness ); MeasurementObjectType* ComplexityOutputObject = static_cast( this->ProcessObject::GetOutput( 3 ) ); ComplexityOutputObject->Set( complexity ); MeasurementObjectType* StrengthOutputObject = static_cast( this->ProcessObject::GetOutput( 4 ) ); StrengthOutputObject->Set( strength ); } template const typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementObjectType* EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetCoarsenessOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementObjectType* EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetContrastOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); } template const typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementObjectType* EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetBusynessOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 2 ) ); } template const typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementObjectType* EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetComplexityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 3 ) ); } template const typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementObjectType* EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetStrengthOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 4 ) ); } template typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementType EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetCoarseness() const { return this->GetCoarsenessOutput()->Get(); } template typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementType EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetContrast() const { return this->GetContrastOutput()->Get(); } template typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementType EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetBusyness() const { return this->GetBusynessOutput()->Get(); } template typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementType EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetComplexity() const { return this->GetComplexityOutput()->Get(); } template typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter::MeasurementType EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetStrength() const { return this->GetStrengthOutput()->Get(); } template typename EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter< THistogram>::MeasurementType EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetFeature( NeighbourhoodGreyLevelDifferenceFeatureName feature ) { switch( feature ) { case Coarseness: return this->GetCoarseness(); case Contrast: return this->GetContrast(); case Busyness: return this->GetBusyness(); case Complexity: return this->GetComplexity(); case Strength: return this->GetStrength(); default: return 0; } } template< typename THistogram> void EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter< THistogram>:: PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os,indent ); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.h index 9bd7524ec5..568ac5b7b9 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.h @@ -1,237 +1,237 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToRunLengthFeaturesFilter_h #define __itkEnhancedHistogramToRunLengthFeaturesFilter_h #include "itkHistogram.h" #include "itkMacro.h" #include "itkProcessObject.h" #include "itkSimpleDataObjectDecorator.h" namespace itk { namespace Statistics { /** \class EnhancedHistogramToRunLengthFeaturesFilter * \brief This class computes texture feature coefficients from a grey level * run-length matrix. * * By default, run length features are computed for each spatial * direction and then averaged afterward, so it is possible to access the * standard deviations of the texture features. These values give a clue as * to texture anisotropy. However, doing this is much more work, because it * involved computing one for each offset given. To compute a single matrix * using the first offset, call FastCalculationsOn(). If this is called, * then the texture standard deviations will not be computed (and will be set * to zero), but texture computation will be much faster. * * This class is templated over the input histogram type. * * Print references: * M. M. Galloway. Texture analysis using gray level run lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa ScalarImageToRunLengthFeaturesFilter * \sa ScalarImageToRunLengthMatrixFilter * \sa EnhancedHistogramToRunLengthFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template< typename THistogram > class EnhancedHistogramToRunLengthFeaturesFilter : public ProcessObject { public: /** Standard typedefs */ typedef EnhancedHistogramToRunLengthFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro( EnhancedHistogramToRunLengthFeaturesFilter, ProcessObject ); /** standard New() method support */ itkNewMacro( Self ); typedef THistogram HistogramType; typedef typename HistogramType::Pointer HistogramPointer; typedef typename HistogramType::ConstPointer HistogramConstPointer; typedef typename HistogramType::MeasurementType MeasurementType; typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; typedef typename HistogramType::IndexType IndexType; typedef typename HistogramType:: TotalAbsoluteFrequencyType FrequencyType; /** Method to Set/Get the input Histogram */ using Superclass::SetInput; void SetInput ( const HistogramType * histogram ); const HistogramType * GetInput() const; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef SimpleDataObjectDecorator MeasurementObjectType; /** Methods to return the short run emphasis. */ MeasurementType GetShortRunEmphasis() const; const MeasurementObjectType* GetShortRunEmphasisOutput() const; /** Methods to return the long run emphasis. */ MeasurementType GetLongRunEmphasis() const; const MeasurementObjectType* GetLongRunEmphasisOutput() const; /** Methods to return the grey level nonuniformity. */ MeasurementType GetGreyLevelNonuniformity() const; const MeasurementObjectType* GetGreyLevelNonuniformityOutput() const; /** Methods to return the grey level nonuniformity. */ MeasurementType GetGreyLevelNonuniformityNormalized() const; const MeasurementObjectType* GetGreyLevelNonuniformityNormalizedOutput() const; /** Methods to return the run length nonuniformity. */ MeasurementType GetRunLengthNonuniformity() const; const MeasurementObjectType* GetRunLengthNonuniformityOutput() const; /** Methods to return the run length nonuniformity. */ MeasurementType GetRunLengthNonuniformityNormalized() const; const MeasurementObjectType* GetRunLengthNonuniformityNormalizedOutput() const; /** Methods to return the low grey level run emphasis. */ MeasurementType GetLowGreyLevelRunEmphasis() const; const MeasurementObjectType* GetLowGreyLevelRunEmphasisOutput() const; /** Methods to return the high grey level run emphasis. */ MeasurementType GetHighGreyLevelRunEmphasis() const; const MeasurementObjectType* GetHighGreyLevelRunEmphasisOutput() const; /** Methods to return the short run low grey level run emphasis. */ MeasurementType GetShortRunLowGreyLevelEmphasis() const; const MeasurementObjectType* GetShortRunLowGreyLevelEmphasisOutput() const; /** Methods to return the short run high grey level run emphasis. */ MeasurementType GetShortRunHighGreyLevelEmphasis() const; const MeasurementObjectType* GetShortRunHighGreyLevelEmphasisOutput() const; /** Methods to return the long run low grey level run emphasis. */ MeasurementType GetLongRunLowGreyLevelEmphasis() const; const MeasurementObjectType* GetLongRunLowGreyLevelEmphasisOutput() const; /** Methods to return the long run high grey level run emphasis. */ MeasurementType GetLongRunHighGreyLevelEmphasis() const; const MeasurementObjectType* GetLongRunHighGreyLevelEmphasisOutput() const; /** Methods to return the long run high grey level run emphasis. */ MeasurementType GetRunPercentage() const; const MeasurementObjectType* GetRunPercentageOutput() const; /** Methods to return the long run high grey level run emphasis. */ MeasurementType GetNumberOfRuns() const; const MeasurementObjectType* GetNumberOfRunsOutput() const; /** Methods to return the grey level variance. */ MeasurementType GetGreyLevelVariance() const; const MeasurementObjectType* GetGreyLevelVarianceOutput() const; /** Methods to return the run length variance. */ MeasurementType GetRunLengthVariance() const; const MeasurementObjectType* GetRunLengthVarianceOutput() const; /** Methods to return the run entropy. */ MeasurementType GetRunEntropy() const; const MeasurementObjectType* GetRunEntropyOutput() const; itkGetMacro( TotalNumberOfRuns, unsigned long ); itkGetConstMacro(NumberOfVoxels, unsigned long); itkSetMacro(NumberOfVoxels, unsigned long); /** Run-length feature types */ typedef enum { ShortRunEmphasis, LongRunEmphasis, GreyLevelNonuniformity, GreyLevelNonuniformityNormalized, RunLengthNonuniformity, RunLengthNonuniformityNormalized, LowGreyLevelRunEmphasis, HighGreyLevelRunEmphasis, ShortRunLowGreyLevelEmphasis, ShortRunHighGreyLevelEmphasis, LongRunLowGreyLevelEmphasis, LongRunHighGreyLevelEmphasis, RunPercentage, NumberOfRuns, GreyLevelVariance, RunLengthVariance, RunEntropy } RunLengthFeatureName; /** convenience method to access the run length values */ MeasurementType GetFeature( RunLengthFeatureName name ); protected: EnhancedHistogramToRunLengthFeaturesFilter(); ~EnhancedHistogramToRunLengthFeaturesFilter() override {}; void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput( DataObjectPointerArraySizeType ) ITK_OVERRIDE; void GenerateData() ITK_OVERRIDE; private: EnhancedHistogramToRunLengthFeaturesFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented unsigned long m_TotalNumberOfRuns; unsigned long m_NumberOfVoxels; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedHistogramToRunLengthFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx index 488404b32c..c4fc4748b3 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx @@ -1,658 +1,658 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToRunLengthFeaturesFilter_hxx #define __itkEnhancedHistogramToRunLengthFeaturesFilter_hxx #include "itkEnhancedHistogramToRunLengthFeaturesFilter.h" #include "itkNumericTraits.h" #include "vnl/vnl_math.h" namespace itk { namespace Statistics { //constructor template EnhancedHistogramToRunLengthFeaturesFilter ::EnhancedHistogramToRunLengthFeaturesFilter() : m_NumberOfVoxels(1) { this->ProcessObject::SetNumberOfRequiredInputs( 1 ); // allocate the data objects for the outputs which are // just decorators real types for( unsigned int i = 0; i < 17; i++ ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } } template void EnhancedHistogramToRunLengthFeaturesFilter< THistogram> ::SetInput( const HistogramType *histogram ) { this->ProcessObject::SetNthInput( 0, const_cast( histogram ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::HistogramType * EnhancedHistogramToRunLengthFeaturesFilter< THistogram> ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return itkDynamicCastInDebugMode(this->ProcessObject::GetInput( 0 ) ); } template typename EnhancedHistogramToRunLengthFeaturesFilter::DataObjectPointer EnhancedHistogramToRunLengthFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return MeasurementObjectType::New().GetPointer(); } template void EnhancedHistogramToRunLengthFeaturesFilter< THistogram>:: GenerateData( void ) { const HistogramType * inputHistogram = this->GetInput(); this->m_TotalNumberOfRuns = static_cast ( inputHistogram->GetTotalFrequency() ); MeasurementType shortRunEmphasis = NumericTraits::ZeroValue(); MeasurementType longRunEmphasis = NumericTraits::ZeroValue(); MeasurementType greyLevelNonuniformity = NumericTraits::ZeroValue(); MeasurementType runLengthNonuniformity = NumericTraits::ZeroValue(); MeasurementType lowGreyLevelRunEmphasis = NumericTraits::ZeroValue(); MeasurementType highGreyLevelRunEmphasis = NumericTraits::ZeroValue(); MeasurementType shortRunLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType shortRunHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType longRunLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType longRunHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType runPercentage = NumericTraits::ZeroValue(); MeasurementType numberOfRuns = NumericTraits::ZeroValue(); //Added 15.07.2016 MeasurementType greyLevelVariance = NumericTraits::ZeroValue(); MeasurementType runLengthVariance = NumericTraits::ZeroValue(); MeasurementType runEntropy = NumericTraits::ZeroValue(); //Added 09.09.2016 MeasurementType greyLevelNonuniformityNormalized = NumericTraits::ZeroValue(); MeasurementType runLengthNonuniformityNormalized = NumericTraits::ZeroValue(); vnl_vector greyLevelNonuniformityVector( inputHistogram->GetSize()[0], 0.0 ); vnl_vector runLengthNonuniformityVector( inputHistogram->GetSize()[1], 0.0 ); typedef typename HistogramType::ConstIterator HistogramIterator; double mu_i = 0.0; double mu_j = 0.0; //Calculate the means. for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { IndexType index = hit.GetIndex(); MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } // MITK_INFO << index[0] + 1 << "|" << index[1] + 1 << " " << frequency; MeasurementVectorType measurement = hit.GetMeasurementVector(); double i = index[0] + 1; double j = index[1] + 1; double p_ij = frequency / (1.0*m_TotalNumberOfRuns); mu_i += i * p_ij; mu_j += j * p_ij; } // MITK_INFO << "Mu_i " << mu_i << " Mu_j " << mu_j; //Calculate the other features. const double log2 = std::log(2.0); for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } MeasurementVectorType measurement = hit.GetMeasurementVector(); IndexType index = hit.GetIndex(); // inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); double i = index[0] + 1; double j = index[1] + 1; double i2 = i*i; double j2 = j*j; double p_ij = frequency / m_TotalNumberOfRuns; greyLevelVariance += ((i - mu_i) * (i - mu_i) * p_ij); runLengthVariance += ((j - mu_j) * (j - mu_j) * p_ij); runEntropy -= ( p_ij > 0.0001 ) ? p_ij *std::log(p_ij) / log2 : 0; // Traditional measures shortRunEmphasis += ( frequency / j2 ); longRunEmphasis += ( frequency * j2 ); greyLevelNonuniformityVector[index[0]] += frequency; runLengthNonuniformityVector[index[1]] += frequency; // measures from Chu et al. lowGreyLevelRunEmphasis += (i2 > 0.0001) ? ( frequency / i2 ) : 0; highGreyLevelRunEmphasis += ( frequency * i2 ); // measures from Dasarathy and Holder shortRunLowGreyLevelEmphasis += ((i2 * j2) > 0.0001) ? ( frequency / ( i2 * j2 ) ) : 0; shortRunHighGreyLevelEmphasis += (j2 > 0.0001) ? ( frequency * i2 / j2 ) : 0; longRunLowGreyLevelEmphasis += (i2 > 0.0001) ? ( frequency * j2 / i2 ) : 0; longRunHighGreyLevelEmphasis += ( frequency * i2 * j2 ); } greyLevelNonuniformity = greyLevelNonuniformityVector.squared_magnitude(); runLengthNonuniformity = runLengthNonuniformityVector.squared_magnitude(); // Normalize all measures by the total number of runs if (this->m_TotalNumberOfRuns > 0) { shortRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); longRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); greyLevelNonuniformity /= static_cast( this->m_TotalNumberOfRuns ); runLengthNonuniformity /= static_cast( this->m_TotalNumberOfRuns ); lowGreyLevelRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); highGreyLevelRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); shortRunLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); shortRunHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); longRunLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); longRunHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); runPercentage = static_cast( this->m_TotalNumberOfRuns ) / static_cast( this->m_NumberOfVoxels ); numberOfRuns = static_cast( this->m_TotalNumberOfRuns ) ; greyLevelNonuniformityNormalized = greyLevelNonuniformity / static_cast(this->m_TotalNumberOfRuns); runLengthNonuniformityNormalized = runLengthNonuniformity / static_cast(this->m_TotalNumberOfRuns); } else { shortRunEmphasis = 0; longRunEmphasis = 0; greyLevelNonuniformity = 0; runLengthNonuniformity= 0; lowGreyLevelRunEmphasis = 0; highGreyLevelRunEmphasis = 0; shortRunLowGreyLevelEmphasis = 0; shortRunHighGreyLevelEmphasis= 0; longRunLowGreyLevelEmphasis = 0; longRunHighGreyLevelEmphasis = 0; runPercentage = 0; greyLevelNonuniformityNormalized = 0; runLengthNonuniformityNormalized = 0; numberOfRuns = static_cast( this->m_TotalNumberOfRuns ) ; } MeasurementObjectType* shortRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 0 ) ); shortRunEmphasisOutputObject->Set( shortRunEmphasis ); MeasurementObjectType* longRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 1 ) ); longRunEmphasisOutputObject->Set( longRunEmphasis ); MeasurementObjectType* greyLevelNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 2 ) ); greyLevelNonuniformityOutputObject->Set( greyLevelNonuniformity ); MeasurementObjectType* greyLevelNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 15 ) ); greyLevelNonuniformityNormalizedOutputObject->Set( greyLevelNonuniformityNormalized ); MeasurementObjectType* runLengthNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 16 ) ); runLengthNonuniformityNormalizedOutputObject->Set( runLengthNonuniformityNormalized ); MeasurementObjectType* runLengthNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 3 ) ); runLengthNonuniformityOutputObject->Set( runLengthNonuniformity ); MeasurementObjectType* lowGreyLevelRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 4 ) ); lowGreyLevelRunEmphasisOutputObject->Set( lowGreyLevelRunEmphasis ); MeasurementObjectType* highGreyLevelRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 5 ) ); highGreyLevelRunEmphasisOutputObject->Set( highGreyLevelRunEmphasis ); MeasurementObjectType* shortRunLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 6 ) ); shortRunLowGreyLevelEmphasisOutputObject->Set( shortRunLowGreyLevelEmphasis ); MeasurementObjectType* shortRunHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 7 ) ); shortRunHighGreyLevelEmphasisOutputObject->Set( shortRunHighGreyLevelEmphasis ); MeasurementObjectType* longRunLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 8 ) ); longRunLowGreyLevelEmphasisOutputObject->Set( longRunLowGreyLevelEmphasis ); MeasurementObjectType* longRunHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 9 ) ); longRunHighGreyLevelEmphasisOutputObject->Set( longRunHighGreyLevelEmphasis ); MeasurementObjectType* runPercentagesOutputObject = static_cast( this->ProcessObject::GetOutput( 10 ) ); runPercentagesOutputObject->Set( runPercentage ); MeasurementObjectType* numberOfRunsOutputObject = static_cast( this->ProcessObject::GetOutput( 11 ) ); numberOfRunsOutputObject->Set( numberOfRuns ); MeasurementObjectType* greyLevelVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 12 ) ); greyLevelVarianceOutputObject->Set( greyLevelVariance ); MeasurementObjectType* runLengthVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 13 ) ); runLengthVarianceOutputObject->Set( runLengthVariance ); MeasurementObjectType* runEntropyOutputObject = static_cast( this->ProcessObject::GetOutput( 14 ) ); runEntropyOutputObject->Set( runEntropy ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunEmphasisOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 2 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 3 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLowGreyLevelRunEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 4 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetHighGreyLevelRunEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 5 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 6 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 7 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 8 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 9 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunPercentageOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 10 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetNumberOfRunsOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 11 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 12 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 13 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunEntropyOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 14 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 15 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 16 ) ); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunEmphasis() const { return this->GetShortRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunEmphasis() const { return this->GetLongRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformity() const { return this->GetGreyLevelNonuniformityOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformity() const { return this->GetRunLengthNonuniformityOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLowGreyLevelRunEmphasis() const { return this->GetLowGreyLevelRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetHighGreyLevelRunEmphasis() const { return this->GetHighGreyLevelRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunLowGreyLevelEmphasis() const { return this->GetShortRunLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunHighGreyLevelEmphasis() const { return this->GetShortRunHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunLowGreyLevelEmphasis() const { return this->GetLongRunLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunHighGreyLevelEmphasis() const { return this->GetLongRunHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunPercentage() const { return this->GetRunPercentageOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetNumberOfRuns() const { return this->GetNumberOfRunsOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelVariance() const { return this->GetGreyLevelVarianceOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthVariance() const { return this->GetRunLengthVarianceOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunEntropy() const { return this->GetRunEntropyOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformityNormalized() const { return this->GetGreyLevelNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformityNormalized() const { return this->GetRunLengthNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter< THistogram>::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetFeature( RunLengthFeatureName feature ) { switch( feature ) { case ShortRunEmphasis: return this->GetShortRunEmphasis(); case LongRunEmphasis: return this->GetLongRunEmphasis(); case GreyLevelNonuniformity: return this->GetGreyLevelNonuniformity(); case GreyLevelNonuniformityNormalized: return this->GetGreyLevelNonuniformityNormalized(); case RunLengthNonuniformity: return this->GetRunLengthNonuniformity(); case RunLengthNonuniformityNormalized: return this->GetRunLengthNonuniformityNormalized(); case LowGreyLevelRunEmphasis: return this->GetLowGreyLevelRunEmphasis(); case HighGreyLevelRunEmphasis: return this->GetHighGreyLevelRunEmphasis(); case ShortRunLowGreyLevelEmphasis: return this->GetShortRunLowGreyLevelEmphasis(); case ShortRunHighGreyLevelEmphasis: return this->GetShortRunHighGreyLevelEmphasis(); case LongRunLowGreyLevelEmphasis: return this->GetLongRunLowGreyLevelEmphasis(); case LongRunHighGreyLevelEmphasis: return this->GetLongRunHighGreyLevelEmphasis(); case RunPercentage: return this->GetRunPercentage(); case NumberOfRuns: return this->GetNumberOfRuns(); case GreyLevelVariance: return this->GetGreyLevelVariance(); case RunLengthVariance: return this->GetRunLengthVariance(); case RunEntropy: return this->GetRunEntropy(); default: return 0; } } template< typename THistogram> void EnhancedHistogramToRunLengthFeaturesFilter< THistogram>:: PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os,indent ); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.h index 6e86fee66f..167abc07e4 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.h @@ -1,236 +1,236 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToSizeZoneFeaturesFilter_h #define __itkEnhancedHistogramToSizeZoneFeaturesFilter_h #include "itkHistogram.h" #include "itkMacro.h" #include "itkProcessObject.h" #include "itkSimpleDataObjectDecorator.h" namespace itk { namespace Statistics { /** \class EnhancedHistogramToSizeZoneFeaturesFilter * \brief This class computes texture feature coefficients from a grey level * Zone-length matrix. * * By default, Zone length features are computed for each spatial * direction and then averaged afterward, so it is possible to access the * standard deviations of the texture features. These values give a clue as * to texture anisotropy. However, doing this is much more work, because it * involved computing one for each offset given. To compute a single matrix * using the first offset, call FastCalculationsOn(). If this is called, * then the texture standard deviations will not be computed (and will be set * to zero), but texture computation will be much faster. * * This class is templated over the input histogram type. * * Print references: * M. M. Galloway. Texture analysis using gray level Zone lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * Zone lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level Zone-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa ScalarImageToSizeZoneFeaturesFilter * \sa ScalarImageToSizeZoneMatrixFilter * \sa EnhancedHistogramToSizeZoneFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template< typename THistogram > class EnhancedHistogramToSizeZoneFeaturesFilter : public ProcessObject { public: /** Standard typedefs */ typedef EnhancedHistogramToSizeZoneFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Zone-time type information (and related methods). */ itkTypeMacro( EnhancedHistogramToSizeZoneFeaturesFilter, ProcessObject ); /** standard New() method support */ itkNewMacro( Self ); typedef THistogram HistogramType; typedef typename HistogramType::Pointer HistogramPointer; typedef typename HistogramType::ConstPointer HistogramConstPointer; typedef typename HistogramType::MeasurementType MeasurementType; typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; typedef typename HistogramType::IndexType IndexType; typedef typename HistogramType:: TotalAbsoluteFrequencyType FrequencyType; /** Method to Set/Get the input Histogram */ using Superclass::SetInput; void SetInput ( const HistogramType * histogram ); const HistogramType * GetInput() const; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef SimpleDataObjectDecorator MeasurementObjectType; /** Methods to return the short Zone emphasis. */ MeasurementType GetSmallZoneEmphasis() const; const MeasurementObjectType* GetSmallZoneEmphasisOutput() const; /** Methods to return the long Zone emphasis. */ MeasurementType GetLargeZoneEmphasis() const; const MeasurementObjectType* GetLargeZoneEmphasisOutput() const; /** Methods to return the grey level nonuniformity. */ MeasurementType GetGreyLevelNonuniformity() const; const MeasurementObjectType* GetGreyLevelNonuniformityOutput() const; /** Methods to return the grey level nonuniformity normalized. */ MeasurementType GetGreyLevelNonuniformityNormalized() const; const MeasurementObjectType* GetGreyLevelNonuniformityNormalizedOutput() const; /** Methods to return the Zone length nonuniformity. */ MeasurementType GetSizeZoneNonuniformity() const; const MeasurementObjectType* GetSizeZoneNonuniformityOutput() const; /** Methods to return the Zone length nonuniformity normalized. */ MeasurementType GetSizeZoneNonuniformityNormalized() const; const MeasurementObjectType* GetSizeZoneNonuniformityNormalizedOutput() const; /** Methods to return the low grey level Zone emphasis. */ MeasurementType GetLowGreyLevelZoneEmphasis() const; const MeasurementObjectType* GetLowGreyLevelZoneEmphasisOutput() const; /** Methods to return the high grey level Zone emphasis. */ MeasurementType GetHighGreyLevelZoneEmphasis() const; const MeasurementObjectType* GetHighGreyLevelZoneEmphasisOutput() const; /** Methods to return the short Zone low grey level Zone emphasis. */ MeasurementType GetSmallZoneLowGreyLevelEmphasis() const; const MeasurementObjectType* GetSmallZoneLowGreyLevelEmphasisOutput() const; /** Methods to return the short Zone high grey level Zone emphasis. */ MeasurementType GetSmallZoneHighGreyLevelEmphasis() const; const MeasurementObjectType* GetSmallZoneHighGreyLevelEmphasisOutput() const; /** Methods to return the long Zone low grey level Zone emphasis. */ MeasurementType GetLargeZoneLowGreyLevelEmphasis() const; const MeasurementObjectType* GetLargeZoneLowGreyLevelEmphasisOutput() const; /** Methods to return the long Zone high grey level Zone emphasis. */ MeasurementType GetLargeZoneHighGreyLevelEmphasis() const; const MeasurementObjectType* GetLargeZoneHighGreyLevelEmphasisOutput() const; /** Methods to return the long Zone high grey level Zone emphasis. */ MeasurementType GetZonePercentage() const; const MeasurementObjectType* GetZonePercentageOutput() const; /** Methods to return the long Zone high grey level Zone emphasis. */ MeasurementType GetNumberOfZones() const; const MeasurementObjectType* GetNumberOfZonesOutput() const; /** Methods to return the grey level variance. */ MeasurementType GetGreyLevelVariance() const; const MeasurementObjectType* GetGreyLevelVarianceOutput() const; /** Methods to return the Zone length variance. */ MeasurementType GetSizeZoneVariance() const; const MeasurementObjectType* GetSizeZoneVarianceOutput() const; /** Methods to return the Zone entropy. */ MeasurementType GetZoneEntropy() const; const MeasurementObjectType* GetZoneEntropyOutput() const; itkGetMacro( TotalNumberOfZones, unsigned long ); itkGetConstMacro(NumberOfVoxels, unsigned long); itkSetMacro(NumberOfVoxels, unsigned long); /** Zone-length feature types */ typedef enum { SmallZoneEmphasis, LargeZoneEmphasis, GreyLevelNonuniformity, GreyLevelNonuniformityNormalized, SizeZoneNonuniformity, SizeZoneNonuniformityNormalized, LowGreyLevelZoneEmphasis, HighGreyLevelZoneEmphasis, SmallZoneLowGreyLevelEmphasis, SmallZoneHighGreyLevelEmphasis, LargeZoneLowGreyLevelEmphasis, LargeZoneHighGreyLevelEmphasis, ZonePercentage, GreyLevelVariance, SizeZoneVariance, ZoneEntropy } SizeZoneFeatureName; /** convenience method to access the Zone length values */ MeasurementType GetFeature( SizeZoneFeatureName name ); protected: EnhancedHistogramToSizeZoneFeaturesFilter(); ~EnhancedHistogramToSizeZoneFeaturesFilter() {}; virtual void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; virtual DataObjectPointer MakeOutput( DataObjectPointerArraySizeType ) ITK_OVERRIDE; virtual void GenerateData() ITK_OVERRIDE; private: EnhancedHistogramToSizeZoneFeaturesFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented unsigned long m_TotalNumberOfZones; unsigned long m_NumberOfVoxels; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx index 5effb5f15f..f698fc2b60 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx @@ -1,665 +1,665 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToSizeZoneFeaturesFilter_hxx #define __itkEnhancedHistogramToSizeZoneFeaturesFilter_hxx #include "itkEnhancedHistogramToSizeZoneFeaturesFilter.h" #include "itkNumericTraits.h" #include "vnl/vnl_math.h" namespace itk { namespace Statistics { //constructor template EnhancedHistogramToSizeZoneFeaturesFilter ::EnhancedHistogramToSizeZoneFeaturesFilter() : m_NumberOfVoxels(1) { this->ProcessObject::SetNumberOfRequiredInputs( 1 ); // allocate the data objects for the outputs which are // just decorators real types for( unsigned int i = 0; i < 17; i++ ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } } template void EnhancedHistogramToSizeZoneFeaturesFilter< THistogram> ::SetInput( const HistogramType *histogram ) { this->ProcessObject::SetNthInput( 0, const_cast( histogram ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::HistogramType * EnhancedHistogramToSizeZoneFeaturesFilter< THistogram> ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return itkDynamicCastInDebugMode(this->ProcessObject::GetInput( 0 ) ); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::DataObjectPointer EnhancedHistogramToSizeZoneFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return MeasurementObjectType::New().GetPointer(); } template void EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>:: GenerateData( void ) { const HistogramType * inputHistogram = this->GetInput(); this->m_TotalNumberOfZones = static_cast ( inputHistogram->GetTotalFrequency() ); MeasurementType SmallZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType LargeZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType greyLevelNonuniformity = NumericTraits::ZeroValue(); MeasurementType SizeZoneNonuniformity = NumericTraits::ZeroValue(); MeasurementType lowGreyLevelZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType highGreyLevelZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType SmallZoneLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType SmallZoneHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType LargeZoneLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType LargeZoneHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType ZonePercentage = NumericTraits::ZeroValue(); MeasurementType numberOfZones = NumericTraits::ZeroValue(); //Added 15.07.2016 MeasurementType greyLevelVariance = NumericTraits::ZeroValue(); MeasurementType SizeZoneVariance = NumericTraits::ZeroValue(); MeasurementType ZoneEntropy = NumericTraits::ZeroValue(); //Added 09.09.2016 MeasurementType greyLevelNonuniformityNormalized = NumericTraits::ZeroValue(); MeasurementType SizeZoneNonuniformityNormalized = NumericTraits::ZeroValue(); vnl_vector greyLevelNonuniformityVector( inputHistogram->GetSize()[0], 0.0 ); vnl_vector SizeZoneNonuniformityVector( inputHistogram->GetSize()[1], 0.0 ); typedef typename HistogramType::ConstIterator HistogramIterator; double mu_i = 0.0; double mu_j = 0.0; //Calculate the means. for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } MeasurementVectorType measurement = hit.GetMeasurementVector(); IndexType index = hit.GetIndex(); int value = floor(measurement[0] + 0.5); int count = measurement[1]; double i = value; double j = count; double p_ij = frequency / m_TotalNumberOfZones; mu_i += i * p_ij; mu_j += j * p_ij; } //Calculate the other features. const double log2 = std::log(2.0); int totNumOfVoxelsUsed = 0; for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } MeasurementVectorType measurement = hit.GetMeasurementVector(); IndexType index = hit.GetIndex(); // inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); int value = floor(measurement[0] + 0.5); int count = measurement[1]; double i = value; double j = count; double i2 = static_cast( i*i ); double j2 = static_cast( j*j ); double p_ij = frequency / m_TotalNumberOfZones; greyLevelVariance += ((i - mu_i) * (i - mu_i) * p_ij); SizeZoneVariance += ((j - mu_j) * (j - mu_j) * p_ij); ZoneEntropy -= ( p_ij > 0.0001 ) ? p_ij *std::log(p_ij) / log2 : 0; // Traditional measures SmallZoneEmphasis += ( frequency / j2 ); LargeZoneEmphasis += ( frequency * j2 ); greyLevelNonuniformityVector[index[0]] += frequency; SizeZoneNonuniformityVector[index[1]] += frequency; // measures from Chu et al. lowGreyLevelZoneEmphasis += (i2 > 0.0001) ? ( frequency / i2 ) : 0; highGreyLevelZoneEmphasis += ( frequency * i2 ); // measures from Dasarathy and Holder SmallZoneLowGreyLevelEmphasis += ((i2 * j2) > 0.0001) ? ( frequency / ( i2 * j2 ) ) : 0; SmallZoneHighGreyLevelEmphasis += (j2 > 0.00001) ? ( frequency * i2 / j2 ) : 0; LargeZoneLowGreyLevelEmphasis += (i2 > 0.00001) ? ( frequency * j2 / i2 ) : 0; LargeZoneHighGreyLevelEmphasis += ( frequency * i2 * j2 ); totNumOfVoxelsUsed += (frequency); } greyLevelNonuniformity = greyLevelNonuniformityVector.squared_magnitude(); SizeZoneNonuniformity = SizeZoneNonuniformityVector.squared_magnitude(); // Normalize all measures by the total number of Zones m_TotalNumberOfZones = totNumOfVoxelsUsed; if (this->m_TotalNumberOfZones > 0) { SmallZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); LargeZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); greyLevelNonuniformity /= static_cast( this->m_TotalNumberOfZones ); SizeZoneNonuniformity /= static_cast( this->m_TotalNumberOfZones ); lowGreyLevelZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); highGreyLevelZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); SmallZoneLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); SmallZoneHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); LargeZoneLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); LargeZoneHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); ZonePercentage = static_cast( this->m_TotalNumberOfZones ) / static_cast( this->m_NumberOfVoxels ); numberOfZones = static_cast( this->m_TotalNumberOfZones ) ; greyLevelNonuniformityNormalized = greyLevelNonuniformity / static_cast(this->m_TotalNumberOfZones); SizeZoneNonuniformityNormalized = SizeZoneNonuniformity / static_cast(this->m_TotalNumberOfZones); } else { SmallZoneEmphasis = 0; LargeZoneEmphasis = 0; greyLevelNonuniformity = 0; SizeZoneNonuniformity = 0; greyLevelNonuniformityNormalized = 0; SizeZoneNonuniformityNormalized = 0; lowGreyLevelZoneEmphasis = 0; highGreyLevelZoneEmphasis = 0; SmallZoneLowGreyLevelEmphasis = 0; SmallZoneHighGreyLevelEmphasis= 0; LargeZoneLowGreyLevelEmphasis = 0; LargeZoneHighGreyLevelEmphasis= 0; ZonePercentage = 0; numberOfZones = static_cast( this->m_TotalNumberOfZones ) ; } MeasurementObjectType* SmallZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 0 ) ); SmallZoneEmphasisOutputObject->Set( SmallZoneEmphasis ); MeasurementObjectType* LargeZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 1 ) ); LargeZoneEmphasisOutputObject->Set( LargeZoneEmphasis ); MeasurementObjectType* greyLevelNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 2 ) ); greyLevelNonuniformityOutputObject->Set( greyLevelNonuniformity ); MeasurementObjectType* SizeZoneNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 3 ) ); SizeZoneNonuniformityOutputObject->Set( SizeZoneNonuniformity ); MeasurementObjectType* lowGreyLevelZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 4 ) ); lowGreyLevelZoneEmphasisOutputObject->Set( lowGreyLevelZoneEmphasis ); MeasurementObjectType* highGreyLevelZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 5 ) ); highGreyLevelZoneEmphasisOutputObject->Set( highGreyLevelZoneEmphasis ); MeasurementObjectType* SmallZoneLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 6 ) ); SmallZoneLowGreyLevelEmphasisOutputObject->Set( SmallZoneLowGreyLevelEmphasis ); MeasurementObjectType* SmallZoneHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 7 ) ); SmallZoneHighGreyLevelEmphasisOutputObject->Set( SmallZoneHighGreyLevelEmphasis ); MeasurementObjectType* LargeZoneLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 8 ) ); LargeZoneLowGreyLevelEmphasisOutputObject->Set( LargeZoneLowGreyLevelEmphasis ); MeasurementObjectType* LargeZoneHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 9 ) ); LargeZoneHighGreyLevelEmphasisOutputObject->Set( LargeZoneHighGreyLevelEmphasis ); MeasurementObjectType* ZonePercentagesOutputObject = static_cast( this->ProcessObject::GetOutput( 10 ) ); ZonePercentagesOutputObject->Set( ZonePercentage ); MeasurementObjectType* numberOfZonesOutputObject = static_cast( this->ProcessObject::GetOutput( 11 ) ); numberOfZonesOutputObject->Set( numberOfZones ); MeasurementObjectType* greyLevelVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 12 ) ); greyLevelVarianceOutputObject->Set( greyLevelVariance ); MeasurementObjectType* SizeZoneVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 13 ) ); SizeZoneVarianceOutputObject->Set( SizeZoneVariance ); MeasurementObjectType* ZoneEntropyOutputObject = static_cast( this->ProcessObject::GetOutput( 14 ) ); ZoneEntropyOutputObject->Set( ZoneEntropy ); MeasurementObjectType* greyLevelNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 15 ) ); greyLevelNonuniformityNormalizedOutputObject->Set( greyLevelNonuniformityNormalized ); MeasurementObjectType* SizeZoneNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 16 ) ); SizeZoneNonuniformityNormalizedOutputObject->Set( SizeZoneNonuniformityNormalized ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneEmphasisOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 2 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 3 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 15 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 16 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLowGreyLevelZoneEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 4 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetHighGreyLevelZoneEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 5 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 6 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 7 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 8 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 9 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetZonePercentageOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 10 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetNumberOfZonesOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 11 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 12 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 13 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetZoneEntropyOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 14 ) ); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneEmphasis() const { return this->GetSmallZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneEmphasis() const { return this->GetLargeZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformity() const { return this->GetGreyLevelNonuniformityOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformityNormalized() const { return this->GetGreyLevelNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformity() const { return this->GetSizeZoneNonuniformityOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformityNormalized() const { return this->GetSizeZoneNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLowGreyLevelZoneEmphasis() const { return this->GetLowGreyLevelZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetHighGreyLevelZoneEmphasis() const { return this->GetHighGreyLevelZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneLowGreyLevelEmphasis() const { return this->GetSmallZoneLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneHighGreyLevelEmphasis() const { return this->GetSmallZoneHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneLowGreyLevelEmphasis() const { return this->GetLargeZoneLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneHighGreyLevelEmphasis() const { return this->GetLargeZoneHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetZonePercentage() const { return this->GetZonePercentageOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetNumberOfZones() const { return this->GetNumberOfZonesOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelVariance() const { return this->GetGreyLevelVarianceOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneVariance() const { return this->GetSizeZoneVarianceOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetZoneEntropy() const { return this->GetZoneEntropyOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetFeature( SizeZoneFeatureName feature ) { switch( feature ) { case SmallZoneEmphasis: return this->GetSmallZoneEmphasis(); case LargeZoneEmphasis: return this->GetLargeZoneEmphasis(); case GreyLevelNonuniformity: return this->GetGreyLevelNonuniformity(); case GreyLevelNonuniformityNormalized: return this->GetGreyLevelNonuniformityNormalized(); case SizeZoneNonuniformity: return this->GetSizeZoneNonuniformity(); case SizeZoneNonuniformityNormalized: return this->GetSizeZoneNonuniformityNormalized(); case LowGreyLevelZoneEmphasis: return this->GetLowGreyLevelZoneEmphasis(); case HighGreyLevelZoneEmphasis: return this->GetHighGreyLevelZoneEmphasis(); case SmallZoneLowGreyLevelEmphasis: return this->GetSmallZoneLowGreyLevelEmphasis(); case SmallZoneHighGreyLevelEmphasis: return this->GetSmallZoneHighGreyLevelEmphasis(); case LargeZoneLowGreyLevelEmphasis: return this->GetLargeZoneLowGreyLevelEmphasis(); case LargeZoneHighGreyLevelEmphasis: return this->GetLargeZoneHighGreyLevelEmphasis(); case ZonePercentage: return this->GetZonePercentage(); case GreyLevelVariance: return this->GetGreyLevelVariance(); case SizeZoneVariance: return this->GetSizeZoneVariance(); case ZoneEntropy: return this->GetZoneEntropy(); default: return 0; } } template< typename THistogram> void EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>:: PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os,indent ); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.h index 0bdae76994..f7992dd190 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.h @@ -1,278 +1,273 @@ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToTextureFeaturesFilter_h #define __itkEnhancedHistogramToTextureFeaturesFilter_h #include "itkHistogram.h" #include "itkMacro.h" #include "itkProcessObject.h" #include "itkSimpleDataObjectDecorator.h" /** Get built-in type. Creates member Get"name"() (e.g., GetVisibility()); */ #define itkMacroGLCMFeatureGetter(name) \ const MeasurementObjectType * Get##name##Output() const; \ \ MeasurementType Get##name() const; namespace itk { namespace Statistics { /** \class EnhancedHistogramToTextureFeaturesFilter * \brief This class computes texture feature coefficients from a grey level * co-occurrence matrix. * * This class computes features that summarize image texture, given a grey level * co-occurrence matrix (generated by a ScalarImageToCooccurrenceMatrixFilter * or related class). * * The features calculated are as follows (where \f$ g(i, j) \f$ is the element in * cell i, j of a a normalized GLCM): * * "Energy" \f$ = f_1 = \sum_{i,j}g(i, j)^2 \f$ * * "Entropy" \f$ = f_2 = -\sum_{i,j}g(i, j) \log_2 g(i, j)\f$, or 0 if \f$g(i, j) = 0\f$ * * "Correlation" \f$ = f_3 = \sum_{i,j}\frac{(i - \mu)(j - \mu)g(i, j)}{\sigma^2} \f$ * * "Difference Moment" \f$= f_4 = \sum_{i,j}\frac{1}{1 + (i - j)^2}g(i, j) \f$ * * "Inertia" \f$ = f_5 = \sum_{i,j}(i - j)^2g(i, j) \f$ (sometimes called "contrast.") * * "Cluster Shade" \f$ = f_6 = \sum_{i,j}((i - \mu) + (j - \mu))^3 g(i, j) \f$ * * "Cluster Prominence" \f$ = f_7 = \sum_{i,j}((i - \mu) + (j - \mu))^4 g(i, j) \f$ * * "Haralick's Correlation" \f$ = f_8 = \frac{\sum_{i,j}(i, j) g(i, j) -\mu_t^2}{\sigma_t^2} \f$ * where \f$\mu_t\f$ and \f$\sigma_t\f$ are the mean and standard deviation of the row * (or column, due to symmetry) sums. * * Above, \f$ \mu = \f$ (weighted pixel average) \f$ = \sum_{i,j}i \cdot g(i, j) = * \sum_{i,j}j \cdot g(i, j) \f$ (due to matrix summetry), and * * \f$ \sigma = \f$ (weighted pixel variance) \f$ = \sum_{i,j}(i - \mu)^2 \cdot g(i, j) = * \sum_{i,j}(j - \mu)^2 \cdot g(i, j) \f$ (due to matrix summetry) * * A good texture feature set to use is the Conners, Trivedi and Harlow set: * features 1, 2, 4, 5, 6, and 7. There is some correlation between the various * features, so using all of them at the same time is not necessarialy a good idea. * * NOTA BENE: The input histogram will be forcably normalized! * This algorithm takes three passes through the input * histogram if the histogram was already normalized, and four if not. * - * Web references: - * - * http://www.cssip.uq.edu.au/meastex/www/algs/algs/algs.html - * http://www.ucalgary.ca/~mhallbey/texture/texture_tutorial.html - * * Print references: * * Haralick, R.M., K. Shanmugam and I. Dinstein. 1973. Textural Features for * Image Classification. IEEE Transactions on Systems, Man and Cybernetics. * SMC-3(6):610-620. * * Haralick, R.M. 1979. Statistical and Structural Approaches to Texture. * Proceedings of the IEEE, 67:786-804. * * R.W. Conners and C.A. Harlow. A Theoretical Comaprison of Texture Algorithms. * IEEE Transactions on Pattern Analysis and Machine Intelligence, 2:204-222, 1980. * * R.W. Conners, M.M. Trivedi, and C.A. Harlow. Segmentation of a High-Resolution * Urban Scene using Texture Operators. Computer Vision, Graphics and Image * Processing, 25:273-310, 1984. * * \sa ScalarImageToCooccurrenceMatrixFilter * \sa ScalarImageToTextureFeaturesFilter * * Author: Zachary Pincus * \ingroup ITKStatistics */ template< typename THistogram > class EnhancedHistogramToTextureFeaturesFilter:public ProcessObject { public: /** Standard typedefs */ typedef EnhancedHistogramToTextureFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro(EnhancedHistogramToTextureFeaturesFilter, ProcessObject); /** standard New() method support */ itkNewMacro(Self); typedef THistogram HistogramType; typedef typename HistogramType::Pointer HistogramPointer; typedef typename HistogramType::ConstPointer HistogramConstPointer; typedef typename HistogramType::MeasurementType MeasurementType; typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; typedef typename HistogramType::IndexType IndexType; typedef typename HistogramType::AbsoluteFrequencyType AbsoluteFrequencyType; typedef typename HistogramType::RelativeFrequencyType RelativeFrequencyType; typedef typename HistogramType::TotalAbsoluteFrequencyType TotalAbsoluteFrequencyType; typedef typename HistogramType::TotalRelativeFrequencyType TotalRelativeFrequencyType; /** Container to hold relative frequencies of the histogram */ typedef std::vector< RelativeFrequencyType > RelativeFrequencyContainerType; /** Method to Set/Get the input Histogram */ using Superclass::SetInput; void SetInput(const HistogramType *histogram); const HistogramType * GetInput() const; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef SimpleDataObjectDecorator< MeasurementType > MeasurementObjectType; /** Return energy texture value. */ MeasurementType GetEnergy() const; const MeasurementObjectType * GetEnergyOutput() const; /** Return entropy texture value. */ MeasurementType GetEntropy() const; const MeasurementObjectType * GetEntropyOutput() const; /** return correlation texture value. */ MeasurementType GetCorrelation() const; const MeasurementObjectType * GetCorrelationOutput() const; /** Return inverse difference moment texture value. */ MeasurementType GetInverseDifferenceMoment() const; const MeasurementObjectType * GetInverseDifferenceMomentOutput() const; /** Return inertia texture value. */ MeasurementType GetInertia() const; const MeasurementObjectType * GetInertiaOutput() const; /** Return cluster shade texture value. */ MeasurementType GetClusterShade() const; const MeasurementObjectType * GetClusterShadeOutput() const; /** Return cluster prominence texture value. */ MeasurementType GetClusterProminence() const; const MeasurementObjectType * GetClusterProminenceOutput() const; /** Return Haralick correlation texture value. */ MeasurementType GetHaralickCorrelation() const; const MeasurementObjectType * GetHaralickCorrelationOutput() const; itkMacroGLCMFeatureGetter(Autocorrelation); itkMacroGLCMFeatureGetter(Contrast); itkMacroGLCMFeatureGetter(Dissimilarity); itkMacroGLCMFeatureGetter(MaximumProbability); itkMacroGLCMFeatureGetter(InverseVariance); itkMacroGLCMFeatureGetter(Homogeneity1); itkMacroGLCMFeatureGetter(ClusterTendency); itkMacroGLCMFeatureGetter(Variance); itkMacroGLCMFeatureGetter(SumAverage); itkMacroGLCMFeatureGetter(SumEntropy); itkMacroGLCMFeatureGetter(SumVariance); itkMacroGLCMFeatureGetter(DifferenceAverage); itkMacroGLCMFeatureGetter(DifferenceEntropy); itkMacroGLCMFeatureGetter(DifferenceVariance); itkMacroGLCMFeatureGetter(InverseDifferenceMomentNormalized); itkMacroGLCMFeatureGetter(InverseDifferenceNormalized); itkMacroGLCMFeatureGetter(InverseDifference); itkMacroGLCMFeatureGetter(JointAverage); itkMacroGLCMFeatureGetter(FirstMeasureOfInformationCorrelation); itkMacroGLCMFeatureGetter(SecondMeasureOfInformationCorrelation); /** Texture feature types */ typedef enum { Energy, Entropy, Correlation, InverseDifferenceMoment, Inertia, ClusterShade, ClusterProminence, HaralickCorrelation, Autocorrelation, Contrast, Dissimilarity, MaximumProbability, InverseVariance, Homogeneity1, ClusterTendency, Variance, SumAverage, SumEntropy, SumVariance, DifferenceAverage, DifferenceEntropy, DifferenceVariance, InverseDifferenceMomentNormalized, InverseDifferenceNormalized, InverseDifference, JointAverage, FirstMeasureOfInformationCorrelation, SecondMeasureOfInformationCorrelation, InvalidFeatureName } TextureFeatureName; /** convenience method to access the texture values */ MeasurementType GetFeature(TextureFeatureName name); protected: EnhancedHistogramToTextureFeaturesFilter(); ~EnhancedHistogramToTextureFeaturesFilter() override {} void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput(DataObjectPointerArraySizeType) ITK_OVERRIDE; void GenerateData() ITK_OVERRIDE; private: EnhancedHistogramToTextureFeaturesFilter(const Self &); //purposely not implemented void operator=(const Self &); //purposely not implemented void ComputeMeansAndVariances(double & pixelMean, double & marginalMean, double & marginalDevSquared, double & pixelVariance); RelativeFrequencyContainerType m_RelativeFrequencyContainer; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedHistogramToTextureFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.hxx index ff154fcf33..8a6356d7f5 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToTextureFeaturesFilter.hxx @@ -1,760 +1,760 @@ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedHistogramToTextureFeaturesFilter_hxx #define __itkEnhancedHistogramToTextureFeaturesFilter_hxx #include "itkEnhancedHistogramToTextureFeaturesFilter.h" #include "itkNumericTraits.h" #include "vnl/vnl_math.h" #include "itkMath.h" #define itkMacroGLCMFeature(name, id) \ template< typename THistogram > \ const \ typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * \ EnhancedHistogramToTextureFeaturesFilter< THistogram > \ ::Get##name##Output() const \ { \ return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(id) ); \ } \ \ template< typename THistogram > \ typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType \ EnhancedHistogramToTextureFeaturesFilter< THistogram > \ ::Get##name() const \ { \ return this->Get##name##Output()->Get(); \ } namespace itk { namespace Statistics { //constructor template< typename THistogram > EnhancedHistogramToTextureFeaturesFilter< THistogram >::EnhancedHistogramToTextureFeaturesFilter(void) { this->ProcessObject::SetNumberOfRequiredInputs(1); // allocate the data objects for the outputs which are // just decorators real types for ( int i = 0; i < 28; ++i ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput(i) ); } } template< typename THistogram > void EnhancedHistogramToTextureFeaturesFilter< THistogram > ::SetInput(const HistogramType *histogram) { this->ProcessObject::SetNthInput( 0, const_cast< HistogramType * >( histogram ) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::HistogramType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetInput() const { return itkDynamicCastInDebugMode< const HistogramType * >( this->GetPrimaryInput() ); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::DataObjectPointer EnhancedHistogramToTextureFeaturesFilter< THistogram > ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed(idx) ) { return MeasurementObjectType::New().GetPointer(); } template< typename THistogram > void EnhancedHistogramToTextureFeaturesFilter< THistogram >::GenerateData(void) { typedef typename HistogramType::ConstIterator HistogramIterator; const HistogramType *inputHistogram = this->GetInput(); //Normalize the absolute frequencies and populate the relative frequency //container TotalRelativeFrequencyType totalFrequency = static_cast< TotalRelativeFrequencyType >( inputHistogram->GetTotalFrequency() ); m_RelativeFrequencyContainer.clear(); typename HistogramType::SizeValueType binsPerAxis = inputHistogram->GetSize(0); std::vector sumP; std::vector diffP; sumP.resize(2*binsPerAxis,0.0); diffP.resize(binsPerAxis,0.0); double numberOfPixels = 0; for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { AbsoluteFrequencyType frequency = hit.GetFrequency(); RelativeFrequencyType relativeFrequency = (totalFrequency > 0) ? frequency / totalFrequency : 0; m_RelativeFrequencyContainer.push_back(relativeFrequency); IndexType index = inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); sumP[index[0] + index[1]] += relativeFrequency; diffP[std::abs(index[0] - index[1])] += relativeFrequency; //if (index[1] == 0) numberOfPixels += frequency; } // Now get the various means and variances. This is takes two passes // through the histogram. double pixelMean; double marginalMean; double marginalDevSquared; double pixelVariance; this->ComputeMeansAndVariances(pixelMean, marginalMean, marginalDevSquared, pixelVariance); // Finally compute the texture features. Another one pass. MeasurementType energy = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType entropy = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType correlation = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType inverseDifferenceMoment = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType inertia = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType clusterShade = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType clusterProminence = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType haralickCorrelation = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType autocorrelation = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType contrast = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType dissimilarity = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType maximumProbability = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType inverseVariance = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType homogeneity1 = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType clusterTendency = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType variance = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType sumAverage = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType sumEntropy = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType sumVariance = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType diffAverage = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType diffEntropy = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType diffVariance = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType inverseDifferenceMomentNormalized = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType inverseDifferenceNormalized = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType inverseDifference = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType averageProbability = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType firstMeasureOfInformationCorrelation = NumericTraits< MeasurementType >::ZeroValue(); MeasurementType secondMeasureOfInformationCorrelation = NumericTraits< MeasurementType >::ZeroValue(); double pixelVarianceSquared = pixelVariance * pixelVariance; // Variance is only used in correlation. If variance is 0, then // (index[0] - pixelMean) * (index[1] - pixelMean) // should be zero as well. In this case, set the variance to 1. in // order to avoid NaN correlation. if( Math::FloatAlmostEqual( pixelVarianceSquared, 0.0, 4, 2*NumericTraits::epsilon() ) ) { pixelVarianceSquared = 1.; } const double log2 = std::log(2.0); typename RelativeFrequencyContainerType::const_iterator rFreqIterator = m_RelativeFrequencyContainer.begin(); IndexType globalIndex(2); for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { RelativeFrequencyType frequency = *rFreqIterator; ++rFreqIterator; if ( frequency == 0 ) { continue; // no use doing these calculations if we're just multiplying by // zero. } IndexType index = inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); globalIndex = index; energy += frequency * frequency; entropy -= ( frequency > 0.0001 ) ? frequency *std::log(frequency) / log2:0; correlation += ( ( index[0] - pixelMean ) * ( index[1] - pixelMean ) * frequency ) / pixelVarianceSquared; inverseDifferenceMoment += frequency / ( 1.0 + ( index[0] - index[1] ) * ( index[0] - index[1] ) ); inertia += ( index[0] - index[1] ) * ( index[0] - index[1] ) * frequency; clusterShade += std::pow( ( index[0] - pixelMean ) + ( index[1] - pixelMean ), 3 ) * frequency; clusterProminence += std::pow( ( index[0] - pixelMean ) + ( index[1] - pixelMean ), 4 ) * frequency; haralickCorrelation += index[0] * index[1] * frequency; // New Features added for Aerts compatibility autocorrelation +=index[0] * index[1] * frequency; contrast += (index[0] - index[1]) * (index[0] - index[1]) * frequency; dissimilarity += std::abs(index[0] - index[1]) * frequency; maximumProbability +=std::max(maximumProbability, frequency); averageProbability += frequency * index[0]; if (index[0] != index[1]) inverseVariance += frequency / ((index[0] - index[1])*(index[0] - index[1])); homogeneity1 +=frequency / ( 1.0 + std::abs( index[0] - index[1] )); clusterTendency += std::pow( ( index[0] - pixelMean ) + ( index[1] - pixelMean ), 2 ) * frequency; variance += std::pow( ( index[0] - pixelMean ), 2) * frequency; if (numberOfPixels > 0) { inverseDifferenceMomentNormalized += frequency / ( 1.0 + ( index[0] - index[1] ) * ( index[0] - index[1] ) / numberOfPixels / numberOfPixels); inverseDifferenceNormalized += frequency / ( 1.0 + std::abs( index[0] - index[1] ) / numberOfPixels ); } else { inverseDifferenceMomentNormalized = 0; inverseDifferenceNormalized = 0; } inverseDifference += frequency / ( 1.0 + std::abs( index[0] - index[1] ) ); } for (int i = 0; i < (int)sumP.size();++i) { double frequency = sumP[i]; sumAverage += i * frequency; sumEntropy -= ( frequency > 0.0001 ) ? frequency *std::log(frequency) / log2:0; } for (int i = 0; i < (int)sumP.size();++i) { double frequency = sumP[i]; sumVariance += (i-sumAverage)*(i-sumAverage) * frequency; } for (int i = 0; i < (int)diffP.size();++i) { double frequency = diffP[i]; diffAverage += i * frequency; diffEntropy -= ( frequency > 0.0001 ) ? frequency *std::log(frequency) / log2:0; } for (int i = 0; i < (int)diffP.size();++i) { double frequency = diffP[i]; sumVariance += (i-diffAverage)*(i-diffAverage) * frequency; } if (marginalDevSquared > 0) { haralickCorrelation = ( haralickCorrelation - marginalMean * marginalMean ) / marginalDevSquared; } else { haralickCorrelation =0; } //Calculate the margin probs std::vector pi_margins; std::vector pj_margins; //pi. for ( std::size_t i = 1; i <= inputHistogram->GetSize(0); i++ ) { double pi_tmp= 0.0; for( std::size_t j = 1; j <= inputHistogram->GetSize(1); j++ ) { globalIndex[0] = i; globalIndex[1] = j; pi_tmp += inputHistogram->GetFrequency(globalIndex); } pi_margins.push_back(pi_tmp); } //pj. for ( std::size_t j = 1; j <= inputHistogram->GetSize(1); j++ ) { double pj_tmp= 0.0; for( std::size_t i = 1; i <= inputHistogram->GetSize(0); i++ ) { globalIndex[0] = i; globalIndex[1] = j; pj_tmp += inputHistogram->GetFrequency(globalIndex); } pj_margins.push_back(pj_tmp); } //Calculate HX double hx = 0.0; for ( std::size_t i = 0; i < inputHistogram->GetSize(0); i++ ) { double pi_margin = pi_margins[i]; hx -= ( pi_margin > 0.0001 ) ? pi_margin *std::log(pi_margin) / log2:0; } //Calculate HXY1 double hxy1 = 0.0; for ( std::size_t i = 0; i < inputHistogram->GetSize(0); i++ ) { for ( std::size_t j = 0; j < inputHistogram->GetSize(1); j++ ) { globalIndex[0] = i; globalIndex[1] = j; double pi_margin = pi_margins[i]; double pj_margin = pj_margins[j]; double p_ij = inputHistogram->GetFrequency(globalIndex); hxy1 -= ( (pi_margin * pj_margin) > 0.0001 ) ? p_ij *std::log(pi_margin * pj_margin) / log2:0; } } //Calculate HXY2 double hxy2 = 0.0; for ( std::size_t i = 0; i < inputHistogram->GetSize(0); i++ ) { for ( std::size_t j = 0; j < inputHistogram->GetSize(1); j++ ) { globalIndex[0] = i; globalIndex[1] = j; double pi_margin = pi_margins[i]; double pj_margin = pj_margins[j]; hxy1 -= ( (pi_margin * pj_margin) > 0.0001 ) ? (pi_margin * pj_margin) *std::log(pi_margin * pj_margin) / log2:0; } } firstMeasureOfInformationCorrelation = (entropy - hxy1) / hx; secondMeasureOfInformationCorrelation = (entropy > hxy2) ? 0 : std::sqrt(1 - std::exp(-2*(hxy2 - entropy))); MeasurementObjectType *energyOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(0) ); energyOutputObject->Set(energy); MeasurementObjectType *entropyOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(1) ); entropyOutputObject->Set(entropy); MeasurementObjectType *correlationOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(2) ); correlationOutputObject->Set(correlation); MeasurementObjectType *inverseDifferenceMomentOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(3) ); inverseDifferenceMomentOutputObject->Set(inverseDifferenceMoment); MeasurementObjectType *inertiaOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(4) ); inertiaOutputObject->Set(inertia); MeasurementObjectType *clusterShadeOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(5) ); clusterShadeOutputObject->Set(clusterShade); MeasurementObjectType *clusterProminenceOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(6) ); clusterProminenceOutputObject->Set(clusterProminence); MeasurementObjectType *haralickCorrelationOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(7) ); haralickCorrelationOutputObject->Set(haralickCorrelation); MeasurementObjectType *autocorrelationOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(8) ); autocorrelationOutputObject->Set(autocorrelation); MeasurementObjectType *contrastOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(9) ); contrastOutputObject->Set(contrast); MeasurementObjectType *dissimilarityOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(10) ); dissimilarityOutputObject->Set(dissimilarity); MeasurementObjectType *maximumProbabilityOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(11) ); maximumProbabilityOutputObject->Set(maximumProbability); MeasurementObjectType *inverseVarianceOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(12) ); inverseVarianceOutputObject->Set(inverseVariance); MeasurementObjectType *homogeneity1OutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(13) ); homogeneity1OutputObject->Set(homogeneity1); MeasurementObjectType *clusterTendencyOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(14) ); clusterTendencyOutputObject->Set(clusterTendency); MeasurementObjectType *varianceOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(15) ); varianceOutputObject->Set(variance); MeasurementObjectType *sumAverageOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(16) ); sumAverageOutputObject->Set(sumAverage); MeasurementObjectType *sumEntropyOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(17) ); sumEntropyOutputObject->Set(sumEntropy); MeasurementObjectType *sumVarianceOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(18) ); sumVarianceOutputObject->Set(sumVariance); MeasurementObjectType *diffAverageOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(19) ); diffAverageOutputObject->Set(diffAverage); MeasurementObjectType *diffEntropyOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(20) ); diffEntropyOutputObject->Set(diffEntropy); MeasurementObjectType *diffVarianceOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(21) ); diffVarianceOutputObject->Set(diffVariance); MeasurementObjectType *inverseDifferenceMomentNormalizedOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(22) ); inverseDifferenceMomentNormalizedOutputObject->Set(inverseDifferenceMomentNormalized); MeasurementObjectType *inverseDifferenceNormalizedOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(23) ); inverseDifferenceNormalizedOutputObject->Set(inverseDifferenceNormalized); MeasurementObjectType *inverseDifferenceOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(24) ); inverseDifferenceOutputObject->Set(inverseDifference); MeasurementObjectType *jointAverageOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(25) ); jointAverageOutputObject->Set(averageProbability); MeasurementObjectType *firstMeasureOfInformationCorrelationOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(26) ); firstMeasureOfInformationCorrelationOutputObject->Set(firstMeasureOfInformationCorrelation); MeasurementObjectType *secondMeasureOfInformationCorrelationOutputObject = static_cast< MeasurementObjectType * >( this->ProcessObject::GetOutput(27) ); secondMeasureOfInformationCorrelationOutputObject->Set(secondMeasureOfInformationCorrelation); } template< typename THistogram > void EnhancedHistogramToTextureFeaturesFilter< THistogram >::ComputeMeansAndVariances(double & pixelMean, double & marginalMean, double & marginalDevSquared, double & pixelVariance) { // This function takes two passes through the histogram and two passes through // an array of the same length as a histogram axis. This could probably be // cleverly compressed to one pass, but it's not clear that that's necessary. typedef typename HistogramType::ConstIterator HistogramIterator; const HistogramType *inputHistogram = this->GetInput(); // Initialize everything typename HistogramType::SizeValueType binsPerAxis = inputHistogram->GetSize(0); double *marginalSums = new double[binsPerAxis]; for ( double *ms_It = marginalSums; ms_It < marginalSums + binsPerAxis; ms_It++ ) { *ms_It = 0; } pixelMean = 0; typename RelativeFrequencyContainerType::const_iterator rFreqIterator = m_RelativeFrequencyContainer.begin(); // Ok, now do the first pass through the histogram to get the marginal sums // and compute the pixel mean HistogramIterator hit = inputHistogram->Begin(); while ( hit != inputHistogram->End() ) { RelativeFrequencyType frequency = *rFreqIterator; IndexType index = inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); pixelMean += index[0] * frequency; marginalSums[index[0]] += frequency; ++hit; ++rFreqIterator; } /* Now get the mean and deviaton of the marginal sums. Compute incremental mean and SD, a la Knuth, "The Art of Computer Programming, Volume 2: Seminumerical Algorithms", section 4.2.2. Compute mean and standard deviation using the recurrence relation: M(1) = x(1), M(k) = M(k-1) + (x(k) - M(k-1) ) / k S(1) = 0, S(k) = S(k-1) + (x(k) - M(k-1)) * (x(k) - M(k)) for 2 <= k <= n, then sigma = std::sqrt(S(n) / n) (or divide by n-1 for sample SD instead of population SD). */ marginalMean = marginalSums[0]; marginalDevSquared = 0; for ( unsigned int arrayIndex = 1; arrayIndex < binsPerAxis; arrayIndex++ ) { int k = arrayIndex + 1; double M_k_minus_1 = marginalMean; double S_k_minus_1 = marginalDevSquared; double x_k = marginalSums[arrayIndex]; double M_k = M_k_minus_1 + ( x_k - M_k_minus_1 ) / k; double S_k = S_k_minus_1 + ( x_k - M_k_minus_1 ) * ( x_k - M_k ); marginalMean = M_k; marginalDevSquared = S_k; } marginalDevSquared = marginalDevSquared / binsPerAxis; rFreqIterator = m_RelativeFrequencyContainer.begin(); // OK, now compute the pixel variances. pixelVariance = 0; for ( hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { RelativeFrequencyType frequency = *rFreqIterator; IndexType index = inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); pixelVariance += ( index[0] - pixelMean ) * ( index[0] - pixelMean ) * frequency; ++rFreqIterator; } delete[] marginalSums; } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetEnergyOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(0) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetEntropyOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(1) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetCorrelationOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(2) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetInverseDifferenceMomentOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(3) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetInertiaOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(4) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetClusterShadeOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(5) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetClusterProminenceOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(6) ); } template< typename THistogram > const typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementObjectType * EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetHaralickCorrelationOutput() const { return static_cast< const MeasurementObjectType * >( this->ProcessObject::GetOutput(7) ); } itkMacroGLCMFeature(Autocorrelation,8) itkMacroGLCMFeature(Contrast,9) itkMacroGLCMFeature(Dissimilarity,10) itkMacroGLCMFeature(MaximumProbability,11) itkMacroGLCMFeature(InverseVariance,12) itkMacroGLCMFeature(Homogeneity1,13) itkMacroGLCMFeature(ClusterTendency,14) itkMacroGLCMFeature(Variance,15) itkMacroGLCMFeature(SumAverage,16) itkMacroGLCMFeature(SumEntropy,17) itkMacroGLCMFeature(SumVariance,18) itkMacroGLCMFeature(DifferenceAverage,19) itkMacroGLCMFeature(DifferenceEntropy,20) itkMacroGLCMFeature(DifferenceVariance,21) itkMacroGLCMFeature(InverseDifferenceMomentNormalized,22) itkMacroGLCMFeature(InverseDifferenceNormalized,23) itkMacroGLCMFeature(InverseDifference,24) itkMacroGLCMFeature(JointAverage,25) itkMacroGLCMFeature(FirstMeasureOfInformationCorrelation,26) itkMacroGLCMFeature(SecondMeasureOfInformationCorrelation,27) template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetEnergy() const { return this->GetEnergyOutput()->Get(); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetEntropy() const { return this->GetEntropyOutput()->Get(); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetCorrelation() const { return this->GetCorrelationOutput()->Get(); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetInverseDifferenceMoment() const { return this->GetInverseDifferenceMomentOutput()->Get(); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetInertia() const { return this->GetInertiaOutput()->Get(); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetClusterShade() const { return this->GetClusterShadeOutput()->Get(); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetClusterProminence() const { return this->GetClusterProminenceOutput()->Get(); } template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetHaralickCorrelation() const { return this->GetHaralickCorrelationOutput()->Get(); } #define itkMacroGLCMFeatureSwitch(name) \ case name : \ return this->Get##name() template< typename THistogram > typename EnhancedHistogramToTextureFeaturesFilter< THistogram >::MeasurementType EnhancedHistogramToTextureFeaturesFilter< THistogram > ::GetFeature(TextureFeatureName feature) { switch ( feature ) { itkMacroGLCMFeatureSwitch(Energy); itkMacroGLCMFeatureSwitch(Entropy); itkMacroGLCMFeatureSwitch(Correlation); itkMacroGLCMFeatureSwitch(InverseDifferenceMoment); itkMacroGLCMFeatureSwitch(Inertia); itkMacroGLCMFeatureSwitch(ClusterShade); itkMacroGLCMFeatureSwitch(ClusterProminence); itkMacroGLCMFeatureSwitch(HaralickCorrelation); itkMacroGLCMFeatureSwitch(Autocorrelation); itkMacroGLCMFeatureSwitch(Contrast); itkMacroGLCMFeatureSwitch(Dissimilarity); itkMacroGLCMFeatureSwitch(MaximumProbability); itkMacroGLCMFeatureSwitch(InverseVariance); itkMacroGLCMFeatureSwitch(Homogeneity1); itkMacroGLCMFeatureSwitch(ClusterTendency); itkMacroGLCMFeatureSwitch(Variance); itkMacroGLCMFeatureSwitch(SumAverage); itkMacroGLCMFeatureSwitch(SumEntropy); itkMacroGLCMFeatureSwitch(SumVariance); itkMacroGLCMFeatureSwitch(DifferenceAverage); itkMacroGLCMFeatureSwitch(DifferenceEntropy); itkMacroGLCMFeatureSwitch(DifferenceVariance); itkMacroGLCMFeatureSwitch(InverseDifferenceMomentNormalized); itkMacroGLCMFeatureSwitch(InverseDifferenceNormalized); itkMacroGLCMFeatureSwitch(InverseDifference); itkMacroGLCMFeatureSwitch(JointAverage); itkMacroGLCMFeatureSwitch(FirstMeasureOfInformationCorrelation); itkMacroGLCMFeatureSwitch(SecondMeasureOfInformationCorrelation); default: return 0; } } #undef itkMacroGLCMFeatureSwitch template< typename THistogram > void EnhancedHistogramToTextureFeaturesFilter< THistogram > ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h index fcb9705d48..3e3dd337ca 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h @@ -1,241 +1,241 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter_h #define __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter_h #include "itkDataObjectDecorator.h" #include "itkEnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h" #include "itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.h" namespace itk { namespace Statistics { /** \class EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter * \brief This class computes run length descriptions from an image. * * By default, run length features are computed for each spatial * direction and then averaged afterward, so it is possible to access the * standard deviations of the texture features. These values give a clue as * to texture anisotropy. However, doing this is much more work, because it * involved computing one for each offset given. To compute a single * matrix using the first offset, call FastCalculationsOn(). If this is called, * then the texture standard deviations will not be computed (and will be set * to zero), but texture computation will be much faster. * * This class is templated over the input image type. * * Template Parameters: * The image type, and the type of histogram frequency container. If you are * using a large number of bins per axis, a sparse frequency container may be * advisable. The default is to use a dense frequency container. * * Inputs and parameters: * -# An image * -# A mask defining the region over which texture features will be * calculated. (Optional) * -# The pixel value that defines the "inside" of the mask. (Optional, defaults * to 1 if a mask is set.) * -# The set of features to be calculated. These features are defined * in the HistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter class. * -# The number of intensity bins. (Optional, defaults to 256.) * -# The set of directions (offsets) to average across. (Optional, defaults to * {(-1, 0), (-1, -1), (0, -1), (1, -1)} for 2D images and scales analogously * for ND images.) * -# The pixel intensity range over which the features will be calculated. * (Optional, defaults to the full dynamic range of the pixel type.) * -# The distance range over which the features will be calculated. * (Optional, defaults to the full dynamic range of double type.) * * In general, the default parameter values should be sufficient. * * Outputs: * (1) The average value of each feature. * (2) The standard deviation in the values of each feature. * * Print references: * M. M. Galloway. Texture analysis using gray level run lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter * \sa ScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter * \sa HistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template< typename TImageType, typename THistogramFrequencyContainer = DenseFrequencyContainer2 > class EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter:public ProcessObject { public: /** Standard typedefs */ typedef EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro(EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter, ProcessObject); /** standard New() method support */ itkNewMacro(Self); typedef THistogramFrequencyContainer FrequencyContainerType; typedef TImageType ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::PixelType PixelType; typedef typename ImageType::OffsetType OffsetType; typedef VectorContainer< unsigned char, OffsetType > OffsetVector; typedef typename OffsetVector::Pointer OffsetVectorPointer; typedef typename OffsetVector::ConstPointer OffsetVectorConstPointer; typedef EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter< ImageType, FrequencyContainerType > NeighbourhoodGreyLevelDifferenceMatrixFilterType; typedef typename NeighbourhoodGreyLevelDifferenceMatrixFilterType::HistogramType HistogramType; typedef EnhancedHistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter< HistogramType > NeighbourhoodGreyLevelDifferenceFeaturesFilterType; typedef short NeighbourhoodGreyLevelDifferenceFeatureName; typedef VectorContainer FeatureNameVector; typedef typename FeatureNameVector::Pointer FeatureNameVectorPointer; typedef typename FeatureNameVector::ConstPointer FeatureNameVectorConstPointer; typedef VectorContainer< unsigned char, double > FeatureValueVector; typedef typename FeatureValueVector::Pointer FeatureValueVectorPointer; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef DataObjectDecorator< FeatureValueVector > FeatureValueVectorDataObjectType; const FeatureValueVectorDataObjectType * GetFeatureMeansOutput() const; const FeatureValueVectorDataObjectType * GetFeatureStandardDeviationsOutput() const; /** Connects the input image for which the features are going to be computed */ using Superclass::SetInput; void SetInput(const ImageType *); const ImageType * GetInput() const; /** Return the feature means and deviations. */ itkGetConstReferenceObjectMacro(FeatureMeans, FeatureValueVector); itkGetConstReferenceObjectMacro(FeatureStandardDeviations, FeatureValueVector); /** Set the desired feature set. Optional, for default value see above. */ itkSetConstObjectMacro(RequestedFeatures, FeatureNameVector); itkGetConstObjectMacro(RequestedFeatures, FeatureNameVector); /** Set the offsets over which the co-occurrence pairs will be computed. Optional; for default value see above. */ itkSetConstObjectMacro(Offsets, OffsetVector); itkGetConstObjectMacro(Offsets, OffsetVector); /** Set number of histogram bins along each axis. Optional; for default value see above. */ void SetNumberOfBinsPerAxis(unsigned int); /** Set the min and max (inclusive) pixel value that will be used for feature calculations. Optional; for default value see above. */ void SetPixelValueMinMax(PixelType min, PixelType max); /** Set the min and max (inclusive) pixel value that will be used for feature calculations. Optional; for default value see above. */ void SetDistanceValueMinMax( double min, double max ); /** Connects the mask image for which the histogram is going to be computed. Optional; for default value see above. */ void SetMaskImage(const ImageType *); const ImageType * GetMaskImage() const; /** Set the pixel value of the mask that should be considered "inside" the object. Optional; for default value see above. */ void SetInsidePixelValue(PixelType InsidePixelValue); itkGetConstMacro(FastCalculations, bool); itkSetMacro(FastCalculations, bool); itkBooleanMacro(FastCalculations); protected: EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter(); ~EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter() override {} void PrintSelf( std::ostream & os, Indent indent ) const ITK_OVERRIDE; void FastCompute(); void FullCompute(); /** This method causes the filter to generate its output. */ void GenerateData() ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput(DataObjectPointerArraySizeType) ITK_OVERRIDE; private: typename NeighbourhoodGreyLevelDifferenceMatrixFilterType::Pointer m_NeighbourhoodGreyLevelDifferenceMatrixGenerator; FeatureValueVectorPointer m_FeatureMeans; FeatureValueVectorPointer m_FeatureStandardDeviations; FeatureNameVectorConstPointer m_RequestedFeatures; OffsetVectorConstPointer m_Offsets; bool m_FastCalculations; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx index 9d1a67c702..cfa5a15036 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.hxx @@ -1,406 +1,406 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter_hxx #define __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter_hxx #include "itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter.h" #include "itkNeighborhood.h" #include #include "vnl/vnl_math.h" namespace itk { namespace Statistics { template EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter() { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 1 ); for( int i = 0; i < 2; ++i ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator = NeighbourhoodGreyLevelDifferenceMatrixFilterType::New(); this->m_FeatureMeans = FeatureValueVector::New(); this->m_FeatureStandardDeviations = FeatureValueVector::New(); // Set the requested features to the default value: // {Energy, Entropy, InverseDifferenceMoment, Inertia, ClusterShade, // ClusterProminence} FeatureNameVectorPointer requestedFeatures = FeatureNameVector::New(); // can't directly set this->m_RequestedFeatures since it is const! requestedFeatures->push_back( NeighbourhoodGreyLevelDifferenceFeaturesFilterType::Coarseness ); requestedFeatures->push_back( NeighbourhoodGreyLevelDifferenceFeaturesFilterType::Contrast ); requestedFeatures->push_back( NeighbourhoodGreyLevelDifferenceFeaturesFilterType::Busyness ); requestedFeatures->push_back( NeighbourhoodGreyLevelDifferenceFeaturesFilterType::Complexity ); requestedFeatures->push_back( NeighbourhoodGreyLevelDifferenceFeaturesFilterType::Strength ); requestedFeatures->push_back( 20 ); this->SetRequestedFeatures( requestedFeatures ); // Set the offset directions to their defaults: half of all the possible // directions 1 pixel away. (The other half is included by symmetry.) // We use a neighborhood iterator to calculate the appropriate offsets. typedef Neighborhood NeighborhoodType; NeighborhoodType hood; hood.SetRadius( 1 ); // select all "previous" neighbors that are face+edge+vertex // connected to the current pixel. do not include the center pixel. unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetVectorPointer offsets = OffsetVector::New(); for( unsigned int d = 0; d < centerIndex; d++ ) { OffsetType offset = hood.GetOffset( d ); offsets->push_back( offset ); } this->SetOffsets( offsets ); this->m_FastCalculations = false; } template typename EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::DataObjectPointer EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed(idx) ) { return FeatureValueVectorDataObjectType::New().GetPointer(); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GenerateData(void) { if ( this->m_FastCalculations ) { this->FastCompute(); } else { this->FullCompute(); } } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::FullCompute() { int numFeatures = this->m_RequestedFeatures->size(); double *features = new double [numFeatures]; unsigned long numberOfVoxels = 0; ImageRegionConstIterator voxelCountIter(this->GetMaskImage(),this->GetMaskImage()->GetLargestPossibleRegion()); while ( ! voxelCountIter.IsAtEnd() ) { if (voxelCountIter.Get() > 0) ++numberOfVoxels; ++voxelCountIter; } // For each offset, calculate each feature typename OffsetVector::ConstIterator offsetIt; int offsetNum, featureNum; typedef typename NeighbourhoodGreyLevelDifferenceFeaturesFilterType::NeighbourhoodGreyLevelDifferenceFeatureName InternalNeighbourhoodGreyLevelDifferenceFeatureName; std::vector tVector; for( offsetIt = this->m_Offsets->Begin(), offsetNum = 0; offsetIt != this->m_Offsets->End(); offsetIt++, offsetNum++ ) { MITK_INFO << "Adding offset " << offsetIt.Value(); tVector.push_back(offsetIt.Value()); } this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->AddOffsets( tVector); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->Update(); typename NeighbourhoodGreyLevelDifferenceFeaturesFilterType::Pointer NeighbourhoodGreyLevelDifferenceMatrixCalculator = NeighbourhoodGreyLevelDifferenceFeaturesFilterType::New(); NeighbourhoodGreyLevelDifferenceMatrixCalculator->SetInput( this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->GetOutput() ); NeighbourhoodGreyLevelDifferenceMatrixCalculator->SetSiMatrix( this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->GetSiMatrix() ); NeighbourhoodGreyLevelDifferenceMatrixCalculator->SetNumberOfVoxels(numberOfVoxels); NeighbourhoodGreyLevelDifferenceMatrixCalculator->Update(); typename FeatureNameVector::ConstIterator fnameIt; for( fnameIt = this->m_RequestedFeatures->Begin(), featureNum = 0; fnameIt != this->m_RequestedFeatures->End(); fnameIt++, featureNum++ ) { InternalNeighbourhoodGreyLevelDifferenceFeatureName tn = ( InternalNeighbourhoodGreyLevelDifferenceFeatureName )fnameIt.Value(); double xx = NeighbourhoodGreyLevelDifferenceMatrixCalculator->GetFeature(tn); features[featureNum] = xx; } // Now get the mean and deviaton of each feature across the offsets. this->m_FeatureMeans->clear(); this->m_FeatureStandardDeviations->clear(); double *tempFeatureMeans = new double[numFeatures]; double *tempFeatureDevs = new double[numFeatures]; /*Compute incremental mean and SD, a la Knuth, "The Art of Computer Programming, Volume 2: Seminumerical Algorithms", section 4.2.2. Compute mean and standard deviation using the recurrence relation: M(1) = x(1), M(k) = M(k-1) + (x(k) - M(k-1) ) / k S(1) = 0, S(k) = S(k-1) + (x(k) - M(k-1)) * (x(k) - M(k)) for 2 <= k <= n, then sigma = std::sqrt(S(n) / n) (or divide by n-1 for sample SD instead of population SD). */ // Set up the initial conditions (k = 1) for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { this->m_FeatureMeans->push_back( features[featureNum] ); //tempFeatureMeans[featureNum] = features[0][featureNum]; //tempFeatureDevs[featureNum] = 0; } // Zone through the recurrence (k = 2 ... N) /*for( offsetNum = 1; offsetNum < numOffsets; offsetNum++ ) { int k = offsetNum + 1; for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { double M_k_minus_1 = tempFeatureMeans[featureNum]; double S_k_minus_1 = tempFeatureDevs[featureNum]; double x_k = features[offsetNum][featureNum]; double M_k = M_k_minus_1 + ( x_k - M_k_minus_1 ) / k; double S_k = S_k_minus_1 + ( x_k - M_k_minus_1 ) * ( x_k - M_k ); tempFeatureMeans[featureNum] = M_k; tempFeatureDevs[featureNum] = S_k; } } for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { tempFeatureDevs[featureNum] = std::sqrt( tempFeatureDevs[featureNum] / numOffsets ); this->m_FeatureMeans->push_back( tempFeatureMeans[featureNum] ); this->m_FeatureStandardDeviations->push_back( tempFeatureDevs[featureNum] ); } */ FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); meanOutputObject->Set( this->m_FeatureMeans ); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); delete[] tempFeatureMeans; delete[] tempFeatureDevs; /*for( int i = 0; i < numOffsets; i++ ) { delete[] features[i]; }*/ delete[] features; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::FastCompute() { // Compute the feature for the first offset typename OffsetVector::ConstIterator offsetIt = this->m_Offsets->Begin(); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->SetOffset( offsetIt.Value() ); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->Update(); typename NeighbourhoodGreyLevelDifferenceFeaturesFilterType::Pointer NeighbourhoodGreyLevelDifferenceMatrixCalculator = NeighbourhoodGreyLevelDifferenceFeaturesFilterType::New(); NeighbourhoodGreyLevelDifferenceMatrixCalculator->SetInput( this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->GetOutput() ); NeighbourhoodGreyLevelDifferenceMatrixCalculator->SetSiMatrix( this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->GetSiMatrix() ); NeighbourhoodGreyLevelDifferenceMatrixCalculator->Update(); typedef typename NeighbourhoodGreyLevelDifferenceFeaturesFilterType::NeighbourhoodGreyLevelDifferenceFeatureName InternalNeighbourhoodGreyLevelDifferenceFeatureName; this->m_FeatureMeans->clear(); this->m_FeatureStandardDeviations->clear(); typename FeatureNameVector::ConstIterator fnameIt; for( fnameIt = this->m_RequestedFeatures->Begin(); fnameIt != this->m_RequestedFeatures->End(); fnameIt++ ) { this->m_FeatureMeans->push_back( NeighbourhoodGreyLevelDifferenceMatrixCalculator->GetFeature( ( InternalNeighbourhoodGreyLevelDifferenceFeatureName )fnameIt.Value() ) ); this->m_FeatureStandardDeviations->push_back( 0.0 ); } FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); meanOutputObject->Set( this->m_FeatureMeans ); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::SetInput( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast( image ) ); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->SetInput( image ); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::SetNumberOfBinsPerAxis( unsigned int numberOfBins ) { itkDebugMacro( "setting NumberOfBinsPerAxis to " << numberOfBins ); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->SetNumberOfBinsPerAxis( numberOfBins ); this->Modified(); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::SetPixelValueMinMax( PixelType min, PixelType max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->SetPixelValueMinMax( min, max ); this->Modified(); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::SetDistanceValueMinMax( double min, double max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->SetDistanceValueMinMax( min, max ); this->Modified(); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::SetMaskImage( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast< ImageType * >( image ) ); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->SetMaskImage( image ); } template const TImage * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 0 ) ); } template const typename EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::FeatureValueVectorDataObjectType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetFeatureMeansOutput() const { return itkDynamicCastInDebugMode (this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::FeatureValueVectorDataObjectType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetFeatureStandardDeviationsOutput() const { return itkDynamicCastInDebugMode< const FeatureValueVectorDataObjectType * > ( this->ProcessObject::GetOutput( 1 ) ); } template const TImage * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::GetMaskImage() const { if ( this->GetNumberOfInputs() < 2 ) { return ITK_NULLPTR; } return static_cast< const ImageType *>( this->ProcessObject::GetInput( 1 ) ); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::SetInsidePixelValue( PixelType insidePixelValue ) { itkDebugMacro( "setting InsidePixelValue to " << insidePixelValue ); this->m_NeighbourhoodGreyLevelDifferenceMatrixGenerator->SetInsidePixelValue( insidePixelValue ); this->Modified(); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "RequestedFeatures: " << this->GetRequestedFeatures() << std::endl; os << indent << "FeatureStandardDeviations: " << this->GetFeatureStandardDeviations() << std::endl; os << indent << "FastCalculations: " << this->GetFastCalculations() << std::endl; os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "FeatureMeans: " << this->GetFeatureMeans() << std::endl; } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.h index 3b55f16b9e..1f58958dd6 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.h @@ -1,295 +1,295 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter_h #define __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter_h #include "itkImage.h" #include "itkHistogram.h" #include "itkNumericTraits.h" #include "itkVectorContainer.h" namespace itk { namespace Statistics { /** \class EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter * \brief This class computes a run length matrix (histogram) from * a given image and a mask image if provided. Run length matrces are * used for image texture description. * * This filters creates a grey-level run length matrix from a N-D scalar * image. This is another possible texture description. See the following * references. * M. M. Galloway. Texture analysis using gray level run lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * * The basic idea is as follows: * Given an image and an offset (e.g. (1, -1) for a 2-d image), each element * in the joint histogram describes the frequency for a particular distance/ * intensity pair within a given image. This distance/intensity pair can be * described as follows: we start at a given voxel which has some intensity. * We then "jump" to neighboring pixels in increments provided by the offset(s) * as long as the pixel to which we are jumping is within the same intensity * bin as the original voxel. The distance component is given by the distance * from the original to the final voxel satisfying our jumping criteria. * * The offset (or offsets) along which the co-occurences are calculated can be * set by the user. Traditionally, only one offset is used per histogram, and * offset components in the range [-1, 1] are used. For rotation-invariant * features averages of features computed over several histograms with different * offsets are generally used, instead of computing features from one histogram * create with several offsets. Additionally, instead of using offsets of two or * more pixels in any direction, multi-resolution techniques (e.g. image * pyramids) are generally used to deal with texture at different spatial * resolutions. * * This class calculates a 2-d histogram of all the intensity/distance pairs in * the given image's requested region, for a given set of offsets. That is, if * a given offset falls outside of the requested region (or outside the mask) * at a particular point, that distance/intensity pair will not be added to * the matrix. * * The number of histogram bins on each axis can be set (defaults to 256). Also, * by default the histogram min and max corresponds to the largest and smallest * possible pixel value of that pixel type. To customize the histogram bounds * for a given image, the max and min pixel values that will be placed in the * histogram can be set manually. NB: The min and max are INCLUSIVE. * * Further, the type of histogram frequency container used is an optional * template parameter. By default, a dense container is used, but for images * with little texture or in cases where the user wants more histogram bins, * a sparse container can be used for the histogram instead. * * WARNING: This probably won't work for pixels of double or long-double type * unless you set the histogram min and max manually. This is because the largest * histogram bin by default has max value of the largest possible pixel value * plus 1. For double and long-double types, whose "RealType" as defined by the * NumericTraits class is the same, and thus cannot hold any larger values, * this would cause a float overflow. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa ScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter * \sa EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter * \sa HistogramToNeighbourhoodGreyLevelDifferenceFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template class EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter : public ProcessObject { public: /** Standard typedefs */ typedef EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter Self; typedef ProcessObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro( EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter, ProcessObject ); /** standard New() method support */ itkNewMacro( Self ); typedef TImageType ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::ConstPointer ImageConstPointer; typedef typename ImageType::PixelType PixelType; typedef typename ImageType::IndexType IndexType; typedef typename ImageType::RegionType RegionType; typedef typename ImageType::SizeType RadiusType; typedef typename ImageType::OffsetType OffsetType; typedef VectorContainer OffsetVector; typedef typename OffsetVector::Pointer OffsetVectorPointer; typedef typename ImageType::PointType PointType; typedef typename NumericTraits::RealType MeasurementType; typedef typename NumericTraits::RealType RealType; typedef Histogram HistogramType; typedef typename HistogramType::Pointer HistogramPointer; typedef typename HistogramType::ConstPointer HistogramConstPointer; typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; /** ImageDimension constants */ itkStaticConstMacro( ImageDimension, unsigned int, TImageType::ImageDimension ); /** Specify the default number of bins per axis */ itkStaticConstMacro( DefaultBinsPerAxis, unsigned int, 256 ); /** * Set the offsets over which the intensity/distance pairs will be computed. * Invoking this function clears the previous offsets. * Note: for each individual offset in the OffsetVector, the rightmost non-zero * offset element must be positive. For example, in the offset list of a 2D image, * (1, 0) means the offset along x-axis. (1, 0) has to be set instead * of (-1, 0). This is required from the iterating order of pixel iterator. * */ itkSetObjectMacro( Offsets, OffsetVector ); /** * Set offset over which the intensity/distance pairs will be computed. * Invoking this function clears the previous offset(s). * Note: for each individual offset, the rightmost non-zero * offset element must be positive. For example, in the offset list of a 2D image, * (1, 0) means the offset along x-axis. (1, 0) has to be set instead * of (-1, 0). This is required from the iterating order of pixel iterator. * */ void SetOffset( const OffsetType offset ); void AddOffsets( const std::vector offset ); /** * Get the current offset(s). */ itkGetModifiableObjectMacro(Offsets, OffsetVector ); /** Set number of histogram bins along each axis */ itkSetMacro( NumberOfBinsPerAxis, unsigned int ); /** Get number of histogram bins along each axis */ itkGetConstMacro( NumberOfBinsPerAxis, unsigned int ); /** * Set the min and max (inclusive) pixel value that will be used in * generating the histogram. */ void SetPixelValueMinMax( PixelType min, PixelType max ); /** Get the min pixel value defining one dimension of the joint histogram. */ itkGetConstMacro( Min, PixelType ); /** Get the max pixel value defining one dimension of the joint histogram. */ itkGetConstMacro( Max, PixelType ); /** * Set the min and max (inclusive) pixel value that will be used in * generating the histogram. */ void SetDistanceValueMinMax( RealType min, RealType max ); /** * Get the min distance value defining one dimension of the joint histogram. */ itkGetConstMacro( MinDistance, RealType ); /** * Get the max distance value defining one dimension of the joint histogram. */ itkGetConstMacro( MaxDistance, RealType ); /** Method to set the input image */ using Superclass::SetInput; void SetInput( const ImageType *image ); /** Method to get the input image */ const ImageType * GetInput() const; /** Method to set the mask image */ void SetMaskImage( const ImageType *image ); /** Method to get the mask image */ const ImageType * GetMaskImage() const; /** method to get the Histogram */ const HistogramType * GetOutput() const; /** method to get the Histogram */ double* GetSiMatrix() const; /** * Set the pixel value of the mask that should be considered "inside" the * object. Defaults to 1. */ itkSetMacro( InsidePixelValue, PixelType ); itkGetConstMacro( InsidePixelValue, PixelType ); protected: EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter(); ~EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter() override {}; void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE; /** Standard itk::ProcessObject subclass method. */ typedef DataObject::Pointer DataObjectPointer; typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput( DataObjectPointerArraySizeType idx ) ITK_OVERRIDE; /** This method causes the filter to generate its output. */ void GenerateData() ITK_OVERRIDE; /** * Normalize the direction of the offset before it is applied. * The last non-zero dimension of the offest has to be positive in order * to match to scanning order of the iterator. Only the sign is changed. * For example, the input offset (-1, 0) will be normalized as * (1, 0). * */ void NormalizeOffsetDirection(OffsetType &offset); private: unsigned int m_NumberOfBinsPerAxis; PixelType m_Min; PixelType m_Max; RealType m_MinDistance; RealType m_MaxDistance; PixelType m_InsidePixelValue; MeasurementVectorType m_LowerBound; MeasurementVectorType m_UpperBound; OffsetVectorPointer m_Offsets; double * m_siMatrix; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx index 05f7bd24b2..bb0e407288 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx @@ -1,396 +1,396 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter_hxx #define __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter_hxx #include "itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.h" #include "itkConstNeighborhoodIterator.h" #include "itkNeighborhood.h" #include "vnl/vnl_math.h" #include "itkMacro.h" #include "itkRescaleIntensityImageFilter.h" #include "itkMaskImageFilter.h" #include "itkLabelStatisticsImageFilter.h" #include "itkScalarConnectedComponentImageFilter.h" #include "itkRelabelComponentImageFilter.h" #include "itkCastImageFilter.h" #include namespace itk { namespace Statistics { template EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter() : m_NumberOfBinsPerAxis( itkGetStaticConstMacro( DefaultBinsPerAxis ) ), m_Min( NumericTraits::NonpositiveMin() ), m_Max( NumericTraits::max() ), m_MinDistance( NumericTraits::ZeroValue() ), m_MaxDistance( NumericTraits::max() ), m_InsidePixelValue( NumericTraits::OneValue() ) { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 1 ); const unsigned int measurementVectorSize = 1; this->ProcessObject::SetNthOutput( 0, this->MakeOutput( 0 ) ); this->ProcessObject::SetNthOutput( 1, this->MakeOutput( 1 ) ); HistogramType *output = const_cast( this->GetOutput() ); output->SetMeasurementVectorSize( measurementVectorSize ); m_siMatrix = new double[m_NumberOfBinsPerAxis]; for(unsigned int i = 0; i < m_NumberOfBinsPerAxis; i++) { m_siMatrix[i] = 0; } this->m_LowerBound.SetSize( measurementVectorSize ); this->m_UpperBound.SetSize( measurementVectorSize ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetOffset( const OffsetType offset ) { OffsetVectorPointer offsetVector = OffsetVector::New(); offsetVector->push_back( offset ); this->SetOffsets( offsetVector ); MITK_WARN << "We now have " << this->GetOffsets()->size() << " offsets in matrixgenerator"; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::AddOffsets( const std::vector _offsets ) { OffsetVectorPointer offsetVector = OffsetVector::New(); typename OffsetVector::ConstIterator offsets; //MITK_WARN << "We have " << this->GetOffsets()->size() << " offsets!"; for( std::size_t i = 0; i < _offsets.size(); i++) { offsetVector->push_back(_offsets[i]); auto k = _offsets[i]; this->NormalizeOffsetDirection(k); offsetVector->push_back(k); } this->SetOffsets( offsetVector ); MITK_WARN << "We now have " << this->GetOffsets()->size() << " offsets in matrixgenerator"; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetInput( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast( image ) ); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetMaskImage( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast( image ) ); } template const TImageType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetInput() const { if( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 0 ) ); } template const TImageType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetMaskImage() const { if( this->GetNumberOfInputs() < 2 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 1 ) ); } template const typename EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter::HistogramType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetOutput() const { const HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); return output; } template double* EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetSiMatrix() const { return m_siMatrix; } template typename EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter::DataObjectPointer EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return HistogramType::New().GetPointer(); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GenerateData() { HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); const ImageType * inputImage = this->GetInput(); const ImageType * maskImage = this->GetMaskImage(); // First, create an appropriate histogram with the right number of bins // and mins and maxes correct for the image type. typename HistogramType::SizeType size( output->GetMeasurementVectorSize() ); size.Fill( this->m_NumberOfBinsPerAxis ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; output->Initialize( size, this->m_LowerBound, this->m_UpperBound ); MeasurementVectorType run( output->GetMeasurementVectorSize() ); typename HistogramType::IndexType hIndex; //Cast the image to a float image - with no respect to the incoming image //to prevent some non-templated itk issues typedef itk::Image FloatImageType; typedef itk::CastImageFilter CastFilterType; typename CastFilterType::Pointer caster = CastFilterType::New(); caster->SetInput(inputImage); caster->Update(); typename FloatImageType::Pointer floatImage = caster->GetOutput(); //Cast the mask to an unsigned short image - with no respect to the incomimg maskimage //to prevent some non-templated itk issues typedef unsigned short LabelPixelType; typedef itk::Image LabelImageType; typedef itk::CastImageFilter MaskCastFilterType; typename MaskCastFilterType::Pointer maskCaster = MaskCastFilterType::New(); maskCaster->SetInput(maskImage); maskCaster->Update(); //Set all values out of the mask to nans. typedef itk::MaskImageFilter< FloatImageType, LabelImageType, FloatImageType > MaskFilterType; typename MaskFilterType::Pointer maskFilter = MaskFilterType::New(); maskFilter->SetInput(floatImage); maskFilter->SetMaskImage(maskCaster->GetOutput()); maskFilter->SetOutsideValue( std::numeric_limits::quiet_NaN()); maskFilter->Update(); FloatImageType::Pointer floatImageMasked = maskFilter->GetOutput(); typedef ConstNeighborhoodIterator NeighborhoodIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill( 1 ); NeighborhoodIteratorType neighborIt( radius, inputImage, inputImage->GetRequestedRegion() ); for( neighborIt.GoToBegin(); !neighborIt.IsAtEnd(); ++neighborIt ) { const PixelType centerPixelIntensity = neighborIt.GetCenterPixel(); IndexType centerIndex = neighborIt.GetIndex(); FloatImageType::IndexType cIndex; cIndex[0] = centerIndex[0]; cIndex[1] = centerIndex[1]; cIndex[2] = centerIndex[2]; float centerFloatPixel = floatImageMasked->GetPixel(cIndex); int px = 0; PixelType sum = 0.0; bool canCalculate = true; typename OffsetVector::ConstIterator offsets; for( offsets = this->GetOffsets()->Begin(); offsets != this->GetOffsets()->End(); offsets++ ) { OffsetType offset = offsets.Value(); IndexType index; index = centerIndex + offset; if(!inputImage->GetRequestedRegion().IsInside(index)) { canCalculate = false; break; } PixelType offsetPixel = inputImage->GetPixel(index); FloatImageType::IndexType fIndex; fIndex[0] = index[0]; fIndex[1] = index[1]; fIndex[2] = index[2]; float floatPixel = floatImageMasked->GetPixel(fIndex); //We have a nan here if(floatPixel != floatPixel || centerFloatPixel!= centerFloatPixel) { canCalculate = false; break; } sum += offsetPixel; px++; } //If we have a nan in the neighbourhood, continue if(!canCalculate) continue; PixelType mean = sum / px; double si = std::abs(mean-centerPixelIntensity); run[0] = centerPixelIntensity; //Check for NaN and inf if(run[0] == run[0] && !std::isinf(std::abs(run[0]))) { output->GetIndex( run, hIndex ); output->IncreaseFrequencyOfIndex( hIndex, 1 ); m_siMatrix[hIndex[0]] += si; } //MITK_WARN << " -> In this round we added: " << centerIndex << " with value " << centerPixelIntensity << " and si = " << si; //MITK_WARN << " -> Values are now siMatrix["< Values are now niMatrix: " << output->GetFrequency(hIndex) << "/" << run; } } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetPixelValueMinMax( PixelType min, PixelType max ) { if( this->m_Min != min || this->m_Max != max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_Min = min; this->m_Max = max; this->Modified(); } } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetDistanceValueMinMax( RealType min, RealType max ) { if( this->m_MinDistance != min || this->m_MaxDistance != max ) { itkDebugMacro( "setting MinDistance to " << min << "and MaxDistance to " << max ); this->m_MinDistance = min; this->m_MaxDistance = max; this->Modified(); } } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::PrintSelf( std::ostream& os, Indent indent ) const { Superclass::PrintSelf( os,indent ); os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "Min: " << this->m_Min << std::endl; os << indent << "Max: " << this->m_Max << std::endl; os << indent << "Min distance: " << this->m_MinDistance << std::endl; os << indent << "Max distance: " << this->m_MaxDistance << std::endl; os << indent << "NumberOfBinsPerAxis: " << this->m_NumberOfBinsPerAxis << std::endl; os << indent << "InsidePixelValue: " << this->m_InsidePixelValue << std::endl; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::NormalizeOffsetDirection(OffsetType &offset) { //MITK_WARN <<" -> NGTDM old offset = " << offset; itkDebugMacro("old offset = " << offset << std::endl); int sign = 1; bool metLastNonZero = false; for (int i = offset.GetOffsetDimension()-1; i>=0; i--) { if (metLastNonZero) { offset[i] *= sign; } else if (offset[i] != 0) { sign = (offset[i] > 0 ) ? 1 : -1; metLastNonZero = true; offset[i] *= sign; } } //MITK_WARN << " ->NGTDM new offset = " << offset; itkDebugMacro("new offset = " << offset << std::endl); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.h index 4081be5c3a..15ddaa3bc5 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.h @@ -1,245 +1,245 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToRunLengthFeaturesFilter_h #define __itkEnhancedScalarImageToRunLengthFeaturesFilter_h #include "itkDataObjectDecorator.h" #include "itkEnhancedHistogramToRunLengthFeaturesFilter.h" #include "itkEnhancedScalarImageToRunLengthMatrixFilter.h" namespace itk { namespace Statistics { /** \class EnhancedScalarImageToRunLengthFeaturesFilter * \brief This class computes run length descriptions from an image. * * By default, run length features are computed for each spatial * direction and then averaged afterward, so it is possible to access the * standard deviations of the texture features. These values give a clue as * to texture anisotropy. However, doing this is much more work, because it * involved computing one for each offset given. To compute a single * matrix using the first offset, call FastCalculationsOn(). If this is called, * then the texture standard deviations will not be computed (and will be set * to zero), but texture computation will be much faster. * * This class is templated over the input image type. * * Template Parameters: * The image type, and the type of histogram frequency container. If you are * using a large number of bins per axis, a sparse frequency container may be * advisable. The default is to use a dense frequency container. * * Inputs and parameters: * -# An image * -# A mask defining the region over which texture features will be * calculated. (Optional) * -# The pixel value that defines the "inside" of the mask. (Optional, defaults * to 1 if a mask is set.) * -# The set of features to be calculated. These features are defined * in the HistogramToRunLengthFeaturesFilter class. * -# The number of intensity bins. (Optional, defaults to 256.) * -# The set of directions (offsets) to average across. (Optional, defaults to * {(-1, 0), (-1, -1), (0, -1), (1, -1)} for 2D images and scales analogously * for ND images.) * -# The pixel intensity range over which the features will be calculated. * (Optional, defaults to the full dynamic range of the pixel type.) * -# The distance range over which the features will be calculated. * (Optional, defaults to the full dynamic range of double type.) * * In general, the default parameter values should be sufficient. * * Outputs: * (1) The average value of each feature. * (2) The standard deviation in the values of each feature. * * Print references: * M. M. Galloway. Texture analysis using gray level run lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa EnhancedScalarImageToRunLengthFeaturesFilter * \sa ScalarImageToRunLengthMatrixFilter * \sa HistogramToRunLengthFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template< typename TImageType, typename THistogramFrequencyContainer = DenseFrequencyContainer2 > class EnhancedScalarImageToRunLengthFeaturesFilter:public ProcessObject { public: /** Standard typedefs */ typedef EnhancedScalarImageToRunLengthFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro(EnhancedScalarImageToRunLengthFeaturesFilter, ProcessObject); /** standard New() method support */ itkNewMacro(Self); typedef THistogramFrequencyContainer FrequencyContainerType; typedef TImageType ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::PixelType PixelType; typedef typename ImageType::OffsetType OffsetType; typedef VectorContainer< unsigned char, OffsetType > OffsetVector; typedef typename OffsetVector::Pointer OffsetVectorPointer; typedef typename OffsetVector::ConstPointer OffsetVectorConstPointer; typedef EnhancedScalarImageToRunLengthMatrixFilter< ImageType, FrequencyContainerType > RunLengthMatrixFilterType; typedef typename RunLengthMatrixFilterType::HistogramType HistogramType; typedef EnhancedHistogramToRunLengthFeaturesFilter< HistogramType > RunLengthFeaturesFilterType; typedef short RunLengthFeatureName; typedef VectorContainer FeatureNameVector; typedef typename FeatureNameVector::Pointer FeatureNameVectorPointer; typedef typename FeatureNameVector::ConstPointer FeatureNameVectorConstPointer; typedef VectorContainer< unsigned char, double > FeatureValueVector; typedef typename FeatureValueVector::Pointer FeatureValueVectorPointer; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef DataObjectDecorator< FeatureValueVector > FeatureValueVectorDataObjectType; const FeatureValueVectorDataObjectType * GetFeatureMeansOutput() const; const FeatureValueVectorDataObjectType * GetFeatureStandardDeviationsOutput() const; /** Connects the input image for which the features are going to be computed */ using Superclass::SetInput; void SetInput(const ImageType *); const ImageType * GetInput() const; /** Return the feature means and deviations. */ itkGetConstReferenceObjectMacro(FeatureMeans, FeatureValueVector); itkGetConstReferenceObjectMacro(FeatureStandardDeviations, FeatureValueVector); /** Set the desired feature set. Optional, for default value see above. */ itkSetConstObjectMacro(RequestedFeatures, FeatureNameVector); itkGetConstObjectMacro(RequestedFeatures, FeatureNameVector); /** Set the offsets over which the co-occurrence pairs will be computed. Optional; for default value see above. */ itkSetConstObjectMacro(Offsets, OffsetVector); itkGetConstObjectMacro(Offsets, OffsetVector); /** Set number of histogram bins along each axis. Optional; for default value see above. */ void SetNumberOfBinsPerAxis(unsigned int); /** Set the min and max (inclusive) pixel value that will be used for feature calculations. Optional; for default value see above. */ void SetPixelValueMinMax(PixelType min, PixelType max); /** Set the min and max (inclusive) pixel value that will be used for feature calculations. Optional; for default value see above. */ void SetDistanceValueMinMax( double min, double max ); /** Connects the mask image for which the histogram is going to be computed. Optional; for default value see above. */ void SetMaskImage(const ImageType *); const ImageType * GetMaskImage() const; /** Set the pixel value of the mask that should be considered "inside" the object. Optional; for default value see above. */ void SetInsidePixelValue(PixelType InsidePixelValue); itkGetConstMacro(FastCalculations, bool); itkSetMacro(FastCalculations, bool); itkBooleanMacro(FastCalculations); itkGetConstMacro(CombinedFeatureCalculation, bool); itkSetMacro(CombinedFeatureCalculation, bool); itkBooleanMacro(CombinedFeatureCalculation); protected: EnhancedScalarImageToRunLengthFeaturesFilter(); ~EnhancedScalarImageToRunLengthFeaturesFilter() override {} void PrintSelf( std::ostream & os, Indent indent ) const ITK_OVERRIDE; void FastCompute(); void FullCompute(); /** This method causes the filter to generate its output. */ void GenerateData() ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput(DataObjectPointerArraySizeType) ITK_OVERRIDE; private: typename RunLengthMatrixFilterType::Pointer m_RunLengthMatrixGenerator; FeatureValueVectorPointer m_FeatureMeans; FeatureValueVectorPointer m_FeatureStandardDeviations; FeatureNameVectorConstPointer m_RequestedFeatures; OffsetVectorConstPointer m_Offsets; bool m_FastCalculations; bool m_CombinedFeatureCalculation; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedScalarImageToRunLengthFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.hxx index 38f6cdb772..99d51032b3 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthFeaturesFilter.hxx @@ -1,431 +1,431 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToRunLengthFeaturesFilter_hxx #define __itkEnhancedScalarImageToRunLengthFeaturesFilter_hxx #include "itkEnhancedScalarImageToRunLengthFeaturesFilter.h" #include "itkNeighborhood.h" #include #include "vnl/vnl_math.h" namespace itk { namespace Statistics { template EnhancedScalarImageToRunLengthFeaturesFilter ::EnhancedScalarImageToRunLengthFeaturesFilter() : m_CombinedFeatureCalculation(false) { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 1 ); for( int i = 0; i < 2; ++i ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } this->m_RunLengthMatrixGenerator = RunLengthMatrixFilterType::New(); this->m_FeatureMeans = FeatureValueVector::New(); this->m_FeatureStandardDeviations = FeatureValueVector::New(); // Set the requested features to the default value: // {Energy, Entropy, InverseDifferenceMoment, Inertia, ClusterShade, // ClusterProminence} FeatureNameVectorPointer requestedFeatures = FeatureNameVector::New(); // can't directly set this->m_RequestedFeatures since it is const! requestedFeatures->push_back( RunLengthFeaturesFilterType::ShortRunEmphasis ); requestedFeatures->push_back( RunLengthFeaturesFilterType::LongRunEmphasis ); requestedFeatures->push_back( RunLengthFeaturesFilterType::GreyLevelNonuniformity ); requestedFeatures->push_back( RunLengthFeaturesFilterType::GreyLevelNonuniformityNormalized ); requestedFeatures->push_back( RunLengthFeaturesFilterType::RunLengthNonuniformity ); requestedFeatures->push_back( RunLengthFeaturesFilterType::RunLengthNonuniformityNormalized ); requestedFeatures->push_back( RunLengthFeaturesFilterType::LowGreyLevelRunEmphasis ); requestedFeatures->push_back( RunLengthFeaturesFilterType::HighGreyLevelRunEmphasis ); requestedFeatures->push_back( RunLengthFeaturesFilterType::ShortRunLowGreyLevelEmphasis ); requestedFeatures->push_back( RunLengthFeaturesFilterType::ShortRunHighGreyLevelEmphasis ); requestedFeatures->push_back( RunLengthFeaturesFilterType::LongRunLowGreyLevelEmphasis ); requestedFeatures->push_back( RunLengthFeaturesFilterType::LongRunHighGreyLevelEmphasis ); requestedFeatures->push_back( 20 ); this->SetRequestedFeatures( requestedFeatures ); // Set the offset directions to their defaults: half of all the possible // directions 1 pixel away. (The other half is included by symmetry.) // We use a neighborhood iterator to calculate the appropriate offsets. typedef Neighborhood NeighborhoodType; NeighborhoodType hood; hood.SetRadius( 1 ); // select all "previous" neighbors that are face+edge+vertex // connected to the current pixel. do not include the center pixel. unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetVectorPointer offsets = OffsetVector::New(); for( unsigned int d = 0; d < centerIndex; d++ ) { OffsetType offset = hood.GetOffset( d ); offsets->push_back( offset ); } this->SetOffsets( offsets ); this->m_FastCalculations = false; } template typename EnhancedScalarImageToRunLengthFeaturesFilter ::DataObjectPointer EnhancedScalarImageToRunLengthFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed(idx) ) { return FeatureValueVectorDataObjectType::New().GetPointer(); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::GenerateData(void) { if ( this->m_FastCalculations ) { this->FastCompute(); } else { this->FullCompute(); } } template void EnhancedScalarImageToRunLengthFeaturesFilter ::FullCompute() { int numOffsets = this->m_Offsets->size(); if (m_CombinedFeatureCalculation) { numOffsets = 1; } int numFeatures = this->m_RequestedFeatures->size(); double **features; features = new double *[numOffsets]; for( int i = 0; i < numOffsets; i++ ) { features[i] = new double[numFeatures]; } unsigned long numberOfVoxels = 0; ImageRegionConstIterator voxelCountIter(this->GetMaskImage(),this->GetMaskImage()->GetLargestPossibleRegion()); while ( ! voxelCountIter.IsAtEnd() ) { if (voxelCountIter.Get() > 0) ++numberOfVoxels; ++voxelCountIter; } // For each offset, calculate each feature typename OffsetVector::ConstIterator offsetIt; int offsetNum, featureNum; typedef typename RunLengthFeaturesFilterType::RunLengthFeatureName InternalRunLengthFeatureName; OffsetVectorPointer offsets = OffsetVector::New(); if (m_CombinedFeatureCalculation) { for (int i = 0; i < this->m_Offsets->Size(); ++i) { offsets->push_back(m_Offsets->ElementAt(i)); } } for( offsetIt = this->m_Offsets->Begin(), offsetNum = 0; offsetIt != this->m_Offsets->End(); offsetIt++, offsetNum++ ) { this->m_RunLengthMatrixGenerator->SetOffset(offsetIt.Value()); if (m_CombinedFeatureCalculation) { this->m_RunLengthMatrixGenerator->SetOffsets(offsets); } this->m_RunLengthMatrixGenerator->Update(); typename RunLengthFeaturesFilterType::Pointer runLengthMatrixCalculator = RunLengthFeaturesFilterType::New(); runLengthMatrixCalculator->SetInput( this->m_RunLengthMatrixGenerator->GetOutput() ); runLengthMatrixCalculator->SetNumberOfVoxels(numberOfVoxels); runLengthMatrixCalculator->Update(); typename FeatureNameVector::ConstIterator fnameIt; for( fnameIt = this->m_RequestedFeatures->Begin(), featureNum = 0; fnameIt != this->m_RequestedFeatures->End(); fnameIt++, featureNum++ ) { features[offsetNum][featureNum] = runLengthMatrixCalculator->GetFeature( ( InternalRunLengthFeatureName )fnameIt.Value() ); } if (m_CombinedFeatureCalculation) { break; } } // Now get the mean and deviaton of each feature across the offsets. this->m_FeatureMeans->clear(); this->m_FeatureStandardDeviations->clear(); double *tempFeatureMeans = new double[numFeatures]; double *tempFeatureDevs = new double[numFeatures]; /*Compute incremental mean and SD, a la Knuth, "The Art of Computer Programming, Volume 2: Seminumerical Algorithms", section 4.2.2. Compute mean and standard deviation using the recurrence relation: M(1) = x(1), M(k) = M(k-1) + (x(k) - M(k-1) ) / k S(1) = 0, S(k) = S(k-1) + (x(k) - M(k-1)) * (x(k) - M(k)) for 2 <= k <= n, then sigma = std::sqrt(S(n) / n) (or divide by n-1 for sample SD instead of population SD). */ // Set up the initial conditions (k = 1) for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { tempFeatureMeans[featureNum] = features[0][featureNum]; tempFeatureDevs[featureNum] = 0; } // Run through the recurrence (k = 2 ... N) for( offsetNum = 1; offsetNum < numOffsets; offsetNum++ ) { int k = offsetNum + 1; for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { double M_k_minus_1 = tempFeatureMeans[featureNum]; double S_k_minus_1 = tempFeatureDevs[featureNum]; double x_k = features[offsetNum][featureNum]; double M_k = M_k_minus_1 + ( x_k - M_k_minus_1 ) / k; double S_k = S_k_minus_1 + ( x_k - M_k_minus_1 ) * ( x_k - M_k ); tempFeatureMeans[featureNum] = M_k; tempFeatureDevs[featureNum] = S_k; } } for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { tempFeatureDevs[featureNum] = std::sqrt( tempFeatureDevs[featureNum] / numOffsets ); this->m_FeatureMeans->push_back( tempFeatureMeans[featureNum] ); this->m_FeatureStandardDeviations->push_back( tempFeatureDevs[featureNum] ); } FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); meanOutputObject->Set( this->m_FeatureMeans ); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); delete[] tempFeatureMeans; delete[] tempFeatureDevs; for( int i = 0; i < numOffsets; i++ ) { delete[] features[i]; } delete[] features; } template void EnhancedScalarImageToRunLengthFeaturesFilter ::FastCompute() { // Compute the feature for the first offset typename OffsetVector::ConstIterator offsetIt = this->m_Offsets->Begin(); this->m_RunLengthMatrixGenerator->SetOffset( offsetIt.Value() ); this->m_RunLengthMatrixGenerator->Update(); typename RunLengthFeaturesFilterType::Pointer runLengthMatrixCalculator = RunLengthFeaturesFilterType::New(); runLengthMatrixCalculator->SetInput( this->m_RunLengthMatrixGenerator->GetOutput() ); runLengthMatrixCalculator->Update(); typedef typename RunLengthFeaturesFilterType::RunLengthFeatureName InternalRunLengthFeatureName; this->m_FeatureMeans->clear(); this->m_FeatureStandardDeviations->clear(); typename FeatureNameVector::ConstIterator fnameIt; for( fnameIt = this->m_RequestedFeatures->Begin(); fnameIt != this->m_RequestedFeatures->End(); fnameIt++ ) { this->m_FeatureMeans->push_back( runLengthMatrixCalculator->GetFeature( ( InternalRunLengthFeatureName )fnameIt.Value() ) ); this->m_FeatureStandardDeviations->push_back( 0.0 ); } FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); meanOutputObject->Set( this->m_FeatureMeans ); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::SetInput( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast( image ) ); this->m_RunLengthMatrixGenerator->SetInput( image ); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::SetNumberOfBinsPerAxis( unsigned int numberOfBins ) { itkDebugMacro( "setting NumberOfBinsPerAxis to " << numberOfBins ); this->m_RunLengthMatrixGenerator->SetNumberOfBinsPerAxis( numberOfBins ); this->Modified(); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::SetPixelValueMinMax( PixelType min, PixelType max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_RunLengthMatrixGenerator->SetPixelValueMinMax( min, max ); this->Modified(); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::SetDistanceValueMinMax( double min, double max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_RunLengthMatrixGenerator->SetDistanceValueMinMax( min, max ); this->Modified(); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::SetMaskImage( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast< ImageType * >( image ) ); this->m_RunLengthMatrixGenerator->SetMaskImage( image ); } template const TImage * EnhancedScalarImageToRunLengthFeaturesFilter ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 0 ) ); } template const typename EnhancedScalarImageToRunLengthFeaturesFilter ::FeatureValueVectorDataObjectType * EnhancedScalarImageToRunLengthFeaturesFilter ::GetFeatureMeansOutput() const { return itkDynamicCastInDebugMode (this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedScalarImageToRunLengthFeaturesFilter ::FeatureValueVectorDataObjectType * EnhancedScalarImageToRunLengthFeaturesFilter ::GetFeatureStandardDeviationsOutput() const { return itkDynamicCastInDebugMode< const FeatureValueVectorDataObjectType * > ( this->ProcessObject::GetOutput( 1 ) ); } template const TImage * EnhancedScalarImageToRunLengthFeaturesFilter ::GetMaskImage() const { if ( this->GetNumberOfInputs() < 2 ) { return ITK_NULLPTR; } return static_cast< const ImageType *>( this->ProcessObject::GetInput( 1 ) ); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::SetInsidePixelValue( PixelType insidePixelValue ) { itkDebugMacro( "setting InsidePixelValue to " << insidePixelValue ); this->m_RunLengthMatrixGenerator->SetInsidePixelValue( insidePixelValue ); this->Modified(); } template void EnhancedScalarImageToRunLengthFeaturesFilter ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "RequestedFeatures: " << this->GetRequestedFeatures() << std::endl; os << indent << "FeatureStandardDeviations: " << this->GetFeatureStandardDeviations() << std::endl; os << indent << "FastCalculations: " << this->GetFastCalculations() << std::endl; os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "FeatureMeans: " << this->GetFeatureMeans() << std::endl; } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.h index 9a9030fb93..dfdaf31361 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.h @@ -1,288 +1,288 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToRunLengthMatrixFilter_h #define __itkEnhancedScalarImageToRunLengthMatrixFilter_h #include "itkImage.h" #include "itkHistogram.h" #include "itkNumericTraits.h" #include "itkVectorContainer.h" namespace itk { namespace Statistics { /** \class EnhancedScalarImageToRunLengthMatrixFilter * \brief This class computes a run length matrix (histogram) from * a given image and a mask image if provided. Run length matrces are * used for image texture description. * * This filters creates a grey-level run length matrix from a N-D scalar * image. This is another possible texture description. See the following * references. * M. M. Galloway. Texture analysis using gray level run lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * * The basic idea is as follows: * Given an image and an offset (e.g. (1, -1) for a 2-d image), each element * in the joint histogram describes the frequency for a particular distance/ * intensity pair within a given image. This distance/intensity pair can be * described as follows: we start at a given voxel which has some intensity. * We then "jump" to neighboring pixels in increments provided by the offset(s) * as long as the pixel to which we are jumping is within the same intensity * bin as the original voxel. The distance component is given by the distance * from the original to the final voxel satisfying our jumping criteria. * * The offset (or offsets) along which the co-occurences are calculated can be * set by the user. Traditionally, only one offset is used per histogram, and * offset components in the range [-1, 1] are used. For rotation-invariant * features averages of features computed over several histograms with different * offsets are generally used, instead of computing features from one histogram * create with several offsets. Additionally, instead of using offsets of two or * more pixels in any direction, multi-resolution techniques (e.g. image * pyramids) are generally used to deal with texture at different spatial * resolutions. * * This class calculates a 2-d histogram of all the intensity/distance pairs in * the given image's requested region, for a given set of offsets. That is, if * a given offset falls outside of the requested region (or outside the mask) * at a particular point, that distance/intensity pair will not be added to * the matrix. * * The number of histogram bins on each axis can be set (defaults to 256). Also, * by default the histogram min and max corresponds to the largest and smallest * possible pixel value of that pixel type. To customize the histogram bounds * for a given image, the max and min pixel values that will be placed in the * histogram can be set manually. NB: The min and max are INCLUSIVE. * * Further, the type of histogram frequency container used is an optional * template parameter. By default, a dense container is used, but for images * with little texture or in cases where the user wants more histogram bins, * a sparse container can be used for the histogram instead. * * WARNING: This probably won't work for pixels of double or long-double type * unless you set the histogram min and max manually. This is because the largest * histogram bin by default has max value of the largest possible pixel value * plus 1. For double and long-double types, whose "RealType" as defined by the * NumericTraits class is the same, and thus cannot hold any larger values, * this would cause a float overflow. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa ScalarImageToRunLengthFeaturesFilter * \sa EnhancedScalarImageToRunLengthMatrixFilter * \sa HistogramToRunLengthFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template class EnhancedScalarImageToRunLengthMatrixFilter : public ProcessObject { public: /** Standard typedefs */ typedef EnhancedScalarImageToRunLengthMatrixFilter Self; typedef ProcessObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro( EnhancedScalarImageToRunLengthMatrixFilter, ProcessObject ); /** standard New() method support */ itkNewMacro( Self ); typedef TImageType ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::ConstPointer ImageConstPointer; typedef typename ImageType::PixelType PixelType; typedef typename ImageType::IndexType IndexType; typedef typename ImageType::RegionType RegionType; typedef typename ImageType::SizeType RadiusType; typedef typename ImageType::OffsetType OffsetType; typedef VectorContainer OffsetVector; typedef typename OffsetVector::Pointer OffsetVectorPointer; typedef typename ImageType::PointType PointType; typedef typename NumericTraits::RealType MeasurementType; typedef typename NumericTraits::RealType RealType; typedef Histogram HistogramType; typedef typename HistogramType::Pointer HistogramPointer; typedef typename HistogramType::ConstPointer HistogramConstPointer; typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; /** ImageDimension constants */ itkStaticConstMacro( ImageDimension, unsigned int, TImageType::ImageDimension ); /** Specify the default number of bins per axis */ itkStaticConstMacro( DefaultBinsPerAxis, unsigned int, 256 ); /** * Set the offsets over which the intensity/distance pairs will be computed. * Invoking this function clears the previous offsets. * Note: for each individual offset in the OffsetVector, the rightmost non-zero * offset element must be positive. For example, in the offset list of a 2D image, * (1, 0) means the offset along x-axis. (1, 0) has to be set instead * of (-1, 0). This is required from the iterating order of pixel iterator. * */ itkSetObjectMacro( Offsets, OffsetVector ); /** * Set offset over which the intensity/distance pairs will be computed. * Invoking this function clears the previous offset(s). * Note: for each individual offset, the rightmost non-zero * offset element must be positive. For example, in the offset list of a 2D image, * (1, 0) means the offset along x-axis. (1, 0) has to be set instead * of (-1, 0). This is required from the iterating order of pixel iterator. * */ void SetOffset( const OffsetType offset ); /** * Get the current offset(s). */ itkGetModifiableObjectMacro(Offsets, OffsetVector ); /** Set number of histogram bins along each axis */ itkSetMacro( NumberOfBinsPerAxis, unsigned int ); /** Get number of histogram bins along each axis */ itkGetConstMacro( NumberOfBinsPerAxis, unsigned int ); /** * Set the min and max (inclusive) pixel value that will be used in * generating the histogram. */ void SetPixelValueMinMax( PixelType min, PixelType max ); /** Get the min pixel value defining one dimension of the joint histogram. */ itkGetConstMacro( Min, PixelType ); /** Get the max pixel value defining one dimension of the joint histogram. */ itkGetConstMacro( Max, PixelType ); /** * Set the min and max (inclusive) pixel value that will be used in * generating the histogram. */ void SetDistanceValueMinMax( RealType min, RealType max ); /** * Get the min distance value defining one dimension of the joint histogram. */ itkGetConstMacro( MinDistance, RealType ); /** * Get the max distance value defining one dimension of the joint histogram. */ itkGetConstMacro( MaxDistance, RealType ); /** Method to set the input image */ using Superclass::SetInput; void SetInput( const ImageType *image ); /** Method to get the input image */ const ImageType * GetInput() const; /** Method to set the mask image */ void SetMaskImage( const ImageType *image ); /** Method to get the mask image */ const ImageType * GetMaskImage() const; /** method to get the Histogram */ const HistogramType * GetOutput() const; /** * Set the pixel value of the mask that should be considered "inside" the * object. Defaults to 1. */ itkSetMacro( InsidePixelValue, PixelType ); itkGetConstMacro( InsidePixelValue, PixelType ); protected: EnhancedScalarImageToRunLengthMatrixFilter(); ~EnhancedScalarImageToRunLengthMatrixFilter() override {}; void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE; /** Standard itk::ProcessObject subclass method. */ typedef DataObject::Pointer DataObjectPointer; typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput( DataObjectPointerArraySizeType idx ) ITK_OVERRIDE; /** This method causes the filter to generate its output. */ void GenerateData() ITK_OVERRIDE; /** * Normalize the direction of the offset before it is applied. * The last non-zero dimension of the offest has to be positive in order * to match to scanning order of the iterator. Only the sign is changed. * For example, the input offset (-1, 0) will be normalized as * (1, 0). * */ void NormalizeOffsetDirection(OffsetType &offset); private: unsigned int m_NumberOfBinsPerAxis; PixelType m_Min; PixelType m_Max; RealType m_MinDistance; RealType m_MaxDistance; PixelType m_InsidePixelValue; MeasurementVectorType m_LowerBound; MeasurementVectorType m_UpperBound; OffsetVectorPointer m_Offsets; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedScalarImageToRunLengthMatrixFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.hxx index 8775a8aef6..4b6b03aa52 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToRunLengthMatrixFilter.hxx @@ -1,411 +1,411 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToRunLengthMatrixFilter_hxx #define __itkEnhancedScalarImageToRunLengthMatrixFilter_hxx #include "itkEnhancedScalarImageToRunLengthMatrixFilter.h" #include "itkConstNeighborhoodIterator.h" #include "itkNeighborhood.h" #include "vnl/vnl_math.h" #include "itkMacro.h" namespace itk { namespace Statistics { template EnhancedScalarImageToRunLengthMatrixFilter ::EnhancedScalarImageToRunLengthMatrixFilter() : m_NumberOfBinsPerAxis( itkGetStaticConstMacro( DefaultBinsPerAxis ) ), m_Min( NumericTraits::NonpositiveMin() ), m_Max( NumericTraits::max() ), m_MinDistance( NumericTraits::ZeroValue() ), m_MaxDistance( NumericTraits::max() ), m_InsidePixelValue( NumericTraits::OneValue() ) { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 1 ); const unsigned int measurementVectorSize = 2; this->ProcessObject::SetNthOutput( 0, this->MakeOutput( 0 ) ); HistogramType *output = const_cast( this->GetOutput() ); output->SetMeasurementVectorSize( measurementVectorSize ); this->m_LowerBound.SetSize( measurementVectorSize ); this->m_UpperBound.SetSize( measurementVectorSize ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; } template void EnhancedScalarImageToRunLengthMatrixFilter ::SetOffset( const OffsetType offset ) { OffsetVectorPointer offsetVector = OffsetVector::New(); offsetVector->push_back( offset ); this->SetOffsets( offsetVector ); } template void EnhancedScalarImageToRunLengthMatrixFilter ::SetInput( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast( image ) ); } template void EnhancedScalarImageToRunLengthMatrixFilter ::SetMaskImage( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast( image ) ); } template const TImageType * EnhancedScalarImageToRunLengthMatrixFilter ::GetInput() const { if( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 0 ) ); } template const TImageType * EnhancedScalarImageToRunLengthMatrixFilter ::GetMaskImage() const { if( this->GetNumberOfInputs() < 2 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 1 ) ); } template const typename EnhancedScalarImageToRunLengthMatrixFilter::HistogramType * EnhancedScalarImageToRunLengthMatrixFilter ::GetOutput() const { const HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); return output; } template typename EnhancedScalarImageToRunLengthMatrixFilter::DataObjectPointer EnhancedScalarImageToRunLengthMatrixFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return HistogramType::New().GetPointer(); } template void EnhancedScalarImageToRunLengthMatrixFilter ::GenerateData() { HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); const ImageType * inputImage = this->GetInput(); // First, create an appropriate histogram with the right number of bins // and mins and maxes correct for the image type. typename HistogramType::SizeType size( output->GetMeasurementVectorSize() ); size.Fill( this->m_NumberOfBinsPerAxis ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; output->Initialize( size, this->m_LowerBound, this->m_UpperBound ); MeasurementVectorType run( output->GetMeasurementVectorSize() ); typename HistogramType::IndexType hIndex; // Iterate over all of those pixels and offsets, adding each // distance/intensity pair to the histogram typedef ConstNeighborhoodIterator NeighborhoodIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill( 1 ); NeighborhoodIteratorType neighborIt( radius, inputImage, inputImage->GetRequestedRegion() ); // this temp image has the same dimension for each offset // moving the allocation out of loop of offsets // while keeping FillBuffer with boolean false in each loop typedef Image BoolImageType; typename BoolImageType::Pointer alreadyVisitedImage = BoolImageType::New(); alreadyVisitedImage->CopyInformation( inputImage ); alreadyVisitedImage->SetRegions( inputImage->GetRequestedRegion() ); alreadyVisitedImage->Allocate(); typename OffsetVector::ConstIterator offsets; for( offsets = this->GetOffsets()->Begin(); offsets != this->GetOffsets()->End(); offsets++ ) { alreadyVisitedImage->FillBuffer( false ); neighborIt.GoToBegin(); OffsetType offset = offsets.Value(); this->NormalizeOffsetDirection(offset); for( neighborIt.GoToBegin(); !neighborIt.IsAtEnd(); ++neighborIt ) { const PixelType centerPixelIntensity = neighborIt.GetCenterPixel(); if (centerPixelIntensity != centerPixelIntensity) // Check for invalid values { continue; } IndexType centerIndex = neighborIt.GetIndex(); if( centerPixelIntensity < this->m_Min || centerPixelIntensity > this->m_Max || alreadyVisitedImage->GetPixel( centerIndex ) || ( this->GetMaskImage() && this->GetMaskImage()->GetPixel( centerIndex ) != this->m_InsidePixelValue ) ) { continue; // don't put a pixel in the histogram if the value // is out-of-bounds or is outside the mask. } itkDebugMacro("===> offset = " << offset << std::endl); MeasurementType centerBinMin = this->GetOutput()-> GetBinMinFromValue( 0, centerPixelIntensity ); MeasurementType centerBinMax = this->GetOutput()-> GetBinMaxFromValue( 0, centerPixelIntensity ); MeasurementType lastBinMax = this->GetOutput()-> GetDimensionMaxs( 0 )[ this->GetOutput()->GetSize( 0 ) - 1 ]; PixelType pixelIntensity( NumericTraits::ZeroValue() ); IndexType index; int steps = 0; index = centerIndex + offset; IndexType lastGoodIndex = centerIndex; bool runLengthSegmentAlreadyVisited = false; // Scan from the current pixel at index, following // the direction of offset. Run length is computed as the // length of continuous pixels whose pixel values are // in the same bin. while ( inputImage->GetRequestedRegion().IsInside(index) ) { pixelIntensity = inputImage->GetPixel(index); // For the same offset, each run length segment can // only be visited once if (alreadyVisitedImage->GetPixel( index ) ) { runLengthSegmentAlreadyVisited = true; break; } if (pixelIntensity != pixelIntensity) { break; } // Special attention paid to boundaries of bins. // For the last bin, // it is left close and right close (following the previous // gerrit patch). // For all // other bins, // the bin is left close and right open. if ( pixelIntensity >= centerBinMin && ( pixelIntensity < centerBinMax || ( pixelIntensity == centerBinMax && centerBinMax == lastBinMax ) ) && (!this->GetMaskImage() || this->GetMaskImage()->GetPixel(index) == this->m_InsidePixelValue)) { alreadyVisitedImage->SetPixel( index, true ); lastGoodIndex = index; index += offset; steps++; } else { break; } } if ( runLengthSegmentAlreadyVisited ) { MITK_INFO << "Already visited 1 " << index; continue; } IndexType lastGoodIndex2 = lastGoodIndex; index = centerIndex - offset; lastGoodIndex = centerIndex; while ( inputImage->GetRequestedRegion().IsInside(index) ) { pixelIntensity = inputImage->GetPixel(index); if (pixelIntensity != pixelIntensity) { break; } if (alreadyVisitedImage->GetPixel( index ) ) { if (pixelIntensity >= centerBinMin && (pixelIntensity < centerBinMax || (pixelIntensity == centerBinMax && centerBinMax == lastBinMax))) { runLengthSegmentAlreadyVisited = true; } break; } if ( pixelIntensity >= centerBinMin && ( pixelIntensity < centerBinMax || ( pixelIntensity == centerBinMax && centerBinMax == lastBinMax ) ) && (!this->GetMaskImage() || this->GetMaskImage()->GetPixel(index) == this->m_InsidePixelValue)) { alreadyVisitedImage->SetPixel( index, true ); lastGoodIndex = index; steps++; index -= offset; } else break; } if (runLengthSegmentAlreadyVisited) { MITK_INFO << "Already visited 2 " << index; continue; } PointType centerPoint; inputImage->TransformIndexToPhysicalPoint( centerIndex, centerPoint ); PointType point; inputImage->TransformIndexToPhysicalPoint( lastGoodIndex, point ); PointType point2; inputImage->TransformIndexToPhysicalPoint( lastGoodIndex2, point2 ); run[0] = centerPixelIntensity; run[1] = steps; //run[1] = point.EuclideanDistanceTo( point2 ); if( run[1] >= this->m_MinDistance && run[1] <= this->m_MaxDistance ) { output->GetIndex( run, hIndex ); output->IncreaseFrequencyOfIndex( hIndex, 1 ); } } } } template void EnhancedScalarImageToRunLengthMatrixFilter ::SetPixelValueMinMax( PixelType min, PixelType max ) { if( this->m_Min != min || this->m_Max != max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_Min = min; this->m_Max = max; this->Modified(); } } template void EnhancedScalarImageToRunLengthMatrixFilter ::SetDistanceValueMinMax( RealType min, RealType max ) { if( this->m_MinDistance != min || this->m_MaxDistance != max ) { itkDebugMacro( "setting MinDistance to " << min << "and MaxDistance to " << max ); this->m_MinDistance = min; this->m_MaxDistance = max; this->Modified(); } } template void EnhancedScalarImageToRunLengthMatrixFilter ::PrintSelf( std::ostream& os, Indent indent ) const { Superclass::PrintSelf( os,indent ); os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "Min: " << this->m_Min << std::endl; os << indent << "Max: " << this->m_Max << std::endl; os << indent << "Min distance: " << this->m_MinDistance << std::endl; os << indent << "Max distance: " << this->m_MaxDistance << std::endl; os << indent << "NumberOfBinsPerAxis: " << this->m_NumberOfBinsPerAxis << std::endl; os << indent << "InsidePixelValue: " << this->m_InsidePixelValue << std::endl; } template void EnhancedScalarImageToRunLengthMatrixFilter ::NormalizeOffsetDirection(OffsetType &offset) { itkDebugMacro("old offset = " << offset << std::endl); int sign = 1; bool metLastNonZero = false; for (int i = offset.GetOffsetDimension()-1; i>=0; i--) { if (metLastNonZero) { offset[i] *= sign; } else if (offset[i] != 0) { sign = (offset[i] > 0 ) ? 1 : -1; metLastNonZero = true; offset[i] *= sign; } } itkDebugMacro("new offset = " << offset << std::endl); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.h index c96a9d4f91..2e40883d5b 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.h @@ -1,241 +1,241 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToSizeZoneFeaturesFilter_h #define __itkEnhancedScalarImageToSizeZoneFeaturesFilter_h #include "itkDataObjectDecorator.h" #include "itkEnhancedHistogramToSizeZoneFeaturesFilter.h" #include "itkEnhancedScalarImageToSizeZoneMatrixFilter.h" namespace itk { namespace Statistics { /** \class EnhancedScalarImageToSizeZoneFeaturesFilter * \brief This class computes run length descriptions from an image. * * By default, run length features are computed for each spatial * direction and then averaged afterward, so it is possible to access the * standard deviations of the texture features. These values give a clue as * to texture anisotropy. However, doing this is much more work, because it * involved computing one for each offset given. To compute a single * matrix using the first offset, call FastCalculationsOn(). If this is called, * then the texture standard deviations will not be computed (and will be set * to zero), but texture computation will be much faster. * * This class is templated over the input image type. * * Template Parameters: * The image type, and the type of histogram frequency container. If you are * using a large number of bins per axis, a sparse frequency container may be * advisable. The default is to use a dense frequency container. * * Inputs and parameters: * -# An image * -# A mask defining the region over which texture features will be * calculated. (Optional) * -# The pixel value that defines the "inside" of the mask. (Optional, defaults * to 1 if a mask is set.) * -# The set of features to be calculated. These features are defined * in the HistogramToSizeZoneFeaturesFilter class. * -# The number of intensity bins. (Optional, defaults to 256.) * -# The set of directions (offsets) to average across. (Optional, defaults to * {(-1, 0), (-1, -1), (0, -1), (1, -1)} for 2D images and scales analogously * for ND images.) * -# The pixel intensity range over which the features will be calculated. * (Optional, defaults to the full dynamic range of the pixel type.) * -# The distance range over which the features will be calculated. * (Optional, defaults to the full dynamic range of double type.) * * In general, the default parameter values should be sufficient. * * Outputs: * (1) The average value of each feature. * (2) The standard deviation in the values of each feature. * * Print references: * M. M. Galloway. Texture analysis using gray level run lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa EnhancedScalarImageToSizeZoneFeaturesFilter * \sa ScalarImageToSizeZoneMatrixFilter * \sa HistogramToSizeZoneFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template< typename TImageType, typename THistogramFrequencyContainer = DenseFrequencyContainer2 > class EnhancedScalarImageToSizeZoneFeaturesFilter:public ProcessObject { public: /** Standard typedefs */ typedef EnhancedScalarImageToSizeZoneFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro(EnhancedScalarImageToSizeZoneFeaturesFilter, ProcessObject); /** standard New() method support */ itkNewMacro(Self); typedef THistogramFrequencyContainer FrequencyContainerType; typedef TImageType ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::PixelType PixelType; typedef typename ImageType::OffsetType OffsetType; typedef VectorContainer< unsigned char, OffsetType > OffsetVector; typedef typename OffsetVector::Pointer OffsetVectorPointer; typedef typename OffsetVector::ConstPointer OffsetVectorConstPointer; typedef EnhancedScalarImageToSizeZoneMatrixFilter< ImageType, FrequencyContainerType > SizeZoneMatrixFilterType; typedef typename SizeZoneMatrixFilterType::HistogramType HistogramType; typedef EnhancedHistogramToSizeZoneFeaturesFilter< HistogramType > SizeZoneFeaturesFilterType; typedef short SizeZoneFeatureName; typedef VectorContainer FeatureNameVector; typedef typename FeatureNameVector::Pointer FeatureNameVectorPointer; typedef typename FeatureNameVector::ConstPointer FeatureNameVectorConstPointer; typedef VectorContainer< unsigned char, double > FeatureValueVector; typedef typename FeatureValueVector::Pointer FeatureValueVectorPointer; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef DataObjectDecorator< FeatureValueVector > FeatureValueVectorDataObjectType; const FeatureValueVectorDataObjectType * GetFeatureMeansOutput() const; const FeatureValueVectorDataObjectType * GetFeatureStandardDeviationsOutput() const; /** Connects the input image for which the features are going to be computed */ using Superclass::SetInput; void SetInput(const ImageType *); const ImageType * GetInput() const; /** Return the feature means and deviations. */ itkGetConstReferenceObjectMacro(FeatureMeans, FeatureValueVector); itkGetConstReferenceObjectMacro(FeatureStandardDeviations, FeatureValueVector); /** Set the desired feature set. Optional, for default value see above. */ itkSetConstObjectMacro(RequestedFeatures, FeatureNameVector); itkGetConstObjectMacro(RequestedFeatures, FeatureNameVector); /** Set the offsets over which the co-occurrence pairs will be computed. Optional; for default value see above. */ itkSetConstObjectMacro(Offsets, OffsetVector); itkGetConstObjectMacro(Offsets, OffsetVector); /** Set number of histogram bins along each axis. Optional; for default value see above. */ void SetNumberOfBinsPerAxis(unsigned int); /** Set the min and max (inclusive) pixel value that will be used for feature calculations. Optional; for default value see above. */ void SetPixelValueMinMax(PixelType min, PixelType max); /** Set the min and max (inclusive) pixel value that will be used for feature calculations. Optional; for default value see above. */ void SetDistanceValueMinMax( double min, double max ); /** Connects the mask image for which the histogram is going to be computed. Optional; for default value see above. */ void SetMaskImage(const ImageType *); const ImageType * GetMaskImage() const; /** Set the pixel value of the mask that should be considered "inside" the object. Optional; for default value see above. */ void SetInsidePixelValue(PixelType InsidePixelValue); itkGetConstMacro(FastCalculations, bool); itkSetMacro(FastCalculations, bool); itkBooleanMacro(FastCalculations); protected: EnhancedScalarImageToSizeZoneFeaturesFilter(); virtual ~EnhancedScalarImageToSizeZoneFeaturesFilter() {} virtual void PrintSelf( std::ostream & os, Indent indent ) const ITK_OVERRIDE; void FastCompute(); void FullCompute(); /** This method causes the filter to generate its output. */ virtual void GenerateData() ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; virtual DataObjectPointer MakeOutput(DataObjectPointerArraySizeType) ITK_OVERRIDE; private: typename SizeZoneMatrixFilterType::Pointer m_SizeZoneMatrixGenerator; FeatureValueVectorPointer m_FeatureMeans; FeatureValueVectorPointer m_FeatureStandardDeviations; FeatureNameVectorConstPointer m_RequestedFeatures; OffsetVectorConstPointer m_Offsets; bool m_FastCalculations; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx index 351002f7ec..98e29defaa 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx @@ -1,408 +1,408 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToSizeZoneFeaturesFilter_hxx #define __itkEnhancedScalarImageToSizeZoneFeaturesFilter_hxx #include "itkEnhancedScalarImageToSizeZoneFeaturesFilter.h" #include "itkNeighborhood.h" #include #include "vnl/vnl_math.h" namespace itk { namespace Statistics { template EnhancedScalarImageToSizeZoneFeaturesFilter ::EnhancedScalarImageToSizeZoneFeaturesFilter() { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 1 ); for( int i = 0; i < 2; ++i ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } this->m_SizeZoneMatrixGenerator = SizeZoneMatrixFilterType::New(); this->m_FeatureMeans = FeatureValueVector::New(); this->m_FeatureStandardDeviations = FeatureValueVector::New(); // Set the requested features to the default value: // {Energy, Entropy, InverseDifferenceMoment, Inertia, ClusterShade, // ClusterProminence} FeatureNameVectorPointer requestedFeatures = FeatureNameVector::New(); // can't directly set this->m_RequestedFeatures since it is const! requestedFeatures->push_back( SizeZoneFeaturesFilterType::SmallZoneEmphasis ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::LargeZoneEmphasis ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::GreyLevelNonuniformity ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::GreyLevelNonuniformityNormalized ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::SizeZoneNonuniformity ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::SizeZoneNonuniformityNormalized ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::LowGreyLevelZoneEmphasis ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::HighGreyLevelZoneEmphasis ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::SmallZoneLowGreyLevelEmphasis ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::SmallZoneHighGreyLevelEmphasis ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::LargeZoneLowGreyLevelEmphasis ); requestedFeatures->push_back( SizeZoneFeaturesFilterType::LargeZoneHighGreyLevelEmphasis ); requestedFeatures->push_back( 20 ); this->SetRequestedFeatures( requestedFeatures ); // Set the offset directions to their defaults: half of all the possible // directions 1 pixel away. (The other half is included by symmetry.) // We use a neighborhood iterator to calculate the appropriate offsets. typedef Neighborhood NeighborhoodType; NeighborhoodType hood; hood.SetRadius( 1 ); // select all "previous" neighbors that are face+edge+vertex // connected to the current pixel. do not include the center pixel. unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetVectorPointer offsets = OffsetVector::New(); for( unsigned int d = 0; d < centerIndex; d++ ) { OffsetType offset = hood.GetOffset( d ); offsets->push_back( offset ); } this->SetOffsets( offsets ); this->m_FastCalculations = false; } template typename EnhancedScalarImageToSizeZoneFeaturesFilter ::DataObjectPointer EnhancedScalarImageToSizeZoneFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed(idx) ) { return FeatureValueVectorDataObjectType::New().GetPointer(); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::GenerateData(void) { if ( this->m_FastCalculations ) { this->FastCompute(); } else { this->FullCompute(); } } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::FullCompute() { int numOffsets = this->m_Offsets->size(); int numFeatures = this->m_RequestedFeatures->size(); double **features; features = new double *[numOffsets]; for( int i = 0; i < numOffsets; i++ ) { features[i] = new double[numFeatures]; } unsigned long numberOfVoxels = 0; ImageRegionConstIterator voxelCountIter(this->GetMaskImage(),this->GetMaskImage()->GetLargestPossibleRegion()); while ( ! voxelCountIter.IsAtEnd() ) { if (voxelCountIter.Get() > 0) ++numberOfVoxels; ++voxelCountIter; } // For each offset, calculate each feature typename OffsetVector::ConstIterator offsetIt; int offsetNum, featureNum; typedef typename SizeZoneFeaturesFilterType::SizeZoneFeatureName InternalSizeZoneFeatureName; for( offsetIt = this->m_Offsets->Begin(), offsetNum = 0; offsetIt != this->m_Offsets->End(); offsetIt++, offsetNum++ ) { this->m_SizeZoneMatrixGenerator->SetOffset( offsetIt.Value() ); this->m_SizeZoneMatrixGenerator->Update(); typename SizeZoneFeaturesFilterType::Pointer SizeZoneMatrixCalculator = SizeZoneFeaturesFilterType::New(); SizeZoneMatrixCalculator->SetInput( this->m_SizeZoneMatrixGenerator->GetOutput() ); SizeZoneMatrixCalculator->SetNumberOfVoxels(numberOfVoxels); SizeZoneMatrixCalculator->Update(); typename FeatureNameVector::ConstIterator fnameIt; for( fnameIt = this->m_RequestedFeatures->Begin(), featureNum = 0; fnameIt != this->m_RequestedFeatures->End(); fnameIt++, featureNum++ ) { features[offsetNum][featureNum] = SizeZoneMatrixCalculator->GetFeature( ( InternalSizeZoneFeatureName )fnameIt.Value() ); } } // Now get the mean and deviaton of each feature across the offsets. this->m_FeatureMeans->clear(); this->m_FeatureStandardDeviations->clear(); double *tempFeatureMeans = new double[numFeatures]; double *tempFeatureDevs = new double[numFeatures]; /*Compute incremental mean and SD, a la Knuth, "The Art of Computer Programming, Volume 2: Seminumerical Algorithms", section 4.2.2. Compute mean and standard deviation using the recurrence relation: M(1) = x(1), M(k) = M(k-1) + (x(k) - M(k-1) ) / k S(1) = 0, S(k) = S(k-1) + (x(k) - M(k-1)) * (x(k) - M(k)) for 2 <= k <= n, then sigma = std::sqrt(S(n) / n) (or divide by n-1 for sample SD instead of population SD). */ // Set up the initial conditions (k = 1) for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { tempFeatureMeans[featureNum] = features[0][featureNum]; tempFeatureDevs[featureNum] = 0; } // Zone through the recurrence (k = 2 ... N) for( offsetNum = 1; offsetNum < numOffsets; offsetNum++ ) { int k = offsetNum + 1; for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { double M_k_minus_1 = tempFeatureMeans[featureNum]; double S_k_minus_1 = tempFeatureDevs[featureNum]; double x_k = features[offsetNum][featureNum]; double M_k = M_k_minus_1 + ( x_k - M_k_minus_1 ) / k; double S_k = S_k_minus_1 + ( x_k - M_k_minus_1 ) * ( x_k - M_k ); tempFeatureMeans[featureNum] = M_k; tempFeatureDevs[featureNum] = S_k; } } for( featureNum = 0; featureNum < numFeatures; featureNum++ ) { tempFeatureDevs[featureNum] = std::sqrt( tempFeatureDevs[featureNum] / numOffsets ); this->m_FeatureMeans->push_back( tempFeatureMeans[featureNum] ); this->m_FeatureStandardDeviations->push_back( tempFeatureDevs[featureNum] ); } FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); meanOutputObject->Set( this->m_FeatureMeans ); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); delete[] tempFeatureMeans; delete[] tempFeatureDevs; for( int i = 0; i < numOffsets; i++ ) { delete[] features[i]; } delete[] features; } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::FastCompute() { // Compute the feature for the first offset typename OffsetVector::ConstIterator offsetIt = this->m_Offsets->Begin(); this->m_SizeZoneMatrixGenerator->SetOffset( offsetIt.Value() ); this->m_SizeZoneMatrixGenerator->Update(); typename SizeZoneFeaturesFilterType::Pointer SizeZoneMatrixCalculator = SizeZoneFeaturesFilterType::New(); SizeZoneMatrixCalculator->SetInput( this->m_SizeZoneMatrixGenerator->GetOutput() ); SizeZoneMatrixCalculator->Update(); typedef typename SizeZoneFeaturesFilterType::SizeZoneFeatureName InternalSizeZoneFeatureName; this->m_FeatureMeans->clear(); this->m_FeatureStandardDeviations->clear(); typename FeatureNameVector::ConstIterator fnameIt; for( fnameIt = this->m_RequestedFeatures->Begin(); fnameIt != this->m_RequestedFeatures->End(); fnameIt++ ) { this->m_FeatureMeans->push_back( SizeZoneMatrixCalculator->GetFeature( ( InternalSizeZoneFeatureName )fnameIt.Value() ) ); this->m_FeatureStandardDeviations->push_back( 0.0 ); } FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); meanOutputObject->Set( this->m_FeatureMeans ); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::SetInput( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast( image ) ); this->m_SizeZoneMatrixGenerator->SetInput( image ); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::SetNumberOfBinsPerAxis( unsigned int numberOfBins ) { itkDebugMacro( "setting NumberOfBinsPerAxis to " << numberOfBins ); this->m_SizeZoneMatrixGenerator->SetNumberOfBinsPerAxis( numberOfBins ); this->Modified(); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::SetPixelValueMinMax( PixelType min, PixelType max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_SizeZoneMatrixGenerator->SetPixelValueMinMax( min, max ); this->Modified(); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::SetDistanceValueMinMax( double min, double max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_SizeZoneMatrixGenerator->SetDistanceValueMinMax( min, max ); this->Modified(); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::SetMaskImage( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast< ImageType * >( image ) ); this->m_SizeZoneMatrixGenerator->SetMaskImage( image ); } template const TImage * EnhancedScalarImageToSizeZoneFeaturesFilter ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 0 ) ); } template const typename EnhancedScalarImageToSizeZoneFeaturesFilter ::FeatureValueVectorDataObjectType * EnhancedScalarImageToSizeZoneFeaturesFilter ::GetFeatureMeansOutput() const { return itkDynamicCastInDebugMode (this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedScalarImageToSizeZoneFeaturesFilter ::FeatureValueVectorDataObjectType * EnhancedScalarImageToSizeZoneFeaturesFilter ::GetFeatureStandardDeviationsOutput() const { return itkDynamicCastInDebugMode< const FeatureValueVectorDataObjectType * > ( this->ProcessObject::GetOutput( 1 ) ); } template const TImage * EnhancedScalarImageToSizeZoneFeaturesFilter ::GetMaskImage() const { if ( this->GetNumberOfInputs() < 2 ) { return ITK_NULLPTR; } return static_cast< const ImageType *>( this->ProcessObject::GetInput( 1 ) ); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::SetInsidePixelValue( PixelType insidePixelValue ) { itkDebugMacro( "setting InsidePixelValue to " << insidePixelValue ); this->m_SizeZoneMatrixGenerator->SetInsidePixelValue( insidePixelValue ); this->Modified(); } template void EnhancedScalarImageToSizeZoneFeaturesFilter ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "RequestedFeatures: " << this->GetRequestedFeatures() << std::endl; os << indent << "FeatureStandardDeviations: " << this->GetFeatureStandardDeviations() << std::endl; os << indent << "FastCalculations: " << this->GetFastCalculations() << std::endl; os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "FeatureMeans: " << this->GetFeatureMeans() << std::endl; } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.h index b160e4a9e8..f8dc88f691 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.h @@ -1,279 +1,279 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToSizeZoneMatrixFilter_h #define __itkEnhancedScalarImageToSizeZoneMatrixFilter_h #include "itkImage.h" #include "itkHistogram.h" #include "itkNumericTraits.h" #include "itkVectorContainer.h" namespace itk { namespace Statistics { /** \class EnhancedScalarImageToSizeZoneMatrixFilter * \brief This class computes a run length matrix (histogram) from * a given image and a mask image if provided. Run length matrces are * used for image texture description. * * This filters creates a grey-level run length matrix from a N-D scalar * image. This is another possible texture description. See the following * references. * M. M. Galloway. Texture analysis using gray level run lengths. Computer * Graphics and Image Processing, 4:172-179, 1975. * * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, * 1990. * * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, * 1991. * * The basic idea is as follows: * Given an image and an offset (e.g. (1, -1) for a 2-d image), each element * in the joint histogram describes the frequency for a particular distance/ * intensity pair within a given image. This distance/intensity pair can be * described as follows: we start at a given voxel which has some intensity. * We then "jump" to neighboring pixels in increments provided by the offset(s) * as long as the pixel to which we are jumping is within the same intensity * bin as the original voxel. The distance component is given by the distance * from the original to the final voxel satisfying our jumping criteria. * * The offset (or offsets) along which the co-occurences are calculated can be * set by the user. Traditionally, only one offset is used per histogram, and * offset components in the range [-1, 1] are used. For rotation-invariant * features averages of features computed over several histograms with different * offsets are generally used, instead of computing features from one histogram * create with several offsets. Additionally, instead of using offsets of two or * more pixels in any direction, multi-resolution techniques (e.g. image * pyramids) are generally used to deal with texture at different spatial * resolutions. * * This class calculates a 2-d histogram of all the intensity/distance pairs in * the given image's requested region, for a given set of offsets. That is, if * a given offset falls outside of the requested region (or outside the mask) * at a particular point, that distance/intensity pair will not be added to * the matrix. * * The number of histogram bins on each axis can be set (defaults to 256). Also, * by default the histogram min and max corresponds to the largest and smallest * possible pixel value of that pixel type. To customize the histogram bounds * for a given image, the max and min pixel values that will be placed in the * histogram can be set manually. NB: The min and max are INCLUSIVE. * * Further, the type of histogram frequency container used is an optional * template parameter. By default, a dense container is used, but for images * with little texture or in cases where the user wants more histogram bins, * a sparse container can be used for the histogram instead. * * WARNING: This probably won't work for pixels of double or long-double type * unless you set the histogram min and max manually. This is because the largest * histogram bin by default has max value of the largest possible pixel value * plus 1. For double and long-double types, whose "RealType" as defined by the * NumericTraits class is the same, and thus cannot hold any larger values, * this would cause a float overflow. * - * IJ article: http://hdl.handle.net/1926/1374 + * IJ article: https://hdl.handle.net/1926/1374 * * \sa ScalarImageToSizeZoneFeaturesFilter * \sa EnhancedScalarImageToSizeZoneMatrixFilter * \sa HistogramToSizeZoneFeaturesFilter * * \author: Nick Tustison * \ingroup ITKStatistics */ template class EnhancedScalarImageToSizeZoneMatrixFilter : public ProcessObject { public: /** Standard typedefs */ typedef EnhancedScalarImageToSizeZoneMatrixFilter Self; typedef ProcessObject Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro( EnhancedScalarImageToSizeZoneMatrixFilter, ProcessObject ); /** standard New() method support */ itkNewMacro( Self ); typedef TImageType ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::ConstPointer ImageConstPointer; typedef typename ImageType::PixelType PixelType; typedef typename ImageType::IndexType IndexType; typedef typename ImageType::RegionType RegionType; typedef typename ImageType::SizeType RadiusType; typedef typename ImageType::OffsetType OffsetType; typedef VectorContainer OffsetVector; typedef typename OffsetVector::Pointer OffsetVectorPointer; typedef typename ImageType::PointType PointType; typedef typename NumericTraits::RealType MeasurementType; typedef typename NumericTraits::RealType RealType; typedef Histogram HistogramType; typedef typename HistogramType::Pointer HistogramPointer; typedef typename HistogramType::ConstPointer HistogramConstPointer; typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; /** ImageDimension constants */ itkStaticConstMacro( ImageDimension, unsigned int, TImageType::ImageDimension ); /** Specify the default number of bins per axis */ itkStaticConstMacro( DefaultBinsPerAxis, unsigned int, 256 ); /** * Set the offsets over which the intensity/distance pairs will be computed. * Invoking this function clears the previous offsets. * Note: for each individual offset in the OffsetVector, the rightmost non-zero * offset element must be positive. For example, in the offset list of a 2D image, * (1, 0) means the offset along x-axis. (1, 0) has to be set instead * of (-1, 0). This is required from the iterating order of pixel iterator. * */ itkSetObjectMacro( Offsets, OffsetVector ); /** * Set offset over which the intensity/distance pairs will be computed. * Invoking this function clears the previous offset(s). * Note: for each individual offset, the rightmost non-zero * offset element must be positive. For example, in the offset list of a 2D image, * (1, 0) means the offset along x-axis. (1, 0) has to be set instead * of (-1, 0). This is required from the iterating order of pixel iterator. * */ void SetOffset( const OffsetType offset ); /** * Get the current offset(s). */ itkGetModifiableObjectMacro(Offsets, OffsetVector ); /** Set number of histogram bins along each axis */ itkSetMacro( NumberOfBinsPerAxis, unsigned int ); /** Get number of histogram bins along each axis */ itkGetConstMacro( NumberOfBinsPerAxis, unsigned int ); /** * Set the min and max (inclusive) pixel value that will be used in * generating the histogram. */ void SetPixelValueMinMax( PixelType min, PixelType max ); /** Get the min pixel value defining one dimension of the joint histogram. */ itkGetConstMacro( Min, PixelType ); /** Get the max pixel value defining one dimension of the joint histogram. */ itkGetConstMacro( Max, PixelType ); /** * Set the min and max (inclusive) pixel value that will be used in * generating the histogram. */ void SetDistanceValueMinMax( RealType min, RealType max ); /** * Get the min distance value defining one dimension of the joint histogram. */ itkGetConstMacro( MinDistance, RealType ); /** * Get the max distance value defining one dimension of the joint histogram. */ itkGetConstMacro( MaxDistance, RealType ); /** Method to set the input image */ using Superclass::SetInput; void SetInput( const ImageType *image ); /** Method to get the input image */ const ImageType * GetInput() const; /** Method to set the mask image */ void SetMaskImage( const ImageType *image ); /** Method to get the mask image */ const ImageType * GetMaskImage() const; /** method to get the Histogram */ const HistogramType * GetOutput() const; /** * Set the pixel value of the mask that should be considered "inside" the * object. Defaults to 1. */ itkSetMacro( InsidePixelValue, PixelType ); itkGetConstMacro( InsidePixelValue, PixelType ); protected: EnhancedScalarImageToSizeZoneMatrixFilter(); virtual ~EnhancedScalarImageToSizeZoneMatrixFilter() {}; virtual void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE; /** Standard itk::ProcessObject subclass method. */ typedef DataObject::Pointer DataObjectPointer; typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; virtual DataObjectPointer MakeOutput( DataObjectPointerArraySizeType idx ) ITK_OVERRIDE; /** This method causes the filter to generate its output. */ virtual void GenerateData() ITK_OVERRIDE; private: unsigned int m_NumberOfBinsPerAxis; PixelType m_Min; PixelType m_Max; RealType m_MinDistance; RealType m_MaxDistance; PixelType m_InsidePixelValue; MeasurementVectorType m_LowerBound; MeasurementVectorType m_UpperBound; OffsetVectorPointer m_Offsets; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx index 7113889382..80ecac0cd5 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx @@ -1,405 +1,405 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToSizeZoneMatrixFilter_hxx #define __itkEnhancedScalarImageToSizeZoneMatrixFilter_hxx #include "itkEnhancedScalarImageToSizeZoneMatrixFilter.h" #include "itkConstNeighborhoodIterator.h" #include "itkNeighborhood.h" #include "vnl/vnl_math.h" #include "itkMacro.h" #include "itkRescaleIntensityImageFilter.h" #include "itkMaskImageFilter.h" #include "itkLabelStatisticsImageFilter.h" #include "itkScalarConnectedComponentImageFilter.h" #include "itkRelabelComponentImageFilter.h" #include "itkCastImageFilter.h" #include namespace itk { namespace Statistics { template EnhancedScalarImageToSizeZoneMatrixFilter ::EnhancedScalarImageToSizeZoneMatrixFilter() : m_NumberOfBinsPerAxis( itkGetStaticConstMacro( DefaultBinsPerAxis ) ), m_Min( NumericTraits::NonpositiveMin() ), m_Max( NumericTraits::max() ), m_MinDistance( NumericTraits::ZeroValue() ), m_MaxDistance( NumericTraits::max() ), m_InsidePixelValue( NumericTraits::OneValue() ) { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 1 ); const unsigned int measurementVectorSize = 2; this->ProcessObject::SetNthOutput( 0, this->MakeOutput( 0 ) ); HistogramType *output = const_cast( this->GetOutput() ); output->SetMeasurementVectorSize( measurementVectorSize ); this->m_LowerBound.SetSize( measurementVectorSize ); this->m_UpperBound.SetSize( measurementVectorSize ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; } template void EnhancedScalarImageToSizeZoneMatrixFilter ::SetOffset( const OffsetType offset ) { OffsetVectorPointer offsetVector = OffsetVector::New(); offsetVector->push_back( offset ); this->SetOffsets( offsetVector ); } template void EnhancedScalarImageToSizeZoneMatrixFilter ::SetInput( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast( image ) ); } template void EnhancedScalarImageToSizeZoneMatrixFilter ::SetMaskImage( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast( image ) ); } template const TImageType * EnhancedScalarImageToSizeZoneMatrixFilter ::GetInput() const { if( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 0 ) ); } template const TImageType * EnhancedScalarImageToSizeZoneMatrixFilter ::GetMaskImage() const { if( this->GetNumberOfInputs() < 2 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 1 ) ); } template const typename EnhancedScalarImageToSizeZoneMatrixFilter::HistogramType * EnhancedScalarImageToSizeZoneMatrixFilter ::GetOutput() const { const HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); return output; } template typename EnhancedScalarImageToSizeZoneMatrixFilter::DataObjectPointer EnhancedScalarImageToSizeZoneMatrixFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return HistogramType::New().GetPointer(); } template void EnhancedScalarImageToSizeZoneMatrixFilter ::GenerateData() { HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); const ImageType * inputImage = this->GetInput(); const ImageType * maskImage = this->GetMaskImage(); // First, create an appropriate histogram with the right number of bins // and mins and maxes correct for the image type. typename HistogramType::SizeType size( output->GetMeasurementVectorSize() ); size.Fill( this->m_NumberOfBinsPerAxis ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; output->Initialize( size, this->m_LowerBound, this->m_UpperBound ); MeasurementVectorType run( output->GetMeasurementVectorSize() ); typename HistogramType::IndexType hIndex; //Cast the image to a float image - with no respect to the incoming image //to prevent some non-templated itk issues typedef itk::Image FloatImageType; typedef itk::CastImageFilter CastFilterType; typename CastFilterType::Pointer caster = CastFilterType::New(); caster->SetInput(inputImage); caster->Update(); typename FloatImageType::Pointer floatImage = caster->GetOutput(); //MITK_WARN << "InputImage casted."; //Cast the mask to an unsigned short image - with no respect to the incomimg maskimage //to prevent some non-templated itk issues typedef unsigned short LabelPixelType; typedef itk::Image LabelImageType; typedef itk::CastImageFilter MaskCastFilterType; typename MaskCastFilterType::Pointer maskCaster = MaskCastFilterType::New(); maskCaster->SetInput(maskImage); maskCaster->Update(); //MITK_WARN << "MaskImage casted."; //Set all values out of the mask to (m_Min + m_Max) / 2. typedef itk::MaskImageFilter< FloatImageType, LabelImageType, FloatImageType > MaskFilterType; typename MaskFilterType::Pointer maskFilter = MaskFilterType::New(); maskFilter->SetInput(floatImage); maskFilter->SetMaskImage(maskCaster->GetOutput()); maskFilter->SetOutsideValue((m_Max + m_Min) / 2); maskFilter->Update(); //MITK_WARN << "InputImage masked."; //Rescale intensity to match the size of the histogram typedef itk::Image< unsigned int, 3 > OutputImageType; typedef itk::RescaleIntensityImageFilter< FloatImageType,OutputImageType> RescalerType; typename RescalerType::Pointer rescaler = RescalerType::New(); //We use 0 for nans, all valid numbers will be 1 < x < size rescaler->SetOutputMinimum( 1 ); rescaler->SetOutputMaximum( size[0] ); rescaler->SetInput(maskFilter->GetOutput()); rescaler->Update(); typename OutputImageType::Pointer rescaled = rescaler->GetOutput(); //MITK_WARN << "Intensities rescaled."; //Write back the nans because they get lost during rescaling int xx = inputImage->GetLargestPossibleRegion().GetSize()[0]; int yy = inputImage->GetLargestPossibleRegion().GetSize()[1]; int zz = inputImage->GetLargestPossibleRegion().GetSize()[2]; for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { FloatImageType::IndexType indexF; indexF[0] = x; indexF[1] = y; indexF[2] = z; OutputImageType::IndexType indexO; indexO[0] = x; indexO[1] = y; indexO[2] = z; //Is Pixel NaN? if(floatImage->GetPixel(indexF) != floatImage->GetPixel(indexF)) { rescaled->SetPixel(indexO,0); } } } } //All nans are now 0, the valid values are within [1,numberOfBins] /* OutputImageType::IndexType indexO; indexO[0] = 0; indexO[1] = 2; indexO[2] = 1; MITK_WARN << "is 0: " << rescaled->GetPixel(indexO); indexO[0] = 0; indexO[1] = 0; indexO[2] = 0; MITK_WARN << "is 1: " << rescaled->GetPixel(indexO); */ PixelType distanceThreshold = 1 - mitk::eps; //Calculate the connected components typedef itk::ScalarConnectedComponentImageFilter ConnectedComponentImageFilterType; typename ConnectedComponentImageFilterType::Pointer connected = ConnectedComponentImageFilterType::New (); connected->SetInput(rescaled); connected->SetMaskImage(maskCaster->GetOutput()); connected->SetDistanceThreshold(distanceThreshold); connected->Update(); /* indexO[0] = 0; indexO[1] = 2; indexO[2] = 1; MITK_WARN << "is 0: " << (connected->GetOutput())->GetPixel(indexO); indexO[0] = 0; indexO[1] = 0; indexO[2] = 0; MITK_WARN << "is 1: " << (connected->GetOutput())->GetPixel(indexO); MITK_WARN << "Connected components calculated."; */ //Relabel the components typedef itk::RelabelComponentImageFilter RelabelFilterType; typename RelabelFilterType::Pointer relabel = RelabelFilterType::New(); typename RelabelFilterType::ObjectSizeType minSize = 1; relabel->SetInput(connected->GetOutput()); relabel->SetMinimumObjectSize(minSize); relabel->Update(); //MITK_WARN << "Components relabeled."; //Get the stats of the componentes typedef itk::LabelStatisticsImageFilter< FloatImageType, OutputImageType> LabelStatisticsImageFilterType; typename LabelStatisticsImageFilterType::Pointer labelStatisticsImageFilter = LabelStatisticsImageFilterType::New(); labelStatisticsImageFilter->SetLabelInput( relabel->GetOutput() ); labelStatisticsImageFilter->SetInput(floatImage); labelStatisticsImageFilter->UseHistogramsOn(); // needed to compute median labelStatisticsImageFilter->Update(); /* std::cout << "Number of labels: " << labelStatisticsImageFilter->GetNumberOfLabels() << std::endl; std::cout << std::endl; */ typedef typename LabelStatisticsImageFilterType::ValidLabelValuesContainerType ValidLabelValuesType; for(typename ValidLabelValuesType::const_iterator vIt = labelStatisticsImageFilter->GetValidLabelValues().begin(); vIt != labelStatisticsImageFilter->GetValidLabelValues().end(); ++vIt) { if ( labelStatisticsImageFilter->HasLabel(*vIt) ) { LabelPixelType labelValue = *vIt; run[0] = labelStatisticsImageFilter->GetMean( labelValue ); run[1] = labelStatisticsImageFilter->GetCount( labelValue ); //Check for NaN and inf if(run[0] == run[0] && !std::isinf(std::abs(run[0]))) { output->GetIndex( run, hIndex ); output->IncreaseFrequencyOfIndex( hIndex, 1 ); /* MITK_INFO << "Adding a region:"; MITK_INFO << "\tmin: " << labelStatisticsImageFilter->GetMinimum( labelValue ); MITK_INFO << "\tmax: " << labelStatisticsImageFilter->GetMaximum( labelValue ); MITK_INFO << "\tmean: " << labelStatisticsImageFilter->GetMean( labelValue ); MITK_INFO << "\tcount: " << labelStatisticsImageFilter->GetCount( labelValue ); */ } } } } template void EnhancedScalarImageToSizeZoneMatrixFilter ::SetPixelValueMinMax( PixelType min, PixelType max ) { if( this->m_Min != min || this->m_Max != max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_Min = min; this->m_Max = max; this->Modified(); } } template void EnhancedScalarImageToSizeZoneMatrixFilter ::SetDistanceValueMinMax( RealType min, RealType max ) { if( this->m_MinDistance != min || this->m_MaxDistance != max ) { itkDebugMacro( "setting MinDistance to " << min << "and MaxDistance to " << max ); this->m_MinDistance = min; this->m_MaxDistance = max; this->Modified(); } } template void EnhancedScalarImageToSizeZoneMatrixFilter ::PrintSelf( std::ostream& os, Indent indent ) const { Superclass::PrintSelf( os,indent ); os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "Min: " << this->m_Min << std::endl; os << indent << "Max: " << this->m_Max << std::endl; os << indent << "Min distance: " << this->m_MinDistance << std::endl; os << indent << "Max distance: " << this->m_MaxDistance << std::endl; os << indent << "NumberOfBinsPerAxis: " << this->m_NumberOfBinsPerAxis << std::endl; os << indent << "InsidePixelValue: " << this->m_InsidePixelValue << std::endl; } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.h index f42ddf4fa7..a3383d9723 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.h +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.h @@ -1,245 +1,245 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToTextureFeaturesFilter_h #define __itkEnhancedScalarImageToTextureFeaturesFilter_h #include "itkDataObjectDecorator.h" #include "itkEnhancedHistogramToTextureFeaturesFilter.h" #include "itkScalarImageToCooccurrenceMatrixFilter.h" namespace itk { namespace Statistics { /** \class EnhancedScalarImageToTextureFeaturesFilter * \brief This class computes texture descriptions from an image. * * This class computes features that summarize the texture of a given image. * The texture features are computed a la Haralick, and have proven to be useful * in image classification for biological and medical imaging. * This class computes the texture features of an image (optionally in a * masked region), averaged across several spatial directions so that they are * invariant to rotation. * * By default, texure features are computed for each spatial * direction and then averaged afterward, so it is possible to access the standard * deviations of the texture features. These values give a clue as to texture * anisotropy. However, doing this is much more work, because it involved computing * one GLCM for each offset given. To compute a single GLCM using the first offset , * call FastCalculationsOn(). If this is called, then the texture standard deviations * will not be computed (and will be set to zero), but texture computation will * be much faster. * * This class is templated over the input image type. * * Template Parameters: * The image type, and the type of histogram frequency container. If you are using * a large number of bins per axis, a sparse frequency container may be advisable. * The default is to use a dense frequency container. * * Inputs and parameters: * -# An image * -# A mask defining the region over which texture features will be * calculated. (Optional) * -# The pixel value that defines the "inside" of the mask. (Optional, defaults * to 1 if a mask is set.) * -# The set of features to be calculated. These features are defined * in the GreyLevelCooccurrenceMatrixTextureCoefficientsCalculator class. (Optional, * defaults to {Energy, Entropy, InverseDifferenceMoment, Inertia, ClusterShade, * ClusterProminence}, as in Conners, Trivedi and Harlow.) * -# The number of intensity bins. (Optional, defaults to 256.) * -# The set of directions (offsets) to average across. (Optional, defaults to * {(-1, 0), (-1, -1), (0, -1), (1, -1)} for 2D images and scales analogously for ND * images.) * -# The pixel intensity range over which the features will be calculated. * (Optional, defaults to the full dynamic range of the pixel type.) * * In general, the default parameter values should be sufficient. * * Outputs: * (1) The average value of each feature. * (2) The standard deviation in the values of each feature. * * Web reference: - * http://www.fp.ucalgary.ca/mhallbey/tutorial.htm + * https://prism.ucalgary.ca/handle/1880/51900 * * Print references: * Haralick, R.M., K. Shanmugam and I. Dinstein. 1973. Textural Features for * Image Classification. IEEE Transactions on Systems, Man and Cybernetics. * SMC-3(6):610-620. * * Haralick, R.M. 1979. Statistical and Structural Approaches to Texture. * Proceedings of the IEEE, 67:786-804. * * R.W. Conners and C.A. Harlow. A Theoretical Comaprison of Texture Algorithms. * IEEE Transactions on Pattern Analysis and Machine Intelligence, 2:204-222, 1980. * * R.W. Conners, M.M. Trivedi, and C.A. Harlow. Segmentation of a High-Resolution * Urban Scene using Texture Operators. Computer Vision, Graphics and Image * Processing, 25:273-310, 1984. * * \sa ScalarImageToCooccurrenceMatrixFilter * \sa HistogramToTextureFeaturesFilter * * Author: Zachary Pincus * \ingroup ITKStatistics */ template< typename TImageType, typename THistogramFrequencyContainer = DenseFrequencyContainer2 > class EnhancedScalarImageToTextureFeaturesFilter:public ProcessObject { public: /** Standard typedefs */ typedef EnhancedScalarImageToTextureFeaturesFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; /** Run-time type information (and related methods). */ itkTypeMacro(EnhancedScalarImageToTextureFeaturesFilter, ProcessObject); /** standard New() method support */ itkNewMacro(Self); typedef THistogramFrequencyContainer FrequencyContainerType; typedef TImageType ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::PixelType PixelType; typedef typename ImageType::OffsetType OffsetType; typedef VectorContainer< unsigned char, OffsetType > OffsetVector; typedef typename OffsetVector::Pointer OffsetVectorPointer; typedef typename OffsetVector::ConstPointer OffsetVectorConstPointer; typedef ScalarImageToCooccurrenceMatrixFilter< ImageType, FrequencyContainerType > CooccurrenceMatrixFilterType; typedef typename CooccurrenceMatrixFilterType::HistogramType HistogramType; typedef EnhancedHistogramToTextureFeaturesFilter< HistogramType > TextureFeaturesFilterType; typedef short TextureFeatureName; typedef VectorContainer< unsigned char, TextureFeatureName > FeatureNameVector; typedef typename FeatureNameVector::Pointer FeatureNameVectorPointer; typedef typename FeatureNameVector::ConstPointer FeatureNameVectorConstPointer; typedef VectorContainer< unsigned char, double > FeatureValueVector; typedef typename FeatureValueVector::Pointer FeatureValueVectorPointer; /** Smart Pointer type to a DataObject. */ typedef DataObject::Pointer DataObjectPointer; /** Type of DataObjects used for scalar outputs */ typedef DataObjectDecorator< FeatureValueVector > FeatureValueVectorDataObjectType; const FeatureValueVectorDataObjectType * GetFeatureMeansOutput() const; const FeatureValueVectorDataObjectType * GetFeatureStandardDeviationsOutput() const; /** Connects the input image for which the features are going to be computed */ using Superclass::SetInput; void SetInput(const ImageType *); const ImageType * GetInput() const; /** Return the feature means and deviations. */ itkGetConstReferenceObjectMacro(FeatureMeans, FeatureValueVector); itkGetConstReferenceObjectMacro(FeatureStandardDeviations, FeatureValueVector); /** Set the desired feature set. Optional, for default value see above. */ itkSetConstObjectMacro(RequestedFeatures, FeatureNameVector); itkGetConstObjectMacro(RequestedFeatures, FeatureNameVector); /** Set the offsets over which the co-occurrence pairs will be computed. Optional; for default value see above. */ itkSetConstObjectMacro(Offsets, OffsetVector); itkGetConstObjectMacro(Offsets, OffsetVector); /** Set number of histogram bins along each axis. Optional; for default value see above. */ void SetNumberOfBinsPerAxis(unsigned int); /** Set the min and max (inclusive) pixel value that will be used for feature calculations. Optional; for default value see above. */ void SetPixelValueMinMax(PixelType min, PixelType max); /** Connects the mask image for which the histogram is going to be computed. Optional; for default value see above. */ void SetMaskImage(const ImageType *); const ImageType * GetMaskImage() const; /** Set the pixel value of the mask that should be considered "inside" the object. Optional; for default value see above. */ void SetInsidePixelValue(PixelType InsidePixelValue); itkGetConstMacro(FastCalculations, bool); itkSetMacro(FastCalculations, bool); itkBooleanMacro(FastCalculations); protected: EnhancedScalarImageToTextureFeaturesFilter(); ~EnhancedScalarImageToTextureFeaturesFilter() override {} void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; void FastCompute(); void FullCompute(); /** This method causes the filter to generate its output. */ void GenerateData() ITK_OVERRIDE; /** Make a DataObject to be used for output output. */ typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput(DataObjectPointerArraySizeType) ITK_OVERRIDE; private: typename CooccurrenceMatrixFilterType::Pointer m_GLCMGenerator; typename TextureFeaturesFilterType::Pointer m_GLCMCalculator; FeatureValueVectorPointer m_FeatureMeans; FeatureValueVectorPointer m_FeatureStandardDeviations; FeatureNameVectorConstPointer m_RequestedFeatures; OffsetVectorConstPointer m_Offsets; bool m_FastCalculations; }; } // end of namespace Statistics } // end of namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkEnhancedScalarImageToTextureFeaturesFilter.hxx" #endif #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.hxx index 889a55ebdf..b082a2da7f 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToTextureFeaturesFilter.hxx @@ -1,341 +1,341 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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.txt +* https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 __itkEnhancedScalarImageToTextureFeaturesFilter_hxx #define __itkEnhancedScalarImageToTextureFeaturesFilter_hxx #include "itkEnhancedScalarImageToTextureFeaturesFilter.h" #include "itkNeighborhood.h" #include "vnl/vnl_math.h" namespace itk { namespace Statistics { template< typename TImage, typename THistogramFrequencyContainer > EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::EnhancedScalarImageToTextureFeaturesFilter() { this->SetNumberOfRequiredInputs(1); this->SetNumberOfRequiredOutputs(1); for ( int i = 0; i < 2; ++i ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput(i) ); } this->m_GLCMGenerator = CooccurrenceMatrixFilterType::New(); this->m_GLCMCalculator = TextureFeaturesFilterType::New(); this->m_GLCMCalculator->SetInput( this->m_GLCMGenerator->GetOutput() ); this->m_FeatureMeans = FeatureValueVector::New(); this->m_FeatureStandardDeviations = FeatureValueVector::New(); // Set the requested features to the default value: // {Energy, Entropy, InverseDifferenceMoment, Inertia, ClusterShade, // ClusterProminence} FeatureNameVectorPointer requestedFeatures = FeatureNameVector::New(); // can't directly set m_RequestedFeatures since it is const! requestedFeatures->push_back(TextureFeaturesFilterType::Energy); requestedFeatures->push_back(TextureFeaturesFilterType::Entropy); requestedFeatures->push_back(TextureFeaturesFilterType::InverseDifferenceMoment); requestedFeatures->push_back(TextureFeaturesFilterType::Inertia); requestedFeatures->push_back(TextureFeaturesFilterType::ClusterShade); requestedFeatures->push_back(TextureFeaturesFilterType::ClusterProminence); this->SetRequestedFeatures(requestedFeatures); // Set the offset directions to their defaults: half of all the possible // directions 1 pixel away. (The other half is included by symmetry.) // We use a neighborhood iterator to calculate the appropriate offsets. typedef Neighborhood< typename ImageType::PixelType, ImageType::ImageDimension > NeighborhoodType; NeighborhoodType hood; hood.SetRadius(1); // select all "previous" neighbors that are face+edge+vertex // connected to the current pixel. do not include the center pixel. unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; OffsetVectorPointer offsets = OffsetVector::New(); for ( unsigned int d = 0; d < centerIndex; d++ ) { offset = hood.GetOffset(d); offsets->push_back(offset); } this->SetOffsets(offsets); m_FastCalculations = false; } template< typename TImage, typename THistogramFrequencyContainer > typename EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::DataObjectPointer EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer > ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed(idx) ) { return FeatureValueVectorDataObjectType::New().GetPointer(); } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::GenerateData(void) { if ( m_FastCalculations ) { this->FastCompute(); } else { this->FullCompute(); } } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::FullCompute(void) { int numOffsets = m_Offsets->size(); int numFeatures = m_RequestedFeatures->size(); double **features; features = new double *[numOffsets]; for ( int i = 0; i < numOffsets; i++ ) { features[i] = new double[numFeatures]; } // For each offset, calculate each feature typename OffsetVector::ConstIterator offsetIt; int offsetNum, featureNum; typedef typename TextureFeaturesFilterType::TextureFeatureName InternalTextureFeatureName; for ( offsetIt = m_Offsets->Begin(), offsetNum = 0; offsetIt != m_Offsets->End(); offsetIt++, offsetNum++ ) { this->m_GLCMGenerator->SetOffset( offsetIt.Value() ); this->m_GLCMCalculator->Update(); typename FeatureNameVector::ConstIterator fnameIt; for ( fnameIt = m_RequestedFeatures->Begin(), featureNum = 0; fnameIt != m_RequestedFeatures->End(); fnameIt++, featureNum++ ) { features[offsetNum][featureNum] = this->m_GLCMCalculator->GetFeature( (InternalTextureFeatureName)fnameIt.Value() ); } } // Now get the mean and deviaton of each feature across the offsets. m_FeatureMeans->clear(); m_FeatureStandardDeviations->clear(); double *tempFeatureMeans = new double[numFeatures]; double *tempFeatureDevs = new double[numFeatures]; /*Compute incremental mean and SD, a la Knuth, "The Art of Computer Programming, Volume 2: Seminumerical Algorithms", section 4.2.2. Compute mean and standard deviation using the recurrence relation: M(1) = x(1), M(k) = M(k-1) + (x(k) - M(k-1) ) / k S(1) = 0, S(k) = S(k-1) + (x(k) - M(k-1)) * (x(k) - M(k)) for 2 <= k <= n, then sigma = std::sqrt(S(n) / n) (or divide by n-1 for sample SD instead of population SD). */ // Set up the initial conditions (k = 1) for ( featureNum = 0; featureNum < numFeatures; featureNum++ ) { tempFeatureMeans[featureNum] = features[0][featureNum]; tempFeatureDevs[featureNum] = 0; } // Run through the recurrence (k = 2 ... N) for ( offsetNum = 1; offsetNum < numOffsets; offsetNum++ ) { int k = offsetNum + 1; for ( featureNum = 0; featureNum < numFeatures; featureNum++ ) { double M_k_minus_1 = tempFeatureMeans[featureNum]; double S_k_minus_1 = tempFeatureDevs[featureNum]; double x_k = features[offsetNum][featureNum]; double M_k = M_k_minus_1 + ( x_k - M_k_minus_1 ) / k; double S_k = S_k_minus_1 + ( x_k - M_k_minus_1 ) * ( x_k - M_k ); tempFeatureMeans[featureNum] = M_k; tempFeatureDevs[featureNum] = S_k; } } for ( featureNum = 0; featureNum < numFeatures; featureNum++ ) { tempFeatureDevs[featureNum] = std::sqrt(tempFeatureDevs[featureNum] / numOffsets); m_FeatureMeans->push_back(tempFeatureMeans[featureNum]); m_FeatureStandardDeviations->push_back(tempFeatureDevs[featureNum]); } FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode< FeatureValueVectorDataObjectType * >( this->ProcessObject::GetOutput(0) ); meanOutputObject->Set(m_FeatureMeans); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode< FeatureValueVectorDataObjectType * >( this->ProcessObject::GetOutput(1) ); standardDeviationOutputObject->Set(m_FeatureStandardDeviations); delete[] tempFeatureMeans; delete[] tempFeatureDevs; for ( int i = 0; i < numOffsets; i++ ) { delete[] features[i]; } delete[] features; } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::FastCompute(void) { // Compute the feature for the first offset typename OffsetVector::ConstIterator offsetIt = m_Offsets->Begin(); this->m_GLCMGenerator->SetOffset( offsetIt.Value() ); this->m_GLCMCalculator->Update(); typedef typename TextureFeaturesFilterType::TextureFeatureName InternalTextureFeatureName; m_FeatureMeans->clear(); m_FeatureStandardDeviations->clear(); typename FeatureNameVector::ConstIterator fnameIt; for ( fnameIt = m_RequestedFeatures->Begin(); fnameIt != m_RequestedFeatures->End(); fnameIt++ ) { m_FeatureMeans->push_back( this->m_GLCMCalculator->GetFeature( (InternalTextureFeatureName)fnameIt.Value() ) ); m_FeatureStandardDeviations->push_back(0.0); } FeatureValueVectorDataObjectType *meanOutputObject = itkDynamicCastInDebugMode< FeatureValueVectorDataObjectType * >( this->ProcessObject::GetOutput(0) ); meanOutputObject->Set(m_FeatureMeans); FeatureValueVectorDataObjectType *standardDeviationOutputObject = itkDynamicCastInDebugMode< FeatureValueVectorDataObjectType * >( this->ProcessObject::GetOutput(1) ); standardDeviationOutputObject->Set(m_FeatureStandardDeviations); } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::SetInput(const ImageType *image) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast< ImageType * >( image ) ); m_GLCMGenerator->SetInput(image); } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::SetNumberOfBinsPerAxis( unsigned int numberOfBins) { itkDebugMacro("setting NumberOfBinsPerAxis to " << numberOfBins); m_GLCMGenerator->SetNumberOfBinsPerAxis(numberOfBins); this->Modified(); } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::SetPixelValueMinMax(PixelType min, PixelType max) { itkDebugMacro("setting Min to " << min << "and Max to " << max); m_GLCMGenerator->SetPixelValueMinMax(min, max); this->Modified(); } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::SetMaskImage(const ImageType *image) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast< ImageType * >( image ) ); m_GLCMGenerator->SetMaskImage(image); } template< typename TImage, typename THistogramFrequencyContainer > const TImage * EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer > ::GetInput() const { return itkDynamicCastInDebugMode< const ImageType * >( this->GetPrimaryInput() ); } template< typename TImage, typename THistogramFrequencyContainer > const typename EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::FeatureValueVectorDataObjectType * EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::GetFeatureMeansOutput() const { return itkDynamicCastInDebugMode< const FeatureValueVectorDataObjectType * >( this->ProcessObject::GetOutput(0) ); } template< typename TImage, typename THistogramFrequencyContainer > const typename EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::FeatureValueVectorDataObjectType * EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer > ::GetFeatureStandardDeviationsOutput() const { return itkDynamicCastInDebugMode< const FeatureValueVectorDataObjectType * >( this->ProcessObject::GetOutput(1) ); } template< typename TImage, typename THistogramFrequencyContainer > const TImage * EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer > ::GetMaskImage() const { return static_cast< const ImageType * >( this->ProcessObject::GetInput(1) ); } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::SetInsidePixelValue( PixelType insidePixelValue) { itkDebugMacro("setting InsidePixelValue to " << insidePixelValue); m_GLCMGenerator->SetInsidePixelValue(insidePixelValue); this->Modified(); } template< typename TImage, typename THistogramFrequencyContainer > void EnhancedScalarImageToTextureFeaturesFilter< TImage, THistogramFrequencyContainer >::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "RequestedFeatures: " << this->GetRequestedFeatures() << std::endl; os << indent << "FeatureStandardDeviations: " << this->GetFeatureStandardDeviations() << std::endl; os << indent << "FastCalculations: " << this->GetFastCalculations() << std::endl; os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "FeatureMeans: " << this->GetFeatureMeans() << std::endl; } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp b/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp index c884a41381..500ff88d23 100644 --- a/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp +++ b/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp @@ -1,321 +1,321 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include template class punct_facet : public std::numpunct { public: punct_facet(charT sep) : m_Sep(sep) { } protected: charT do_decimal_point() const override { return m_Sep; } private: charT m_Sep; }; void AddPropertyAsNode(const mitk::Image* image, const std::string& key, const std::string& tag, tinyxml2::XMLElement* rootNode) { auto prop = image->GetProperty(key.c_str()); if (prop.IsNotNull()) { auto* doc = rootNode->GetDocument(); auto propNode = doc->NewElement(tag.c_str()); auto* valueText = doc->NewText(prop->GetValueAsString().c_str()); propNode->InsertEndChild(valueText); rootNode->InsertEndChild(propNode); } } void AddSeriesInstanceUID(const mitk::Image* image, tinyxml2::XMLElement* xmlNode) { AddPropertyAsNode(image, mitk::DICOMTagPathToPropertyName(mitk::DICOMTagPath(0x0020, 0x000e)), "mp:seriesInstanceUID", xmlNode); } void AddFilePath(const mitk::Image* image, tinyxml2::XMLElement* xmlNode) { AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION()), "mp:filePath", xmlNode); } void AddSOPInstanceUIDs(const mitk::Image* image, tinyxml2::XMLElement* xmlNode) { auto prop = image->GetProperty(mitk::DICOMTagPathToPropertyName(mitk::DICOMTagPath(0x0008, 0x0018)).c_str()); auto dicomProp = dynamic_cast(prop.GetPointer()); auto* doc = xmlNode->GetDocument(); if (dicomProp != nullptr) { auto* instanceUIDsNode = doc->NewElement("mp:sopInstanceUIDs"); xmlNode->InsertEndChild(instanceUIDsNode); if (dicomProp->IsUniform()) { auto* instanceUIDNode = doc->NewElement("mp:sopInstanceUID"); auto* valueText = doc->NewText(dicomProp->GetValueAsString().c_str()); instanceUIDNode->InsertEndChild(valueText); instanceUIDsNode->InsertEndChild(instanceUIDNode); } else { const auto timeSteps = dicomProp->GetAvailableTimeSteps(); for (auto timeStep : timeSteps) { const auto slices = dicomProp->GetAvailableSlices(timeStep); for (auto slice : slices) { auto instanceUIDNode = doc->NewElement("mp:sopInstanceUID"); instanceUIDNode->SetAttribute("z", static_cast(slice)); instanceUIDNode->SetAttribute("t", static_cast(timeStep)); auto* valueText = doc->NewText(dicomProp->GetValue(timeStep, slice).c_str()); instanceUIDNode->InsertEndChild(valueText); instanceUIDsNode->InsertEndChild(instanceUIDNode); } } } } } void AddDateAndTime(tinyxml2::XMLElement* rootNode) { auto* doc = rootNode->GetDocument(); auto* dateNode = doc->NewElement("mp:generationDate"); auto time = std::time(nullptr); std::ostringstream sstream; sstream << std::put_time(std::localtime(&time), "%Y%m%d"); auto* valueText = doc->NewText(sstream.str().c_str()); dateNode->InsertEndChild(valueText); rootNode->InsertEndChild(dateNode); auto* timeNode = doc->NewElement("mp:generationTime"); std::ostringstream timestream; timestream << std::put_time(std::localtime(&time), "%H%M%S"); valueText = doc->NewText(timestream.str().c_str()); timeNode->InsertEndChild(valueText); rootNode->InsertEndChild(timeNode); } void AddParameters(const std::map& parameters, tinyxml2::XMLElement* paramsNode) { auto* doc = paramsNode->GetDocument(); for (const auto& param : parameters) { mitk::LocaleSwitch lswitch("C"); auto paramNode = doc->NewElement("mp:parameter"); paramNode->SetAttribute("name", param.first.c_str()); auto* valueText = doc->NewText(param.second.ToString().c_str()); paramNode->InsertEndChild(valueText); paramsNode->InsertEndChild(paramNode); } } void AddFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features, tinyxml2::XMLElement* featsNode) { auto* doc = featsNode->GetDocument(); for (const auto& feat : features) { auto featNode = doc->NewElement("mp:feature"); featNode->SetAttribute("name", feat.first.name.c_str()); featNode->SetAttribute("version", feat.first.version.c_str()); featNode->SetAttribute("class", feat.first.featureClass.c_str()); featNode->SetAttribute("setting", feat.first.settingID.c_str()); std::ostringstream sstream; sstream.imbue(std::locale("C")); sstream << feat.second; auto* valueText = doc->NewText(sstream.str().c_str()); featNode->InsertEndChild(valueText); featsNode->InsertEndChild(featNode); } } void AddFeatureSettings(const mitk::AbstractGlobalImageFeature::FeatureListType& features, tinyxml2::XMLElement* featSettingsNode) { auto* doc = featSettingsNode->GetDocument(); std::list coveredSettings; for (const auto& feat : features) { auto finding = std::find(coveredSettings.begin(), coveredSettings.end(), feat.first.settingID); if (finding == coveredSettings.end()) { auto featSettingNode = doc->NewElement("mp:featureSetting"); featSettingsNode->InsertEndChild(featSettingNode); featSettingNode->SetAttribute("name", feat.first.settingID.c_str()); AddParameters(feat.first.parameters, featSettingNode); coveredSettings.push_back(feat.first.settingID); } } } void AddReaderInfo(const mitk::Image* image, tinyxml2::XMLElement* imageNode) { auto* doc = imageNode->GetDocument(); auto ioNode = doc->NewElement("mp:IOReader"); imageNode->InsertEndChild(ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION()), "mp:description", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_VERSION()), "mp:version", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()), "mp:configuration", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM()), "mp:gdcmVersion", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK()), "mp:dcmtkVersion", ioNode); } void WriteDocument(std::ostream& stream, const mitk::Image* image, const mitk::Image* mask, const mitk::AbstractGlobalImageFeature::FeatureListType& features, const std::string& methodName, const std::string& organisation, const std::string& version, const std::string& pipelineUID, const std::map& cliArgs) { tinyxml2::XMLDocument doc; doc.InsertEndChild(doc.NewDeclaration()); auto* rootNode = doc.NewElement("mp:measurement"); - rootNode->SetAttribute("xmlns:mp", "http://www.mitk.org/Phenotyping"); + rootNode->SetAttribute("xmlns:mp", "https://www.mitk.org/Phenotyping"); doc.InsertEndChild(rootNode); auto* methodNode = doc.NewElement("mp:measurementMethod"); rootNode->InsertEndChild(methodNode); auto* methodNameNode = doc.NewElement("mp:name"); auto* valueText = doc.NewText(methodName.c_str()); methodNameNode->InsertEndChild(valueText); methodNode->InsertEndChild(methodNameNode); auto* organisationNode = doc.NewElement("mp:organisation"); valueText = doc.NewText(organisation.c_str()); organisationNode->InsertEndChild(valueText); methodNode->InsertEndChild(organisationNode); auto* versionNode = doc.NewElement("mp:version"); valueText = doc.NewText(version.c_str()); versionNode->InsertEndChild(valueText); methodNode->InsertEndChild(versionNode); auto* imageNode = doc.NewElement("mp:image"); rootNode->InsertEndChild(imageNode); AddSeriesInstanceUID(image, imageNode); AddFilePath(image, imageNode); AddSOPInstanceUIDs(image, imageNode); AddReaderInfo(image,imageNode); auto* maskNode = doc.NewElement("mp:mask"); rootNode->InsertEndChild(maskNode); AddSeriesInstanceUID(mask, maskNode); AddFilePath(mask, maskNode); AddSOPInstanceUIDs(mask, maskNode); AddReaderInfo(mask, maskNode); //todo mask reader meta info AddDateAndTime(rootNode); auto* pipelineNode = doc.NewElement("mp:pipelineUID"); valueText = doc.NewText(pipelineUID.c_str()); pipelineNode->InsertEndChild(valueText); rootNode->InsertEndChild(pipelineNode); auto* paramsNode = doc.NewElement("mp:parameters"); rootNode->InsertEndChild(paramsNode); AddParameters(cliArgs, paramsNode); auto* featsNode = doc.NewElement("mp:features"); rootNode->InsertEndChild(featsNode); AddFeatures(features, featsNode); auto* featSettingsNode = doc.NewElement("mp:featureSettings"); rootNode->InsertEndChild(featSettingsNode); AddFeatureSettings(features, featSettingsNode); tinyxml2::XMLPrinter printer; doc.Print(&printer); stream << printer.CStr(); } void mitk::cl::CLResultXMLWriter::SetImage(const Image* image) { m_Image = image; } void mitk::cl::CLResultXMLWriter::SetMask(const Image* mask) { m_Mask = mask; } void mitk::cl::CLResultXMLWriter::SetFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features) { m_Features = features; } void mitk::cl::CLResultXMLWriter::SetMethodName(const std::string& name) { m_MethodName = name; } void mitk::cl::CLResultXMLWriter::SetMethodVersion(const std::string& version) { m_MethodVersion = version; } void mitk::cl::CLResultXMLWriter::SetOrganisation(const std::string& orga) { m_Organisation = orga; } void mitk::cl::CLResultXMLWriter::SetPipelineUID(const std::string& pipelineUID) { m_PipelineUID = pipelineUID; } void mitk::cl::CLResultXMLWriter::SetCLIArgs(const std::map& args) { m_CLIArgs = args; } void mitk::cl::CLResultXMLWriter::write(const std::string& filePath) const { std::ofstream resultFile; resultFile.open(filePath.c_str()); if (resultFile.is_open()) { this->write(resultFile); resultFile.close(); } else { MITK_ERROR << "Cannot write xml results. Unable to open file: \""< #include #include #include /** * * The MITK command line parser, based on the CTK command line parser. * * Use this class to add information about the command line arguments * your program understands and to easily parse them from a given list * of strings. * * This parser provides the following features: * *
    *
  • Add arguments by supplying a long name and/or a short name. * Arguments are validated using a regular expression. They can have * a default value and a help string.
  • *
  • Deprecated arguments.
  • *
  • Custom regular expressions for argument validation.
  • *
  • Set different argument name prefixes for native platform look and feel.
  • *
  • Create a help text for the command line arguments with support for * grouping arguments.
  • *
* * The main difference between the MITK command line parser and the CTK command line * parser is that the former does not depend on Qt. Apart from that an image type was * added and XML output improved for automatic GUI generation. * * std::out is used for output to keep dependencies to a minimum. */ class MITKCOMMANDLINE_EXPORT mitkCommandLineParser { public: enum Type { String = 0, Bool = 1, StringList = 2, Int = 3, Float = 4, Directory = 5, File = 6, Image = 7 }; enum Channel { None = 0, Input = 1, Output = 2 }; typedef std::vector StringContainerType; mitkCommandLineParser(); ~mitkCommandLineParser(); /** * Parse a given list of command line arguments. * * This method parses a list of string elements considering the known arguments * added by calls to addArgument(). If any one of the argument * values does not match the corresponding regular expression, * ok is set to false and an empty map object is returned. * * The keys in the returned map object correspond to the long argument string, * if it is not empty. Otherwise, the short argument string is used as key. The * us::Any values can safely be converted to the type specified in the * addArgument() method call. * * @param arguments A StringContainerType containing command line arguments. * @param ok A pointer to a boolean variable. Will be set to true * if all regular expressions matched, false otherwise. * @return A map object mapping the long argument (if empty, the short one) * to a us::Any containing the value. */ std::map parseArguments(const StringContainerType &arguments, bool *ok = nullptr); /** * Convenient method allowing to parse a given list of command line arguments. * @see parseArguments(const StringContainerType &, bool*) */ std::map parseArguments(int argc, char **argv, bool *ok = nullptr); /** * Returns a detailed error description if a call to parseArguments() * failed. * * @return The error description, empty if no error occured. * @see parseArguments(const StringContainerType&, bool*) */ std::string errorString() const; /** * This method returns all unparsed arguments, i.e. all arguments * for which no long or short name has been registered via a call * to addArgument(). * * @see addArgument() * * @return A list containing unparsed arguments. */ const StringContainerType &unparsedArguments() const; /** * Checks if the given argument has been added via a call * to addArgument(). * * @see addArgument() * * @param argument The argument to be checked. * @return true if the argument was added, false * otherwise. */ bool argumentAdded(const std::string &argument) const; /** * Checks if the given argument has been parsed successfully by a previous * call to parseArguments(). * * @param argument The argument to be checked. * @return true if the argument was parsed, false * otherwise. */ bool argumentParsed(const std::string &argument) const; /** * Adds a command line argument. An argument can have a long name * (like --long-argument-name), a short name (like -l), or both. The type * of the argument can be specified by using the type parameter. * The following types are supported: * * * * * * * * *
Type# of parametersDefault regular exprExample
us::Any::String1.*--test-string StringParameter
us::Any::Bool0does not apply--enable-something
us::Any::StringList-1.*--test-list string1 string2
us::Any::Int1-?[0-9]+--test-int -5
* * The regular expressions are used to validate the parameters of command line * arguments. You can restrict the valid set of parameters by calling * setExactMatchRegularExpression() for your argument. * * Optionally, a help string and a default value can be provided for the argument. If * the us::Any type of the default value does not match type, an * exception is thrown. Arguments with default values are always returned by * parseArguments(). * * You can also declare an argument deprecated, by setting deprecated * to true. Alternatively you can add a deprecated argument by calling * addDeprecatedArgument(). * * If the long or short argument has already been added, or if both are empty strings, * the method call has no effect. * * @param longarg The long argument name. * @param shortarg The short argument name. * @param type The argument type (see the list above for supported types). * @param argLabel The label of this argument, when auto generated interface is used. * @param argHelp A help string describing the argument. * @param defaultValue A default value for the argument. * @param optional * @param ignoreRest All arguments after the current one will be ignored. * @param deprecated Declares the argument deprecated. * @param channel * * @see setExactMatchRegularExpression() * @see addDeprecatedArgument() * @throws std::logic_error If the us::Any type of defaultValue * does not match type, a std::logic_error is thrown. */ void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp = std::string(), const us::Any &defaultValue = us::Any(), bool optional = true, bool ignoreRest = false, bool deprecated = false, mitkCommandLineParser::Channel channel = mitkCommandLineParser::Channel::None); /** * Adds a deprecated command line argument. If a deprecated argument is provided * on the command line, argHelp is displayed in the console and * processing continues with the next argument. * * Deprecated arguments are grouped separately at the end of the help text * returned by helpText(). * * @param longarg The long argument name. * @param shortarg The short argument name. * @param argLabel * @param argHelp A help string describing alternatives to the deprecated argument. */ void addDeprecatedArgument(const std::string &longarg, const std::string &shortarg, const std::string &argLabel, const std::string &argHelp); /** * Returns the vector of current Command line Parameter * */ std::vector < std::map > getArgumentList(); /** * Sets a custom regular expression for validating argument parameters. The method * errorString() can be used the get the last error description. * * @param argument The previously added long or short argument name. * @param expression A regular expression which the arugment parameters must match. * @param exactMatchFailedMessage An error message explaining why the parameter did * not match. * * @return true if the argument was found and the regular expression was set, * false otherwise. * * @see errorString() */ bool setExactMatchRegularExpression(const std::string &argument, const std::string &expression, const std::string &exactMatchFailedMessage); /** * The field width for the argument names without the help text. * * @return The argument names field width in the help text. */ std::string::size_type fieldWidth() const; /** * Creates a help text containing properly formatted argument names and help strings * provided by calls to addArgument(). The arguments can be grouped by * using beginGroup() and endGroup(). * * @return The formatted help text. */ std::string helpText() const; /** * Sets the argument prefix for long and short argument names. This can be used * to create native command line arguments without changing the calls to * addArgument(). For example on Unix-based systems, long argument * names start with "--" and short names with "-", while on Windows argument names * always start with "/". * * Note that all methods in mitkCommandLineParser which take an argument name * expect the name as it was supplied to addArgument. * * Example usage: * * \code * ctkCommandLineParser parser; * parser.setArgumentPrefix("--", "-"); * parser.addArgument("long-argument", "l", us::Any::String); * StringContainerType args; * args << "program name" << "--long-argument Hi"; * parser.parseArguments(args); * \endcode * * @param longPrefix The prefix for long argument names. * @param shortPrefix The prefix for short argument names. */ void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix); /** * Begins a new group for documenting arguments. All newly added arguments via * addArgument() will be put in the new group. You can close the * current group by calling endGroup() or be opening a new group. * * Note that groups cannot be nested and all arguments which do not belong to * a group will be listed at the top of the text created by helpText(). * * @param description The description of the group */ void beginGroup(const std::string &description); /** * Ends the current group. * * @see beginGroup(const std::string&) */ void endGroup(); /** * Can be used to teach the parser to stop parsing the arguments and return False when * an unknown argument is encountered. By default StrictMode is disabled. * * @see parseArguments(const StringContainerType &, bool*) */ void setStrictModeEnabled(bool strictMode); /** * Is used to generate an XML output for any commandline program. */ void generateXmlOutput(); /** * Is used to set the title of the auto generated interface. * * @param title The title of the app. */ void setTitle(std::string title); /** * Is used to set the contributor for the help view in the auto generated interface. * * @param contributor Contributor of the app. */ void setContributor(std::string contributor); /** * Is used to categorize the apps in the commandline module. * * @param category The category of the app. */ void setCategory(std::string category); /** * Is used as the help text in the auto generated interface. * * @param description A short description for the app. */ void setDescription(std::string description); /** * Is used to group several Parameters in one groupbox in the auto generated interface. * Default name is "Parameters", with the tooltip: "Groupbox containing parameters." * * To change the group of several arguments, call this method before the arguments are added. * * @param name The name of the groupbox. * @param tooltip The tooltip of the groupbox. */ void changeParameterGroup(std::string name, std::string tooltip); protected: class ctkInternal; ctkInternal *Internal; std::string Title; std::string Contributor; std::string Category; std::string Description; std::string ParameterGroupName; std::string ParameterGroupDescription; }; #endif diff --git a/Modules/CommandLine/src/mitkCommandLineParser.cpp b/Modules/CommandLine/src/mitkCommandLineParser.cpp index 7b663c3464..cf60f88d99 100644 --- a/Modules/CommandLine/src/mitkCommandLineParser.cpp +++ b/Modules/CommandLine/src/mitkCommandLineParser.cpp @@ -1,1056 +1,1056 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ /*========================================================================= Library: CTK Copyright (c) Kitware Inc. 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.txt + https://www.apache.org/licenses/LICENSE-2.0.txt 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. =========================================================================*/ // STL includes #include #include // MITK includes #include "mitkCommandLineParser.h" using namespace std; namespace { // -------------------------------------------------------------------------- class CommandLineParserArgumentDescription { public: CommandLineParserArgumentDescription(const string &longArg, const string &longArgPrefix, const string &shortArg, const string &shortArgPrefix, mitkCommandLineParser::Type type, const string &argHelp, const string &argLabel, const us::Any &defaultValue, bool ignoreRest, bool deprecated, bool optional, mitkCommandLineParser::Channel channel, string &argGroup, string &groupDescription) : LongArg(longArg), LongArgPrefix(longArgPrefix), ShortArg(shortArg), ShortArgPrefix(shortArgPrefix), ArgHelp(argHelp), ArgLabel(argLabel), ArgGroup(argGroup), ArgGroupDescription(groupDescription), IgnoreRest(ignoreRest), NumberOfParametersToProcess(0), Deprecated(deprecated), Optional(optional), Channel(channel), DefaultValue(defaultValue), Value(type), ValueType(type) { Value = defaultValue; switch (type) { case mitkCommandLineParser::String: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Bool: { NumberOfParametersToProcess = 0; } break; case mitkCommandLineParser::StringList: { NumberOfParametersToProcess = -1; } break; case mitkCommandLineParser::Int: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Float: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Directory: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::File: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Image: { NumberOfParametersToProcess = 1; } break; default: std::cout << "Type not supported: " << static_cast(type); } } ~CommandLineParserArgumentDescription() {} bool addParameter(const string &value); string helpText(); string LongArg; string LongArgPrefix; string ShortArg; string ShortArgPrefix; string ArgHelp; string ArgLabel; string ArgGroup; string ArgGroupDescription; bool IgnoreRest; int NumberOfParametersToProcess; bool Deprecated; bool Optional; mitkCommandLineParser::Channel Channel; us::Any DefaultValue; us::Any Value; mitkCommandLineParser::Type ValueType; }; // -------------------------------------------------------------------------- bool CommandLineParserArgumentDescription::addParameter(const string &value) { switch (ValueType) { case mitkCommandLineParser::String: { Value = value; } break; case mitkCommandLineParser::Bool: { if (value.compare("true") == 0) Value = true; else Value = false; } break; case mitkCommandLineParser::StringList: { try { mitkCommandLineParser::StringContainerType list = us::any_cast(Value); list.push_back(value); Value = list; } catch (...) { mitkCommandLineParser::StringContainerType list; list.push_back(value); Value = list; } } break; case mitkCommandLineParser::Int: { stringstream ss(value); int i; ss >> i; Value = i; } break; case mitkCommandLineParser::Float: { stringstream ss(value); float f; ss >> f; Value = f; } break; case mitkCommandLineParser::Directory: case mitkCommandLineParser::Image: case mitkCommandLineParser::File: { Value = value; } break; default: return false; } return true; } // -------------------------------------------------------------------------- string CommandLineParserArgumentDescription::helpText() { string text; string shortAndLongArg; if (!this->ShortArg.empty()) { shortAndLongArg = " "; shortAndLongArg += this->ShortArgPrefix; shortAndLongArg += this->ShortArg; } if (!this->LongArg.empty()) { if (this->ShortArg.empty()) shortAndLongArg.append(" "); else shortAndLongArg.append(", "); shortAndLongArg += this->LongArgPrefix; shortAndLongArg += this->LongArg; } text = text + shortAndLongArg + ", " + this->ArgHelp; if (this->Optional) text += " (optional)"; if (!this->DefaultValue.Empty()) { if (this->ValueType == 1) { if (this->DefaultValue.ToString() == "0") text = text + ", (default: false)"; else text = text + ", (default: true)"; } else text = text + ", (default: " + this->DefaultValue.ToString() + ")"; } string value_type = "Unknown"; switch (this->ValueType) { case 0: { value_type = "String"; break; } case 1: { value_type = "Bool"; break; } case 2: { value_type = "StringList"; break; } case 3: { value_type = "Int"; break; } case 4: { value_type = "Float"; break; } case 5: { value_type = "Directory"; break; } case 6: { value_type = "File"; break; } case 7: { value_type = "Image"; } } text = text + ", Type: " + value_type; if (this->Channel == mitkCommandLineParser::Input) text = text + ", Channel: input"; else if (this->Channel == mitkCommandLineParser::Output) text = text + ", Channel: output"; text += "\n"; return text; } } // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal class // -------------------------------------------------------------------------- class mitkCommandLineParser::ctkInternal { public: ctkInternal() : Debug(false), FieldWidth(0), StrictMode(false) {} ~ctkInternal() {} CommandLineParserArgumentDescription *argumentDescription(const string &argument); vector ArgumentDescriptionList; map ArgNameToArgumentDescriptionMap; map> GroupToArgumentDescriptionListMap; StringContainerType UnparsedArguments; StringContainerType ProcessedArguments; string ErrorString; bool Debug; string::size_type FieldWidth; string LongPrefix; string ShortPrefix; string CurrentGroup; string DisableQSettingsLongArg; string DisableQSettingsShortArg; bool StrictMode; }; // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal methods // -------------------------------------------------------------------------- CommandLineParserArgumentDescription *mitkCommandLineParser::ctkInternal::argumentDescription(const string &argument) { string unprefixedArg = argument; if (!LongPrefix.empty() && argument.compare(0, LongPrefix.size(), LongPrefix) == 0) { // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix if (argument == LongPrefix && !ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0) { unprefixedArg = argument.substr(ShortPrefix.size(), argument.size()); } else { unprefixedArg = argument.substr(LongPrefix.size(), argument.size()); } } else if (!ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0) { unprefixedArg = argument.substr(ShortPrefix.size(), argument.size()); } else if (!LongPrefix.empty() && !ShortPrefix.empty()) { return nullptr; } if (ArgNameToArgumentDescriptionMap.count(unprefixedArg)) { return this->ArgNameToArgumentDescriptionMap[unprefixedArg]; } return nullptr; } // -------------------------------------------------------------------------- // ctkCommandLineParser methods // -------------------------------------------------------------------------- mitkCommandLineParser::mitkCommandLineParser() { this->Internal = new ctkInternal(); this->Category = string(); this->Title = string(); this->Contributor = string(); this->Description = string(); this->ParameterGroupName = "Parameters"; this->ParameterGroupDescription = "Parameters"; } // -------------------------------------------------------------------------- mitkCommandLineParser::~mitkCommandLineParser() { delete this->Internal; } // -------------------------------------------------------------------------- map mitkCommandLineParser::parseArguments(const StringContainerType &arguments, bool *ok) { // Reset this->Internal->UnparsedArguments.clear(); this->Internal->ProcessedArguments.clear(); this->Internal->ErrorString.clear(); // foreach (CommandLineParserArgumentDescription* desc, this->Internal->ArgumentDescriptionList) for (unsigned int i = 0; i < Internal->ArgumentDescriptionList.size(); i++) { CommandLineParserArgumentDescription *desc = Internal->ArgumentDescriptionList.at(i); desc->Value = us::Any(desc->ValueType); if (!desc->DefaultValue.Empty()) { desc->Value = desc->DefaultValue; } } bool error = false; bool ignoreRest = false; CommandLineParserArgumentDescription *currentArgDesc = nullptr; vector parsedArgDescriptions; for (unsigned int i = 1; i < arguments.size(); ++i) { string argument = arguments.at(i); if (this->Internal->Debug) { std::cout << "Processing" << argument; } if (!argument.compare("--version")) { std::cout << "Git commit hash: " << MITK_REVISION << std::endl; std::cout << "Git branch name: " << MITK_REVISION_NAME << "\n" << std::endl; } if (!argument.compare("--xml") || !argument.compare("-xml") || !argument.compare("--XML") || !argument.compare("-XML")) { this->generateXmlOutput(); return map(); } // should argument be ignored ? if (ignoreRest) { if (this->Internal->Debug) { std::cout << " Skipping: IgnoreRest flag was been set"; } this->Internal->UnparsedArguments.push_back(argument); continue; } // Skip if the argument does not start with the defined prefix if (!(argument.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 || argument.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0)) { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Unknown argument "; this->Internal->ErrorString += argument; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: It does not start with the defined prefix"; } this->Internal->UnparsedArguments.push_back(argument); continue; } // Skip if argument has already been parsed ... bool alreadyProcessed = false; for (const auto &alreadyHandledArgument : Internal->ProcessedArguments) if (argument.compare(alreadyHandledArgument) == 0) { alreadyProcessed = true; break; } if (alreadyProcessed) { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Argument "; this->Internal->ErrorString += argument; this->Internal->ErrorString += " already processed !"; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: Already processed !"; } continue; } // Retrieve corresponding argument description currentArgDesc = this->Internal->argumentDescription(argument); // Is there a corresponding argument description ? if (currentArgDesc) { // If the argument is deprecated, print the help text but continue processing if (currentArgDesc->Deprecated) { std::cout << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp; } else { parsedArgDescriptions.push_back(currentArgDesc); } this->Internal->ProcessedArguments.push_back(currentArgDesc->ShortArg); this->Internal->ProcessedArguments.push_back(currentArgDesc->LongArg); int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess; ignoreRest = currentArgDesc->IgnoreRest; if (this->Internal->Debug && ignoreRest) { std::cout << " IgnoreRest flag is True"; } // Is the number of parameters associated with the argument being processed known ? if (numberOfParametersToProcess == 0) { currentArgDesc->addParameter("true"); } else if (numberOfParametersToProcess > 0) { string missingParameterError = "Argument %1 has %2 value(s) associated whereas exacly %3 are expected."; for (int j = 1; j <= numberOfParametersToProcess; ++j) { if (i + j >= arguments.size()) { // this->Internal->ErrorString = // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } string parameter = arguments.at(i + j); if (this->Internal->Debug) { std::cout << " Processing parameter" << j << ", value:" << parameter; } if (this->argumentAdded(parameter)) { // this->Internal->ErrorString = // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } if (!currentArgDesc->addParameter(parameter)) { // this->Internal->ErrorString = string( // "Value(s) associated with argument %1 are incorrect. %2"). // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } } // Update main loop increment i = i + numberOfParametersToProcess; } else if (numberOfParametersToProcess == -1) { if (this->Internal->Debug) { std::cout << " Proccessing StringList ..."; } int j = 1; while (j + i < arguments.size()) { if (this->argumentAdded(arguments.at(j + i))) { if (this->Internal->Debug) { std::cout << " No more parameter for" << argument; } break; } string parameter = arguments.at(j + i); if (parameter.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 || parameter.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0) { j--; break; } if (this->Internal->Debug) { std::cout << " Processing parameter" << j << ", value:" << parameter; } if (!currentArgDesc->addParameter(parameter)) { // this->Internal->ErrorString = string( // "Value(s) associated with argument %1 are incorrect. %2"). // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } j++; } // Update main loop increment i = i + j; } } else { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Unknown argument "; this->Internal->ErrorString += argument; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: Unknown argument"; } this->Internal->UnparsedArguments.push_back(argument); } } if (ok) { *ok = !error; } map parsedArguments; int obligatoryArgs = 0; vector::iterator it; for (it = Internal->ArgumentDescriptionList.begin(); it != Internal->ArgumentDescriptionList.end(); ++it) { CommandLineParserArgumentDescription *desc = *it; if (!desc->Optional) obligatoryArgs++; } int parsedObligatoryArgs = 0; for (it = parsedArgDescriptions.begin(); it != parsedArgDescriptions.end(); ++it) { CommandLineParserArgumentDescription *desc = *it; string key; if (!desc->LongArg.empty()) { key = desc->LongArg; } else { key = desc->ShortArg; } if (!desc->Optional) parsedObligatoryArgs++; std::pair elem; elem.first = key; elem.second = desc->Value; parsedArguments.insert(elem); } if (obligatoryArgs > parsedObligatoryArgs) { parsedArguments.clear(); cout << helpText(); } return parsedArguments; } // ------------------------------------------------------------------------- map mitkCommandLineParser::parseArguments(int argc, char **argv, bool *ok) { std::cout << "Running Command Line Utility *" << Title << "*" << std::endl; StringContainerType arguments; // Create a StringContainerType of arguments for (int i = 0; i < argc; ++i) arguments.push_back(argv[i]); return this->parseArguments(arguments, ok); } // ------------------------------------------------------------------------- string mitkCommandLineParser::errorString() const { return this->Internal->ErrorString; } // ------------------------------------------------------------------------- const mitkCommandLineParser::StringContainerType &mitkCommandLineParser::unparsedArguments() const { return this->Internal->UnparsedArguments; } // -------------------------------------------------------------------------- void mitkCommandLineParser::addArgument(const string &longarg, const string &shortarg, Type type, const string &argLabel, const string &argHelp, const us::Any &defaultValue, bool optional, bool ignoreRest, bool deprecated, mitkCommandLineParser::Channel channel) { if (longarg.empty() && shortarg.empty()) { return; } /* Make sure it's not already added */ bool added = (this->Internal->ArgNameToArgumentDescriptionMap.count(longarg) != 0); if (added) { return; } added = (this->Internal->ArgNameToArgumentDescriptionMap.count(shortarg) != 0); if (added) { return; } auto argDesc = new CommandLineParserArgumentDescription(longarg, this->Internal->LongPrefix, shortarg, this->Internal->ShortPrefix, type, argHelp, argLabel, defaultValue, ignoreRest, deprecated, optional, channel, ParameterGroupName, ParameterGroupDescription); std::string::size_type argWidth = 0; if (!longarg.empty()) { this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc; argWidth += longarg.size() + this->Internal->LongPrefix.size(); } if (!shortarg.empty()) { this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc; argWidth += shortarg.size() + this->Internal->ShortPrefix.size() + 2; } argWidth += 5; // Set the field width for the arguments if (argWidth > this->Internal->FieldWidth) { this->Internal->FieldWidth = argWidth; } this->Internal->ArgumentDescriptionList.push_back(argDesc); this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup].push_back(argDesc); } // -------------------------------------------------------------------------- void mitkCommandLineParser::addDeprecatedArgument(const string &longarg, const string &shortarg, const string &argLabel, const string &argHelp) { addArgument(longarg, shortarg, StringList, argLabel, argHelp, us::Any(), false, true, false); } // -------------------------------------------------------------------------- std::vector < std::map > mitkCommandLineParser::getArgumentList() { std::vector < std::map > parameterList; //for (CommandLineParserArgumentDescription* argument : this->Internal->ArgumentDescriptionList) for (std::size_t i = 0; i< this->Internal->ArgumentDescriptionList.size(); ++i) { CommandLineParserArgumentDescription* argument = this->Internal->ArgumentDescriptionList[i]; std::map tmpMap; //tmpMap["helptext"] = us::Any(argument->helpText); tmpMap["longarg"] = us::Any(argument->LongArg); tmpMap["longargprefix"] = us::Any(argument->LongArgPrefix); tmpMap["shortarg"] = us::Any(argument->ShortArg); tmpMap["shortargprefix"] = us::Any(argument->ShortArgPrefix); tmpMap["arghelp"] = us::Any(argument->ArgHelp); tmpMap["arglabel"] = us::Any(argument->ArgLabel); tmpMap["arggroup"] = us::Any(argument->ArgGroup); tmpMap["arggroupdescription"] = us::Any(argument->ArgGroupDescription); tmpMap["ignorerest"] = us::Any(argument->IgnoreRest); tmpMap["numberofparameterstoprocess"] = us::Any(argument->NumberOfParametersToProcess); tmpMap["deprecated"] = us::Any(argument->Deprecated); tmpMap["optional"] = us::Any(argument->Optional); tmpMap["defaultvalue"] = argument->DefaultValue; tmpMap["value"] = argument->Value; tmpMap["valuetype"] = us::Any(argument->ValueType); tmpMap["channel"] = us::Any(argument->Channel); parameterList.push_back(tmpMap); } return parameterList; } // -------------------------------------------------------------------------- std::string::size_type mitkCommandLineParser::fieldWidth() const { return this->Internal->FieldWidth; } // -------------------------------------------------------------------------- void mitkCommandLineParser::beginGroup(const string &description) { this->Internal->CurrentGroup = description; } // -------------------------------------------------------------------------- void mitkCommandLineParser::endGroup() { this->Internal->CurrentGroup.clear(); } // -------------------------------------------------------------------------- string mitkCommandLineParser::helpText() const { string text; vector deprecatedArgs; text = "Command Line Utility *" + Title + "* in Category *" + Category + "*\n"; text += Description + "\n"; text += Contributor + "\n\n"; text += "Use --xml to generate an XML description parsable as a CTK Command Line Module Plugin.\n"; text += "Use --version to print MITK revision information.\n"; // Loop over grouped argument descriptions map>::iterator it; for (it = Internal->GroupToArgumentDescriptionListMap.begin(); it != Internal->GroupToArgumentDescriptionListMap.end(); ++it) { if (!(*it).first.empty()) { text = text + "\n" + (*it).first + "\n"; } vector::iterator it2; for (it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2) { CommandLineParserArgumentDescription *argDesc = *it2; if (argDesc->Deprecated) { deprecatedArgs.push_back(argDesc); } else { text += argDesc->helpText(); } } } if (!deprecatedArgs.empty()) { text += "\nDeprecated arguments:\n"; vector::iterator it2; for (it2 = deprecatedArgs.begin(); it2 != deprecatedArgs.end(); ++it2) { CommandLineParserArgumentDescription *argDesc = *it2; text += argDesc->helpText(); } } return text; } // -------------------------------------------------------------------------- bool mitkCommandLineParser::argumentAdded(const string &argument) const { return (this->Internal->ArgNameToArgumentDescriptionMap.count(argument) != 0); } // -------------------------------------------------------------------------- bool mitkCommandLineParser::argumentParsed(const string &argument) const { for (unsigned int i = 0; i < Internal->ProcessedArguments.size(); i++) if (argument.compare(Internal->ProcessedArguments.at(i)) == 0) return true; return false; } // -------------------------------------------------------------------------- void mitkCommandLineParser::setArgumentPrefix(const string &longPrefix, const string &shortPrefix) { this->Internal->LongPrefix = longPrefix; this->Internal->ShortPrefix = shortPrefix; } // -------------------------------------------------------------------------- void mitkCommandLineParser::setStrictModeEnabled(bool strictMode) { this->Internal->StrictMode = strictMode; } void mitkCommandLineParser::generateXmlOutput() { std::stringstream xml; xml << "" << endl; xml << "" << Category << "" << endl; xml << "" << Title << "" << endl; xml << "" << Description << "" << endl; xml << "" << Contributor << "" << endl; xml << "" << endl; std::vector::iterator it; std::string lastParameterGroup = ""; for (it = this->Internal->ArgumentDescriptionList.begin(); it != this->Internal->ArgumentDescriptionList.end(); it++) { std::string type; switch ((*it)->ValueType) { case mitkCommandLineParser::String: type = "string"; break; case mitkCommandLineParser::Bool: type = "boolean"; break; case mitkCommandLineParser::StringList: type = "string-vector"; break; case mitkCommandLineParser::Int: type = "integer"; break; case mitkCommandLineParser::Float: type = "float"; break; case mitkCommandLineParser::Directory: type = "directory"; break; case mitkCommandLineParser::Image: type = "image"; break; case mitkCommandLineParser::File: type = "file"; break; } if (lastParameterGroup.compare((*it)->ArgGroup)) { if (it != this->Internal->ArgumentDescriptionList.begin()) { xml << "" << endl; xml << "" << endl; } xml << "" << endl; xml << "" << (*it)->ArgGroupDescription << "" << endl; lastParameterGroup = (*it)->ArgGroup; } // Skip help item, as it's no use in GUI if ((*it)->ShortArg == "h") continue; auto name = (*it)->LongArg; if (name.empty()) name = (*it)->ShortArg; xml << "<" << type << ">" << endl; xml << "" << name << "" << endl; xml << "" << (*it)->ArgHelp << "" << endl; xml << "" << endl; if (!(*it)->DefaultValue.Empty()) xml << "" << (*it)->DefaultValue.ToString() << "" << endl; xml << "" << (*it)->LongArg << "" << endl; xml << "" << (*it)->ShortArg << "" << endl; if (((*it)->ValueType == mitkCommandLineParser::File || (*it)->ValueType == mitkCommandLineParser::Directory || (*it)->ValueType == mitkCommandLineParser::Image) && (*it)->Channel == mitkCommandLineParser::Channel::Input) { xml << "input" << endl; } else if (((*it)->ValueType == mitkCommandLineParser::File || (*it)->ValueType == mitkCommandLineParser::Directory || (*it)->ValueType == mitkCommandLineParser::Image) && (*it)->Channel == mitkCommandLineParser::Channel::Output) { xml << "output" << endl; } else if ((*it)->Channel == mitkCommandLineParser::Channel::Output || (*it)->Channel == mitkCommandLineParser::Channel::Input) { std::cout << "Only the types Directory, File or Image may be flagged as Input or Output! Ignoring flag for parameter " + name << std::endl; } xml << "" << endl; } xml << "" << endl; xml << "" << endl; cout << xml.str(); } void mitkCommandLineParser::setTitle(string title) { Title = title; } void mitkCommandLineParser::setContributor(string contributor) { Contributor = contributor; } void mitkCommandLineParser::setCategory(string category) { Category = category; } void mitkCommandLineParser::setDescription(string description) { Description = description; } void mitkCommandLineParser::changeParameterGroup(string name, string tooltip) { ParameterGroupName = name; ParameterGroupDescription = tooltip; } diff --git a/Modules/Core/resource/Interactions/Legacy/DisplayConfigMITKTools.xml b/Modules/Core/resource/Interactions/Legacy/DisplayConfigMITKTools.xml index 4836b9b51b..61c49425df 100644 --- a/Modules/Core/resource/Interactions/Legacy/DisplayConfigMITKTools.xml +++ b/Modules/Core/resource/Interactions/Legacy/DisplayConfigMITKTools.xml @@ -1,49 +1,49 @@ diff --git a/Modules/Core/resource/mitkAnatomicalStructureColorPresets.xml b/Modules/Core/resource/mitkAnatomicalStructureColorPresets.xml index aacfce3746..5e6bb30325 100644 --- a/Modules/Core/resource/mitkAnatomicalStructureColorPresets.xml +++ b/Modules/Core/resource/mitkAnatomicalStructureColorPresets.xml @@ -1,760 +1,760 @@ diff --git a/Modules/Core/test/mitkPlaneGeometryTest.cpp b/Modules/Core/test/mitkPlaneGeometryTest.cpp index f255f79b46..bf61cc4606 100644 --- a/Modules/Core/test/mitkPlaneGeometryTest.cpp +++ b/Modules/Core/test/mitkPlaneGeometryTest.cpp @@ -1,1093 +1,1093 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkAffineTransform3D.h" #include "mitkBaseGeometry.h" #include "mitkGeometry3D.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include "mitkPlaneGeometry.h" #include "mitkRotationOperation.h" #include "mitkSlicedGeometry3D.h" #include "mitkThinPlateSplineCurvedGeometry.h" #include #include #include #include #include #include #include #include static const mitk::ScalarType testEps = 1E-9; // the epsilon used in this test == at least float precision. class mitkPlaneGeometryTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPlaneGeometryTestSuite); MITK_TEST(TestInitializeStandardPlane); MITK_TEST(TestProjectPointOntoPlane); MITK_TEST(TestPlaneGeometryCloning); MITK_TEST(TestInheritance); MITK_TEST(TestSetExtendInMM); MITK_TEST(TestRotate); MITK_TEST(TestClone); MITK_TEST(TestPlaneComparison); MITK_TEST(TestAxialInitialization); MITK_TEST(TestCoronalInitialization); MITK_TEST(TestSagittalInitialization); MITK_TEST(TestLefthandedCoordinateSystem); MITK_TEST(TestDominantAxesError); MITK_TEST(TestCheckRotationMatrix); // Currently commented out, see See bug 15990 // MITK_TEST(testPlaneGeometryInitializeOrder); MITK_TEST(TestIntersectionPoint); MITK_TEST(TestCase1210); CPPUNIT_TEST_SUITE_END(); private: // private test members that are initialized by setUp() mitk::PlaneGeometry::Pointer planegeometry; mitk::Point3D origin; mitk::Vector3D right, bottom, normal, spacing; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; public: void setUp() override { planegeometry = mitk::PlaneGeometry::New(); width = 100; widthInMM = width; height = 200; heightInMM = height; thicknessInMM = 1.0; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); mitk::FillVector3D(normal, 0, 0, thicknessInMM); mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right, bottom); planegeometry->SetOrigin(origin); planegeometry->SetSpacing(spacing); } void tearDown() override {} // This test verifies inheritance behaviour, this test will fail if the behaviour changes in the future void TestInheritance() { mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); mitk::Geometry3D::Pointer g3d = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Planegeometry should not be castable to Geometry 3D", g3d.IsNull()); mitk::BaseGeometry::Pointer base = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Planegeometry should be castable to BaseGeometry", base.IsNotNull()); g3d = mitk::Geometry3D::New(); base = dynamic_cast(g3d.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Geometry3D should be castable to BaseGeometry", base.IsNotNull()); mitk::SlicedGeometry3D::Pointer sliced = mitk::SlicedGeometry3D::New(); g3d = dynamic_cast(sliced.GetPointer()); CPPUNIT_ASSERT_MESSAGE("SlicedGeometry3D should not be castable to Geometry3D", g3d.IsNull()); mitk::ThinPlateSplineCurvedGeometry::Pointer thin = mitk::ThinPlateSplineCurvedGeometry::New(); plane = dynamic_cast(thin.GetPointer()); CPPUNIT_ASSERT_MESSAGE("AbstractTransformGeometry should be castable to PlaneGeometry", plane.IsNotNull()); plane = mitk::PlaneGeometry::New(); mitk::AbstractTransformGeometry::Pointer atg = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("PlaneGeometry should not be castable to AbstractTransofrmGeometry", atg.IsNull()); } void TestDominantAxesError() { auto image = mitk::IOUtil::Load(GetTestDataFilePath("NotQuiteARotationMatrix.nrrd")); auto matrix = image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().transpose(); std::vector< int > axes = mitk::PlaneGeometry::CalculateDominantAxes(matrix); CPPUNIT_ASSERT_MESSAGE("Domiant axes cannot be determined in this dataset. Output should be default ordering.", axes.at(0)==0 && axes.at(1)==1 && axes.at(2)==2); } void TestCheckRotationMatrix() { auto image = mitk::IOUtil::Load(GetTestDataFilePath("NotQuiteARotationMatrix.nrrd")); bool is_rotation = mitk::PlaneGeometry::CheckRotationMatrix(image->GetGeometry()->GetIndexToWorldTransform(), 1e-8); CPPUNIT_ASSERT_MESSAGE("Since the test data matrix is not quite a rotation matrix, this should be detected.", !is_rotation); } void TestLefthandedCoordinateSystem() { /** * @brief This method tests InitializeStandardPlane() and IndexToWorld() * with a left-handed coordinate orientation or indexToWorldMatrix. * * Of course this test does not use standard Parameters, which are right-handed. - * See also discussion of bug #11477: http://bugs.mitk.org/show_bug.cgi?id=11477 + * See also discussion of bug #11477: https://phabricator.mitk.org/T11477 */ planegeometry = mitk::PlaneGeometry::New(); width = 100; widthInMM = 5; height = 200; heightInMM = 3; thicknessInMM = 1.0; mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); // This one negative sign results in lefthanded coordinate orientation and det(matrix) < 0. mitk::FillVector3D(normal, 0, 0, -thicknessInMM); mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType matrix; mitk::AffineTransform3D::MatrixType::InternalMatrixType &vnl_matrix = matrix.GetVnlMatrix(); vnl_matrix.set_column(0, right); vnl_matrix.set_column(1, bottom); vnl_matrix.set_column(2, normal); // making sure that we didn't screw up this special test case or else fail deadly: assert(vnl_determinant(vnl_matrix) < 0.0); transform->SetIdentity(); transform->SetMatrix(matrix); planegeometry->InitializeStandardPlane(width, height, transform); // Crux of the matter. CPPUNIT_ASSERT_MESSAGE( "Testing if IndexToWorldMatrix is correct after InitializeStandardPlane( width, height, transform ) ", mitk::MatrixEqualElementWise(planegeometry->GetIndexToWorldTransform()->GetMatrix(), matrix)); mitk::Point3D p_index; p_index[0] = 10.; p_index[1] = 10.; p_index[2] = 0.; mitk::Point3D p_world; mitk::Point3D p_expectedResult; p_expectedResult[0] = 50.; p_expectedResult[1] = 30.; p_expectedResult[2] = 0.; ((mitk::BaseGeometry::Pointer)planegeometry)->IndexToWorld(p_index, p_world); // Crux of the matter. CPPUNIT_ASSERT_MESSAGE("Testing if IndexToWorld(a,b) function works correctly with lefthanded matrix ", mitk::Equal(p_world, p_expectedResult, testEps)); } // See bug 1210 // Test does not use standard Parameters void TestCase1210() { mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, down, spacing; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, 1.015625, 1.015625, 1.1999969482421875); mitk::FillVector3D(down, 1.4012984643248170709237295832899161312802619418765e-45, 0, 0); mitk::FillVector3D(spacing, 0, 1.4713633875410579244699160624544119378442750389703e-43, 9.2806360452222355258639080851310540729807238879469e-32); std::cout << "Testing InitializeStandardPlane(rightVector, downVector, spacing = nullptr): " << std::endl; CPPUNIT_ASSERT_NO_THROW(planegeometry->InitializeStandardPlane(right, down, &spacing)); /* std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(planegeometry->GetExtent(0),width)==false) || (mitk::Equal(planegeometry->GetExtent(1),height)==false) || (mitk::Equal(planegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0),widthInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(1),heightInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) ) { std::cout<<"[FAILED]"< 0. * */ // Test does not use standard Parameters void TestIntersectionPoint() { // init plane with its parameter mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; origin[0] = 0.0; origin[1] = 2.0; origin[2] = 0.0; mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 1.0; normal[2] = 0.0; myPlaneGeometry->InitializePlane(origin, normal); // generate points and line for intersection testing // point distance of given line > 1 mitk::Point3D pointP1; pointP1[0] = 2.0; pointP1[1] = 1.0; pointP1[2] = 0.0; mitk::Point3D pointP2; pointP2[0] = 2.0; pointP2[1] = 4.0; pointP2[2] = 0.0; mitk::Vector3D lineDirection; lineDirection[0] = pointP2[0] - pointP1[0]; lineDirection[1] = pointP2[1] - pointP1[1]; lineDirection[2] = pointP2[2] - pointP1[2]; mitk::Line3D xingline(pointP1, lineDirection); mitk::Point3D calcXingPoint; myPlaneGeometry->IntersectionPoint(xingline, calcXingPoint); // point distance of given line < 1 mitk::Point3D pointP3; pointP3[0] = 2.0; pointP3[1] = 2.2; pointP3[2] = 0.0; mitk::Point3D pointP4; pointP4[0] = 2.0; pointP4[1] = 1.7; pointP4[2] = 0.0; mitk::Vector3D lineDirection2; lineDirection2[0] = pointP4[0] - pointP3[0]; lineDirection2[1] = pointP4[1] - pointP3[1]; lineDirection2[2] = pointP4[2] - pointP3[2]; mitk::Line3D xingline2(pointP3, lineDirection2); mitk::Point3D calcXingPoint2; myPlaneGeometry->IntersectionPoint(xingline2, calcXingPoint2); // intersection points must be the same CPPUNIT_ASSERT_MESSAGE("Failed to calculate Intersection Point", calcXingPoint == calcXingPoint2); } /** * @brief This method tests method ProjectPointOntoPlane. * * See also bug #3409. */ // Test does not use standard Parameters void TestProjectPointOntoPlane() { mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); // create normal mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 0.0; normal[2] = 1.0; // create origin mitk::Point3D origin; origin[0] = -27.582859; origin[1] = 50; origin[2] = 200.27742; // initialize plane geometry myPlaneGeometry->InitializePlane(origin, normal); // output to descripe the test std::cout << "Testing PlaneGeometry according to bug #3409" << std::endl; std::cout << "Our normal is: " << normal << std::endl; std::cout << "So ALL projected points should have exactly the same z-value!" << std::endl; // create a number of points mitk::Point3D myPoints[5]; myPoints[0][0] = -27.582859; myPoints[0][1] = 50.00; myPoints[0][2] = 200.27742; myPoints[1][0] = -26.58662; myPoints[1][1] = 50.00; myPoints[1][2] = 200.19026; myPoints[2][0] = -26.58662; myPoints[2][1] = 50.00; myPoints[2][2] = 200.33124; myPoints[3][0] = 104.58662; myPoints[3][1] = 452.12313; myPoints[3][2] = 866.41236; myPoints[4][0] = -207.58662; myPoints[4][1] = 312.00; myPoints[4][2] = -300.12346; // project points onto plane mitk::Point3D myProjectedPoints[5]; for (unsigned int i = 0; i < 5; ++i) { myProjectedPoints[i] = myPlaneGeometry->ProjectPointOntoPlane(myPoints[i]); } // compare z-values with z-value of plane (should be equal) bool allPointsOnPlane = true; for (auto &myProjectedPoint : myProjectedPoints) { if (fabs(myProjectedPoint[2] - origin[2]) > mitk::sqrteps) { allPointsOnPlane = false; } } CPPUNIT_ASSERT_MESSAGE("All points lie not on the same plane", allPointsOnPlane); } void TestPlaneGeometryCloning() { mitk::PlaneGeometry::Pointer geometry2D = createPlaneGeometry(); try { mitk::PlaneGeometry::Pointer clone = geometry2D->Clone(); itk::Matrix matrix = clone->GetIndexToWorldTransform()->GetMatrix(); CPPUNIT_ASSERT_MESSAGE("Test if matrix element exists...", matrix[0][0] == 31); double origin = geometry2D->GetOrigin()[0]; CPPUNIT_ASSERT_MESSAGE("First Point of origin as expected...", mitk::Equal(origin, 8)); double spacing = geometry2D->GetSpacing()[0]; CPPUNIT_ASSERT_MESSAGE("First Point of spacing as expected...", mitk::Equal(spacing, 31)); } catch (...) { CPPUNIT_FAIL("Error during access on a member of cloned geometry"); } // direction [row] [coloum] MITK_TEST_OUTPUT(<< "Casting a rotated 2D ITK Image to a MITK Image and check if Geometry is still same"); } void TestPlaneGeometryInitializeOrder() { mitk::Vector3D mySpacing; mySpacing[0] = 31; mySpacing[1] = 0.1; mySpacing[2] = 5.4; mitk::Point3D myOrigin; myOrigin[0] = 8; myOrigin[1] = 9; myOrigin[2] = 10; mitk::AffineTransform3D::Pointer myTransform = mitk::AffineTransform3D::New(); itk::Matrix transMatrix; transMatrix.Fill(0); transMatrix[0][0] = 1; transMatrix[1][1] = 2; transMatrix[2][2] = 4; myTransform->SetMatrix(transMatrix); mitk::PlaneGeometry::Pointer geometry2D1 = mitk::PlaneGeometry::New(); geometry2D1->SetIndexToWorldTransform(myTransform); geometry2D1->SetSpacing(mySpacing); geometry2D1->SetOrigin(myOrigin); mitk::PlaneGeometry::Pointer geometry2D2 = mitk::PlaneGeometry::New(); geometry2D2->SetSpacing(mySpacing); geometry2D2->SetOrigin(myOrigin); geometry2D2->SetIndexToWorldTransform(myTransform); mitk::PlaneGeometry::Pointer geometry2D3 = mitk::PlaneGeometry::New(); geometry2D3->SetIndexToWorldTransform(myTransform); geometry2D3->SetSpacing(mySpacing); geometry2D3->SetOrigin(myOrigin); geometry2D3->SetIndexToWorldTransform(myTransform); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 1 matches that of Geometry 2.", mitk::Equal(geometry2D1->GetOrigin(), geometry2D2->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 1 match those of Geometry 3.", mitk::Equal(geometry2D1->GetOrigin(), geometry2D3->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 2 match those of Geometry 3.", mitk::Equal(geometry2D2->GetOrigin(), geometry2D3->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 1 match those of Geometry 2.", mitk::Equal(geometry2D1->GetSpacing(), geometry2D2->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 1 match those of Geometry 3.", mitk::Equal(geometry2D1->GetSpacing(), geometry2D3->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 2 match those of Geometry 3.", mitk::Equal(geometry2D2->GetSpacing(), geometry2D3->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 1 match those of Geometry 2.", compareMatrix(geometry2D1->GetIndexToWorldTransform()->GetMatrix(), geometry2D2->GetIndexToWorldTransform()->GetMatrix())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 1 match those of Geometry 3.", compareMatrix(geometry2D1->GetIndexToWorldTransform()->GetMatrix(), geometry2D3->GetIndexToWorldTransform()->GetMatrix())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 2 match those of Geometry 3.", compareMatrix(geometry2D2->GetIndexToWorldTransform()->GetMatrix(), geometry2D3->GetIndexToWorldTransform()->GetMatrix())); } void TestInitializeStandardPlane() { CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: width", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: height", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: depth", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: width in mm", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: heght in mm", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: depth in mm", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorRight", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorBottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorNormal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mitk::Vector3D spacing; thicknessInMM = 1.5; normal.Normalize(); normal *= thicknessInMM; mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right.GetVnlVector(), bottom.GetVnlVector(), &spacing); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: width", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: height", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: depth", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: width in mm", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: height in mm", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: depth in mm", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorRight", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorBottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorNormal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); ; } void TestSetExtendInMM() { normal.Normalize(); normal *= thicknessInMM; planegeometry->SetExtentInMM(2, thicknessInMM); CPPUNIT_ASSERT_MESSAGE("Testing SetExtentInMM(2, ...), querying by GetExtentInMM(2): ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetExtentInMM(2, ...), querying by GetAxisVector(2) and comparing to normal: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); planegeometry->SetOrigin(origin); CPPUNIT_ASSERT_MESSAGE("Testing SetOrigin", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Right", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestRotate() { // Changing the IndexToWorldTransform to a rotated version by SetIndexToWorldTransform() (keep origin): mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = planegeometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::VnlVector axis(3); mitk::FillVector3D(axis, 1.0, 1.0, 1.0); axis.normalize(); vnl_quaternion rotation(axis, 0.223); vnlmatrix = rotation.rotation_matrix_transpose() * vnlmatrix; mitk::Matrix3D matrix; matrix = vnlmatrix; transform->SetMatrix(matrix); transform->SetOffset(planegeometry->GetIndexToWorldTransform()->GetOffset()); right.SetVnlVector(rotation.rotation_matrix_transpose() * right.GetVnlVector()); bottom.SetVnlVector(rotation.rotation_matrix_transpose() * bottom.GetVnlVector()); normal.SetVnlVector(rotation.rotation_matrix_transpose() * normal.GetVnlVector()); planegeometry->SetIndexToWorldTransform(transform); // The origin changed,because m_Origin=m_IndexToWorldTransform->GetOffset()+GetAxisVector(2)*0.5 // and the AxisVector changes due to the rotation. In other words: the rotation was done around // the corner of the box, not around the planes origin. Now change it to a rotation around // the origin, simply by re-setting the origin to the original one: planegeometry->SetOrigin(origin); CPPUNIT_ASSERT_MESSAGE("Testing whether SetIndexToWorldTransform kept origin: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); mitk::Point2D point; point[0] = 4; point[1] = 3; mitk::Point2D dummy; planegeometry->WorldToIndex(point, dummy); planegeometry->IndexToWorld(dummy, dummy); CPPUNIT_ASSERT_MESSAGE("Testing consistency of index and world coordinates.", dummy == point); CPPUNIT_ASSERT_MESSAGE("Testing width of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: right ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(), planegeometry->GetExtentInMM(0), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(), planegeometry->GetExtentInMM(1), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(), planegeometry->GetExtentInMM(2), testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); width *= 2; height *= 3; planegeometry->SetSizeInUnits(width, height); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: right ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(), planegeometry->GetExtentInMM(0), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(), planegeometry->GetExtentInMM(1), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(), planegeometry->GetExtentInMM(2), testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestClone() { mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); // Cave: Statement below is negated! CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry.IsNull()) || (clonedplanegeometry->GetReferenceCount() != 1))); CPPUNIT_ASSERT_MESSAGE("Testing origin of cloned version: ", mitk::Equal(clonedplanegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing extent (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: right", mitk::Equal(clonedplanegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: bottom", mitk::Equal(clonedplanegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: normal", mitk::Equal(clonedplanegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(clonedplanegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestSagittalInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); mitk::PlaneGeometry::Pointer clonedplanegeometry = planegeometry->Clone(); // Testing InitializeStandardPlane(clonedplanegeometry, planeorientation = Sagittal, zPosition = 0, frontside=true): planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Sagittal); mitk::Vector3D newright, newbottom, newnormal; mitk::ScalarType newthicknessInMM; newright = bottom; newthicknessInMM = widthInMM / width * 1.0; // extent in normal direction is 1; newnormal = right; newnormal.Normalize(); newnormal *= newthicknessInMM; newbottom = normal; newbottom.Normalize(); newbottom *= thicknessInMM; CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of sagittally initialized version:", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0, testEps)); // ok, corner was fine, so we can dare to believe the origin is ok. origin = planegeometry->GetOrigin(); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), newnormal, testEps)); mappingTests2D(planegeometry, height, 1, heightInMM, thicknessInMM, origin, newright, newbottom); // set origin back to the one of the axial slice: origin = clonedplanegeometry->GetOrigin(); // Testing backside initialization: InitializeStandardPlane(clonedplanegeometry, planeorientation = Axial, zPosition // = 0, frontside=false, rotated=true): planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Axial, 0, false, true); mitk::Point3D backsideorigin; backsideorigin = origin + clonedplanegeometry->GetAxisVector(1); //+clonedplanegeometry->GetAxisVector(2); CPPUNIT_ASSERT_MESSAGE("Testing origin of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetOrigin(), backsideorigin, testEps)); mitk::Point3D backsidecornerpoint0; backsidecornerpoint0 = cornerpoint0 + clonedplanegeometry->GetAxisVector(1); //+clonedplanegeometry->GetAxisVector(2); CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of sagittally initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), backsidecornerpoint0, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), -bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, backsideorigin, right, -bottom); } void TestCoronalInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); //-------- mitk::Vector3D newright, newbottom, newnormal; mitk::ScalarType newthicknessInMM; // Testing InitializeStandardPlane(clonedplanegeometry, planeorientation = Coronal, zPosition = 0, frontside=true) planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Coronal); newright = right; newbottom = normal; newbottom.Normalize(); newbottom *= thicknessInMM; newthicknessInMM = heightInMM / height * 1.0 /*extent in normal direction is 1*/; newnormal = -bottom; newnormal.Normalize(); newnormal *= newthicknessInMM; CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of coronally initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0, testEps)); // ok, corner was fine, so we can dare to believe the origin is ok. origin = planegeometry->GetOrigin(); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, width, 1, widthInMM, thicknessInMM, origin, newright, newbottom); // Changing plane to in-plane unit spacing using SetSizeInUnits: planegeometry->SetSizeInUnits(planegeometry->GetExtentInMM(0), planegeometry->GetExtentInMM(1)); CPPUNIT_ASSERT_MESSAGE("Testing origin of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, widthInMM, thicknessInMM, widthInMM, thicknessInMM, origin, newright, newbottom); // Changing plane to unit spacing also in normal direction using SetExtentInMM(2, 1.0): planegeometry->SetExtentInMM(2, 1.0); newnormal.Normalize(); CPPUNIT_ASSERT_MESSAGE("Testing origin of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), 1.0, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, widthInMM, thicknessInMM, widthInMM, thicknessInMM, origin, newright, newbottom); } void TestAxialInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); // Clone, move, rotate and test for 'IsParallel' and 'IsOnPlane' mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry.IsNull()) || (clonedplanegeometry->GetReferenceCount() != 1))); std::cout << "Testing InitializeStandardPlane(clonedplanegeometry, planeorientation = Axial, zPosition = 0, " "frontside=true): " << std::endl; planegeometry->InitializeStandardPlane(clonedplanegeometry); CPPUNIT_ASSERT_MESSAGE("Testing origin of axially initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin)); CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of axially initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0)); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of axially initialized version (should be same as in mm due to " "unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of axially initialized version (should be same as in mm due to " "unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in units) of axially initialized version (should be same as in mm due " "to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestPlaneComparison() { // Clone, move, rotate and test for 'IsParallel' and 'IsOnPlane' mitk::PlaneGeometry::Pointer clonedplanegeometry2 = dynamic_cast(planegeometry->Clone().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry2.IsNull()) || (clonedplanegeometry2->GetReferenceCount() != 1))); CPPUNIT_ASSERT_MESSAGE("Testing wheter original and clone are at the same position", clonedplanegeometry2->IsOnPlane(planegeometry.GetPointer())); CPPUNIT_ASSERT_MESSAGE(" Asserting that origin is on the plane cloned plane:", clonedplanegeometry2->IsOnPlane(origin)); mitk::VnlVector newaxis(3); mitk::FillVector3D(newaxis, 1.0, 1.0, 1.0); newaxis.normalize(); vnl_quaternion rotation2(newaxis, 0.0); mitk::Vector3D clonednormal = clonedplanegeometry2->GetNormal(); mitk::Point3D clonedorigin = clonedplanegeometry2->GetOrigin(); auto planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 180.0); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE(" Asserting that a flipped plane is still on the original plane: ", clonedplanegeometry2->IsOnPlane(planegeometry.GetPointer())); clonedorigin += clonednormal; clonedplanegeometry2->SetOrigin(clonedorigin); CPPUNIT_ASSERT_MESSAGE("Testing if the translated (cloned, flipped) plane is parallel to its origin plane: ", clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 0.5); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-paralell plane gets recognized as not paralell [rotation +0.5 degree] : ", !clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), -1.0); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-paralell plane gets recognized as not paralell [rotation -0.5 degree] : ", !clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 360.5); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-paralell plane gets recognized as paralell [rotation 360 degree] : ", clonedplanegeometry2->IsParallel(planegeometry)); } private: // helper Methods for the Tests mitk::PlaneGeometry::Pointer createPlaneGeometry() { mitk::Vector3D mySpacing; mySpacing[0] = 31; mySpacing[1] = 0.1; mySpacing[2] = 5.4; mitk::Point3D myOrigin; myOrigin[0] = 8; myOrigin[1] = 9; myOrigin[2] = 10; mitk::AffineTransform3D::Pointer myTransform = mitk::AffineTransform3D::New(); itk::Matrix transMatrix; transMatrix.Fill(0); transMatrix[0][0] = 1; transMatrix[1][1] = 2; transMatrix[2][2] = 4; myTransform->SetMatrix(transMatrix); mitk::PlaneGeometry::Pointer geometry2D = mitk::PlaneGeometry::New(); geometry2D->SetIndexToWorldTransform(myTransform); geometry2D->SetSpacing(mySpacing); geometry2D->SetOrigin(myOrigin); return geometry2D; } bool compareMatrix(itk::Matrix left, itk::Matrix right) { bool equal = true; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) equal &= mitk::Equal(left[i][j], right[i][j]); return equal; } /** * This function tests for correct mapping and is called several times from other tests **/ void mappingTests2D(const mitk::PlaneGeometry *planegeometry, const mitk::ScalarType &width, const mitk::ScalarType &height, const mitk::ScalarType &widthInMM, const mitk::ScalarType &heightInMM, const mitk::Point3D &origin, const mitk::Vector3D &right, const mitk::Vector3D &bottom) { std::cout << "Testing mapping Map(pt2d_mm(x=widthInMM/2.3,y=heightInMM/2.5), pt3d_mm) and compare with expected: "; mitk::Point2D pt2d_mm; mitk::Point3D pt3d_mm, expected_pt3d_mm; pt2d_mm[0] = widthInMM / 2.3; pt2d_mm[1] = heightInMM / 2.5; expected_pt3d_mm = origin + right * (pt2d_mm[0] / right.GetNorm()) + bottom * (pt2d_mm[1] / bottom.GetNorm()); planegeometry->Map(pt2d_mm, pt3d_mm); CPPUNIT_ASSERT_MESSAGE( "Testing mapping Map(pt2d_mm(x=widthInMM/2.3,y=heightInMM/2.5), pt3d_mm) and compare with expected", mitk::Equal(pt3d_mm, expected_pt3d_mm, testEps)); std::cout << "Testing mapping Map(pt3d_mm, pt2d_mm) and compare with expected: "; mitk::Point2D testpt2d_mm; planegeometry->Map(pt3d_mm, testpt2d_mm); std::cout << std::setprecision(12) << "Expected pt2d_mm " << pt2d_mm << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_mm " << testpt2d_mm << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing mapping Map(pt3d_mm, pt2d_mm) and compare with expected", mitk::Equal(pt2d_mm, testpt2d_mm, 10 * mitk::eps)); std::cout << "Testing IndexToWorld(pt2d_units, pt2d_mm) and compare with expected: "; mitk::Point2D pt2d_units; pt2d_units[0] = width / 2.0; pt2d_units[1] = height / 2.0; pt2d_mm[0] = widthInMM / 2.0; pt2d_mm[1] = heightInMM / 2.0; planegeometry->IndexToWorld(pt2d_units, testpt2d_mm); std::cout << std::setprecision(12) << "Expected pt2d_mm " << pt2d_mm << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_mm " << testpt2d_mm << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing IndexToWorld(pt2d_units, pt2d_mm) and compare with expected: ", mitk::Equal(pt2d_mm, testpt2d_mm, 10 * mitk::eps)); std::cout << "Testing WorldToIndex(pt2d_mm, pt2d_units) and compare with expected: "; mitk::Point2D testpt2d_units; planegeometry->WorldToIndex(pt2d_mm, testpt2d_units); std::cout << std::setprecision(12) << "Expected pt2d_units " << pt2d_units << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_units " << testpt2d_units << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing WorldToIndex(pt2d_mm, pt2d_units) and compare with expected:", mitk::Equal(pt2d_units, testpt2d_units, 10 * mitk::eps)); } }; MITK_TEST_SUITE_REGISTRATION(mitkPlaneGeometry) diff --git a/Modules/CppMicroServices/CMakeLists.txt b/Modules/CppMicroServices/CMakeLists.txt index 3faee251b5..4a7d9ca897 100644 --- a/Modules/CppMicroServices/CMakeLists.txt +++ b/Modules/CppMicroServices/CMakeLists.txt @@ -1,443 +1,440 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 2) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) cmake_minimum_required(VERSION 2.8.12) cmake_policy(VERSION 2.8.12) cmake_policy(SET CMP0017 NEW) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(US_CMAKE_DIR ${PROJECT_SOURCE_DIR}/cmake) set(CMAKE_MODULE_PATH ${US_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CMakeParseArguments) include(CMakePackageConfigHelpers) include(CheckCXXSourceCompiles) include(usFunctionAddResources) include(usFunctionEmbedResources) include(usFunctionGetResourceSource) include(usFunctionCheckResourceLinking) include(usFunctionCheckCompilerFlags) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) include(usMacroCreateModule) if(US_BUILD_TESTING) include(usFunctionCompileSnippets) endif() #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) endif() endif() # Determine the name of the install component for "SDK" artifacts. # The default is "sdk" if(NOT DEFINED US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT sdk) elseif(US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT ${US_SDK_INSTALL_COMPONENT}) endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_ENABLE_DEBUG_OUTPUT OFF BOOL "Enable debug messages" ADVANCED) us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") us_cache_var(US_BUILD_EXAMPLES OFF BOOL "Build example projects") if(US_BUILD_TESTING) enable_testing() endif() if(WIN32 AND NOT CYGWIN) set(default_runtime_install_dir bin/) set(default_library_install_dir bin/) set(default_archive_install_dir lib/) set(default_header_install_dir include/) set(default_auxiliary_install_dir share/) else() set(default_runtime_install_dir bin/) set(default_library_install_dir lib/${PROJECT_NAME}) set(default_archive_install_dir lib/${PROJECT_NAME}) set(default_header_install_dir include/${PROJECT_NAME}) set(default_auxiliary_install_dir share/${PROJECT_NAME}) endif() us_cache_var(RUNTIME_INSTALL_DIR ${default_runtime_install_dir} STRING "Relative install location for binaries" ADVANCED) us_cache_var(LIBRARY_INSTALL_DIR ${default_library_install_dir} STRING "Relative install location for libraries" ADVANCED) us_cache_var(ARCHIVE_INSTALL_DIR ${default_archive_install_dir} STRING "Relative install location for archives" ADVANCED) us_cache_var(HEADER_INSTALL_DIR ${default_header_install_dir} STRING "Relative install location for headers" ADVANCED) us_cache_var(AUXILIARY_INSTALL_DIR ${default_auxiliary_install_dir} STRING "Relative install location for auxiliary files" ADVANCED) set(AUXILIARY_CMAKE_INSTALL_DIR ${AUXILIARY_INSTALL_DIR}/cmake) us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ Micro Services symbols") set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) set(US_MODULE_INIT_TEMPLATE "${US_CMAKE_DIR}/usModuleInit.cpp" CACHE INTERNAL "The module initialization template code") set(US_RESOURCE_RC_TEMPLATE "${US_CMAKE_DIR}/us_resources.rc.in" CACHE INTERNAL "The Windows RC resource template") set(US_CMAKE_RESOURCE_DEPENDENCIES_CPP "${US_CMAKE_DIR}/usCMakeResourceDependencies.cpp" CACHE INTERNAL "The dummy resource dependencies code") #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- if(US_IS_EMBEDDED) set(CMAKE_C_FLAGS) set(CMAKE_C_FLAGS_RELEASE) set(CMAKE_C_FLAGS_DEBUG) set(CMAKE_CXX_FLAGS) set(CMAKE_CXX_FLAGS_RELEASE) set(CMAKE_CXX_FLAGS_DEBUG) set(CMAKE_LINK_FLAGS) set(CMAKE_LINK_FLAGS_RELEASE) set(CMAKE_LINK_FLAGS_DEBUG) endif() # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option -Wno-error=deprecated-copy -Wno-error=implicit-int-float-conversion) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() endif() set(US_HAVE_VISIBILITY_ATTRIBUTE 0) usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" _have_visibility) if(_have_visibility) set(US_HAVE_VISIBILITY_ATTRIBUTE 1) endif() if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) if(${GCC_VERSION} VERSION_LESS "4.0.0") message(FATAL_ERROR "gcc version ${GCC_VERSION} not supported. Please use gcc >= 4.") endif() # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() # Enable visibility support (only for gcc >= 4.5) # We only support hidden visibility with gcc for now. # # Clang has troubles with correctly marking template declarations and explicit template # instantiations as exported across shared library boundaries. Specifically, comparing # type_info objects from STL types does not work (used in us::Any::Type() == typeid(std::string)) # which could be related to the default visibility of STL types declared in libstdc++ and/or libc++ # but also to using RTLD_LOCAL or RTLD_GLOBAL when loading shared libraries via dlopen(). # - # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 - # and http://llvm.org/bugs/show_bug.cgi?id=10113 - # if(_have_visibility AND NOT ${GCC_VERSION} VERSION_LESS "4.5") set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") else() set(US_GCC_RTTI_WORKAROUND_NEEDED 1) endif() usFunctionCheckCompilerFlags("-O1 -D_FORTIFY_SOURCE=2" _fortify_source_flag) if(_fortify_source_flag) set(US_CXX_FLAGS_RELEASE "${US_CXX_FLAGS_RELEASE} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") endif() endif() if(MSVC) set(US_CXX_FLAGS "/MP /WX /wd4180 /wd4996 /wd4251 /wd4503 ${US_CXX_FLAGS}") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${US_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") set(CMAKE_C_FLAGS_REALEASE "${CMAKE_C_FLAGS_RELEASE} ${US_C_FLAGS_RELEASE}") #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() usFunctionCheckResourceLinking() #----------------------------------------------------------------------------- # US Header Checks #----------------------------------------------------------------------------- include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) CHECK_INCLUDE_FILE_CXX(cxxabi.h US_HAVE_CXXABI_H) CHECK_INCLUDE_FILE_CXX(stdint.h US_HAVE_STDINT_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_map US_HAVE_TR1_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_set US_HAVE_TR1_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(tr1/functional US_HAVE_TR1_FUNCTIONAL_H) CHECK_INCLUDE_FILE_CXX(unordered_map US_HAVE_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(unordered_set US_HAVE_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(functional US_HAVE_FUNCTIONAL_H) if(US_HAVE_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() elseif(US_HAVE_TR1_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() else() message(SEND_ERROR "The header file \"unordered_map\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_MAP OR US_HAVE_STD_UNORDERED_MAP)) message(SEND_ERROR "The \"unordered_map\" type is not available.") endif() if(US_HAVE_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) elseif(US_HAVE_TR1_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) else() message(SEND_ERROR "The header file \"unordered_set\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_SET OR US_HAVE_STD_UNORDERED_SET)) message(SEND_ERROR "The \"unordered_set\" type is not available.") endif() if(NOT (US_HAVE_FUNCTIONAL_H OR US_HAVE_TR1_FUNCTIONAL_H)) message(SEND_ERROR "The header file \"functional\" is not available.") endif() if(US_HAVE_FUNCTIONAL_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if((NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) AND US_HAVE_TR1_FUNCTIONAL_H) unset(US_HAVE_TR1_FUNCTION CACHE) unset(US_HAVE_STD_FUNCTION CACHE) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if(NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) message(SEND_ERROR "The \"function\" type is not available.") endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/third_party ${PROJECT_BINARY_DIR}/include) # Configure CppMicroServicesConfig.cmake for the build tree. # The file is used in sub-directories. set(PACKAGE_CONFIG_INCLUDE_DIR ${US_INCLUDE_DIRS}) set(PACKAGE_CONFIG_RUNTIME_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(PACKAGE_CONFIG_CMAKE_DIR ${US_CMAKE_DIR}) set(US_RCC_EXECUTABLE_NAME usResourceCompiler CACHE INTERNAL "The target name of the usResourceCompiler executable.") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) set(us_global_config_h_file "${PROJECT_BINARY_DIR}/include/usGlobalConfig.h") configure_file(${US_CMAKE_DIR}/usGlobalConfig.h.in ${us_global_config_h_file}) include_directories(${US_INCLUDE_DIRS}) add_subdirectory(tools) add_subdirectory(core) #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(doc) #----------------------------------------------------------------------------- # Last configuration and install steps #----------------------------------------------------------------------------- # Version information configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) export(TARGETS ${US_RCC_EXECUTABLE_NAME} FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake) if(NOT US_NO_INSTALL) install(EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) set(_install_cmake_scripts ${US_MODULE_INIT_TEMPLATE} ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} ${US_CMAKE_DIR}/usFunctionGenerateModuleInit.cmake ${US_CMAKE_DIR}/usFunctionAddResources.cmake ${US_CMAKE_DIR}/usFunctionEmbedResources.cmake ${US_CMAKE_DIR}/usFunctionGetResourceSource.cmake ${US_CMAKE_DIR}/usFunctionCheckResourceLinking.cmake ${US_CMAKE_DIR}/usFunctionCheckCompilerFlags.cmake ) install(FILES ${_install_cmake_scripts} DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) install(FILES ${us_global_config_h_file} DESTINATION ${HEADER_INSTALL_DIR}) # Configure CppMicroServicesConfig.cmake for the install tree set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) set(CONFIG_RUNTIME_DIR ${RUNTIME_INSTALL_DIR}) set(CONFIG_CMAKE_DIR ${AUXILIARY_CMAKE_INSTALL_DIR}) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_DIR CONFIG_CMAKE_DIR NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} ) endif() diff --git a/Modules/CppMicroServices/LICENSE b/Modules/CppMicroServices/LICENSE index d645695673..62589edd12 100644 --- a/Modules/CppMicroServices/LICENSE +++ b/Modules/CppMicroServices/LICENSE @@ -1,202 +1,202 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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 + https://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. diff --git a/Modules/CppMicroServices/README.md b/Modules/CppMicroServices/README.md index fcac6bd1d5..aeef8c7e66 100644 --- a/Modules/CppMicroServices/README.md +++ b/Modules/CppMicroServices/README.md @@ -1,100 +1,98 @@ -[![Build Status](https://secure.travis-ci.org/saschazelzer/CppMicroServices.png)](http://travis-ci.org/saschazelzer/CppMicroServices) - [![Coverity Scan Build Status](https://scan.coverity.com/projects/1329/badge.svg)](https://scan.coverity.com/projects/1329) C++ Micro Services ================== Introduction ------------ The C++ Micro Services library provides a dynamic service registry and module system, partially based the OSGi Core Release 5 specifications. It enables developers to create a service oriented and dynamic software stack. Proper usage of the C++ Micro Services library leads to - Re-use of software components - Loose coupling - Separation of concerns - Clean APIs based on service interfaces - Extensible systems and more. Requirements ------------ This is a pure C++ implementation of the OSGi service model and does not have any third-party library dependencies. Supported Platforms ------------------- The library should compile on many different platforms. Below is a list of tested compiler/OS combinations: - GCC 4.6 (Ubuntu 12.04) - GCC 4.8 (Ubuntu 13.10) - Clang 3.2 (Ubuntu 13.10) - Clang (MacOS X 10.8 and 10.9) - Visual Studio 2008 SP1, 2010, 2012, 2013 (Windows 7) Legal ----- Copyright (c) German Cancer Research Center (DKFZ). Licensed under the [Apache License v2.0][apache_license]. Quick Start ----------- Essentially, the C++ Micro Services library provides you with a powerful dynamic service registry. Each shared or static library has an associated `ModuleContext` object, through which the service registry is accessed. To query the registry for a service object implementing one or more specific interfaces, the code would look like this: ```cpp #include #include using namespace us; void UseService(ModuleContext* context) { ServiceReference serviceRef = context->GetServiceReference(); if (serviceRef) { SomeInterface* service = context->GetService(serviceRef); if (service) { /* do something */ } } } ``` Registering a service object against a certain interface looks like this: ```cpp #include #include using namespace us; void RegisterSomeService(ModuleContext* context, SomeInterface* service) { context->RegisterService(service); } ``` The OSGi service model additionally allows to annotate services with properties and using these properties during service look-ups. It also allows to track the life-cycle of service objects. -Please see the [Documentation](http://cppmicroservices.org/doc_latest/index.html) for more +Please see the [Documentation](https://cppmicroservices.org/doc_latest/index.html) for more examples and tutorials and the API reference. There is also a blog post about -[OSGi Lite for C++](http://blog.cppmicroservices.org/2012/04/15/osgi-lite-for-c++). +[OSGi Lite for C++](https://blog.cppmicroservices.org/2012/04/15/osgi-lite-for-c++). Build Instructions ------------------ Please visit the [Build Instructions][bi_master] page online. -[bi_master]: http://cppmicroservices.org/doc_latest/BuildInstructions.html -[apache_license]: http://www.apache.org/licenses/LICENSE-2.0 +[bi_master]: https://cppmicroservices.org/doc_latest/BuildInstructions.html +[apache_license]: https://www.apache.org/licenses/LICENSE-2.0 diff --git a/Modules/CppMicroServices/cmake/usCMakeResourceDependencies.cpp b/Modules/CppMicroServices/cmake/usCMakeResourceDependencies.cpp index 03703b6bb6..79e22db6c1 100644 --- a/Modules/CppMicroServices/cmake/usCMakeResourceDependencies.cpp +++ b/Modules/CppMicroServices/cmake/usCMakeResourceDependencies.cpp @@ -1,33 +1,33 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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. ============================================================================*/ namespace { // This is dummy code to silence some linkers warning about // empty object files. struct CMakeResourceDependencies { CMakeResourceDependencies() { } }; } diff --git a/Modules/CppMicroServices/cmake/usModuleInit.cpp b/Modules/CppMicroServices/cmake/usModuleInit.cpp index d8c7483773..93fbfcc180 100644 --- a/Modules/CppMicroServices/cmake/usModuleInit.cpp +++ b/Modules/CppMicroServices/cmake/usModuleInit.cpp @@ -1,24 +1,24 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include US_INITIALIZE_MODULE diff --git a/Modules/CppMicroServices/core/README.md b/Modules/CppMicroServices/core/README.md index fcac6bd1d5..aeef8c7e66 100644 --- a/Modules/CppMicroServices/core/README.md +++ b/Modules/CppMicroServices/core/README.md @@ -1,100 +1,98 @@ -[![Build Status](https://secure.travis-ci.org/saschazelzer/CppMicroServices.png)](http://travis-ci.org/saschazelzer/CppMicroServices) - [![Coverity Scan Build Status](https://scan.coverity.com/projects/1329/badge.svg)](https://scan.coverity.com/projects/1329) C++ Micro Services ================== Introduction ------------ The C++ Micro Services library provides a dynamic service registry and module system, partially based the OSGi Core Release 5 specifications. It enables developers to create a service oriented and dynamic software stack. Proper usage of the C++ Micro Services library leads to - Re-use of software components - Loose coupling - Separation of concerns - Clean APIs based on service interfaces - Extensible systems and more. Requirements ------------ This is a pure C++ implementation of the OSGi service model and does not have any third-party library dependencies. Supported Platforms ------------------- The library should compile on many different platforms. Below is a list of tested compiler/OS combinations: - GCC 4.6 (Ubuntu 12.04) - GCC 4.8 (Ubuntu 13.10) - Clang 3.2 (Ubuntu 13.10) - Clang (MacOS X 10.8 and 10.9) - Visual Studio 2008 SP1, 2010, 2012, 2013 (Windows 7) Legal ----- Copyright (c) German Cancer Research Center (DKFZ). Licensed under the [Apache License v2.0][apache_license]. Quick Start ----------- Essentially, the C++ Micro Services library provides you with a powerful dynamic service registry. Each shared or static library has an associated `ModuleContext` object, through which the service registry is accessed. To query the registry for a service object implementing one or more specific interfaces, the code would look like this: ```cpp #include #include using namespace us; void UseService(ModuleContext* context) { ServiceReference serviceRef = context->GetServiceReference(); if (serviceRef) { SomeInterface* service = context->GetService(serviceRef); if (service) { /* do something */ } } } ``` Registering a service object against a certain interface looks like this: ```cpp #include #include using namespace us; void RegisterSomeService(ModuleContext* context, SomeInterface* service) { context->RegisterService(service); } ``` The OSGi service model additionally allows to annotate services with properties and using these properties during service look-ups. It also allows to track the life-cycle of service objects. -Please see the [Documentation](http://cppmicroservices.org/doc_latest/index.html) for more +Please see the [Documentation](https://cppmicroservices.org/doc_latest/index.html) for more examples and tutorials and the API reference. There is also a blog post about -[OSGi Lite for C++](http://blog.cppmicroservices.org/2012/04/15/osgi-lite-for-c++). +[OSGi Lite for C++](https://blog.cppmicroservices.org/2012/04/15/osgi-lite-for-c++). Build Instructions ------------------ Please visit the [Build Instructions][bi_master] page online. -[bi_master]: http://cppmicroservices.org/doc_latest/BuildInstructions.html -[apache_license]: http://www.apache.org/licenses/LICENSE-2.0 +[bi_master]: https://cppmicroservices.org/doc_latest/BuildInstructions.html +[apache_license]: https://www.apache.org/licenses/LICENSE-2.0 diff --git a/Modules/CppMicroServices/core/doc/doxygen/standalone/BuildInstructions.md b/Modules/CppMicroServices/core/doc/doxygen/standalone/BuildInstructions.md index 201410319c..9cf1dcb75f 100644 --- a/Modules/CppMicroServices/core/doc/doxygen/standalone/BuildInstructions.md +++ b/Modules/CppMicroServices/core/doc/doxygen/standalone/BuildInstructions.md @@ -1,55 +1,55 @@ Build Instructions {#BuildInstructions} ================== The C++ Micro Services library provides [CMake][cmake] build scripts which allow the generation of platform and IDE specific project files. The library should compile on many different platforms. Below is a list of tested compiler/OS combinations: - GCC 4.6 (Ubuntu 12.04) - GCC 4.8 (Ubuntu 13.10) - Clang 3.2 (Ubuntu 13.10) - Clang (MacOS X 10.8 and 10.9) - Visual Studio 2008 SP1, 2010, 2012, 2013 (Windows 7) Prerequisites ------------- - [CMake][cmake] 2.8 (Visual Studio 2010 and 2012 users should use the latest CMake version available) Configuring the Build --------------------- When building the C++ Micro Services library, you have a few configuration options at hand. ### General build options - **CMAKE_INSTALL_PREFIX** The installation path. - **US_BUILD_SHARED_LIBS** Specify if the library should be build shared or static. See \ref MicroServices_StaticModules for detailed information about static CppMicroServices modules. - **US_BUILD_TESTING** Build unit tests and code snippets. - **US_ENABLE_AUTOLOADING_SUPPORT** Enable auto-loading of modules located in special sub-directories. See \ref MicroServices_AutoLoading for detailed information about this feature. - **US_ENABLE_THREADING_SUPPORT** Enable the use of synchronization primitives (atomics and pthread mutexes or Windows primitives) to make the API thread-safe. If your application is not multi-threaded, turn this option OFF to get maximum performance. ### Customizing naming conventions - **US_NAMESPACE** The default namespace is `us` but you may override this at will. - **US_HEADER_PREFIX** By default, all public headers have a "us" prefix. You may specify an arbitrary prefix to match your naming conventions. The above options are mainly useful when embedding the C++ Micro Services source code in your own library and you want to make it look like native source code. -[cmake]: http://www.cmake.org +[cmake]: https://www.cmake.org diff --git a/Modules/CppMicroServices/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp b/Modules/CppMicroServices/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp index ca70b39ecb..330f2a6073 100644 --- a/Modules/CppMicroServices/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp +++ b/Modules/CppMicroServices/core/doc/snippets/uServices-staticmodules/MyStaticModule.cpp @@ -1,39 +1,39 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include US_USE_NAMESPACE struct MyStaticModuleActivator : public ModuleActivator { void Load(ModuleContext* /*context*/) override { std::cout << "Hello from a static module." << std::endl; } void Unload(ModuleContext* /*context*/) override {} }; US_EXPORT_MODULE_ACTIVATOR(MyStaticModuleActivator) US_INITIALIZE_MODULE diff --git a/Modules/CppMicroServices/core/examples/dictionaryclient/Activator.cpp b/Modules/CppMicroServices/core/examples/dictionaryclient/Activator.cpp index 45f9782701..b906378932 100644 --- a/Modules/CppMicroServices/core/examples/dictionaryclient/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/dictionaryclient/Activator.cpp @@ -1,121 +1,121 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include US_USE_NAMESPACE namespace { /** * This class implements a module activator that uses a dictionary service to check for * the proper spelling of a word by check for its existence in the dictionary. * This modules uses the first service that it finds and does not monitor the * dynamic availability of the service (i.e., it does not listen for the arrival * or departure of dictionary services). When loading this module, the thread * calling the Load() method is used to read words from standard input. You can * stop checking words by entering an empty line, but to start checking words * again you must unload and then load the module again. */ class US_ABI_LOCAL Activator : public ModuleActivator { public: /** * Implements ModuleActivator::Load(). Queries for all available dictionary * services. If none are found it simply prints a message and returns, * otherwise it reads words from standard input and checks for their * existence from the first dictionary that it finds. * * \note It is very bad practice to use the calling thread to perform a lengthy * process like this; this is only done for the purpose of the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { // Query for all service references matching any language. std::vector > refs = context->GetServiceReferences("(Language=*)"); if (!refs.empty()) { std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a word. std::cout << "Enter word: "; std::string word; std::getline(std::cin, word); // If the user entered a blank line, then // exit the loop. if (word.empty()) { break; } // First, get a dictionary service and then check // if the word is correct. IDictionaryService* dictionary = context->GetService(refs.front()); if ( dictionary->CheckWord( word ) ) { std::cout << "Correct." << std::endl; } else { std::cout << "Incorrect." << std::endl; } // Unget the dictionary service. context->UngetService(refs.front()); } } else { std::cout << "Couldn't find any dictionary service..." << std::endl; } } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically released. } }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/Modules/CppMicroServices/core/examples/dictionaryclient2/Activator.cpp b/Modules/CppMicroServices/core/examples/dictionaryclient2/Activator.cpp index bd3b2d5da6..0f64b229eb 100644 --- a/Modules/CppMicroServices/core/examples/dictionaryclient2/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/dictionaryclient2/Activator.cpp @@ -1,218 +1,218 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include US_USE_NAMESPACE namespace { /** * This class implements a module activator that uses a dictionary service to check for * the proper spelling of a word by checking for its existence in the * dictionary. This module is more complex than the module in Example 3 because * it monitors the dynamic availability of the dictionary services. In other * words, if the service it is using departs, then it stops using it gracefully, * or if it needs a service and one arrives, then it starts using it * automatically. As before, the module uses the first service that it finds and * uses the calling thread of the Load() method to read words from standard * input. You can stop checking words by entering an empty line, but to start * checking words again you must unload and then load the module again. */ class US_ABI_LOCAL Activator : public ModuleActivator { public: Activator() : m_context(nullptr) , m_dictionary(nullptr) {} /** * Implements ModuleActivator::Load(). Adds itself as a listener for service * events, then queries for available dictionary services. If any * dictionaries are found it gets a reference to the first one available and * then starts its "word checking loop". If no dictionaries are found, then * it just goes directly into its "word checking loop", but it will not be * able to check any words until a dictionary service arrives; any arriving * dictionary service will be automatically used by the client if a * dictionary is not already in use. Once it has dictionary, it reads words * from standard input and checks for their existence in the dictionary that * it is using. * * \note It is very bad practice to use the calling thread to perform a * lengthy process like this; this is only done for the purpose of * the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { m_context = context; { // Use your favorite thread library to synchronize member // variable access within this scope while registering // the service listener and performing our initial // dictionary service lookup since we // don't want to receive service events when looking up the // dictionary service, if one exists. // MutexLocker lock(&m_mutex); // Listen for events pertaining to dictionary services. m_context->AddServiceListener(this, &Activator::ServiceChanged, std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")" + "(Language=*))"); // Query for any service references matching any language. std::vector > refs = context->GetServiceReferences("(Language=*)"); // If we found any dictionary services, then just get // a reference to the first one so we can use it. if (!refs.empty()) { m_ref = refs.front(); m_dictionary = m_context->GetService(m_ref); } } std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a word. std::cout << "Enter word: "; std::string word; std::getline(std::cin, word); // If the user entered a blank line, then // exit the loop. if (word.empty()) { break; } // If there is no dictionary, then say so. else if (m_dictionary == nullptr) { std::cout << "No dictionary available." << std::endl; } // Otherwise print whether the word is correct or not. else if (m_dictionary->CheckWord( word )) { std::cout << "Correct." << std::endl; } else { std::cout << "Incorrect." << std::endl; } } } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically released. } /** * Implements ServiceListener.serviceChanged(). Checks to see if the service * we are using is leaving or tries to get a service if we need one. * * @param event the fired service event. */ void ServiceChanged(const ServiceEvent event) { // Use your favorite thread library to synchronize this // method with the Load() method. // MutexLocker lock(&m_mutex); // If a dictionary service was registered, see if we // need one. If so, get a reference to it. if (event.GetType() == ServiceEvent::REGISTERED) { if (!m_ref) { // Get a reference to the service object. m_ref = event.GetServiceReference(); m_dictionary = m_context->GetService(m_ref); } } // If a dictionary service was unregistered, see if it // was the one we were using. If so, unget the service // and try to query to get another one. else if (event.GetType() == ServiceEvent::UNREGISTERING) { if (event.GetServiceReference() == m_ref) { // Unget service object and null references. m_context->UngetService(m_ref); m_ref = 0; m_dictionary = nullptr; // Query to see if we can get another service. std::vector > refs; try { refs = m_context->GetServiceReferences("(Language=*)"); } catch (const std::invalid_argument& e) { std::cout << e.what() << std::endl; } if (!refs.empty()) { // Get a reference to the first service object. m_ref = refs.front(); m_dictionary = m_context->GetService(m_ref); } } } } private: // Module context ModuleContext* m_context; // The service reference being used ServiceReference m_ref; // The service object being used IDictionaryService* m_dictionary; }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/Modules/CppMicroServices/core/examples/dictionaryclient3/Activator.cpp b/Modules/CppMicroServices/core/examples/dictionaryclient3/Activator.cpp index f3c8616993..f61bd74382 100644 --- a/Modules/CppMicroServices/core/examples/dictionaryclient3/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/dictionaryclient3/Activator.cpp @@ -1,146 +1,146 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include #include US_USE_NAMESPACE namespace { /** * This class implements a module activator that uses a dictionary * service to check for the proper spelling of a word by * checking for its existence in the dictionary. This module * uses a service tracker to dynamically monitor the availability * of a dictionary service, instead of providing a custom service * listener as in Example 4. The module uses the service returned * by the service tracker, which is selected based on a ranking * algorithm defined by the C++ Micro Services library. * Again, the calling thread of the Load() method is used to read * words from standard input, checking its existence in the dictionary. * You can stop checking words by entering an empty line, but * to start checking words again you must unload and then load * the module again. */ class US_ABI_LOCAL Activator : public ModuleActivator { public: Activator() : m_context(nullptr) , m_tracker(nullptr) {} /** * Implements ModuleActivator::Load(). Creates a service * tracker to monitor dictionary services and starts its "word * checking loop". It will not be able to check any words until * the service tracker finds a dictionary service; any discovered * dictionary service will be automatically used by the client. * It reads words from standard input and checks for their * existence in the discovered dictionary. * * \note It is very bad practice to use the calling thread to perform a * lengthy process like this; this is only done for the purpose of * the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { m_context = context; // Create a service tracker to monitor dictionary services. m_tracker = new ServiceTracker( m_context, LDAPFilter(std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")" + "(Language=*))") ); m_tracker->Open(); std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a word. std::cout << "Enter word: "; std::string word; std::getline(std::cin, word); // Get the selected dictionary, if available. IDictionaryService* dictionary = m_tracker->GetService(); // If the user entered a blank line, then // exit the loop. if (word.empty()) { break; } // If there is no dictionary, then say so. else if (dictionary == nullptr) { std::cout << "No dictionary available." << std::endl; } // Otherwise print whether the word is correct or not. else if (dictionary->CheckWord(word)) { std::cout << "Correct." << std::endl; } else { std::cout << "Incorrect." << std::endl; } } // This automatically closes the tracker delete m_tracker; } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { } private: // Module context ModuleContext* m_context; // The service tracker ServiceTracker* m_tracker; }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/Modules/CppMicroServices/core/examples/dictionaryservice/Activator.cpp b/Modules/CppMicroServices/core/examples/dictionaryservice/Activator.cpp index 3a00e7fde5..a5d3a9065c 100644 --- a/Modules/CppMicroServices/core/examples/dictionaryservice/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/dictionaryservice/Activator.cpp @@ -1,120 +1,120 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include #include #include #include US_USE_NAMESPACE namespace { /** * This class implements a module activator that uses the module * context to register an English language dictionary service * with the C++ Micro Services registry during static initialization * of the module. The dictionary service interface is * defined in a separate file and is implemented by a nested class. */ class US_ABI_LOCAL Activator : public ModuleActivator { private: /** * A private inner class that implements a dictionary service; * see IDictionaryService for details of the service. */ class DictionaryImpl : public IDictionaryService { // The set of words contained in the dictionary. std::set m_dictionary; public: DictionaryImpl() { m_dictionary.insert("welcome"); m_dictionary.insert("to"); m_dictionary.insert("the"); m_dictionary.insert("micro"); m_dictionary.insert("services"); m_dictionary.insert("tutorial"); } /** * Implements IDictionaryService::CheckWord(). Determines * if the passed in word is contained in the dictionary. * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ bool CheckWord(const std::string& word) { std::string lword(word); std::transform(lword.begin(), lword.end(), lword.begin(), ::tolower); return m_dictionary.find(lword) != m_dictionary.end(); } }; std::unique_ptr m_dictionaryService; public: /** * Implements ModuleActivator::Load(). Registers an * instance of a dictionary service using the module context; * attaches properties to the service that can be queried * when performing a service look-up. * @param context the context for the module. */ void Load(ModuleContext* context) { m_dictionaryService.reset(new DictionaryImpl); ServiceProperties props; props["Language"] = std::string("English"); context->RegisterService(m_dictionaryService.get(), props); } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unregister any registered services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically unregistered } }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.cpp b/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.cpp index c375ff0cc5..b3dc99f9bb 100644 --- a/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.cpp +++ b/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.cpp @@ -1,25 +1,25 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "IDictionaryService.h" IDictionaryService::~IDictionaryService() {} diff --git a/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.h b/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.h index 58d288748c..f80aae1cbc 100644 --- a/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.h +++ b/Modules/CppMicroServices/core/examples/dictionaryservice/IDictionaryService.h @@ -1,60 +1,60 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef IDICTIONARYSERVICE_H #define IDICTIONARYSERVICE_H //! [service] #include #include #ifdef US_BUILD_SHARED_LIBS #ifdef Example_dictionaryservice_EXPORTS #define DICTIONARYSERVICE_EXPORT US_ABI_EXPORT #else #define DICTIONARYSERVICE_EXPORT US_ABI_IMPORT #endif #else #define DICTIONARYSERVICE_EXPORT US_ABI_EXPORT #endif /** * A simple service interface that defines a dictionary service. * A dictionary service simply verifies the existence of a word. **/ struct DICTIONARYSERVICE_EXPORT IDictionaryService { // Out-of-line virtual desctructor for proper dynamic cast // support with older versions of gcc. virtual ~IDictionaryService(); /** * Check for the existence of a word. * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ virtual bool CheckWord(const std::string& word) = 0; }; //! [service] #endif // DICTIONARYSERVICE_H diff --git a/Modules/CppMicroServices/core/examples/driver/main.cpp b/Modules/CppMicroServices/core/examples/driver/main.cpp index 5949a084a0..ee7ffbdb42 100644 --- a/Modules/CppMicroServices/core/examples/driver/main.cpp +++ b/Modules/CppMicroServices/core/examples/driver/main.cpp @@ -1,309 +1,309 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include "usCoreExamplesDriverConfig.h" #if defined(US_PLATFORM_POSIX) #include #elif defined(US_PLATFORM_WINDOWS) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #else #error Unsupported platform #endif #include #include #include #include #include #include #include US_USE_NAMESPACE #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif std::vector GetExampleModules() { std::vector names; #ifdef US_BUILD_SHARED_LIBS names.push_back("eventlistener"); names.push_back("dictionaryservice"); names.push_back("frenchdictionary"); names.push_back("dictionaryclient"); names.push_back("dictionaryclient2"); names.push_back("dictionaryclient3"); names.push_back("spellcheckservice"); names.push_back("spellcheckclient"); #endif return names; } int main(int /*argc*/, char** /*argv*/) { char cmd[256]; std::vector availableModules = GetExampleModules(); /* module path -> lib handle */ std::map libraryHandles; SharedLibrary sharedLib(LIB_PATH, ""); std::cout << "> "; while(std::cin.getline(cmd, sizeof(cmd))) { std::string strCmd(cmd); if (strCmd == "q") { break; } else if (strCmd == "h") { std::cout << std::left << std::setw(15) << "h" << " This help text\n" << std::setw(15) << "l " << " Load the module with id or name \n" << std::setw(15) << "u " << " Unload the module with id \n" << std::setw(15) << "s" << " Print status information\n" << std::setw(15) << "q" << " Quit\n" << std::flush; } else if (strCmd.find("l ") != std::string::npos) { std::string idOrName; idOrName.assign(strCmd.begin()+2, strCmd.end()); std::stringstream ss(idOrName); long int id = -1; ss >> id; if (id > 0) { Module* module = ModuleRegistry::GetModule(id); if (!module) { std::cout << "Error: unknown id" << std::endl; } else if (module->IsLoaded()) { std::cout << "Info: module already loaded" << std::endl; } else { try { std::map::iterator libIter = libraryHandles.find(module->GetLocation()); if (libIter != libraryHandles.end()) { libIter->second.Load(); } else { // The module has been loaded previously due to a // linker dependency SharedLibrary libHandle(module->GetLocation()); libHandle.Load(); libraryHandles.insert(std::make_pair(libHandle.GetFilePath(), libHandle)); } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } } else { Module* module = ModuleRegistry::GetModule(idOrName); if (!module) { try { std::map::iterator libIter = libraryHandles.find(sharedLib.GetFilePath(idOrName)); if (libIter != libraryHandles.end()) { libIter->second.Load(); } else { bool libFound = false; for (std::vector::const_iterator availableModuleIter = availableModules.begin(); availableModuleIter != availableModules.end(); ++availableModuleIter) { if (*availableModuleIter == idOrName) { libFound = true; } } if (!libFound) { std::cout << "Error: unknown example module" << std::endl; } else { SharedLibrary libHandle(LIB_PATH, idOrName); libHandle.Load(); libraryHandles.insert(std::make_pair(libHandle.GetFilePath(), libHandle)); } } std::vector modules = ModuleRegistry::GetModules(); for (std::vector::const_iterator moduleIter = modules.begin(); moduleIter != modules.end(); ++moduleIter) { availableModules.erase(std::remove(availableModules.begin(), availableModules.end(), (*moduleIter)->GetName()), availableModules.end()); } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } else if (!module->IsLoaded()) { try { const std::string modulePath = module->GetLocation(); std::map::iterator libIter = libraryHandles.find(modulePath); if (libIter != libraryHandles.end()) { libIter->second.Load(); } else { SharedLibrary libHandle(LIB_PATH, idOrName); libHandle.Load(); libraryHandles.insert(std::make_pair(libHandle.GetFilePath(), libHandle)); } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } else if (module) { std::cout << "Info: module already loaded" << std::endl; } } } else if (strCmd.find("u ") != std::string::npos) { std::stringstream ss(strCmd); ss.ignore(2); long int id = -1; ss >> id; if (id == 1) { std::cout << "Info: Unloading not possible" << std::endl; } else { Module* const module = ModuleRegistry::GetModule(id); if (module) { std::map::iterator libIter = libraryHandles.find(module->GetLocation()); if (libIter == libraryHandles.end()) { std::cout << "Info: Unloading not possible. The module was loaded by a dependent module." << std::endl; } else { try { libIter->second.Unload(); // Check if it has really been unloaded if (module->IsLoaded()) { std::cout << "Info: The module is still referenced by another loaded module. It will be unloaded when all dependent modules are unloaded." << std::endl; } } catch (const std::exception& e) { std::cout << e.what() << std::endl; } } } else { std::cout << "Error: unknown id" << std::endl; } } } else if (strCmd == "s") { std::vector modules = ModuleRegistry::GetModules(); std::cout << std::left; std::cout << "Id | " << std::setw(20) << "Name" << " | " << std::setw(9) << "Status" << std::endl; std::cout << "-----------------------------------\n"; for (std::vector::const_iterator nameIter = availableModules.begin(); nameIter != availableModules.end(); ++nameIter) { std::cout << " - | " << std::setw(20) << *nameIter << " | " << std::setw(9) << "-" << std::endl; } for (std::vector::const_iterator moduleIter = modules.begin(); moduleIter != modules.end(); ++moduleIter) { std::cout << std::right << std::setw(2) << (*moduleIter)->GetModuleId() << std::left << " | "; std::cout << std::setw(20) << (*moduleIter)->GetName() << " | "; std::cout << std::setw(9) << ((*moduleIter)->IsLoaded() ? "LOADED" : "UNLOADED"); std::cout << std::endl; } } else { std::cout << "Unknown command: " << strCmd << " (type 'h' for help)" << std::endl; } std::cout << "> "; } return 0; } #ifndef US_BUILD_SHARED_LIBS US_IMPORT_MODULE(CppMicroServices) US_IMPORT_MODULE(eventlistener) US_IMPORT_MODULE(dictionaryservice) US_IMPORT_MODULE(dictionaryclient) #endif diff --git a/Modules/CppMicroServices/core/examples/driver/usCoreExamplesDriverConfig.h.in b/Modules/CppMicroServices/core/examples/driver/usCoreExamplesDriverConfig.h.in index 95af0c8cc3..1fa983d856 100644 --- a/Modules/CppMicroServices/core/examples/driver/usCoreExamplesDriverConfig.h.in +++ b/Modules/CppMicroServices/core/examples/driver/usCoreExamplesDriverConfig.h.in @@ -1,41 +1,41 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USEXAMPLEDRIVERCONFIG_H #define USEXAMPLEDRIVERCONFIG_H #include "usGlobalConfig.h" #ifdef US_PLATFORM_POSIX #define PATH_SEPARATOR "/" #else #define PATH_SEPARATOR "\\" #endif #ifdef CMAKE_INTDIR #define US_LIBRARY_OUTPUT_DIRECTORY "@CMAKE_LIBRARY_OUTPUT_DIRECTORY_NATIVE@" PATH_SEPARATOR CMAKE_INTDIR #define US_RUNTIME_OUTPUT_DIRECTORY "@CMAKE_RUNTIME_OUTPUT_DIRECTORY_NATIVE@" PATH_SEPARATOR CMAKE_INTDIR #else #define US_LIBRARY_OUTPUT_DIRECTORY "@CMAKE_LIBRARY_OUTPUT_DIRECTORY_NATIVE@" #define US_RUNTIME_OUTPUT_DIRECTORY "@CMAKE_RUNTIME_OUTPUT_DIRECTORY_NATIVE@" #endif #endif // USEXAMPLEDRIVERCONFIG_H diff --git a/Modules/CppMicroServices/core/examples/eventlistener/Activator.cpp b/Modules/CppMicroServices/core/examples/eventlistener/Activator.cpp index a4462a7339..e749f64dc4 100644 --- a/Modules/CppMicroServices/core/examples/eventlistener/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/eventlistener/Activator.cpp @@ -1,94 +1,94 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include #include US_USE_NAMESPACE namespace { /** * This class implements a simple module that utilizes the CppMicroServices's * event mechanism to listen for service events. Upon receiving a service event, * it prints out the event's details. */ class Activator : public ModuleActivator { private: /** * Implements ModuleActivator::Load(). Prints a message and adds a member * function to the module context as a service listener. * * @param context the framework context for the module. */ void Load(ModuleContext* context) { std::cout << "Starting to listen for service events." << std::endl; context->AddServiceListener(this, &Activator::ServiceChanged); } /** * Implements ModuleActivator::Unload(). Prints a message and removes the * member function from the module context as a service listener. * * @param context the framework context for the module. */ void Unload(ModuleContext* context) { context->RemoveServiceListener(this, &Activator::ServiceChanged); std::cout << "Stopped listening for service events." << std::endl; // Note: It is not required that we remove the listener here, // since the framework will do it automatically anyway. } /** * Prints the details of any service event from the framework. * * @param event the fired service event. */ void ServiceChanged(const ServiceEvent event) { std::string objectClass = ref_any_cast >(event.GetServiceReference().GetProperty(ServiceConstants::OBJECTCLASS())).front(); if (event.GetType() == ServiceEvent::REGISTERED) { std::cout << "Ex1: Service of type " << objectClass << " registered." << std::endl; } else if (event.GetType() == ServiceEvent::UNREGISTERING) { std::cout << "Ex1: Service of type " << objectClass << " unregistered." << std::endl; } else if (event.GetType() == ServiceEvent::MODIFIED) { std::cout << "Ex1: Service of type " << objectClass << " modified." << std::endl; } } }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //! [Activator] diff --git a/Modules/CppMicroServices/core/examples/frenchdictionary/Activator.cpp b/Modules/CppMicroServices/core/examples/frenchdictionary/Activator.cpp index 009b45f2f3..f89f114e19 100644 --- a/Modules/CppMicroServices/core/examples/frenchdictionary/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/frenchdictionary/Activator.cpp @@ -1,122 +1,122 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include #include #include #include #include #include US_USE_NAMESPACE namespace { /** * This class implements a module activator that uses the module * context to register a French language dictionary service * with the C++ Micro Services registry during static initialization * of the module. The dictionary service interface is * defined in Example 2 (dictionaryservice) and is implemented by a * nested class. This class is identical to the class in Example 2, * except that the dictionary contains French words. */ class US_ABI_LOCAL Activator : public ModuleActivator { private: /** * A private inner class that implements a dictionary service; * see DictionaryService for details of the service. */ class DictionaryImpl : public IDictionaryService { // The set of words contained in the dictionary. std::set m_dictionary; public: DictionaryImpl() { m_dictionary.insert("bienvenue"); m_dictionary.insert("au"); m_dictionary.insert("tutoriel"); m_dictionary.insert("micro"); m_dictionary.insert("services"); } /** * Implements DictionaryService.checkWord(). Determines * if the passed in word is contained in the dictionary. * @param word the word to be checked. * @return true if the word is in the dictionary, * false otherwise. **/ bool CheckWord(const std::string& word) { std::string lword(word); std::transform(lword.begin(), lword.end(), lword.begin(), ::tolower); return m_dictionary.find(lword) != m_dictionary.end(); } }; std::unique_ptr m_dictionaryService; public: /** * Implements ModuleActivator::Load(). Registers an * instance of a dictionary service using the module context; * attaches properties to the service that can be queried * when performing a service look-up. * @param context the context for the module. */ void Load(ModuleContext* context) { m_dictionaryService.reset(new DictionaryImpl); ServiceProperties props; props["Language"] = std::string("French"); context->RegisterService(m_dictionaryService.get(), props); } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unregister any registered services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically unregistered } }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/Modules/CppMicroServices/core/examples/spellcheckclient/Activator.cpp b/Modules/CppMicroServices/core/examples/spellcheckclient/Activator.cpp index 11cabc3748..0b9c174dc9 100644 --- a/Modules/CppMicroServices/core/examples/spellcheckclient/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/spellcheckclient/Activator.cpp @@ -1,147 +1,147 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include "ISpellCheckService.h" #include #include #include #include #include US_USE_NAMESPACE namespace { /** * This class implements a module that uses a spell checker * service to check the spelling of a passage. This module * is essentially identical to Example 5, in that it uses the * Service Tracker to monitor the dynamic availability of the * spell checker service. When loading this module, the thread * calling the Load() method is used to read passages from * standard input. You can stop spell checking passages by * entering an empty line, but to start spell checking again * you must un-load and then load the module again. **/ class US_ABI_LOCAL Activator : public ModuleActivator { public: Activator() : m_context(nullptr) , m_tracker(nullptr) {} /** * Implements ModuleActivator::Load(). Creates a service * tracker object to monitor spell checker services. Enters * a spell check loop where it reads passages from standard * input and checks their spelling using the spell checker service. * * \note It is very bad practice to use the calling thread to perform a * lengthy process like this; this is only done for the purpose of * the tutorial. * * @param context the module context for this module. */ void Load(ModuleContext *context) { m_context = context; // Create a service tracker to monitor spell check services. m_tracker = new ServiceTracker(m_context); m_tracker->Open(); std::cout << "Enter a blank line to exit." << std::endl; // Loop endlessly until the user enters a blank line while (std::cin) { // Ask the user to enter a passage. std::cout << "Enter passage: "; std::string passage; std::getline(std::cin, passage); // Get the selected spell check service, if available. ISpellCheckService* checker = m_tracker->GetService(); // If the user entered a blank line, then // exit the loop. if (passage.empty()) { break; } // If there is no spell checker, then say so. else if (checker == nullptr) { std::cout << "No spell checker available." << std::endl; } // Otherwise check passage and print misspelled words. else { std::vector errors = checker->Check(passage); if (errors.empty()) { std::cout << "Passage is correct." << std::endl; } else { std::cout << "Incorrect word(s):" << std::endl; for (std::size_t i = 0; i < errors.size(); ++i) { std::cout << " " << errors[i] << std::endl; } } } } // This automatically closes the tracker delete m_tracker; } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unget any used services. * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { } private: // Module context ModuleContext* m_context; // The service tracker ServiceTracker* m_tracker; }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/Modules/CppMicroServices/core/examples/spellcheckservice/Activator.cpp b/Modules/CppMicroServices/core/examples/spellcheckservice/Activator.cpp index 3aba6c53d6..4b5baada5f 100644 --- a/Modules/CppMicroServices/core/examples/spellcheckservice/Activator.cpp +++ b/Modules/CppMicroServices/core/examples/spellcheckservice/Activator.cpp @@ -1,229 +1,229 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ //! [Activator] #include "IDictionaryService.h" #include "ISpellCheckService.h" #include #include #include #include #include #include #include #include US_USE_NAMESPACE namespace { /** * This class implements a module that implements a spell * checker service. The spell checker service uses all available * dictionary services to check for the existence of words in * a given sentence. This module uses a ServiceTracker to * monitors the dynamic availability of dictionary services, * and to aggregate all available dictionary services as they * arrive and depart. The spell checker service is only registered * if there are dictionary services available, thus the spell * checker service will appear and disappear as dictionary * services appear and disappear, respectively. **/ class US_ABI_LOCAL Activator : public ModuleActivator, public ServiceTrackerCustomizer { private: /** * A private inner class that implements a spell check service; see * ISpellCheckService for details of the service. */ class SpellCheckImpl : public ISpellCheckService { private: typedef std::map, IDictionaryService*> RefToServiceType; RefToServiceType m_refToSvcMap; public: /** * Implements ISpellCheckService::Check(). Checks the given passage for * misspelled words. * * @param passage the passage to spell check. * @return A list of misspelled words. */ std::vector Check(const std::string& passage) { std::vector errorList; // No misspelled words for an empty string. if (passage.empty()) { return errorList; } // Tokenize the passage using spaces and punctuation. const char* delimiters = " ,.!?;:"; char* passageCopy = new char[passage.size()+1]; std::memcpy(passageCopy, passage.c_str(), passage.size()+1); char* pch = std::strtok(passageCopy, delimiters); { // Lock the m_refToSvcMap member using your favorite thread library here... // MutexLocker lock(&m_refToSvcMapMutex) // Loop through each word in the passage. while (pch) { std::string word(pch); bool correct = false; // Check each available dictionary for the current word. for (RefToServiceType::const_iterator i = m_refToSvcMap.begin(); (!correct) && (i != m_refToSvcMap.end()); ++i) { IDictionaryService* dictionary = i->second; if (dictionary->CheckWord(word)) { correct = true; } } // If the word is not correct, then add it // to the incorrect word list. if (!correct) { errorList.push_back(word); } pch = std::strtok(nullptr, delimiters); } } delete[] passageCopy; return errorList; } std::size_t AddDictionary(const ServiceReference& ref, IDictionaryService* dictionary) { // Lock the m_refToSvcMap member using your favorite thread library here... // MutexLocker lock(&m_refToSvcMapMutex) m_refToSvcMap.insert(std::make_pair(ref, dictionary)); return m_refToSvcMap.size(); } std::size_t RemoveDictionary(const ServiceReference& ref) { // Lock the m_refToSvcMap member using your favorite thread library here... // MutexLocker lock(&m_refToSvcMapMutex) m_refToSvcMap.erase(ref); return m_refToSvcMap.size(); } }; virtual IDictionaryService* AddingService(const ServiceReference& reference) { IDictionaryService* dictionary = m_context->GetService(reference); std::size_t count = m_spellCheckService->AddDictionary(reference, dictionary); if (!m_spellCheckReg && count > 1) { m_spellCheckReg = m_context->RegisterService(m_spellCheckService.get()); } return dictionary; } virtual void ModifiedService(const ServiceReference& /*reference*/, IDictionaryService* /*service*/) { // do nothing } virtual void RemovedService(const ServiceReference& reference, IDictionaryService* /*service*/) { if (m_spellCheckService->RemoveDictionary(reference) < 2 && m_spellCheckReg) { m_spellCheckReg.Unregister(); m_spellCheckReg = 0; } } std::unique_ptr m_spellCheckService; ServiceRegistration m_spellCheckReg; ModuleContext* m_context; std::unique_ptr > m_tracker; public: Activator() : m_context(nullptr) {} /** * Implements ModuleActivator::Load(). Registers an * instance of a dictionary service using the module context; * attaches properties to the service that can be queried * when performing a service look-up. * * @param context the context for the module. */ void Load(ModuleContext* context) { m_context = context; m_spellCheckService.reset(new SpellCheckImpl); m_tracker.reset(new ServiceTracker(context, this)); m_tracker->Open(); } /** * Implements ModuleActivator::Unload(). Does nothing since * the C++ Micro Services library will automatically unregister any registered services * and release any used services. * * @param context the context for the module. */ void Unload(ModuleContext* /*context*/) { // NOTE: The service is automatically unregistered m_tracker->Close(); } }; } US_EXPORT_MODULE_ACTIVATOR(Activator) //![Activator] diff --git a/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.cpp b/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.cpp index 7041dd070b..5968877fda 100644 --- a/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.cpp +++ b/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.cpp @@ -1,25 +1,25 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "ISpellCheckService.h" ISpellCheckService::~ISpellCheckService() {} diff --git a/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.h b/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.h index 47e35399fe..d72b59fe8e 100644 --- a/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.h +++ b/Modules/CppMicroServices/core/examples/spellcheckservice/ISpellCheckService.h @@ -1,66 +1,66 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef ISPELLCHECKSERVICE_H #define ISPELLCHECKSERVICE_H //! [service] #include #include #include #ifdef US_BUILD_SHARED_LIBS #ifdef Example_spellcheckservice_EXPORTS #define SPELLCHECKSERVICE_EXPORT US_ABI_EXPORT #else #define SPELLCHECKSERVICE_EXPORT US_ABI_IMPORT #endif #else #define SPELLCHECKSERVICE_EXPORT US_ABI_EXPORT #endif /** * A simple service interface that defines a spell check service. A spell check * service checks the spelling of all words in a given passage. A passage is any * number of words separated by a space character and the following punctuation * marks: comma, period, exclamation mark, question mark, semi-colon, and colon. */ struct SPELLCHECKSERVICE_EXPORT ISpellCheckService { // Out-of-line virtual desctructor for proper dynamic cast // support with older versions of gcc. virtual ~ISpellCheckService(); /** * Checks a given passage for spelling errors. A passage is any number of * words separated by a space and any of the following punctuation marks: * comma (,), period (.), exclamation mark (!), question mark (?), * semi-colon (;), and colon(:). * * @param passage the passage to spell check. * @return A list of misspelled words. */ virtual std::vector Check(const std::string& passage) = 0; }; //! [service] //! #endif // ISPELLCHECKSERVICE_H diff --git a/Modules/CppMicroServices/core/include/usGetModuleContext.h b/Modules/CppMicroServices/core/include/usGetModuleContext.h index 77b70cc7ba..e1d964c609 100644 --- a/Modules/CppMicroServices/core/include/usGetModuleContext.h +++ b/Modules/CppMicroServices/core/include/usGetModuleContext.h @@ -1,65 +1,65 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USGETMODULECONTEXT_H #define USGETMODULECONTEXT_H #ifndef US_MODULE_NAME #error Missing preprocessor define US_MODULE_NAME #endif #include #include #include #include #include US_BEGIN_NAMESPACE class ModuleContext; /** * \ingroup MicroServices * * \brief Returns the module context of the calling module. * * This function allows easy access to the ModuleContext instance from * inside a C++ Micro Services module. * * \return The ModuleContext of the calling module. */ static inline ModuleContext* GetModuleContext() { Module* module = ModuleRegistry::GetModule(US_STR(US_MODULE_NAME)); if (module) { return module->GetModuleContext(); } US_WARN << "Module '" << US_STR(US_MODULE_NAME) << "' unknown. " "The calling module probably misses a US_MODULE_NAME compile definition " "and/or a call to US_INITIALIZE_MODULE in one of its source files."; return nullptr; } US_END_NAMESPACE #endif // USGETMODULECONTEXT_H diff --git a/Modules/CppMicroServices/core/include/usLDAPFilter.h b/Modules/CppMicroServices/core/include/usLDAPFilter.h index e9ee922366..3340e04340 100644 --- a/Modules/CppMicroServices/core/include/usLDAPFilter.h +++ b/Modules/CppMicroServices/core/include/usLDAPFilter.h @@ -1,171 +1,171 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USLDAPFILTER_H #define USLDAPFILTER_H #include "usServiceProperties.h" #include "usSharedData.h" US_BEGIN_NAMESPACE class LDAPFilterData; class ServiceReferenceBase; /** * \ingroup MicroServices * - * An RFC 1960-based Filter. + * 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. * * \sa LDAPProp for a fluent API generating LDAP filter strings */ class US_Core_EXPORT LDAPFilter { private: typedef SharedDataPointer LDAPFilter::*bool_type; 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_type() 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 ServiceReferenceBase& 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; }; US_END_NAMESPACE /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(LDAPFilter)& filter); #endif // USLDAPFILTER_H diff --git a/Modules/CppMicroServices/core/include/usLDAPProp.h b/Modules/CppMicroServices/core/include/usLDAPProp.h index e0a03ababd..4376518b6d 100644 --- a/Modules/CppMicroServices/core/include/usLDAPProp.h +++ b/Modules/CppMicroServices/core/include/usLDAPProp.h @@ -1,226 +1,226 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USLDAPPROP_H #define USLDAPPROP_H #include #include US_BEGIN_NAMESPACE /// \cond class US_Core_EXPORT LDAPPropExpr { public: explicit LDAPPropExpr(const std::string& expr); LDAPPropExpr& operator!(); operator std::string() const; bool IsNull() const; private: LDAPPropExpr& operator=(const LDAPPropExpr&); std::string m_ldapExpr; }; /// \endcond /** * \ingroup MicroServicesUtils * * A fluent API for creating LDAP filter strings. * * Examples for creating LDAPFilter objects: * \code * // This creates the filter "(&(name=Ben)(!(count=1)))" * LDAPFilter filter(LDAPProp("name") == "Ben" && !(LDAPProp("count") == 1)); * * // This creates the filter "(|(presence=*)(!(absence=*)))" * LDAPFilter filter(LDAPProp("presence") || !LDAPProp("absence")); * * // This creates the filter "(&(ge>=-3)(approx~=hi))" * LDAPFilter filter(LDAPProp("ge") >= -3 && LDAPProp("approx").Approx("hi")); * \endcode * * \sa LDAPFilter */ class US_Core_EXPORT LDAPProp { public: /** * Create a LDAPProp instance for the named LDAP property. * * @param property The name of the LDAP property. */ LDAPProp(const std::string& property); /** * LDAP equality '=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator==(const std::string& s) const; LDAPPropExpr operator==(const us::Any& s) const; template LDAPPropExpr operator==(const T& s) const { std::stringstream ss; ss << s; return LDAPPropExpr("(" + m_property + "=" + ss.str() + ")"); } /// @} operator LDAPPropExpr () const; /** * States the absence of the LDAP property. * * @return A LDAP expression object. */ LDAPPropExpr operator!() const; /** * Convenience operator for LDAP inequality. * * Writing either * \code * LDAPProp("attr") != "val" * \endcode * or * \code * !(LDAPProp("attr") == "val") * \endcode * leads to the same string "(!(attr=val))". * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator!=(const std::string& s) const; LDAPPropExpr operator!=(const us::Any& s) const; template LDAPPropExpr operator!=(const T& s) const { std::stringstream ss; ss << s; return operator!=(ss.str()); } /// @} /** * LDAP greater or equal '>=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator>=(const std::string& s) const; LDAPPropExpr operator>=(const us::Any& s) const; template LDAPPropExpr operator>=(const T& s) const { std::stringstream ss; ss << s; return operator>=(ss.str()); } /// @} /** * LDAP less or equal '<=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator<=(const std::string& s) const; LDAPPropExpr operator<=(const us::Any& s) const; template LDAPPropExpr operator<=(const T& s) const { std::stringstream ss; ss << s; return operator<=(ss.str()); } /// @} /** * LDAP approximation '~=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr Approx(const std::string& s) const; LDAPPropExpr Approx(const us::Any& s) const; template LDAPPropExpr Approx(const T& s) const { std::stringstream ss; ss << s; return Approx(ss.str()); } /// @} private: LDAPProp& operator=(const LDAPProp&); std::string m_property; }; US_END_NAMESPACE /** * \ingroup MicroServicesUtils * * LDAP logical and '&' * * @param left A LDAP expression. * @param right A LDAP expression. * @return A LDAP expression */ US_Core_EXPORT us::LDAPPropExpr operator&&(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right); /** * \ingroup MicroServicesUtils * * LDAP logical or '|' * * @param left A LDAP expression. * @param right A LDAP expression. * @return A LDAP expression */ US_Core_EXPORT us::LDAPPropExpr operator||(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right); #endif // USLDAPPROP_H diff --git a/Modules/CppMicroServices/core/include/usModule.h b/Modules/CppMicroServices/core/include/usModule.h index 489f98eb24..163f574ccc 100644 --- a/Modules/CppMicroServices/core/include/usModule.h +++ b/Modules/CppMicroServices/core/include/usModule.h @@ -1,367 +1,367 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULE_H #define USMODULE_H #include "usModuleVersion.h" #include US_BEGIN_NAMESPACE class Any; class CoreModuleContext; struct ModuleInfo; class ModuleContext; class ModuleResource; class ModulePrivate; template class ServiceReference; typedef ServiceReference ServiceReferenceU; /** * \ingroup MicroServices * * Represents a CppMicroServices module. * *

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

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

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

    *
  • LOADED *
  • UNLOADED *
*

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

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

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

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

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

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

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

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

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

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

* This method continues to return this module's version while * this module is in the UNLOADED state. * * @return The version of this module. */ ModuleVersion GetVersion() const; /** * Returns the value of the specified property for this module. The * method returns an empty Any if the property is not found. * * @param key The name of the requested property. * @return The value of the requested property, or an empty string * if the property is undefined. * * @sa GetPropertyKeys() * @sa \ref MicroServices_ModuleProperties */ Any GetProperty(const std::string& key) const; /** * Returns a list of top-level property keys for this module. * * @return A list of available property keys. * * @sa \ref MicroServices_ModuleProperties */ std::vector GetPropertyKeys() const; /** * Returns this module's ServiceReference list for all services it * has registered or an empty list if this module has no registered * services. * * The list is valid at the time of the call to this method, however, * as the framework is a very dynamic environment, services can be * modified or unregistered at anytime. * * @return A list of ServiceReference objects for services this * module has registered. */ std::vector GetRegisteredServices() const; /** * Returns this module's ServiceReference list for all services it is * using or returns an empty list if this module is not using any * services. A module is considered to be using a service if its use * count for that service is greater than zero. * * The list is valid at the time of the call to this method, however, * as the framework is a very dynamic environment, services can be * modified or unregistered at anytime. * * @return A list of ServiceReference objects for all services this * module is using. */ std::vector GetServicesInUse() const; /** * Returns the resource at the specified \c path in this module. * The specified \c path is always relative to the root of this module and may * begin with '/'. A path value of "/" indicates the root of this module. * * @param path The path name of the resource. * @return A ModuleResource object for the given \c path. If the \c path cannot * be found in this module or the module's state is \c UNLOADED, an invalid * ModuleResource object is returned. */ ModuleResource GetResource(const std::string& path) const; /** * Returns resources in this module. * * This method is intended to be used to obtain configuration, setup, localization * and other information from this module. * * This method can either return only resources in the specified \c path or recurse * into subdirectories returning resources in the directory tree beginning at the * specified path. * * Examples: * \snippet uServices-resources/main.cpp 0 * * @param path The path name in which to look. The path is always relative to the root * of this module and may begin with '/'. A path value of "/" indicates the root of this module. * @param filePattern The resource name pattern for selecting entries in the specified path. * The pattern is only matched against the last element of the resource path. Substring * matching is supported using the wildcard charachter ('*'). If \c filePattern is empty, * this is equivalent to "*" and matches all resources. * @param recurse If \c true, recurse into subdirectories. Otherwise only return resources * from the specified path. * @return A vector of ModuleResource objects for each matching entry. */ std::vector FindResources(const std::string& path, const std::string& filePattern, bool recurse) const; private: friend class CoreModuleActivator; friend class ModuleRegistry; friend class ServiceReferencePrivate; ModulePrivate* d; Module(); void Init(CoreModuleContext* coreCtx, ModuleInfo* info); void Uninit(); void Start(); void Stop(); // purposely not implemented Module(const Module &); Module& operator=(const Module&); }; US_END_NAMESPACE /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(Module)& module); /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, US_PREPEND_NAMESPACE(Module) const * module); #endif // USMODULE_H diff --git a/Modules/CppMicroServices/core/include/usModuleActivator.h b/Modules/CppMicroServices/core/include/usModuleActivator.h index 6231f065ff..9ed4ccc241 100644 --- a/Modules/CppMicroServices/core/include/usModuleActivator.h +++ b/Modules/CppMicroServices/core/include/usModuleActivator.h @@ -1,134 +1,134 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEACTIVATOR_H_ #define USMODULEACTIVATOR_H_ #ifndef US_MODULE_NAME #error Missing US_MODULE_NAME preprocessor define #endif #include #include US_BEGIN_NAMESPACE class ModuleContext; /** * \ingroup MicroServices * * Customizes the starting and stopping of a CppMicroServices module. *

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

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

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

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

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

* This method must complete and return to its caller in a timely manner. * * @param context The execution context of the module being unloaded. * @throws std::exception If this method throws an exception, the * module is still marked as unloaded, and the framework will remove * the module's listeners, unregister all services registered by the * module, and release all services used by the module. */ virtual void Unload(ModuleContext* context) = 0; }; US_END_NAMESPACE /** * \ingroup MicroServices * * \brief Export a module activator class. * * \param _activator_type The fully-qualified type-name of the module activator class. * * Call this macro after the definition of your module activator to make it * accessible by the CppMicroServices library. * * Example: * \snippet uServices-activator/main.cpp 0 */ #define US_EXPORT_MODULE_ACTIVATOR(_activator_type) \ extern "C" US_ABI_EXPORT US_PREPEND_NAMESPACE(ModuleActivator)* US_CONCAT(_us_module_activator_instance_, US_MODULE_NAME) () \ { \ struct ScopedPointer \ { \ ScopedPointer(US_PREPEND_NAMESPACE(ModuleActivator)* activator = 0) : m_Activator(activator) {} \ ~ScopedPointer() { delete m_Activator; } \ US_PREPEND_NAMESPACE(ModuleActivator)* m_Activator; \ }; \ \ static ScopedPointer activatorPtr; \ if (activatorPtr.m_Activator == 0) activatorPtr.m_Activator = new _activator_type; \ return activatorPtr.m_Activator; \ } #endif /* USMODULEACTIVATOR_H_ */ diff --git a/Modules/CppMicroServices/core/include/usModuleContext.h b/Modules/CppMicroServices/core/include/usModuleContext.h index 358cbe4d8b..bfee00510d 100644 --- a/Modules/CppMicroServices/core/include/usModuleContext.h +++ b/Modules/CppMicroServices/core/include/usModuleContext.h @@ -1,851 +1,851 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULECONTEXT_H_ #define USMODULECONTEXT_H_ // TODO: Replace includes with forward directives! #include "usListenerFunctors_p.h" #include "usServiceInterface.h" #include "usServiceEvent.h" #include "usServiceRegistration.h" #include "usServiceException.h" #include "usModuleEvent.h" US_BEGIN_NAMESPACE typedef US_SERVICE_LISTENER_FUNCTOR ServiceListener; typedef US_MODULE_LISTENER_FUNCTOR ModuleListener; class ModuleContextPrivate; class ServiceFactory; template class ServiceObjects; /** * \ingroup MicroServices * * A module's execution context within the framework. The context is used to * grant access to other methods so that this module can interact with the * Micro Services Framework. * *

* ModuleContext methods allow a module to: *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* If the (receiver,callback) pair is not contained in this * context module's list of listeners, this method does nothing. * * @tparam R The type of the receiver (containing the member function to be removed) * @param receiver The object from which to disconnect. * @param callback The member function pointer to remove. * @throws std::logic_error If this ModuleContext is no * longer valid. * @see AddModuleListener() */ template void RemoveModuleListener(R* receiver, void(R::*callback)(const ModuleEvent)) { RemoveModuleListener(ModuleListenerMemberFunctor(receiver, callback), static_cast(receiver)); } /** * Get the absolute path for a file or directory in the persistent * storage area provided for the module. The returned path * might be empty if no storage path has been set previously. * If the path is non-empty, it is safe to assume that the path is writable. * * @see ModuleSettings::SetStoragePath(const std::string&) * * @param filename A relative name to the file or directory to be accessed. * @return The absolute path to the persistent storage area for the given file name. */ std::string GetDataFile(const std::string& filename) const; private: friend class Module; friend class ModulePrivate; ModuleContext(ModulePrivate* module); // purposely not implemented ModuleContext(const ModuleContext&); ModuleContext& operator=(const ModuleContext&); void AddServiceListener(const ServiceListener& delegate, void* data, const std::string& filter); void RemoveServiceListener(const ServiceListener& delegate, void* data); void AddModuleListener(const ModuleListener& delegate, void* data); void RemoveModuleListener(const ModuleListener& delegate, void* data); ModuleContextPrivate * const d; }; US_END_NAMESPACE #endif /* USMODULECONTEXT_H_ */ diff --git a/Modules/CppMicroServices/core/include/usModuleEvent.h b/Modules/CppMicroServices/core/include/usModuleEvent.h index 03d7007d30..8a745018f3 100644 --- a/Modules/CppMicroServices/core/include/usModuleEvent.h +++ b/Modules/CppMicroServices/core/include/usModuleEvent.h @@ -1,153 +1,153 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEEVENT_H #define USMODULEEVENT_H #include #include "usSharedData.h" US_BEGIN_NAMESPACE class Module; class ModuleEventData; /** * \ingroup MicroServices * * An event from the Micro Services framework describing a module lifecycle change. *

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

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

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

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

* The module's * \link ModuleActivator::Unload(ModuleContext*) ModuleActivator Unload\endlink method * is about to be called. */ UNLOADING }; /** * Creates an invalid instance. */ ModuleEvent(); ~ModuleEvent(); /** * Can be used to check if this ModuleEvent instance is valid, * or if it has been constructed using the default constructor. * * @return true if this event object is valid, * false otherwise. */ bool IsNull() const; /** * Creates a module event of the specified type. * * @param type The event type. * @param module The module which had a lifecycle change. */ ModuleEvent(Type type, Module* module); ModuleEvent(const ModuleEvent& other); ModuleEvent& operator=(const ModuleEvent& other); /** * Returns the module which had a lifecycle change. * * @return The module that had a change occur in its lifecycle. */ Module* GetModule() const; /** * Returns the type of lifecyle event. The type values are: *

    *
  • {@link #LOADING} *
  • {@link #LOADED} *
  • {@link #UNLOADING} *
  • {@link #UNLOADED} *
* * @return The type of lifecycle event. */ Type GetType() const; }; /** * \ingroup MicroServices * @{ */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, ModuleEvent::Type eventType); US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const ModuleEvent& event); /** @}*/ US_END_NAMESPACE #endif // USMODULEEVENT_H diff --git a/Modules/CppMicroServices/core/include/usModuleEventHook.h b/Modules/CppMicroServices/core/include/usModuleEventHook.h index 6ccebe0c46..94d72814f2 100644 --- a/Modules/CppMicroServices/core/include/usModuleEventHook.h +++ b/Modules/CppMicroServices/core/include/usModuleEventHook.h @@ -1,70 +1,70 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEEVENTHOOK_H #define USMODULEEVENTHOOK_H #include "usServiceInterface.h" #include "usShrinkableVector.h" US_BEGIN_NAMESPACE class ModuleContext; class ModuleEvent; /** * @ingroup MicroServices * * %Module Event Hook Service. * *

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

* This method is called one and only one time for * each module event generated, this includes module events which are * generated when there are no module listeners registered. * * @param event The module event to be delivered. * @param contexts A list of Module Contexts for modules which have * listeners to which the specified event will be delivered. The * implementation of this method may remove module contexts from the * list to prevent the event from being delivered to the * associated modules. */ virtual void Event(const ModuleEvent& event, ShrinkableVector& contexts) = 0; }; US_END_NAMESPACE #endif // USMODULEEVENTHOOK_H diff --git a/Modules/CppMicroServices/core/include/usModuleFindHook.h b/Modules/CppMicroServices/core/include/usModuleFindHook.h index c5a5324ec5..5e5b21591e 100644 --- a/Modules/CppMicroServices/core/include/usModuleFindHook.h +++ b/Modules/CppMicroServices/core/include/usModuleFindHook.h @@ -1,71 +1,71 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEFINDHOOK_H #define USMODULEFINDHOOK_H #include "usServiceInterface.h" #include "usShrinkableVector.h" US_BEGIN_NAMESPACE class Module; class ModuleContext; /** * @ingroup MicroServices * * %Module Context Hook Service. * *

* Modules registering this service will be called during module find * (get modules) operations. * * @remarks Implementations of this interface are required to be thread-safe. */ struct US_Core_EXPORT ModuleFindHook { virtual ~ModuleFindHook(); /** * Find hook method. This method is called for module find operations * using ModuleContext::GetBundle(long) * and ModuleContext::GetModules() methods. The find method can * filter the result of the find operation. * * \note A find operation using the ModuleContext::GetModule(const std::string&) * method does not cause the find method to be called, neither does any * call to the static methods of the ModuleRegistry class. * * @param context The module context of the module performing the find * operation. * @param modules A list of Modules to be returned as a result of the * find operation. The implementation of this method may remove * modules from the list to prevent the modules from being * returned to the module performing the find operation. */ virtual void Find(const ModuleContext* context, ShrinkableVector& modules) = 0; }; US_END_NAMESPACE #endif // USMODULEFINDHOOK_H diff --git a/Modules/CppMicroServices/core/include/usModuleImport.h b/Modules/CppMicroServices/core/include/usModuleImport.h index f503118e41..36f67faeb8 100644 --- a/Modules/CppMicroServices/core/include/usModuleImport.h +++ b/Modules/CppMicroServices/core/include/usModuleImport.h @@ -1,93 +1,93 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEIMPORT_H #define USMODULEIMPORT_H #include #include US_BEGIN_NAMESPACE struct ModuleActivator; US_END_NAMESPACE /** * \ingroup MicroServices * * \brief Initialize a static module. * * \param _module_name The name of the module to initialize. * * This macro initializes the static module named \c _module_name. * * It the module provides an activator, use the #US_IMPORT_MODULE macro instead, * to ensure that the activator is called. Do not forget to actually link * the static module to the importing executable or shared library. * * \sa US_IMPORT_MODULE * \sa US_IMPORT_MODULE_RESOURCES * \sa \ref MicroServices_StaticModules */ #define US_INITIALIZE_STATIC_MODULE(_module_name) \ extern "C" void _us_import_module_initializer_ ## _module_name(); \ struct StaticModuleInitializer_ ## _module_name \ { \ StaticModuleInitializer_ ## _module_name() \ { \ _us_import_module_initializer_ ## _module_name(); \ } \ }; \ static StaticModuleInitializer_ ## _module_name _InitializeModule_ ## _module_name; /** * \ingroup MicroServices * * \brief Import a static module. * * \param _module_name The name of the module to import. * * This macro imports the static module named \c _module_name. * * Inserting this macro into your application's source code will allow you to make use of * a static module. It will initialize the static module and calls its * ModuleActivator. It the module does not provide an activator, use the * #US_INITIALIZE_STATIC_MODULE macro instead. Do not forget to actually link * the static module to the importing executable or shared library. * * Example: * \snippet uServices-staticmodules/main.cpp ImportStaticModuleIntoMain * * \sa US_INITIALIZE_STATIC_MODULE * \sa US_IMPORT_MODULE_RESOURCES * \sa \ref MicroServices_StaticModules */ #define US_IMPORT_MODULE(_module_name) \ US_INITIALIZE_STATIC_MODULE(_module_name) \ extern "C" US_PREPEND_NAMESPACE(ModuleActivator)* _us_module_activator_instance_ ## _module_name (); \ void _dummy_reference_to_ ## _module_name ## _activator() \ { \ _us_module_activator_instance_ ## _module_name(); \ } #endif // USMODULEREGISTRY_H diff --git a/Modules/CppMicroServices/core/include/usModuleInfo.h b/Modules/CppMicroServices/core/include/usModuleInfo.h index 175b41d8c7..c2a5264936 100644 --- a/Modules/CppMicroServices/core/include/usModuleInfo.h +++ b/Modules/CppMicroServices/core/include/usModuleInfo.h @@ -1,50 +1,50 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEINFO_H #define USMODULEINFO_H #include #include US_BEGIN_NAMESPACE struct ModuleActivator; /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. */ struct US_Core_EXPORT ModuleInfo { ModuleInfo(const std::string& name); std::string name; std::string location; std::string autoLoadDir; long id; }; US_END_NAMESPACE #endif // USMODULEINFO_H diff --git a/Modules/CppMicroServices/core/include/usModuleInitialization.h b/Modules/CppMicroServices/core/include/usModuleInitialization.h index c8691e0233..f0ea791b8d 100644 --- a/Modules/CppMicroServices/core/include/usModuleInitialization.h +++ b/Modules/CppMicroServices/core/include/usModuleInitialization.h @@ -1,120 +1,120 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef US_MODULE_NAME #error Missing US_MODULE_NAME preprocessor define #endif #ifndef USMODULEINITIALIZATION_H #define USMODULEINITIALIZATION_H #include #include #include #include #include /** * \ingroup MicroServices * * \brief Creates initialization code for a module. * * Each module which wants to register itself with the CppMicroServices library * has to put a call to this macro in one of its source files. Further, the modules * source files must be compiled with the \c US_MODULE_NAME pre-processor definition * set to a module-unique identifier. * * Calling the \c US_INITIALIZE_MODULE macro will initialize the module for use with * the CppMicroServices library, using a default auto-load directory named after the * \c US_MODULE_NAME definition. * * \sa MicroServices_AutoLoading * * \remarks If you are using CMake, consider using the provided CMake macro * usFunctionGenerateModuleInit(). */ #define US_INITIALIZE_MODULE \ US_BEGIN_NAMESPACE \ namespace { \ \ /* Declare a file scoped ModuleInfo object */ \ US_GLOBAL_STATIC_WITH_ARGS(ModuleInfo, moduleInfo, (US_STR(US_MODULE_NAME))) \ \ /* This class is used to statically initialize the library within the C++ Micro services \ library. It looks up a library specific C-style function returning an instance \ of the ModuleActivator interface. */ \ class US_ABI_LOCAL US_CONCAT(ModuleInitializer_, US_MODULE_NAME) { \ \ public: \ \ US_CONCAT(ModuleInitializer_, US_MODULE_NAME)() \ { \ ModuleInfo*(*moduleInfoPtr)() = moduleInfo; \ void* moduleInfoSym = nullptr; \ std::memcpy(&moduleInfoSym, &moduleInfoPtr, sizeof(void*)); \ std::string location = ModuleUtils::GetLibraryPath(moduleInfoSym); \ moduleInfoPtr()->location = location; \ \ Register(); \ } \ \ static void Register() \ { \ ModuleRegistry::Register(moduleInfo()); \ } \ \ ~US_CONCAT(ModuleInitializer_, US_MODULE_NAME)() \ { \ ModuleRegistry::UnRegister(moduleInfo()); \ } \ \ }; \ \ \ US_DEFINE_MODULE_INITIALIZER \ } \ \ US_END_NAMESPACE \ \ /* A helper function which is called by the US_IMPORT_MODULE macro to initialize \ static modules */ \ extern "C" void US_ABI_LOCAL US_CONCAT(_us_import_module_initializer_, US_MODULE_NAME)() \ { \ static US_PREPEND_NAMESPACE(US_CONCAT(ModuleInitializer_, US_MODULE_NAME)) US_CONCAT(_InitializeModule_, US_MODULE_NAME); \ } // Create a file-scoped static object for registering the module // during static initialization of the shared library #define US_DEFINE_MODULE_INITIALIZER \ static US_CONCAT(ModuleInitializer_, US_MODULE_NAME) US_CONCAT(_InitializeModule_, US_MODULE_NAME); // Static modules don't create a file-scoped static object for initialization // (it would be discarded during static linking anyway). The initialization code // is triggered by the US_IMPORT_MODULE macro instead. #if defined(US_STATIC_MODULE) #undef US_DEFINE_MODULE_INITIALIZER #define US_DEFINE_MODULE_INITIALIZER #endif #endif // USMODULEINITIALIZATION_H diff --git a/Modules/CppMicroServices/core/include/usModuleRegistry.h b/Modules/CppMicroServices/core/include/usModuleRegistry.h index 587a2a8e06..ce91c98be9 100644 --- a/Modules/CppMicroServices/core/include/usModuleRegistry.h +++ b/Modules/CppMicroServices/core/include/usModuleRegistry.h @@ -1,90 +1,90 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEREGISTRY_H #define USMODULEREGISTRY_H #include #include #include US_BEGIN_NAMESPACE class Module; struct ModuleInfo; struct ModuleActivator; /** * \ingroup MicroServices * * Here we handle all the modules that are loaded in the framework. */ class US_Core_EXPORT ModuleRegistry { public: /** * Get the module that has the specified module identifier. * * @param id The identifier of the module to get. * @return Module or null * if the module was not found. */ static Module* GetModule(long id); /** * Get the module that has specified module name. * * @param name The name of the module to get. * @return Module or null. */ static Module* GetModule(const std::string& name); /** * Get all known modules. * * @return A list which is filled with all known modules. */ static std::vector GetModules(); /** * Get all modules currently in module state LOADED. * * @return A list which is filled with all modules in * state LOADED */ static std::vector GetLoadedModules(); static void Register(ModuleInfo* info); static void UnRegister(const ModuleInfo* info); private: // disabled ModuleRegistry(); }; US_END_NAMESPACE #endif // USMODULEREGISTRY_H diff --git a/Modules/CppMicroServices/core/include/usModuleResource.h b/Modules/CppMicroServices/core/include/usModuleResource.h index ffbe66c728..fa06df61e1 100644 --- a/Modules/CppMicroServices/core/include/usModuleResource.h +++ b/Modules/CppMicroServices/core/include/usModuleResource.h @@ -1,312 +1,312 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULERESOURCE_H #define USMODULERESOURCE_H #include #include #include US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class ModuleResourcePrivate; class ModuleResourceContainer; /** * \ingroup MicroServices * * Represents a resource (text file, image, etc.) embedded in a CppMicroServices module. * * A \c %ModuleResource object provides information about a resource (external file) which * was embedded into this module's shared library. \c %ModuleResource objects can be obtained * be calling Module#GetResource or Module#FindResources. * * Example code for retreiving a resource object and reading its contents: * \snippet uServices-resources/main.cpp 1 * * %ModuleResource objects have value semantics and copies are very inexpensive. * * \see ModuleResourceStream * \see \ref MicroServices_Resources */ class US_Core_EXPORT ModuleResource { private: typedef ModuleResourcePrivate* ModuleResource::*bool_type; public: /** * Creates in invalid %ModuleResource object. */ ModuleResource(); /** * Copy constructor. * @param resource The object to be copied. */ ModuleResource(const ModuleResource& resource); ~ModuleResource(); /** * Assignment operator. * * @param resource The %ModuleResource object which is assigned to this instance. * @return A reference to this %ModuleResource instance. */ ModuleResource& operator=(const ModuleResource& resource); /** * A less then operator using the full resource path as returned by * GetResourcePath() to define the ordering. * * @param resource The object to which this %ModuleResource object is compared to. * @return \c true if this %ModuleResource object is less then \c resource, * \c false otherwise. */ bool operator<(const ModuleResource& resource) const; /** * Equality operator for %ModuleResource objects. * * @param resource The object for testing equality. * @return \c true if this %ModuleResource object is equal to \c resource, i.e. * they are coming from the same module (shared or static) and have an equal * resource path, \c false otherwise. */ bool operator==(const ModuleResource& resource) const; /** * Inequality operator for %ModuleResource objects. * * @param resource The object for testing inequality. * @return The result of !(*this == resource). */ bool operator!=(const ModuleResource& resource) const; /** * Tests this %ModuleResource object for validity. * * Invalid %ModuleResource objects are created by the default constructor or * can be returned by the Module class if the resource path is not found. * * @return \c true if this %ModuleReource object is valid and can safely be used, * \c false otherwise. */ bool IsValid() const; /** * Boolean conversion operator using IsValid(). */ operator bool_type() const; /** * Returns the name of the resource, excluding the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string name = resource.GetName(); // name = "archive.tar.gz" * \endcode * * @return The resource name. * @see GetPath(), GetResourcePath() */ std::string GetName() const; /** * Returns the resource's path, without the file name. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string path = resource.GetPath(); // path = "/data/" * \endcode * * The path with always begin and end with a forward slash. * * @return The resource path without the name. * @see GetResourcePath(), GetName() and IsDir() */ std::string GetPath() const; /** * Returns the resource path including the file name. * * @return The resource path including the file name. * @see GetPath(), GetName() and IsDir() */ std::string GetResourcePath() const; /** * Returns the base name of the resource without the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string base = resource.GetBaseName(); // base = "archive" * \endcode * * @return The resource base name. * @see GetName(), GetSuffix(), GetCompleteSuffix() and GetCompleteBaseName() */ std::string GetBaseName() const; /** * Returns the complete base name of the resource without the path. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string base = resource.GetCompleteBaseName(); // base = "archive.tar" * \endcode * * @return The resource's complete base name. * @see GetName(), GetSuffix(), GetCompleteSuffix(), and GetBaseName() */ std::string GetCompleteBaseName() const; /** * Returns the suffix of the resource. * * The suffix consists of all characters in the resource name after (but not * including) the last '.'. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string suffix = resource.GetSuffix(); // suffix = "gz" * \endcode * * @return The resource name suffix. * @see GetName(), GetCompleteSuffix(), GetBaseName() and GetCompleteBaseName() */ std::string GetSuffix() const; /** * Returns the complete suffix of the resource. * * The suffix consists of all characters in the resource name after (but not * including) the first '.'. * * Example: * \code * ModuleResource resource = module->GetResource("/data/archive.tar.gz"); * std::string suffix = resource.GetCompleteSuffix(); // suffix = "tar.gz" * \endcode * * @return The resource name suffix. * @see GetName(), GetSuffix(), GetBaseName(), and GetCompleteBaseName() */ std::string GetCompleteSuffix() const; /** * Returns \c true if this %ModuleResource object points to a directory and thus * may have child resources. * * @return \c true if this object points to a directory, \c false otherwise. */ bool IsDir() const; /** * Returns \c true if this %ModuleResource object points to a file resource. * * @return \c true if this object points to an embedded file, \c false otherwise. */ bool IsFile() const; /** * Returns a list of resource names which are children of this object. * * The returned names are relative to the path of this %ModuleResource object * and may contain file as well as directory entries. * * @return A list of child resource names. */ std::vector GetChildren() const; /** * Returns a list of resource objects which are children of this object. * * The return ModuleResource objects may contain files as well as * directory resources. * * @return A list of child resource objects. */ std::vector GetChildResources() const; /** * Returns the size of the resource data for this %ModuleResource object. * * @return The resource data size. */ int GetSize() const; /** * Returns the last modified time of this resource in seconds from the epoch. * * @return Last modified time of this resource. */ time_t GetLastModified() const; private: ModuleResource(const std::string& file, const ModuleResourceContainer& resourceContainer); ModuleResource(int index, const ModuleResourceContainer& resourceContainer); friend class Module; friend class ModulePrivate; friend class ModuleResourceContainer; friend class ModuleResourceStream; US_HASH_FUNCTION_FRIEND(ModuleResource); std::size_t Hash() const; void* GetData() const; ModuleResourcePrivate* d; }; US_END_NAMESPACE US_MSVC_POP_WARNING /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ModuleResource)& resource); US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ModuleResource)) return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USMODULERESOURCE_H diff --git a/Modules/CppMicroServices/core/include/usModuleResourceStream.h b/Modules/CppMicroServices/core/include/usModuleResourceStream.h index 1522423c35..f0fdb96371 100644 --- a/Modules/CppMicroServices/core/include/usModuleResourceStream.h +++ b/Modules/CppMicroServices/core/include/usModuleResourceStream.h @@ -1,70 +1,70 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULERESOURCESTREAM_H #define USMODULERESOURCESTREAM_H #include "usModuleResourceBuffer_p.h" #include US_BEGIN_NAMESPACE class ModuleResource; /** * \ingroup MicroServices * * An input stream class for ModuleResource objects. * * This class provides access to the resource data embedded in a module's * shared library via a STL input stream interface. * * \see ModuleResource for an example how to use this class. */ class US_Core_EXPORT ModuleResourceStream : private ModuleResourceBuffer, public std::istream { public: /** * Construct a %ModuleResourceStream object. * * @param resource The ModuleResource object for which an input stream * should be constructed. * @param mode The open mode of the stream. If \c std::ios_base::binary * is used, the resource data will be treated as binary data, otherwise * the data is interpreted as text data and the usual platform specific * end-of-line translations take place. */ ModuleResourceStream(const ModuleResource& resource, std::ios_base::openmode mode = std::ios_base::in); private: // purposely not implemented ModuleResourceStream(const ModuleResourceStream&); ModuleResourceStream& operator=(const ModuleResourceStream&); }; US_END_NAMESPACE #endif // USMODULERESOURCESTREAM_H diff --git a/Modules/CppMicroServices/core/include/usModuleSettings.h b/Modules/CppMicroServices/core/include/usModuleSettings.h index 71e5e5c216..7f1c17ee1a 100644 --- a/Modules/CppMicroServices/core/include/usModuleSettings.h +++ b/Modules/CppMicroServices/core/include/usModuleSettings.h @@ -1,171 +1,171 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULESETTINGS_H #define USMODULESETTINGS_H #include "usCoreConfig.h" #include #include US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * Query and set certain properties of the CppMicroServices library. * * The following environment variables influence the runtime behavior * of the CppMicroServices library: * * - \e US_DISABLE_AUTOLOADING If set, auto-loading of modules is disabled. * - \e US_AUTOLOAD_PATHS A ':' (Unix) or ';' (Windows) separated list of paths * from which modules should be auto-loaded. * * \remarks This class is thread safe. */ class US_Core_EXPORT ModuleSettings { public: typedef std::vector PathList; /** * Returns a special string which can be used as an argument for a * AddAutoLoadPath() call. * * When a module is loaded and this string has been added as a path * to the list of auto-load paths the CppMicroServices library will * auto-load all modules from the currently being loaded module's * auto-load directory. * * \return A string to be used in AddAutoLoadPath(). * * \remarks The returned string is contained in the default set of * auto-load paths, unless a new set of paths is given by a call to * SetAutoLoadPaths(). * * \sa MicroServices_AutoLoading * \sa US_INITIALIZE_MODULE */ static std::string CURRENT_MODULE_PATH(); /** * \return \c true if threading support has been configured into the * CppMicroServices library, \c false otherwise. */ static bool IsThreadingSupportEnabled(); /** * \return \c true if support for module auto-loading is enabled, * \c false otherwise. * * \remarks This method will always return \c false if support for auto-loading * has not been configured into the CppMicroServices library or if it has been * disabled by defining the US_DISABLE_AUTOLOADING environment variable. */ static bool IsAutoLoadingEnabled(); /** * Enable or disable auto-loading support. * * \param enable If \c true, enable auto-loading support, disable it otherwise. * * \remarks Calling this method will have no effect if support for * auto-loading has not been configured into the CppMicroServices library of it * it has been disabled by defining the US_DISABLE_AUTOLOADING envrionment variable. */ static void SetAutoLoadingEnabled(bool enable); /** * \return A list of paths in the file-system from which modules will be * auto-loaded. */ static PathList GetAutoLoadPaths(); /** * Set a list of paths in the file-system from which modules should be * auto-loaded. * @param paths A list of absolute file-system paths. */ static void SetAutoLoadPaths(const PathList& paths); /** * Add a path in the file-system to the list of paths from which modules * will be auto-loaded. * * @param path The additional absolute auto-load path in the file-system. */ static void AddAutoLoadPath(const std::string& path); /** * Set a local storage path for persistend module data. * * This path is used as a base directory for providing modules * with a storage path for writing persistent data. The callee * must ensure that the provided path exists and is writable. * * @see ModuleContext::GetDataFile(const std::string&) * * @param path An absolute path for writing persistent data. */ static void SetStoragePath(const std::string& path); /** * Get the absolute path for persistent data. The returned path * might be empty. If the path is non-empty, it is safe to assume * that the path exists and is writable. * * @return The absolute path to the persistent storage path. */ static std::string GetStoragePath(); /** * Set the logging level for log messages from CppMicroServices modules. * * Higher logging levels will discard messages with lower priority. * E.g. a logging level of WarningMsg will discard all messages of * type DebugMsg and InfoMsg. * * @param level The new logging level. */ static void SetLogLevel(MsgType level); /** * Get the current logging level. * * @return The currently used logging level. */ static MsgType GetLogLevel(); private: // purposely not implemented ModuleSettings(); ModuleSettings(const ModuleSettings&); ModuleSettings& operator=(const ModuleSettings&); }; US_END_NAMESPACE #endif // USMODULESETTINGS_H diff --git a/Modules/CppMicroServices/core/include/usModuleVersion.h b/Modules/CppMicroServices/core/include/usModuleVersion.h index 90eca373e9..88b8fcb48d 100644 --- a/Modules/CppMicroServices/core/include/usModuleVersion.h +++ b/Modules/CppMicroServices/core/include/usModuleVersion.h @@ -1,254 +1,254 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USMODULEVERSION_H #define USMODULEVERSION_H #include #include US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * Version identifier for CppMicroServices 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 US_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; }; US_END_NAMESPACE /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ModuleVersion)& v); #endif // USMODULEVERSION_H diff --git a/Modules/CppMicroServices/core/include/usPrototypeServiceFactory.h b/Modules/CppMicroServices/core/include/usPrototypeServiceFactory.h index 2558f053c4..5992d4689f 100644 --- a/Modules/CppMicroServices/core/include/usPrototypeServiceFactory.h +++ b/Modules/CppMicroServices/core/include/usPrototypeServiceFactory.h @@ -1,102 +1,102 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USPROTOTYPESERVICEFACTORY_H #define USPROTOTYPESERVICEFACTORY_H #include US_BEGIN_NAMESPACE /** * @ingroup MicroServices * * A factory for \link ServiceConstants::SCOPE_PROTOTYPE prototype scope\endlink services. * The factory can provide multiple, unique service objects. * * When registering a service, a PrototypeServiceFactory object can be used * instead of a service object, so that the module developer can create a * unique service object for each caller that is using the service. * When a caller uses a ServiceObjects to request a service instance, the * framework calls the GetService method to return a service object specifically * for the requesting caller. The caller can release the returned service object * and the framework will call the UngetService method with the service object. * When a module uses the ModuleContext::GetService(const ServiceReferenceBase&) * method to obtain a service object, the framework acts as if the service * has module scope. That is, the framework will call the GetService method to * obtain a module-scoped instance which will be cached and have a use count. * See ServiceFactory. * * A module can use both ServiceObjects and ModuleContext::GetService(const ServiceReferenceBase&) * to obtain a service object for a service. ServiceObjects::GetService() will always * return an instance provided by a call to GetService(Module*, const ServiceRegistrationBase&) * and ModuleContext::GetService(const ServiceReferenceBase&) will always * return the module-scoped instance. * PrototypeServiceFactory objects are only used by the framework and are not made * available to other modules. The framework may concurrently call a PrototypeServiceFactory. * * @see ModuleContext::GetServiceObjects() * @see ServiceObjects */ struct PrototypeServiceFactory : public ServiceFactory { /** * Returns a service object for a caller. * * The framework invokes this method for each caller requesting a service object using * ServiceObjects::GetService(). The factory can then return a specific service object for the caller. * The framework checks that the returned service object is valid. If the returned service * object is empty or does not contain entries for all the interfaces named when the service * was registered, a warning is issued and nullptr is returned to the caller. If this * method throws an exception, a warning is issued and nullptr is returned to the caller. * * @param module The module requesting the service. * @param registration The ServiceRegistrationBase object for the requested service. * @return A service object that must contain entries for all the interfaces named when * the service was registered. * * @see ServiceObjects#GetService() * @see InterfaceMap */ InterfaceMap GetService(Module* module, const ServiceRegistrationBase& registration) override = 0; /** * Releases a service object created for a caller. * * The framework invokes this method when a service has been released by a modules such as * by calling ServiceObjects::UngetService(). The service object may then be destroyed. * If this method throws an exception, a warning is issued. * * @param module The module releasing the service. * @param registration The ServiceRegistrationBase object for the service being released. * @param service The service object returned by a previous call to the GetService method. * * @see ServiceObjects::UngetService() */ void UngetService(Module* module, const ServiceRegistrationBase& registration, const InterfaceMap& service) override = 0; }; US_END_NAMESPACE #endif // USPROTOTYPESERVICEFACTORY_H diff --git a/Modules/CppMicroServices/core/include/usServiceEvent.h b/Modules/CppMicroServices/core/include/usServiceEvent.h index 4243c12275..399928e5d4 100644 --- a/Modules/CppMicroServices/core/include/usServiceEvent.h +++ b/Modules/CppMicroServices/core/include/usServiceEvent.h @@ -1,188 +1,188 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEEVENT_H #define USSERVICEEVENT_H #ifdef REGISTERED #ifdef _WIN32 #error The REGISTERED preprocessor define clashes with the ServiceEvent::REGISTERED\ enum type. Try to reorder your includes, compile with WIN32_LEAN_AND_MEAN, or undef\ the REGISTERED macro befor including this header. #else #error The REGISTERED preprocessor define clashes with the ServiceEvent::REGISTERED\ enum type. Try to reorder your includes or undef the REGISTERED macro befor including\ this header. #endif #endif #include "usSharedData.h" #include "usServiceReference.h" US_BEGIN_NAMESPACE class ServiceEventData; /** * \ingroup MicroServices * * An event from the Micro Services framework describing a service lifecycle change. *

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

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

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

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

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

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

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

    *
  • {@link #REGISTERED}
  • *
  • {@link #MODIFIED}
  • *
  • {@link #MODIFIED_ENDMATCH}
  • *
  • {@link #UNREGISTERING}
  • *
* * @return Type of service lifecycle change. */ Type GetType() const; }; /** * \ingroup MicroServices * @{ */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const ServiceEvent::Type& type); US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const ServiceEvent& event); /** @}*/ US_END_NAMESPACE #endif // USSERVICEEVENT_H diff --git a/Modules/CppMicroServices/core/include/usServiceEventListenerHook.h b/Modules/CppMicroServices/core/include/usServiceEventListenerHook.h index 949f6df8a8..54e909b6af 100644 --- a/Modules/CppMicroServices/core/include/usServiceEventListenerHook.h +++ b/Modules/CppMicroServices/core/include/usServiceEventListenerHook.h @@ -1,70 +1,70 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEEVENTLISTENERHOOK_H #define USSERVICEEVENTLISTENERHOOK_H #include "usServiceInterface.h" #include "usServiceListenerHook.h" #include "usShrinkableVector.h" #include "usShrinkableMap.h" US_BEGIN_NAMESPACE class ModuleContext; class ServiceEvent; /** * @ingroup MicroServices * * Service Event Listener Hook Service. * *

* Modules registering this service will be called during service * (register, modify, and unregister service) operations. * * @remarks Implementations of this interface are required to be thread-safe. */ struct US_Core_EXPORT ServiceEventListenerHook { typedef ShrinkableMap > ShrinkableMapType; virtual ~ServiceEventListenerHook(); /** * Event listener hook method. This method is called prior to service event * delivery when a publishing module registers, modifies or unregisters a * service. This method can filter the listeners which receive the event. * * @param event The service event to be delivered. * @param listeners A map of Module Contexts to a list of Listener * Infos for the module's listeners to which the specified event will * be delivered. The implementation of this method may remove module * contexts from the map and listener infos from the list * values to prevent the event from being delivered to the associated * listeners. */ virtual void Event(const ServiceEvent& event, ShrinkableMapType& listeners) = 0; }; US_END_NAMESPACE #endif // USSERVICEEVENTLISTENERHOOK_H diff --git a/Modules/CppMicroServices/core/include/usServiceException.h b/Modules/CppMicroServices/core/include/usServiceException.h index 0004e25398..0f34b94f84 100644 --- a/Modules/CppMicroServices/core/include/usServiceException.h +++ b/Modules/CppMicroServices/core/include/usServiceException.h @@ -1,126 +1,126 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USSERVICEEXCEPTION_H #define USSERVICEEXCEPTION_H #include #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4275) #endif US_BEGIN_NAMESPACE /** * \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 US_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. */ ServiceException(const std::string& msg, const Type& type = UNSPECIFIED); ServiceException(const ServiceException& o); ServiceException& operator=(const ServiceException& o); ~ServiceException() throw() override { } /** * 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; }; US_END_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif /** * \ingroup MicroServices * @{ */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceException)& exc); /** @}*/ #endif // USSERVICEEXCEPTION_H diff --git a/Modules/CppMicroServices/core/include/usServiceFactory.h b/Modules/CppMicroServices/core/include/usServiceFactory.h index 906c457094..e201da0e18 100644 --- a/Modules/CppMicroServices/core/include/usServiceFactory.h +++ b/Modules/CppMicroServices/core/include/usServiceFactory.h @@ -1,119 +1,119 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USSERVICEFACTORY_H #define USSERVICEFACTORY_H #include "usServiceInterface.h" #include "usServiceRegistration.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * A factory for \link ServiceConstants::SCOPE_MODULE module scope\endlink services. * The factory can provide service objects unique to each module. * *

* 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 * @see PrototypeServiceFactory * @remarks This class is thread safe. */ class ServiceFactory { public: virtual ~ServiceFactory() {} /** * 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 ServiceReferenceBase&) method. The * service factory can then return a specific service object for each * module. * *

* The framework caches the value returned (unless the InterfaceMap is empty), * and will return the same service object on any future call to * ModuleContext::GetService for the same modules. This means the * framework does not allow this method to be concurrently called for the * same module. * * @param module The module using the service. * @param registration The ServiceRegistrationBase object for the * service. * @return A service object that must contain entries for all * the interfaces named when the service was registered. * @see ModuleContext#GetService * @see InterfaceMap */ virtual InterfaceMap GetService(Module* module, const ServiceRegistrationBase& 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 * @see InterfaceMap */ virtual void UngetService(Module* module, const ServiceRegistrationBase& registration, const InterfaceMap& service) = 0; }; US_END_NAMESPACE #endif // USSERVICEFACTORY_H diff --git a/Modules/CppMicroServices/core/include/usServiceFindHook.h b/Modules/CppMicroServices/core/include/usServiceFindHook.h index 5ffb9ec048..9e6e6ffde1 100644 --- a/Modules/CppMicroServices/core/include/usServiceFindHook.h +++ b/Modules/CppMicroServices/core/include/usServiceFindHook.h @@ -1,74 +1,74 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEFINDHOOK_H #define USSERVICEFINDHOOK_H #include "usServiceInterface.h" #include "usShrinkableVector.h" #include US_BEGIN_NAMESPACE class Module; class ModuleContext; class ServiceReferenceBase; /** * @ingroup MicroServices * * Service Find Hook Service. * *

* Modules registering this service will be called during service find * (get service references) operations. * * @remarks Implementations of this interface are required to be thread-safe. */ struct US_Core_EXPORT ServiceFindHook { virtual ~ServiceFindHook(); /** * Find hook method. This method is called during the service find operation * (for example, ModuleContext::GetServiceReferences()). This method can * filter the result of the find operation. * * @param context The module context of the module performing the find * operation. * @param name The class name of the services to find or an empty string to * find all services. * @param filter The filter criteria of the services to find or an empty string * for no filter criteria. * @param references A list of Service References to be returned as a result of the * find operation. The implementation of this method may remove * service references from the list to prevent the references from being * returned to the module performing the find operation. */ virtual void Find(const ModuleContext* context, const std::string& name, const std::string& filter, ShrinkableVector& references) = 0; }; US_END_NAMESPACE #endif // USSERVICEFINDHOOK_H diff --git a/Modules/CppMicroServices/core/include/usServiceInterface.h b/Modules/CppMicroServices/core/include/usServiceInterface.h index 66a2b4afe7..0c1927374a 100644 --- a/Modules/CppMicroServices/core/include/usServiceInterface.h +++ b/Modules/CppMicroServices/core/include/usServiceInterface.h @@ -1,343 +1,343 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEINTERFACE_H #define USSERVICEINTERFACE_H #include #include #include #include #include US_BEGIN_NAMESPACE std::string GetDemangledName(const std::type_info& typeInfo); US_END_NAMESPACE /** * \ingroup MicroServices * * Returns a unique id for a given type. By default, the * demangled name of \c T is returned. * * This template method may be specialized directly or be * using the macro #US_DECLARE_SERVICE_INTERFACE to return * a custom id for each service interface. * * @tparam T The service interface type. * @return A unique id for the service interface type T. */ template std::string us_service_interface_iid() { return US_PREPEND_NAMESPACE(GetDemangledName)(typeid(T)); } /// \cond template<> inline std::string us_service_interface_iid() { return std::string(); } /// \endcond /** * \ingroup MicroServices * * \brief Declare a service interface id. * * This macro associates the given identifier \e _service_interface_id (a string literal) to the * interface class called _service_interface_type. The Identifier must be unique. For example: * * \code * #include * * struct ISomeInterace { ... }; * * US_DECLARE_SERVICE_INTERFACE(ISomeInterface, "com.mycompany.service.ISomeInterface/1.0") * \endcode * * The usage of this macro is optional and the service interface id which is automatically * associated with any type is usually good enough (the demangled type name). However, care must * be taken if the default id is compared with a string literal hard-coding a service interface * id. E.g. the default id for templated types in the STL may differ between platforms. For * user-defined types and templates the ids are typically consistent, but platform specific * default template arguments will lead to different ids. * * This macro is normally used right after the class definition for _service_interface_type, * in a header file. * * If you want to use #US_DECLARE_SERVICE_INTERFACE with interface classes declared in a * namespace then you have to make sure the #US_DECLARE_SERVICE_INTERFACE macro call is not * inside a namespace though. For example: * * \code * #include * * namespace Foo * { * struct ISomeInterface { ... }; * } * * US_DECLARE_SERVICE_INTERFACE(Foo::ISomeInterface, "com.mycompany.service.ISomeInterface/1.0") * \endcode * * @param _service_interface_type The service interface type. * @param _service_interface_id A string literal representing a globally unique identifier. */ #define US_DECLARE_SERVICE_INTERFACE(_service_interface_type, _service_interface_id) \ template<> inline std::string us_service_interface_iid<_service_interface_type>() \ { return _service_interface_id; } \ US_BEGIN_NAMESPACE class ServiceFactory; /** * @ingroup MicroServices * * A helper type used in several methods to get proper * method overload resolutions. */ template struct InterfaceType {}; /** * @ingroup MicroServices * * A map containing interfaces ids and their corresponding service object * pointers. InterfaceMap instances represent a complete service object * which implementes one or more service interfaces. For each implemented * service interface, there is an entry in the map with the key being * the service interface id and the value a pointer to the service * interface implementation. * * To create InterfaceMap instances, use the MakeInterfaceMap helper class. * * @note This is a low-level type and should only rarely be used. * * @see MakeInterfaceMap */ typedef std::map InterfaceMap; template bool InsertInterfaceType(InterfaceMap& im, I* i) { if (us_service_interface_iid().empty()) { throw ServiceException(std::string("The interface class ") + typeid(I).name() + " uses an invalid id in its US_DECLARE_SERVICE_INTERFACE macro call."); } im.insert(std::make_pair(std::string(us_service_interface_iid()), static_cast(static_cast(i)))); return true; } template<> inline bool InsertInterfaceType(InterfaceMap&, void*) { return false; } /** * @ingroup MicroServices * * Helper class for constructing InterfaceMap instances based * on service implementations or service factories. * * Example usage: * \code * MyService service; // implementes I1 and I2 * InterfaceMap im = MakeInterfaceMap(&service); * \endcode * * The MakeInterfaceMap supports service implementations with * up to three service interfaces. * * @see InterfaceMap */ template struct MakeInterfaceMap { ServiceFactory* m_factory; I1* m_interface1; I2* m_interface2; I3* m_interface3; /** * Constructor taking a service implementation pointer. * * @param impl A service implementation pointer, which must * be castable to a all specified service interfaces. */ template MakeInterfaceMap(Impl* impl) : m_factory(nullptr) , m_interface1(static_cast(impl)) , m_interface2(static_cast(impl)) , m_interface3(static_cast(impl)) {} /** * Constructor taking a service factory. * * @param factory A service factory. */ MakeInterfaceMap(ServiceFactory* factory) : m_factory(factory) , m_interface1(nullptr) , m_interface2(nullptr) , m_interface3(nullptr) { if (factory == nullptr) { throw ServiceException("The service factory argument must not be nullptr."); } } operator InterfaceMap () { InterfaceMap sim; InsertInterfaceType(sim, m_interface1); InsertInterfaceType(sim, m_interface2); InsertInterfaceType(sim, m_interface3); if (m_factory) { sim.insert(std::make_pair(std::string("org.cppmicroservices.factory"), static_cast(m_factory))); } return sim; } }; /// \cond template struct MakeInterfaceMap { ServiceFactory* m_factory; I1* m_interface1; I2* m_interface2; template MakeInterfaceMap(Impl* impl) : m_factory(nullptr) , m_interface1(static_cast(impl)) , m_interface2(static_cast(impl)) {} MakeInterfaceMap(ServiceFactory* factory) : m_factory(factory) , m_interface1(nullptr) , m_interface2(nullptr) { if (factory == nullptr) { throw ServiceException("The service factory argument must not be nullptr."); } } operator InterfaceMap () { InterfaceMap sim; InsertInterfaceType(sim, m_interface1); InsertInterfaceType(sim, m_interface2); if (m_factory) { sim.insert(std::make_pair(std::string("org.cppmicroservices.factory"), static_cast(m_factory))); } return sim; } }; template struct MakeInterfaceMap { ServiceFactory* m_factory; I1* m_interface1; template MakeInterfaceMap(Impl* impl) : m_factory(nullptr) , m_interface1(static_cast(impl)) {} MakeInterfaceMap(ServiceFactory* factory) : m_factory(factory) , m_interface1(nullptr) { if (factory == nullptr) { throw ServiceException("The service factory argument must not be nullptr."); } } operator InterfaceMap () { InterfaceMap sim; InsertInterfaceType(sim, m_interface1); if (m_factory) { sim.insert(std::make_pair(std::string("org.cppmicroservices.factory"), static_cast(m_factory))); } return sim; } }; template<> struct MakeInterfaceMap; /// \endcond /** * @ingroup MicroServices * * Extract a service interface pointer from a given InterfaceMap instance. * * @param map a InterfaceMap instance. * @return The service interface pointer for the service interface id of the * \c I1 interface type or nullptr if \c map does not contain an entry * for the given type. * * @see MakeInterfaceMap */ template I1* ExtractInterface(const InterfaceMap& map) { InterfaceMap::const_iterator iter = map.find(us_service_interface_iid()); if (iter != map.end()) { return reinterpret_cast(iter->second); } return nullptr; } US_END_NAMESPACE #endif // USSERVICEINTERFACE_H diff --git a/Modules/CppMicroServices/core/include/usServiceListenerHook.h b/Modules/CppMicroServices/core/include/usServiceListenerHook.h index 599af5b196..7cdc2ceed7 100644 --- a/Modules/CppMicroServices/core/include/usServiceListenerHook.h +++ b/Modules/CppMicroServices/core/include/usServiceListenerHook.h @@ -1,174 +1,174 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICELISTENERHOOK_H #define USSERVICELISTENERHOOK_H #include "usServiceInterface.h" #include "usShrinkableVector.h" #include "usSharedData.h" #include US_BEGIN_NAMESPACE class ModuleContext; class ServiceListenerEntry; /** * @ingroup MicroServices * * Service Listener Hook Service. * *

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

* There is an extremely rare case in which removed notification to * {@link ServiceListenerHook}s can be made before added notification if two * threads are racing to add and remove the same service listener. * Because {@link ServiceListenerHook}s are called synchronously during service * listener addition and removal, the CppMicroServices library cannot guarantee * in-order delivery of added and removed notification for a given * service listener. This method can be used to detect this rare * occurrence. * * @return \c false if the listener has not been been removed, * \c true otherwise. */ bool IsRemoved() const; /** * Compares this \c ListenerInfo to another \c ListenerInfo. * Two {@code ListenerInfo}s are equal if they refer to the same * listener for a given addition and removal life cycle. If the same * listener is added again, it will have a different * \c ListenerInfo which is not equal to this \c ListenerInfo. * * @param other The object to compare against this \c ListenerInfo. * @return \c true if the other object is a \c ListenerInfo * object and both objects refer to the same listener for a * given addition and removal life cycle. */ bool operator==(const ListenerInfo& other) const; private: friend class ServiceListenerEntry; US_HASH_FUNCTION_FRIEND(ServiceListenerHook::ListenerInfo); ListenerInfo(ListenerInfoData* data); ExplicitlySharedDataPointer d; }; virtual ~ServiceListenerHook(); /** * Added listeners hook method. This method is called to provide the hook * implementation with information on newly added service listeners. This * method will be called as service listeners are added while this hook is * registered. Also, immediately after registration of this hook, this * method will be called to provide the current collection of service * listeners which had been added prior to the hook being registered. * * @param listeners A collection of \c ListenerInfo objects for newly added * service listeners which are now listening to service events. */ virtual void Added(const std::vector& listeners) = 0; /** * Removed listeners hook method. This method is called to provide the hook * implementation with information on newly removed service listeners. This * method will be called as service listeners are removed while this hook is * registered. * * @param listeners A collection of \c ListenerInfo objects for newly removed * service listeners which are no longer listening to service events. */ virtual void Removed(const std::vector& listeners) = 0; }; US_END_NAMESPACE US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceListenerHook::ListenerInfo)) return US_HASH_FUNCTION(const US_PREPEND_NAMESPACE(ServiceListenerHook::ListenerInfoData)*, arg.d.Data()); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USSERVICELISTENERHOOK_H diff --git a/Modules/CppMicroServices/core/include/usServiceObjects.h b/Modules/CppMicroServices/core/include/usServiceObjects.h index 4a3bd1bcaf..07bfe4f230 100644 --- a/Modules/CppMicroServices/core/include/usServiceObjects.h +++ b/Modules/CppMicroServices/core/include/usServiceObjects.h @@ -1,259 +1,259 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USSERVICEOBJECTS_H #define USSERVICEOBJECTS_H #include #include #include #include #include US_BEGIN_NAMESPACE class ServiceObjectsBasePrivate; class US_Core_EXPORT ServiceObjectsBase { private: ServiceObjectsBasePrivate* d; protected: ServiceObjectsBase(ModuleContext* context, const ServiceReferenceBase& reference); ServiceObjectsBase(const ServiceObjectsBase& other); ~ServiceObjectsBase(); ServiceObjectsBase& operator=(const ServiceObjectsBase& other); // Called by ServiceObjects with S != void void* GetService() const; // Called by the ServiceObjects specialization InterfaceMap GetServiceInterfaceMap() const; // Called by ServiceObjects with S != void void UngetService(void* service); // Called by the ServiceObjects specialization void UngetService(const InterfaceMap& interfaceMap); ServiceReferenceBase GetReference() const; }; /** * @ingroup MicroServices * * Allows multiple service objects for a service to be obtained. * * For services with \link ServiceConstants::SCOPE_PROTOTYPE prototype\endlink scope, * multiple service objects for the service can be obtained. For services with * \link ServiceConstants::SCOPE_SINGLETON singleton\endlink or * \link ServiceConstants::SCOPE_MODULE module \endlink scope, only one, use-counted * service object is available. Any unreleased service objects obtained from this * ServiceObjects object are automatically released by the framework when the modules * associated with the ModuleContext used to create this ServiceObjects object is * stopped. * * @tparam S Type of Service. */ template class ServiceObjects : private ServiceObjectsBase { public: /** * Returns a service object for the referenced service. * * This ServiceObjects object can be used to obtain multiple service objects for * the referenced service if the service has \link ServiceConstants::SCOPE_PROTOTYPE prototype\endlink * scope. If the referenced service has \link ServiceConstants::SCOPE_SINGLETON singleton\endlink * or \link ServiceConstants::SCOPE_MODULE module\endlink scope, this method * behaves the same as calling the ModuleContext::GetService(const ServiceReferenceBase&) * method for the referenced service. That is, only one, use-counted service object * is available from this ServiceObjects object. * * This method will always return \c nullptr when the referenced service has been unregistered. * * For a prototype scope service, the following steps are taken to get the service object: * *

    *
  1. If the referenced service has been unregistered, \c nullptr is returned.
  2. *
  3. The PrototypeServiceFactory::GetService(Module*, const ServiceRegistrationBase&) * method is called to create a service object for the caller.
  4. *
  5. If the service object (an instance of InterfaceMap) returned by the * PrototypeServiceFactory object is empty, does not contain all the interfaces * named when the service was registered or the PrototypeServiceFactory object * throws an exception, \c nullptr is returned and a warning message is issued.
  6. *
  7. The service object is returned.
  8. *
* * @return A service object for the referenced service or \c nullptr if the service is not * registered, the service object returned by a ServiceFactory does not contain * all the classes under which it was registered or the ServiceFactory threw an * exception. * * @throw std::logic_error If the ModuleContext used to create this ServiceObjects object * is no longer valid. * * @see UngetService() */ S* GetService() const { return reinterpret_cast(this->ServiceObjectsBase::GetService()); } /** * Releases a service object for the referenced service. * * This ServiceObjects object can be used to obtain multiple service objects for * the referenced service if the service has \link ServiceConstants::SCOPE_PROTOTYPE prototype\endlink * scope. If the referenced service has \link ServiceConstants::SCOPE_SINGLETON singleton\endlink * or \link ServiceConstants::SCOPE_MODULE module\endlink scope, this method * behaves the same as calling the ModuleContext::UngetService(const ServiceReferenceBase&) * method for the referenced service. That is, only one, use-counted service object * is available from this ServiceObjects object. * * For a prototype scope service, the following steps are take to release the service object: * *
    *
  1. If the referenced service has been unregistered, this method returns without * doing anything.
  2. *
  3. The PrototypeServiceFactory::UngetService(Module*, const ServiceRegistrationBase&, const InterfaceMap&) * method is called to release the specified service object.
  4. *
  5. The specified service object must no longer be used and all references to it * should be destroyed after calling this method.
  6. *
* * @param service A service object previously provided by this ServiceObjects object. * * @throw std::logic_error If the ModuleContext used to create this ServiceObjects * object is no longer valid. * @throw std::invalid_argument If the specified service was not provided by this * ServiceObjects object. * * @see GetService() */ void UngetService(S* service) { this->ServiceObjectsBase::UngetService(service); } /** * Returns the ServiceReference for this ServiceObjects object. * * @return The ServiceReference for this ServiceObjects object. */ ServiceReference GetServiceReference() const { return this->ServiceObjectsBase::GetReference(); } private: friend class ModuleContext; ServiceObjects(ModuleContext* context, const ServiceReference& reference) : ServiceObjectsBase(context, reference) {} }; /** * @ingroup MicroServices * * Allows multiple service objects for a service to be obtained. * * This is a specialization of the ServiceObjects class template for * "void", which maps to all service interface types. * * @see ServiceObjects */ template<> class US_Core_EXPORT ServiceObjects : private ServiceObjectsBase { public: /** * Returns a service object as a InterfaceMap instance for the referenced service. * * This method is the same as ServiceObjects::GetService() except for the * return type. Further, this method will always return an empty InterfaeMap * object when the referenced service has been unregistered. * * @return A InterfaceMap object for the referenced service, which is empty if the * service is not registered, the InterfaceMap returned by a ServiceFactory * does not contain all the classes under which the service object was * registered or the ServiceFactory threw an exception. * * @throw std::logic_error If the ModuleContext used to create this ServiceObjects object * is no longer valid. * * @see ServiceObjects::GetService() * @see UngetService() */ InterfaceMap GetService() const; /** * Releases a service object for the referenced service. * * This method is the same as ServiceObjects::UngetService() except for the * parameter type. * * @param service An InterfaceMap object previously provided by this ServiceObjects object. * * @throw std::logic_error If the ModuleContext used to create this ServiceObjects * object is no longer valid. * @throw std::invalid_argument If the specified service was not provided by this * ServiceObjects object. * * @see ServiceObjects::UngetService() * @see GetService() */ void UngetService(const InterfaceMap& service); /** * Returns the ServiceReference for this ServiceObjects object. * * @return The ServiceReference for this ServiceObjects object. */ ServiceReferenceU GetServiceReference() const; private: friend class ModuleContext; ServiceObjects(ModuleContext* context, const ServiceReferenceU& reference); }; US_END_NAMESPACE #endif // USSERVICEOBJECTS_H diff --git a/Modules/CppMicroServices/core/include/usServiceProperties.h b/Modules/CppMicroServices/core/include/usServiceProperties.h index c72545a836..83e5044174 100644 --- a/Modules/CppMicroServices/core/include/usServiceProperties.h +++ b/Modules/CppMicroServices/core/include/usServiceProperties.h @@ -1,138 +1,138 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef US_SERVICE_PROPERTIES_H #define US_SERVICE_PROPERTIES_H #include #include #include "usAny.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * A hash table with std::string as the key type and Any as the value * type. It is typically used for passing service properties to * ModuleContext::RegisterService. */ typedef US_UNORDERED_MAP_TYPE ServiceProperties; /** * \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::vector<std::string>. * *

* This property is set by the framework when a service is registered. */ US_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. */ US_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. */ US_Core_EXPORT const std::string& SERVICE_RANKING(); // = "service.ranking" /** * Service property identifying a service's scope. * This property is set by the framework when a service is registered. If the * registered object implements PrototypeServiceFactory, then the value of this * service property will be SCOPE_PROTOTYPE(). Otherwise, if the registered * object implements ServiceFactory, then the value of this service property will * be SCOPE_MODULE(). Otherwise, the value of this service property will be * SCOPE_SINGLETON(). */ US_Core_EXPORT const std::string& SERVICE_SCOPE(); // = "service.scope" /** * Service scope is singleton. All modules using the service receive the same * service object. * * @see SERVICE_SCOPE() */ US_Core_EXPORT const std::string& SCOPE_SINGLETON(); // = "singleton" /** * Service scope is module. Each module using the service receives a distinct * service object. * * @see SERVICE_SCOPE() */ US_Core_EXPORT const std::string& SCOPE_MODULE(); // = "module" /** * Service scope is prototype. Each module using the service receives either * a distinct service object or can request multiple distinct service objects * via ServiceObjects. * * @see SERVICE_SCOPE() */ US_Core_EXPORT const std::string& SCOPE_PROTOTYPE(); // = "prototype" } US_END_NAMESPACE #endif // US_SERVICE_PROPERTIES_H diff --git a/Modules/CppMicroServices/core/include/usServiceReference.h b/Modules/CppMicroServices/core/include/usServiceReference.h index 031f774d85..64cad4406a 100644 --- a/Modules/CppMicroServices/core/include/usServiceReference.h +++ b/Modules/CppMicroServices/core/include/usServiceReference.h @@ -1,142 +1,142 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEREFERENCE_H #define USSERVICEREFERENCE_H #include #include US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * A reference to a service. * *

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

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

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

* If the same service object is registered multiple times, * ServiceReference objects associated with different * ServiceRegistration objects are not equal. * * @tparam S The class type of the service interface * @see ModuleContext::GetServiceReference * @see ModuleContext::GetServiceReferences * @see ModuleContext::GetService * @remarks This class is thread safe. */ template class ServiceReference : public ServiceReferenceBase { public: typedef S ServiceType; /** * Creates an invalid ServiceReference object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceReference() : ServiceReferenceBase() { } ServiceReference(const ServiceReferenceBase& base) : ServiceReferenceBase(base) { const std::string interfaceId(us_service_interface_iid()); if (GetInterfaceId() != interfaceId) { if (this->IsConvertibleTo(interfaceId)) { this->SetInterfaceId(interfaceId); } else { this->operator =(0); } } } using ServiceReferenceBase::operator=; }; /** * \cond * * Specialization for void, representing a generic service * reference not bound to any interface identifier. * */ template<> class ServiceReference : public ServiceReferenceBase { public: /** * Creates an invalid ServiceReference object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceReference() : ServiceReferenceBase() { } ServiceReference(const ServiceReferenceBase& base) : ServiceReferenceBase(base) { } using ServiceReferenceBase::operator=; typedef void ServiceType; }; /// \endcond /** * \ingroup MicroServices * * A service reference of unknown type, which is not bound to any * interface identifier. */ typedef ServiceReference ServiceReferenceU; US_END_NAMESPACE #endif // USSERVICEREFERENCE_H diff --git a/Modules/CppMicroServices/core/include/usServiceReferenceBase.h b/Modules/CppMicroServices/core/include/usServiceReferenceBase.h index 69b78b5c08..7ce3d84636 100644 --- a/Modules/CppMicroServices/core/include/usServiceReferenceBase.h +++ b/Modules/CppMicroServices/core/include/usServiceReferenceBase.h @@ -1,234 +1,234 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEREFERENCEBASE_H #define USSERVICEREFERENCEBASE_H #include US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class Module; class ServiceRegistrationBasePrivate; class ServiceReferenceBasePrivate; /** * \ingroup MicroServices * * A reference to a service. * * \note This class is provided as public API for low-level service queries only. * In almost all cases you should use the template ServiceReference instead. */ class US_Core_EXPORT ServiceReferenceBase { private: typedef ServiceReferenceBasePrivate* ServiceReferenceBase::*bool_type; public: ServiceReferenceBase(const ServiceReferenceBase& ref); /** * Converts this ServiceReferenceBase instance into a boolean * expression. If this instance was default constructed or * the service it references has been unregistered, the conversion * returns false, otherwise it returns true. */ operator bool_type() const; /** * Releases any resources held or locked by this * ServiceReferenceBase and renders it invalid. */ ServiceReferenceBase& operator=(int null); ~ServiceReferenceBase(); /** * Returns the property value to which the specified property key is mapped * in the properties ServiceProperties object of the service * referenced by this ServiceReferenceBase object. * *

* Property keys are case-insensitive. * *

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

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

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

* If this ServiceReferenceBase and the specified * ServiceReferenceBase have the same \link ServiceConstants::SERVICE_ID() * service id\endlink they are equal. This ServiceReferenceBase is less * than the specified ServiceReferenceBase if it has a lower * {@link ServiceConstants::SERVICE_RANKING service ranking} and greater if it has a * higher service ranking. Otherwise, if this ServiceReferenceBase * and the specified ServiceReferenceBase have the same * {@link ServiceConstants::SERVICE_RANKING service ranking}, this * ServiceReferenceBase is less than the specified * ServiceReferenceBase if it has a higher * {@link ServiceConstants::SERVICE_ID service id} and greater if it has a lower * service id. * * @param reference The ServiceReferenceBase to be compared. * @return Returns a false or true if this * ServiceReferenceBase is less than or greater * than the specified ServiceReferenceBase. */ bool operator<(const ServiceReferenceBase& reference) const; bool operator==(const ServiceReferenceBase& reference) const; ServiceReferenceBase& operator=(const ServiceReferenceBase& reference); private: friend class ModulePrivate; friend class ModuleContext; friend class ModuleHooks; friend class ServiceHooks; friend class ServiceObjectsBase; friend class ServiceObjectsBasePrivate; friend class ServiceRegistrationBase; friend class ServiceRegistrationBasePrivate; friend class ServiceListeners; friend class ServiceRegistry; friend class LDAPFilter; template friend class ServiceReference; US_HASH_FUNCTION_FRIEND(ServiceReferenceBase); std::size_t Hash() const; /** * Creates an invalid ServiceReferenceBase object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceReferenceBase(); ServiceReferenceBase(ServiceRegistrationBasePrivate* reg); void SetInterfaceId(const std::string& interfaceId); ServiceReferenceBasePrivate* d; }; US_END_NAMESPACE US_MSVC_POP_WARNING /** * \ingroup MicroServices */ US_Core_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceReferenceBase)& serviceRef); US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceReferenceBase)) return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USSERVICEREFERENCEBASE_H diff --git a/Modules/CppMicroServices/core/include/usServiceRegistration.h b/Modules/CppMicroServices/core/include/usServiceRegistration.h index 34be9ee3dd..8c925bd588 100644 --- a/Modules/CppMicroServices/core/include/usServiceRegistration.h +++ b/Modules/CppMicroServices/core/include/usServiceRegistration.h @@ -1,203 +1,203 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEREGISTRATION_H #define USSERVICEREGISTRATION_H #include "usServiceRegistrationBase.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * A registered service. * *

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

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

* The ServiceReference object may be shared with other * modules. * * @throws std::logic_error If this * ServiceRegistration object has already been * unregistered or if it is invalid. * @return ServiceReference object. */ ServiceReference GetReference(InterfaceType) const { return this->ServiceRegistrationBase::GetReference(us_service_interface_iid()); } ServiceReference GetReference(InterfaceType) const { return this->ServiceRegistrationBase::GetReference(us_service_interface_iid()); } ServiceReference GetReference(InterfaceType) const { return this->ServiceRegistrationBase::GetReference(us_service_interface_iid()); } ///@} using ServiceRegistrationBase::operator=; private: friend class ModuleContext; ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } }; /// \cond template class ServiceRegistration : public ServiceRegistrationBase { public: ServiceRegistration() : ServiceRegistrationBase() { } ServiceReference GetReference(InterfaceType) const { return ServiceReference(this->ServiceRegistrationBase::GetReference(us_service_interface_iid())); } ServiceReference GetReference(InterfaceType) const { return ServiceReference(this->ServiceRegistrationBase::GetReference(us_service_interface_iid())); } using ServiceRegistrationBase::operator=; private: friend class ModuleContext; ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } }; template class ServiceRegistration : public ServiceRegistrationBase { public: ServiceRegistration() : ServiceRegistrationBase() { } ServiceReference GetReference() const { return this->GetReference(InterfaceType()); } ServiceReference GetReference(InterfaceType) const { return ServiceReference(this->ServiceRegistrationBase::GetReference(us_service_interface_iid())); } using ServiceRegistrationBase::operator=; private: friend class ModuleContext; ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } }; template<> class ServiceRegistration : public ServiceRegistrationBase { public: /** * Creates an invalid ServiceReference object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceRegistration() : ServiceRegistrationBase() { } ServiceRegistration(const ServiceRegistrationBase& base) : ServiceRegistrationBase(base) { } using ServiceRegistrationBase::operator=; }; /// \endcond /** * \ingroup MicroServices * * A service registration object of unknown type. */ typedef ServiceRegistration ServiceRegistrationU; US_END_NAMESPACE #endif // USSERVICEREGISTRATION_H diff --git a/Modules/CppMicroServices/core/include/usServiceRegistrationBase.h b/Modules/CppMicroServices/core/include/usServiceRegistrationBase.h index e6c5072ba4..1577aac8a1 100644 --- a/Modules/CppMicroServices/core/include/usServiceRegistrationBase.h +++ b/Modules/CppMicroServices/core/include/usServiceRegistrationBase.h @@ -1,223 +1,223 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEREGISTRATIONBASE_H #define USSERVICEREGISTRATIONBASE_H #include "usServiceProperties.h" #include "usServiceReference.h" US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class ModulePrivate; class ServiceRegistrationBasePrivate; class ServicePropertiesImpl; /** * \ingroup MicroServices * * A registered service. * *

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

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

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

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

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

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

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

    *
  1. The service is removed from the framework service registry so that * it can no longer be obtained. *
  2. A service event of type ServiceEvent#UNREGISTERING is fired * so that modules using this service can release their use of the service. * Once delivery of the service event is complete, the * ServiceRegistrationBase objects for the service may no longer be * used to get a service object for the service. *
  3. For each module whose use count for this service is greater than * zero:
    * The module's use count for this service is set to zero.
    * If the service was registered with a ServiceFactory object, the * ServiceFactory#UngetService method is called to release * the service object for the module. *
* * @throws std::logic_error If this * ServiceRegistrationBase object has already been * unregistered or if it is invalid. * @see ModuleContext#UngetService * @see ServiceFactory#UngetService */ void Unregister(); /** * Compare two ServiceRegistrationBase objects. * * If both ServiceRegistrationBase objects are valid, the comparison is done * using the underlying ServiceReference object. Otherwise, this ServiceRegistrationBase * object is less than the other object if and only if this object is invalid and * the other object is valid. * * @param o The ServiceRegistrationBase object to compare with. * @return \c true if this ServiceRegistrationBase object is less than the other object. */ bool operator<(const ServiceRegistrationBase& o) const; bool operator==(const ServiceRegistrationBase& registration) const; ServiceRegistrationBase& operator=(const ServiceRegistrationBase& registration); private: friend class ServiceRegistry; friend class ServiceReferenceBasePrivate; template friend class ServiceRegistration; US_HASH_FUNCTION_FRIEND(ServiceRegistrationBase); /** * Creates an invalid ServiceRegistrationBase object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceRegistrationBase(); ServiceRegistrationBase(ServiceRegistrationBasePrivate* registrationPrivate); ServiceRegistrationBase(ModulePrivate* module, const InterfaceMap& service, const ServicePropertiesImpl& props); ServiceRegistrationBasePrivate* d; }; US_END_NAMESPACE US_MSVC_POP_WARNING US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceRegistrationBase)) return US_HASH_FUNCTION(US_PREPEND_NAMESPACE(ServiceRegistrationBasePrivate)*, arg.d); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END inline std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceRegistrationBase)& /*reg*/) { return os << "US_PREPEND_NAMESPACE(ServiceRegistrationBase) object"; } #endif // USSERVICEREGISTRATIONBASE_H diff --git a/Modules/CppMicroServices/core/include/usServiceTracker.h b/Modules/CppMicroServices/core/include/usServiceTracker.h index 49a309fd22..abff1471e6 100644 --- a/Modules/CppMicroServices/core/include/usServiceTracker.h +++ b/Modules/CppMicroServices/core/include/usServiceTracker.h @@ -1,597 +1,597 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICETRACKER_H #define USSERVICETRACKER_H #include #include "usServiceReference.h" #include "usServiceTrackerCustomizer.h" #include "usLDAPFilter.h" US_BEGIN_NAMESPACE template class TrackedService; template class ServiceTrackerPrivate; class ModuleContext; /** * \ingroup MicroServices * * A base class template for type traits for objects tracked by a * ServiceTracker instance. It provides the \c TrackedType typedef * and two dummy method definitions. * * Tracked type traits (TTT) classes must additionally provide the * following methods: * *
    *
  • static bool IsValid(const TrackedType& t) Returns \c true if \c t is a valid object, \c false otherwise.
  • *
  • static void Dispose(TrackedType& t) Clears any resources held by the tracked object \c t.
  • *
  • static TrackedType DefaultValue() Returns the default value for newly created tracked objects.
  • *
* * @tparam T The type of the tracked object. * @tparam TTT The tracked type traits class deriving from this class. * * @see ServiceTracker */ template struct TrackedTypeTraitsBase { typedef T TrackedType; // Needed for S == void static TrackedType ConvertToTrackedType(const InterfaceMap&) { throw std::runtime_error("A custom ServiceTrackerCustomizer instance is required for custom tracked objects."); //return TTT::DefaultValue(); } // Needed for S != void static TrackedType ConvertToTrackedType(void*) { throw std::runtime_error("A custom ServiceTrackerCustomizer instance is required for custom tracked objects."); //return TTT::DefaultValue(); } }; /// \cond template struct TrackedTypeTraits; /// \endcond /** * \ingroup MicroServices * * Default type traits for custom tracked objects of pointer type. * * Use this tracked type traits template for custom tracked objects of * pointer type with the ServiceTracker class. * * @tparam S The type of the service being tracked. * @tparam T The type of the tracked object. */ template struct TrackedTypeTraits : public TrackedTypeTraitsBase > { typedef T* TrackedType; static bool IsValid(const TrackedType& t) { return t != nullptr; } static TrackedType DefaultValue() { return nullptr; } static void Dispose(TrackedType& t) { t = nullptr; } }; /// \cond template struct TrackedTypeTraits { typedef S* TrackedType; static bool IsValid(const TrackedType& t) { return t != nullptr; } static TrackedType DefaultValue() { return nullptr; } static void Dispose(TrackedType& t) { t = nullptr; } static TrackedType ConvertToTrackedType(S* s) { return s; } }; /// \endcond /// \cond /* * This specialization is "special" because the tracked type is not * void* (as specified in the second template parameter) but InterfaceMap. * This is in line with the ModuleContext::GetService(...) overloads to * return either S* or InterfaceMap dependening on the template parameter. */ template<> struct TrackedTypeTraits { typedef InterfaceMap TrackedType; static bool IsValid(const TrackedType& t) { return !t.empty(); } static TrackedType DefaultValue() { return TrackedType(); } static void Dispose(TrackedType& t) { t.clear(); } static TrackedType ConvertToTrackedType(const InterfaceMap& im) { return im; } }; /// \endcond /** * \ingroup MicroServices * * The ServiceTracker class simplifies using services from the * framework's service registry. *

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

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

* The service referenced by the specified ServiceReference * will be tracked by this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param reference The ServiceReference for the service to be * tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this * ServiceTracker will be used as the * ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, const ServiceReferenceType& reference, ServiceTrackerCustomizer* customizer = nullptr); /** * 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 = nullptr); /** * 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 = nullptr); /** * Open this ServiceTracker and begin tracking services. * *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* This method can be overridden in a subclass. If the default * implementation of \link AddingService(const ServiceReferenceType&) AddingService\endlink * method was used, this method must unget the service. * * @param reference The reference to removed service. * @param service The service object for the removed service. * @see ServiceTrackerCustomizer::RemovedService(const ServiceReferenceType&, T) */ void RemovedService(const ServiceReferenceType& reference, T service) override; private: typedef ServiceTracker _ServiceTracker; typedef TrackedService _TrackedService; typedef ServiceTrackerPrivate _ServiceTrackerPrivate; typedef ServiceTrackerCustomizer _ServiceTrackerCustomizer; friend class TrackedService; friend class ServiceTrackerPrivate; _ServiceTrackerPrivate* const d; }; US_END_NAMESPACE #include "usServiceTracker.tpp" #endif // USSERVICETRACKER_H diff --git a/Modules/CppMicroServices/core/include/usServiceTrackerCustomizer.h b/Modules/CppMicroServices/core/include/usServiceTrackerCustomizer.h index 8c728d6f5a..3e7ab79c94 100644 --- a/Modules/CppMicroServices/core/include/usServiceTrackerCustomizer.h +++ b/Modules/CppMicroServices/core/include/usServiceTrackerCustomizer.h @@ -1,118 +1,118 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICETRACKERCUSTOMIZER_H #define USSERVICETRACKERCUSTOMIZER_H #include "usServiceReference.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices * * The ServiceTrackerCustomizer interface allows a * ServiceTracker to customize the service objects that are * tracked. A ServiceTrackerCustomizer is called when a service is * being added to a ServiceTracker. The * ServiceTrackerCustomizer can then return an object for the * tracked service. A ServiceTrackerCustomizer is also called when * a tracked service is modified or has been removed from a * ServiceTracker. * *

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

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

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

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

* This method is called after a service is no longer being tracked by the * ServiceTracker. * * @param reference The reference to the service that has been removed. * @param service The service object for the specified referenced service. */ virtual void RemovedService(const ServiceReferenceType& reference, TrackedType service) = 0; }; US_END_NAMESPACE #endif // USSERVICETRACKERCUSTOMIZER_H diff --git a/Modules/CppMicroServices/core/include/usSharedData.h b/Modules/CppMicroServices/core/include/usSharedData.h index 33a442ce7f..d3edd48ae3 100644 --- a/Modules/CppMicroServices/core/include/usSharedData.h +++ b/Modules/CppMicroServices/core/include/usSharedData.h @@ -1,277 +1,277 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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. ============================================================================*/ /*============================================================================ Modified version of qshareddata.h from Qt 4.7.3 for CppMicroServices. Original copyright (c) Nokia Corporation. Usage covered by the GNU Lesser General Public License version 2.1 -(http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and the Nokia Qt +(https://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 USSHAREDDATA_H #define USSHAREDDATA_H #include "usAtomicInt_p.h" #include #include US_BEGIN_NAMESPACE /** * \ingroup MicroServicesUtils */ class 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&); }; /** * \ingroup MicroServicesUtils */ 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(nullptr) { } 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; }; /** * \ingroup MicroServicesUtils */ 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 != nullptr; } 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(US_PREPEND_NAMESPACE(SharedDataPointer& p1, US_PREPEND_NAMESPACE(SharedDataPointer& p2) { p1.Swap(p2); } template void swap(US_PREPEND_NAMESPACE(ExplicitlySharedDataPointer& p1, US_PREPEND_NAMESPACE(ExplicitlySharedDataPointer& p2) { p1.Swap(p2); } US_END_NAMESPACE #endif // USSHAREDDATA_H diff --git a/Modules/CppMicroServices/core/include/usSharedLibrary.h b/Modules/CppMicroServices/core/include/usSharedLibrary.h index 81a7981aa9..2a7f3453ff 100644 --- a/Modules/CppMicroServices/core/include/usSharedLibrary.h +++ b/Modules/CppMicroServices/core/include/usSharedLibrary.h @@ -1,214 +1,214 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USSHAREDLIBRARY_H #define USSHAREDLIBRARY_H #include "usCoreConfig.h" #include "usSharedData.h" #include US_BEGIN_NAMESPACE class SharedLibraryPrivate; /** * \ingroup MicroServicesUtils * * The SharedLibrary class loads shared libraries at runtime. */ class US_Core_EXPORT SharedLibrary { public: SharedLibrary(); SharedLibrary(const SharedLibrary& other); /** * Construct a SharedLibrary object using a library search path and * a library base name. * * @param libPath An absolute path containing the shared library * @param name The base name of the shared library, without prefix * and suffix. */ SharedLibrary(const std::string& libPath, const std::string& name); /** * Construct a SharedLibrary object using an absolute file path to * the shared library. Using this constructor effectively disables * all setters except SetFilePath(). * * @param absoluteFilePath The absolute path to the shared library. */ SharedLibrary(const std::string& absoluteFilePath); /** * Destroys this object but does not unload the shared library. */ ~SharedLibrary(); SharedLibrary& operator=(const SharedLibrary& other); /** * Loads the shared library pointed to by this SharedLibrary object. * On POSIX systems dlopen() is called with the RTLD_LAZY and * RTLD_LOCAL flags unless the compiler is gcc 4.4.x or older. Then * the RTLD_LAZY and RTLD_GLOBAL flags are used to load the shared library * to work around RTTI problems across shared library boundaries. * * @throws std::logic_error If the library is already loaded. * @throws std::runtime_error If loading the library failed. */ void Load(); /** * Loads the shared library pointed to by this SharedLibrary object, * using the specified flags on POSIX systems. * * @throws std::logic_error If the library is already loaded. * @throws std::runtime_error If loading the library failed. */ void Load(int flags); /** * Un-loads the shared library pointed to by this SharedLibrary object. * * @throws std::runtime_error If an error occurred while un-loading the * shared library. */ void Unload(); /** * Sets the base name of the shared library. Does nothing if the shared * library is already loaded or the SharedLibrary(const std::string&) * constructor was used. * * @param name The base name of the shared library, without prefix and * suffix. */ void SetName(const std::string& name); /** * Gets the base name of the shared library. * @return The shared libraries base name. */ std::string GetName() const; /** * Gets the absolute file path for the shared library with base name * \c name, using the search path returned by GetLibraryPath(). * * @param name The shared library base name. * @return The absolute file path of the shared library. */ std::string GetFilePath(const std::string& name) const; /** * Sets the absolute file path of this SharedLibrary object. * Using this methods with a non-empty \c absoluteFilePath argument * effectively disables all other setters. * * @param absoluteFilePath The new absolute file path of this SharedLibrary * object. */ void SetFilePath(const std::string& absoluteFilePath); /** * Gets the absolute file path of this SharedLibrary object. * * @return The absolute file path of the shared library. */ std::string GetFilePath() const; /** * Sets a new library search path. Does nothing if the shared * library is already loaded or the SharedLibrary(const std::string&) * constructor was used. * * @param path The new shared library search path. */ void SetLibraryPath(const std::string& path); /** * Gets the library search path of this SharedLibrary object. * * @return The library search path. */ std::string GetLibraryPath() const; /** * Sets the suffix for shared library names (e.g. lib). Does nothing if the shared * library is already loaded or the SharedLibrary(const std::string&) * constructor was used. * * @param suffix The shared library name suffix. */ void SetSuffix(const std::string& suffix); /** * Gets the file name suffix of this SharedLibrary object. * * @return The file name suffix of the shared library. */ std::string GetSuffix() const; /** * Sets the file name prefix for shared library names (e.g. .dll or .so). * Does nothing if the shared library is already loaded or the * SharedLibrary(const std::string&) constructor was used. * * @param prefix The shared library name prefix. */ void SetPrefix(const std::string& prefix); /** * Gets the file name prefix of this SharedLibrary object. * * @return The file name prefix of the shared library. */ std::string GetPrefix() const; /** * Gets the internal handle of this SharedLibrary object. * * @return \c nullptr if the shared library is not loaded, the operating * system specific handle otherwise. */ void* GetHandle() const; /** * Gets the loaded/unloaded stated of this SharedLibrary object. * * @return \c true if the shared library is loaded, \c false otherwise. */ bool IsLoaded() const; private: ExplicitlySharedDataPointer d; }; US_END_NAMESPACE #endif // USTESTUTILSHAREDLIBRARY_H diff --git a/Modules/CppMicroServices/core/include/usShrinkableMap.h b/Modules/CppMicroServices/core/include/usShrinkableMap.h index 604e6c6e24..f5b72c2998 100644 --- a/Modules/CppMicroServices/core/include/usShrinkableMap.h +++ b/Modules/CppMicroServices/core/include/usShrinkableMap.h @@ -1,181 +1,181 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSHRINKABLEMAP_H #define USSHRINKABLEMAP_H #include "usGlobalConfig.h" #include US_BEGIN_NAMESPACE /** * \ingroup MicroServicesUtils * * A std::map style associative container allowing query and removal * operations only. */ template class ShrinkableMap { private: static std::map emptyContainer; public: typedef std::map container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename container_type::size_type size_type; typedef typename container_type::key_type key_type; typedef typename container_type::mapped_type mapped_type; typedef typename container_type::value_type value_type; typedef typename container_type::reference reference; typedef typename container_type::const_reference const_reference; ShrinkableMap() : container(emptyContainer) { } iterator begin() { return container.begin(); } const_iterator begin() const { return container.begin(); } iterator end() { return container.end(); } const_iterator end() const { return container.end(); } void erase(iterator pos) { return container.erase(pos); } void erase(iterator first, iterator last) { return container.erase(first, last); } size_type erase(const Key& key) { return container.erase(key); } bool empty() const { return container.empty(); } void clear() { container.clear(); } size_type size() const { return container.size(); } size_type max_size() const { return container.max_size(); } T& operator[](const Key& key) { return container[key]; } size_type count(const Key& key) const { return container.count(key); } iterator find(const Key& key) { return container.find(key); } const_iterator find(const Key& key) const { return container.find(key); } std::pair equal_range(const Key& key) { return container.equal_range(key); } std::pair equal_range(const Key& key) const { return container.equal_range(key); } iterator lower_bound(const Key& key) { return container.lower_bound(key); } const_iterator lower_bound(const Key& key) const { return container.lower_bound(key); } iterator upper_bound(const Key& key) { return container.upper_bound(key); } const_iterator upper_bound(const Key& key) const { return container.upper_bound(key); } private: friend class ServiceHooks; ShrinkableMap(container_type& container) : container(container) {} container_type& container; }; template std::map ShrinkableMap::emptyContainer; US_END_NAMESPACE #endif // USSHRINKABLEMAP_H diff --git a/Modules/CppMicroServices/core/include/usShrinkableVector.h b/Modules/CppMicroServices/core/include/usShrinkableVector.h index b823650c17..27e0ac3e6d 100644 --- a/Modules/CppMicroServices/core/include/usShrinkableVector.h +++ b/Modules/CppMicroServices/core/include/usShrinkableVector.h @@ -1,164 +1,164 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSHRINKABLEVECTOR_H #define USSHRINKABLEVECTOR_H #include "usGlobalConfig.h" #include US_BEGIN_NAMESPACE /** * \ingroup MicroServicesUtils * * A std::vector style container allowing query and removal * operations only. */ template class ShrinkableVector { private: static std::vector emptyVector; public: typedef std::vector container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename container_type::size_type size_type; typedef typename container_type::reference reference; typedef typename container_type::const_reference const_reference; ShrinkableVector() : container(emptyVector) { } iterator begin() { return container.begin(); } const_iterator begin() const { return container.begin(); } iterator end() { return container.end(); } const_iterator end() const { return container.end(); } reference front() { return container.front(); } const_reference front() const { return container.front(); } reference back() { return container.back(); } const_reference back() const { return container.back(); } iterator erase(iterator pos) { return container.erase(pos); } iterator erase(iterator first, iterator last) { return container.erase(first, last); } void pop_back() { container.pop_back(); } bool empty() const { return container.empty(); } void clear() { container.clear(); } size_type size() const { return container.size(); } reference at(size_type pos) { return container.at(pos); } const_reference at(size_type pos) const { return container.at(pos); } const_reference operator[](size_type i) const { return container[i]; } reference operator[](size_type i) { return container[i]; } private: friend class ModuleHooks; friend class ServiceHooks; ShrinkableVector(container_type& container) : container(container) {} container_type& container; }; template std::vector ShrinkableVector::emptyVector; US_END_NAMESPACE #endif // USSHRINKABLEVECTOR_H diff --git a/Modules/CppMicroServices/core/src/module/usCoreModuleActivator.cpp b/Modules/CppMicroServices/core/src/module/usCoreModuleActivator.cpp index c5064e1f4b..8eccfe3007 100644 --- a/Modules/CppMicroServices/core/src/module/usCoreModuleActivator.cpp +++ b/Modules/CppMicroServices/core/src/module/usCoreModuleActivator.cpp @@ -1,47 +1,47 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleActivator.h" #include "usModule.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE class CoreModuleActivator : public ModuleActivator { void Load(ModuleContext* mc) override { mc->GetModule()->d->coreCtx->Init(); } void Unload(ModuleContext* /*mc*/) override { //mc->GetModule()->d->coreCtx->Uninit(); } }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(CoreModuleActivator)) diff --git a/Modules/CppMicroServices/core/src/module/usCoreModuleContext.cpp b/Modules/CppMicroServices/core/src/module/usCoreModuleContext.cpp index b48ee75cc7..2b836b4c23 100644 --- a/Modules/CppMicroServices/core/src/module/usCoreModuleContext.cpp +++ b/Modules/CppMicroServices/core/src/module/usCoreModuleContext.cpp @@ -1,53 +1,53 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include US_MSVC_DISABLE_WARNING(4355) #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE CoreModuleContext::CoreModuleContext() : listeners(this) , services(this) , serviceHooks(this) , moduleHooks(this) { } CoreModuleContext::~CoreModuleContext() { } void CoreModuleContext::Init() { serviceHooks.Open(); } void CoreModuleContext::Uninit() { serviceHooks.Close(); } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usCoreModuleContext_p.h b/Modules/CppMicroServices/core/src/module/usCoreModuleContext_p.h index ee01d8bf1e..85af6542d6 100644 --- a/Modules/CppMicroServices/core/src/module/usCoreModuleContext_p.h +++ b/Modules/CppMicroServices/core/src/module/usCoreModuleContext_p.h @@ -1,76 +1,76 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USCOREMODULECONTEXT_H #define USCOREMODULECONTEXT_H #include "usServiceListeners_p.h" #include "usServiceRegistry_p.h" #include "usModuleHooks_p.h" #include "usServiceHooks_p.h" US_BEGIN_NAMESPACE /** * This class is not part of the public API. */ class CoreModuleContext { public: /** * All listeners in this framework. */ ServiceListeners listeners; /** * All registered services in this framework. */ ServiceRegistry services; /** * All service hooks. */ ServiceHooks serviceHooks; /** * All module hooks. */ ModuleHooks moduleHooks; /** * Contruct a core context * */ CoreModuleContext(); ~CoreModuleContext(); void Init(); void Uninit(); }; US_END_NAMESPACE #endif // USCOREMODULECONTEXT_H diff --git a/Modules/CppMicroServices/core/src/module/usModule.cpp b/Modules/CppMicroServices/core/src/module/usModule.cpp index 9b4fb91d13..ef282a92c0 100644 --- a/Modules/CppMicroServices/core/src/module/usModule.cpp +++ b/Modules/CppMicroServices/core/src/module/usModule.cpp @@ -1,313 +1,313 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModule.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usModulePrivate.h" #include "usModuleResource.h" #include "usModuleSettings.h" #include "usCoreModuleContext_p.h" #include "usCoreConfig.h" US_BEGIN_NAMESPACE const std::string& Module::PROP_ID() { static const std::string s("module.id"); return s; } const std::string& Module::PROP_NAME() { static const std::string s("module.name"); return s; } const std::string& Module::PROP_LOCATION() { static const std::string s("module.location"); return s; } const std::string& Module::PROP_VERSION() { static const std::string s("module.version"); return s; } const std::string&Module::PROP_VENDOR() { static const std::string s("module.vendor"); return s; } const std::string&Module::PROP_DESCRIPTION() { static const std::string s("module.description"); return s; } const std::string&Module::PROP_AUTOLOAD_DIR() { static const std::string s("module.autoload_dir"); return s; } const std::string&Module::PROP_AUTOLOADED_MODULES() { static const std::string s("module.autoloaded_modules"); return s; } Module::Module() : d(nullptr) { } Module::~Module() { delete d; } void Module::Init(CoreModuleContext* coreCtx, ModuleInfo* info) { ModulePrivate* mp = new ModulePrivate(this, coreCtx, info); std::swap(mp, d); delete mp; } void Module::Uninit() { if (d->moduleContext != nullptr) { //d->coreCtx->listeners.HooksModuleStopped(d->moduleContext); d->RemoveModuleResources(); delete d->moduleContext; d->moduleContext = nullptr; d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); d->moduleActivator = nullptr; } } bool Module::IsLoaded() const { return d->moduleContext != nullptr; } void Module::Start() { if (d->moduleContext) { US_WARN << "Module " << d->info.name << " already started."; return; } d->moduleContext = new ModuleContext(this->d); typedef ModuleActivator*(*ModuleActivatorHook)(void); ModuleActivatorHook activatorHook = nullptr; std::string activator_func = "_us_module_activator_instance_" + d->info.name; void* activatorHookSym = ModuleUtils::GetSymbol(d->info, activator_func.c_str()); std::memcpy(&activatorHook, &activatorHookSym, sizeof(void*)); d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADING, this)); // try to get a ModuleActivator instance if (activatorHook) { try { d->moduleActivator = activatorHook(); } catch (...) { US_ERROR << "Creating the module activator of " << d->info.name << " failed"; throw; } // This method should be "noexcept" and by not catching exceptions // here we semantically treat it that way since any exception during // static initialization will either terminate the program or cause // the dynamic loader to report an error. d->moduleActivator->Load(d->moduleContext); } #ifdef US_ENABLE_AUTOLOADING_SUPPORT if (ModuleSettings::IsAutoLoadingEnabled()) { const std::vector loadedPaths = AutoLoadModules(d->info); if (!loadedPaths.empty()) { d->moduleManifest.SetValue(PROP_AUTOLOADED_MODULES(), Any(loadedPaths)); } } #endif d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADED, this)); } void Module::Stop() { if (d->moduleContext == nullptr) { US_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 (...) { US_WARN << "Calling the module activator Unload() method of " << d->info.name << " failed!"; try { this->Uninit(); } catch (...) {} throw; } this->Uninit(); } ModuleContext* Module::GetModuleContext() const { return d->moduleContext; } long Module::GetModuleId() const { return d->info.id; } std::string Module::GetLocation() const { return d->info.location; } std::string Module::GetName() const { return d->info.name; } ModuleVersion Module::GetVersion() const { return d->version; } Any Module::GetProperty(const std::string& key) const { return d->moduleManifest.GetValue(key); } std::vector Module::GetPropertyKeys() const { return d->moduleManifest.GetKeys(); } std::vector Module::GetRegisteredServices() const { std::vector sr; std::vector res; d->coreCtx->services.GetRegisteredByModule(d, sr); for (std::vector::const_iterator i = sr.begin(); i != sr.end(); ++i) { res.push_back(i->GetReference()); } return res; } std::vector Module::GetServicesInUse() const { std::vector sr; std::vector res; d->coreCtx->services.GetUsedByModule(const_cast(this), sr); for (std::vector::const_iterator i = sr.begin(); i != sr.end(); ++i) { res.push_back(i->GetReference()); } return res; } ModuleResource Module::GetResource(const std::string& path) const { if (!d->resourceContainer.IsValid()) { return ModuleResource(); } ModuleResource result(path, d->resourceContainer); if (result) return result; return ModuleResource(); } std::vector Module::FindResources(const std::string& path, const std::string& filePattern, bool recurse) const { std::vector result; if (!d->resourceContainer.IsValid()) { return result; } std::string normalizedPath = path; // add a leading and trailing slash if (normalizedPath.empty()) normalizedPath.push_back('/'); if (*normalizedPath.begin() != '/') normalizedPath = '/' + normalizedPath; if (*normalizedPath.rbegin() != '/') normalizedPath.push_back('/'); d->resourceContainer.FindNodes(d->info.name + normalizedPath, filePattern.empty() ? "*" : filePattern, recurse, result); return result; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const Module& module) { os << "Module[" << "id=" << module.GetModuleId() << ", loc=" << module.GetLocation() << ", name=" << module.GetName() << "]"; return os; } std::ostream& operator<<(std::ostream& os, Module const * module) { return operator<<(os, *module); } diff --git a/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked.tpp b/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked.tpp index ae1a27f8bd..148991d0a1 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked.tpp +++ b/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked.tpp @@ -1,316 +1,316 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include US_BEGIN_NAMESPACE template const bool ModuleAbstractTracked::DEBUG_OUTPUT = false; template ModuleAbstractTracked::ModuleAbstractTracked() { closed = false; } template ModuleAbstractTracked::~ModuleAbstractTracked() { } template void ModuleAbstractTracked::SetInitial(const std::vector& initiallist) { std::copy(initiallist.begin(), initiallist.end(), std::back_inserter(initial)); if (DEBUG_OUTPUT) { for(typename std::list::const_iterator item = initial.begin(); item != initial.end(); ++item) { US_DEBUG << "ModuleAbstractTracked::setInitial: " << (*item); } } } template void ModuleAbstractTracked::TrackInitial() { while (true) { S item; { US_UNUSED(Lock(this)); if (closed || (initial.size() == 0)) { /* * if there are no more initial items */ return; /* we are done */ } /* * move the first item from the initial list to the adding list * within this synchronized block. */ item = initial.front(); initial.pop_front(); if (TTT::IsValid(tracked[item])) { /* if we are already tracking this item */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackInitial[already tracked]: " << item; continue; /* skip this item */ } if (std::find(adding.begin(), adding.end(), item) != adding.end()) { /* * if this item is already in the process of being added. */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackInitial[already adding]: " << item; continue; /* skip this item */ } adding.push_back(item); } US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackInitial: " << item; TrackAdding(item, R()); /* * Begin tracking it. We call trackAdding * since we have already put the item in the * adding list. */ } } template void ModuleAbstractTracked::Close() { closed = true; } template void ModuleAbstractTracked::Track(S item, R related) { T object = TTT::DefaultValue(); { US_UNUSED(Lock(this)); if (closed) { return; } object = tracked[item]; if (!TTT::IsValid(object)) { /* we are not tracking the item */ if (std::find(adding.begin(), adding.end(),item) != adding.end()) { /* if this item is already in the process of being added. */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::track[already adding]: " << item; return; } adding.push_back(item); /* mark this item is being added */ } else { /* we are currently tracking this item */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::track[modified]: " << item; Modified(); /* increment modification count */ } } if (!TTT::IsValid(object)) { /* we are not tracking the item */ TrackAdding(item, related); } else { /* Call customizer outside of synchronized region */ CustomizerModified(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to * let it propagate */ } } template void ModuleAbstractTracked::Untrack(S item, R related) { T object = TTT::DefaultValue(); { US_UNUSED(Lock(this)); std::size_t initialSize = initial.size(); initial.remove(item); if (initialSize != initial.size()) { /* if this item is already in the list * of initial references to process */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::untrack[removed from initial]: " << item; return; /* we have removed it from the list and it will not be * processed */ } std::size_t addingSize = adding.size(); adding.remove(item); if (addingSize != adding.size()) { /* if the item is in the process of * being added */ US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::untrack[being added]: " << item; return; /* * in case the item is untracked while in the process of * adding */ } object = tracked[item]; /* * must remove from tracker before * calling customizer callback */ tracked.erase(item); if (!TTT::IsValid(object)) { /* are we actually tracking the item */ return; } Modified(); /* increment modification count */ } US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::untrack[removed]: " << item; /* Call customizer outside of synchronized region */ CustomizerRemoved(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to let it * propagate */ } template std::size_t ModuleAbstractTracked::Size() const { return tracked.size(); } template bool ModuleAbstractTracked::IsEmpty() const { return tracked.empty(); } template typename ModuleAbstractTracked::T ModuleAbstractTracked::GetCustomizedObject(S item) const { typename TrackingMap::const_iterator i = tracked.find(item); if (i != tracked.end()) return i->second; return T(); } template void ModuleAbstractTracked::GetTracked(std::vector& items) const { for (typename TrackingMap::const_iterator i = tracked.begin(); i != tracked.end(); ++i) { items.push_back(i->first); } } template void ModuleAbstractTracked::Modified() { trackingCount.Ref(); } template int ModuleAbstractTracked::GetTrackingCount() const { return trackingCount; } template void ModuleAbstractTracked::CopyEntries(TrackingMap& map) const { map.insert(tracked.begin(), tracked.end()); } template bool ModuleAbstractTracked::CustomizerAddingFinal(S item, const T& custom) { US_UNUSED(Lock(this)); std::size_t addingSize = adding.size(); adding.remove(item); if (addingSize != adding.size() && !closed) { /* * if the item was not untracked during the customizer * callback */ if (TTT::IsValid(custom)) { tracked[item] = custom; Modified(); /* increment modification count */ this->NotifyAll(); /* notify any waiters */ } return false; } else { return true; } } template void ModuleAbstractTracked::TrackAdding(S item, R related) { US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackAdding:" << item; T object = TTT::DefaultValue(); bool becameUntracked = false; /* Call customizer outside of synchronized region */ try { object = CustomizerAdding(item, related); becameUntracked = this->CustomizerAddingFinal(item, object); } catch (...) { /* * If the customizer throws an exception, it will * propagate after the cleanup code. */ this->CustomizerAddingFinal(item, object); throw; } /* * The item became untracked during the customizer callback. */ if (becameUntracked && TTT::IsValid(object)) { US_DEBUG(DEBUG_OUTPUT) << "ModuleAbstractTracked::trackAdding[removed]: " << item; /* Call customizer outside of synchronized region */ CustomizerRemoved(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to * let it propagate */ } } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked_p.h b/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked_p.h index 1f09be6aa1..c1a6ac0a13 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked_p.h +++ b/Modules/CppMicroServices/core/src/module/usModuleAbstractTracked_p.h @@ -1,293 +1,293 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEABSTRACTTRACKED_H #define USMODULEABSTRACTTRACKED_H #include #include "usAtomicInt_p.h" #include "usAny.h" US_BEGIN_NAMESPACE /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. * * Abstract class to track items. If a Tracker is reused (closed then reopened), * then a new ModuleAbstractTracked object is used. This class acts as a map of tracked * item -> customized object. Subclasses of this class will act as the listener * object for the tracker. This class is used to synchronize access to the * tracked items. This is not a public class. It is only for use by the * implementation of the Tracker class. * * @tparam S The tracked item. It is the key. * @tparam T The value mapped to the tracked item. * @tparam R The reason the tracked item is being tracked or untracked. * @ThreadSafe */ template class ModuleAbstractTracked : public MultiThreaded { public: typedef typename TTT::TrackedType T; /* set this to true to compile in debug messages */ static const bool DEBUG_OUTPUT; // = false; typedef std::map TrackingMap; /** * ModuleAbstractTracked constructor. */ ModuleAbstractTracked(); virtual ~ModuleAbstractTracked(); /** * Set initial list of items into tracker before events begin to be * received. * * This method must be called from Tracker's open method while synchronized * on this object in the same synchronized block as the add listener call. * * @param list The initial list of items to be tracked. null * entries in the list are ignored. * @GuardedBy this */ void SetInitial(const std::vector& list); /** * Track the initial list of items. This is called after events can begin to * be received. * * This method must be called from Tracker's open method while not * synchronized on this object after the add listener call. * */ void TrackInitial(); /** * Called by the owning Tracker object when it is closed. */ void Close(); /** * Begin to track an item. * * @param item S to be tracked. * @param related Action related object. */ void Track(S item, R related); /** * Discontinue tracking the item. * * @param item S to be untracked. * @param related Action related object. */ void Untrack(S item, R related); /** * Returns the number of tracked items. * * @return The number of tracked items. * * @GuardedBy this */ std::size_t Size() const; /** * Returns if the tracker is empty. * * @return Whether the tracker is empty. * * @GuardedBy this */ bool IsEmpty() const; /** * Return the customized object for the specified item * * @param item The item to lookup in the map * @return The customized object for the specified item. * * @GuardedBy this */ T GetCustomizedObject(S item) const; /** * Return the list of tracked items. * * @return The tracked items. * @GuardedBy this */ void GetTracked(std::vector& items) const; /** * Increment the modification count. If this method is overridden, the * overriding method MUST call this method to increment the tracking count. * * @GuardedBy this */ virtual void Modified(); /** * Returns the tracking count for this ServiceTracker object. * * The tracking count is initialized to 0 when this object is opened. Every * time an item is added, modified or removed from this object the tracking * count is incremented. * * @GuardedBy this * @return The tracking count for this object. */ int GetTrackingCount() const; /** * Copy the tracked items and associated values into the specified map. * * @param map The map into which to copy the tracked items and associated * values. This map must not be a user provided map so that user code * is not executed while synchronized on this. * @return The specified map. * @GuardedBy this */ void CopyEntries(TrackingMap& map) const; /** * Call the specific customizer adding method. This method must not be * called while synchronized on this object. * * @param item S to be tracked. * @param related Action related object. * @return Customized object for the tracked item or null if * the item is not to be tracked. */ virtual T CustomizerAdding(S item, const R& related) = 0; /** * Call the specific customizer modified method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ virtual void CustomizerModified(S item, const R& related, T object) = 0; /** * Call the specific customizer removed method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ virtual void CustomizerRemoved(S item, const R& related, T object) = 0; /** * List of items in the process of being added. This is used to deal with * nesting of events. Since events may be synchronously delivered, events * can be nested. For example, when processing the adding of a service and * the customizer causes the service to be unregistered, notification to the * nested call to untrack that the service was unregistered can be made to * the track method. * * Since the std::vector implementation is not synchronized, all access to * this list must be protected by the same synchronized object for * thread-safety. * * @GuardedBy this */ std::list adding; /** * true if the tracked object is closed. * * This field is volatile because it is set by one thread and read by * another. */ volatile bool closed; /** * Initial list of items for the tracker. This is used to correctly process * the initial items which could be modified before they are tracked. This * is necessary since the initial set of tracked items are not "announced" * by events and therefore the event which makes the item untracked could be * delivered before we track the item. * * An item must not be in both the initial and adding lists at the same * time. An item must be moved from the initial list to the adding list * "atomically" before we begin tracking it. * * Since the LinkedList implementation is not synchronized, all access to * this list must be protected by the same synchronized object for * thread-safety. * * @GuardedBy this */ std::list initial; /** * Common logic to add an item to the tracker used by track and * trackInitial. The specified item must have been placed in the adding list * before calling this method. * * @param item S to be tracked. * @param related Action related object. */ void TrackAdding(S item, R related); private: typedef ModuleAbstractTracked Self; /** * Map of tracked items to customized objects. * * @GuardedBy this */ TrackingMap tracked; /** * Modification count. This field is initialized to zero and incremented by * modified. * * @GuardedBy this */ AtomicInt trackingCount; bool CustomizerAddingFinal(S item, const T& custom); }; US_END_NAMESPACE #include "usModuleAbstractTracked.tpp" #endif // USMODULEABSTRACTTRACKED_H diff --git a/Modules/CppMicroServices/core/src/module/usModuleContext.cpp b/Modules/CppMicroServices/core/src/module/usModuleContext.cpp index 05ffd4c5f5..1f92098b8b 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleContext.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleContext.cpp @@ -1,196 +1,196 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleContext.h" #include "usModuleRegistry.h" #include "usModulePrivate.h" #include "usModuleSettings.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistry_p.h" #include "usServiceReferenceBasePrivate.h" #include US_BEGIN_NAMESPACE class ModuleContextPrivate { public: ModuleContextPrivate(ModulePrivate* module) : module(module) {} ModulePrivate* module; }; ModuleContext::ModuleContext(ModulePrivate* module) : d(new ModuleContextPrivate(module)) {} ModuleContext::~ModuleContext() { delete d; } Module* ModuleContext::GetModule() const { return d->module->q; } Module* ModuleContext::GetModule(long id) const { return d->module->coreCtx->moduleHooks.FilterModule(this, ModuleRegistry::GetModule(id)); } Module* ModuleContext::GetModule(const std::string& name) { return ModuleRegistry::GetModule(name); } std::vector ModuleContext::GetModules() const { std::vector modules = ModuleRegistry::GetModules(); d->module->coreCtx->moduleHooks.FilterModules(this, modules); return modules; } ServiceRegistrationU ModuleContext::RegisterService(const InterfaceMap& service, const ServiceProperties& properties) { return d->module->coreCtx->services.RegisterService(d->module, service, properties); } std::vector ModuleContext::GetServiceReferences(const std::string& clazz, const std::string& filter) { std::vector result; std::vector refs; d->module->coreCtx->services.Get(clazz, filter, d->module, refs); for (std::vector::const_iterator iter = refs.begin(); iter != refs.end(); ++iter) { result.push_back(ServiceReferenceU(*iter)); } return result; } ServiceReferenceU ModuleContext::GetServiceReference(const std::string& clazz) { return d->module->coreCtx->services.Get(d->module, clazz); } void* ModuleContext::GetService(const ServiceReferenceBase& reference) { if (!reference) { throw std::invalid_argument("Default constructed ServiceReference is not a valid input to GetService()"); } return reference.d->GetService(d->module->q); } InterfaceMap ModuleContext::GetService(const ServiceReferenceU& reference) { if (!reference) { throw std::invalid_argument("Default constructed ServiceReference is not a valid input to GetService()"); } return reference.d->GetServiceInterfaceMap(d->module->q); } bool ModuleContext::UngetService(const ServiceReferenceBase& reference) { ServiceReferenceBase ref = reference; return ref.d->UngetService(d->module->q, true); } void ModuleContext::AddServiceListener(const ServiceListener& delegate, const std::string& filter) { d->module->coreCtx->listeners.AddServiceListener(this, delegate, nullptr, filter); } void ModuleContext::RemoveServiceListener(const ServiceListener& delegate) { d->module->coreCtx->listeners.RemoveServiceListener(this, delegate, nullptr); } void ModuleContext::AddModuleListener(const ModuleListener& delegate) { d->module->coreCtx->listeners.AddModuleListener(this, delegate, nullptr); } void ModuleContext::RemoveModuleListener(const ModuleListener& delegate) { d->module->coreCtx->listeners.RemoveModuleListener(this, delegate, nullptr); } void ModuleContext::AddServiceListener(const ServiceListener& delegate, void* data, const std::string &filter) { d->module->coreCtx->listeners.AddServiceListener(this, delegate, data, filter); } void ModuleContext::RemoveServiceListener(const ServiceListener& delegate, void* data) { d->module->coreCtx->listeners.RemoveServiceListener(this, delegate, data); } void ModuleContext::AddModuleListener(const ModuleListener& delegate, void* data) { d->module->coreCtx->listeners.AddModuleListener(this, delegate, data); } void ModuleContext::RemoveModuleListener(const ModuleListener& delegate, void* data) { d->module->coreCtx->listeners.RemoveModuleListener(this, delegate, data); } std::string ModuleContext::GetDataFile(const std::string &filename) const { // compute the module storage path #ifdef US_PLATFORM_WINDOWS static const char separator = '\\'; #else static const char separator = '/'; #endif std::string baseStoragePath = ModuleSettings::GetStoragePath(); if (baseStoragePath.empty()) return std::string(); if (baseStoragePath != d->module->baseStoragePath) { d->module->baseStoragePath = baseStoragePath; d->module->storagePath.clear(); } if (d->module->storagePath.empty()) { char buf[50]; sprintf(buf, "%ld", d->module->info.id); d->module->storagePath = baseStoragePath + separator + buf + "_" + d->module->info.name + separator; } return d->module->storagePath + filename; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleEvent.cpp b/Modules/CppMicroServices/core/src/module/usModuleEvent.cpp index 3378fa788e..5b1613901b 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleEvent.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleEvent.cpp @@ -1,119 +1,119 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleEvent.h" #include "usModule.h" US_BEGIN_NAMESPACE class ModuleEventData : public SharedData { public: ModuleEventData(ModuleEvent::Type type, Module* module) : type(type), module(module) { } ModuleEventData(const ModuleEventData& other) : SharedData(other), type(other.type), module(other.module) { } const ModuleEvent::Type type; Module* const module; private: // purposely not implemented ModuleEventData& operator=(const ModuleEventData&); }; ModuleEvent::ModuleEvent() : d(nullptr) { } 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, ModuleEvent::Type eventType) { switch (eventType) { case ModuleEvent::LOADED: return os << "LOADED"; case ModuleEvent::UNLOADED: return os << "UNLOADED"; case ModuleEvent::LOADING: return os << "LOADING"; case ModuleEvent::UNLOADING: return os << "UNLOADING"; default: return os << "Unknown module event type (" << static_cast(eventType) << ")"; } } std::ostream& operator<<(std::ostream& os, const ModuleEvent& event) { if (event.IsNull()) return os << "NONE"; Module* m = event.GetModule(); os << event.GetType() << " #" << m->GetModuleId() << " (" << m->GetLocation() << ")"; return os; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleEventHook.cpp b/Modules/CppMicroServices/core/src/module/usModuleEventHook.cpp index f49842e6fa..43b579f020 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleEventHook.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleEventHook.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usModuleEventHook.h" US_BEGIN_NAMESPACE ModuleEventHook::~ModuleEventHook() { } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleFindHook.cpp b/Modules/CppMicroServices/core/src/module/usModuleFindHook.cpp index 93c9880271..e928171051 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleFindHook.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleFindHook.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usModuleFindHook.h" US_BEGIN_NAMESPACE ModuleFindHook::~ModuleFindHook() { } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleHooks.cpp b/Modules/CppMicroServices/core/src/module/usModuleHooks.cpp index 3014222275..2a9af393c3 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleHooks.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleHooks.cpp @@ -1,170 +1,170 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleHooks_p.h" #include "usModuleEventHook.h" #include "usModuleFindHook.h" #include "usCoreModuleContext_p.h" #include "usGetModuleContext.h" #include "usModuleContext.h" #include "usServiceReferenceBasePrivate.h" US_BEGIN_NAMESPACE ModuleHooks::ModuleHooks(CoreModuleContext* ctx) : coreCtx(ctx) { } Module* ModuleHooks::FilterModule(const ModuleContext* mc, Module* module) const { if(module == nullptr) { return nullptr; } std::vector srl; coreCtx->services.Get(us_service_interface_iid(), srl); if (srl.empty()) { return module; } else { std::vector ml; ml.push_back(module); this->FilterModules(mc, ml); return ml.empty() ? nullptr : module; } } void ModuleHooks::FilterModules(const ModuleContext* mc, std::vector& modules) const { std::vector srl; coreCtx->services.Get(us_service_interface_iid(), srl); ShrinkableVector filtered(modules); std::sort(srl.begin(), srl.end()); for (std::vector::reverse_iterator srBaseIter = srl.rbegin(), srBaseEnd = srl.rend(); srBaseIter != srBaseEnd; ++srBaseIter) { ServiceReference sr = srBaseIter->GetReference(); ModuleFindHook* const fh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); if (fh != nullptr) { try { fh->Find(mc, filtered); } catch (const std::exception& e) { US_WARN << "Failed to call Module FindHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": " << e.what(); } catch (...) { US_WARN << "Failed to call Module FindHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": unknown exception type"; } } } } void ModuleHooks::FilterModuleEventReceivers(const ModuleEvent& evt, ServiceListeners::ModuleListenerMap& moduleListeners) { std::vector eventHooks; coreCtx->services.Get(us_service_interface_iid(), eventHooks); { MutexLock lock(coreCtx->listeners.moduleListenerMapMutex); moduleListeners = coreCtx->listeners.moduleListenerMap; } if(!eventHooks.empty()) { std::vector moduleContexts; for (ServiceListeners::ModuleListenerMap::iterator le = moduleListeners.begin(), leEnd = moduleListeners.end(); le != leEnd; ++le) { moduleContexts.push_back(le->first); } std::sort(moduleContexts.begin(), moduleContexts.end()); moduleContexts.erase(std::unique(moduleContexts.begin(), moduleContexts.end()), moduleContexts.end()); const std::size_t unfilteredSize = moduleContexts.size(); ShrinkableVector filtered(moduleContexts); std::sort(eventHooks.begin(), eventHooks.end()); for (std::vector::reverse_iterator iter = eventHooks.rbegin(), iterEnd = eventHooks.rend(); iter != iterEnd; ++iter) { ServiceReference sr; try { sr = iter->GetReference(); } catch (const std::logic_error& e) { US_WARN << "Failed to get event hook service reference: " << e.what(); continue; } ModuleEventHook* eh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); if (eh != nullptr) { try { eh->Event(evt, filtered); } catch (const std::exception& e) { US_WARN << "Failed to call Module EventHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": " << e.what(); } catch (...) { US_WARN << "Failed to call Module EventHook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": unknown exception type"; } } } if (unfilteredSize != moduleContexts.size()) { for (ServiceListeners::ModuleListenerMap::iterator le = moduleListeners.begin(); le != moduleListeners.end();) { if(std::find(moduleContexts.begin(), moduleContexts.end(), le->first) == moduleContexts.end()) { moduleListeners.erase(le++); } else { ++le; } } } } } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleHooks_p.h b/Modules/CppMicroServices/core/src/module/usModuleHooks_p.h index d32bad924a..37980a9c0e 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleHooks_p.h +++ b/Modules/CppMicroServices/core/src/module/usModuleHooks_p.h @@ -1,58 +1,58 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEHOOKS_P_H #define USMODULEHOOKS_P_H #include "usServiceListeners_p.h" #include US_BEGIN_NAMESPACE class CoreModuleContext; class Module; class ModuleContext; class ModuleEvent; class ModuleHooks { private: CoreModuleContext* const coreCtx; public: ModuleHooks(CoreModuleContext* ctx); Module* FilterModule(const ModuleContext* mc, Module* module) const; void FilterModules(const ModuleContext* mc, std::vector& modules) const; void FilterModuleEventReceivers(const ModuleEvent& evt, ServiceListeners::ModuleListenerMap& moduleListeners); }; US_END_NAMESPACE #endif // USMODULEHOOKS_P_H diff --git a/Modules/CppMicroServices/core/src/module/usModuleInfo.cpp b/Modules/CppMicroServices/core/src/module/usModuleInfo.cpp index 36b13cf415..396ddccca0 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleInfo.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleInfo.cpp @@ -1,33 +1,33 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleInfo.h" US_BEGIN_NAMESPACE ModuleInfo::ModuleInfo(const std::string& name) : name(name) , id(0) { } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleManifest.cpp b/Modules/CppMicroServices/core/src/module/usModuleManifest.cpp index c897cfc168..1357195b35 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleManifest.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleManifest.cpp @@ -1,156 +1,156 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleManifest_p.h" #include #include using namespace nlohmann; US_BEGIN_NAMESPACE namespace { typedef std::map AnyMap; typedef std::vector AnyVector; void ParseJsonObject(const json& jsonObject, AnyMap& anyMap); void ParseJsonArray(const json& jsonArray, AnyVector& anyVector); Any ParseJsonValue(const json& jsonValue) { if (jsonValue.is_object()) { Any any = AnyMap(); ParseJsonObject(jsonValue, ref_any_cast(any)); return any; } else if (jsonValue.is_array()) { Any any = AnyVector(); ParseJsonArray(jsonValue, ref_any_cast(any)); return any; } else if (jsonValue.is_string()) { return Any(jsonValue.get()); } else if (jsonValue.is_boolean()) { return Any(jsonValue.get()); } else if (jsonValue.is_number_integer()) { return Any(jsonValue.get()); } else if (jsonValue.is_number_float()) { return Any(jsonValue.get()); } return Any(); } void ParseJsonObject(const json& jsonObject, AnyMap& anyMap) { for (const auto& [key, jsonValue] : jsonObject.items()) { Any anyValue = ParseJsonValue(jsonValue); if (!anyValue.Empty()) { anyMap.insert(std::make_pair(key, anyValue)); } } } void ParseJsonArray(const json& jsonArray, AnyVector& anyVector) { for (const auto& jsonValue : jsonArray) { Any anyValue = ParseJsonValue(jsonValue); if (!anyValue.Empty()) { anyVector.push_back(anyValue); } } } } ModuleManifest::ModuleManifest() { } void ModuleManifest::Parse(std::istream& is) { json root; try { root = json::parse(is); } catch (const json::exception& e) { throw std::runtime_error(e.what()); } if (!root.is_object()) { throw std::runtime_error("The Json root element must be an object."); } ParseJsonObject(root, m_Properties); } bool ModuleManifest::Contains(const std::string& key) const { return m_Properties.count(key) > 0; } Any ModuleManifest::GetValue(const std::string& key) const { AnyMap::const_iterator iter = m_Properties.find(key); if (iter != m_Properties.end()) { return iter->second; } return Any(); } std::vector ModuleManifest::GetKeys() const { std::vector keys; for (AnyMap::const_iterator iter = m_Properties.begin(); iter != m_Properties.end(); ++iter) { keys.push_back(iter->first); } return keys; } void ModuleManifest::SetValue(const std::string& key, const Any& value) { m_Properties[key] = value; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleManifest_p.h b/Modules/CppMicroServices/core/src/module/usModuleManifest_p.h index 8a1b871780..8455c70345 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleManifest_p.h +++ b/Modules/CppMicroServices/core/src/module/usModuleManifest_p.h @@ -1,54 +1,54 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEMANIFEST_P_H #define USMODULEMANIFEST_P_H #include "usAny.h" US_BEGIN_NAMESPACE class ModuleManifest { public: ModuleManifest(); void Parse(std::istream& is); bool Contains(const std::string& key) const; Any GetValue(const std::string& key) const; std::vector GetKeys() const; void SetValue(const std::string& key, const Any& value); private: typedef std::map AnyMap; AnyMap m_Properties; }; US_END_NAMESPACE #endif // USMODULEMANIFEST_P_H diff --git a/Modules/CppMicroServices/core/src/module/usModulePrivate.cpp b/Modules/CppMicroServices/core/src/module/usModulePrivate.cpp index 21fcabbb3a..6dd0c70f05 100644 --- a/Modules/CppMicroServices/core/src/module/usModulePrivate.cpp +++ b/Modules/CppMicroServices/core/src/module/usModulePrivate.cpp @@ -1,148 +1,148 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModulePrivate.h" #include "usModule.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usModuleUtils_p.h" #include "usModuleSettings.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistration.h" #include "usServiceReferenceBasePrivate.h" #include #include #include #include US_BEGIN_NAMESPACE AtomicInt ModulePrivate::idCounter; ModulePrivate::ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info) : coreCtx(coreCtx) , info(*info) , resourceContainer(info) , moduleContext(nullptr) , moduleActivator(nullptr) , q(qq) { // Check if the module provides a manifest.json file and if yes, parse it. if (resourceContainer.IsValid()) { ModuleResource manifestRes("/manifest.json", resourceContainer); if (manifestRes) { ModuleResourceStream manifestStream(manifestRes); try { moduleManifest.Parse(manifestStream); } catch (const std::exception& e) { US_ERROR << "Parsing of manifest.json for module " << info->location << " failed: " << e.what(); } } } // Check if we got version information and validate the version identifier if (moduleManifest.Contains(Module::PROP_VERSION())) { Any versionAny = moduleManifest.GetValue(Module::PROP_VERSION()); std::string errMsg; if (versionAny.Type() != typeid(std::string)) { errMsg = std::string("The version identifier must be a string"); } try { version = ModuleVersion(versionAny.ToString()); } catch (const std::exception& e) { errMsg = std::string("The version identifier is invalid: ") + e.what(); } if (!errMsg.empty()) { throw std::invalid_argument(std::string("The Json value for ") + Module::PROP_VERSION() + " for module " + info->location + " is not valid: " + errMsg); } } std::stringstream propId; propId << this->info.id; moduleManifest.SetValue(Module::PROP_ID(), propId.str()); moduleManifest.SetValue(Module::PROP_LOCATION(), this->info.location); moduleManifest.SetValue(Module::PROP_NAME(), this->info.name); if (moduleManifest.Contains(Module::PROP_AUTOLOAD_DIR())) { this->info.autoLoadDir = moduleManifest.GetValue(Module::PROP_AUTOLOAD_DIR()).ToString(); } else { this->info.autoLoadDir = this->info.name; moduleManifest.SetValue(Module::PROP_AUTOLOAD_DIR(), Any(this->info.autoLoadDir)); } } ModulePrivate::~ModulePrivate() { delete moduleContext; } void ModulePrivate::RemoveModuleResources() { coreCtx->listeners.RemoveAllListeners(moduleContext); std::vector srs; coreCtx->services.GetRegisteredByModule(this, srs); for (std::vector::iterator i = srs.begin(); i != srs.end(); ++i) { try { i->Unregister(); } catch (const std::logic_error& /*ignore*/) { // Someone has unregistered the service after stop completed. // This should not occur, but we don't want get stuck in // an illegal state so we catch it. } } srs.clear(); coreCtx->services.GetUsedByModule(q, srs); for (std::vector::const_iterator i = srs.begin(); i != srs.end(); ++i) { i->GetReference(std::string()).d->UngetService(q, false); } } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModulePrivate.h b/Modules/CppMicroServices/core/src/module/usModulePrivate.h index a61b7928f1..47032ffc9e 100644 --- a/Modules/CppMicroServices/core/src/module/usModulePrivate.h +++ b/Modules/CppMicroServices/core/src/module/usModulePrivate.h @@ -1,97 +1,97 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEPRIVATE_H #define USMODULEPRIVATE_H #include #include #include "usModuleRegistry.h" #include "usModuleVersion.h" #include "usModuleInfo.h" #include "usModuleManifest_p.h" #include "usModuleResourceContainer_p.h" #include "usAtomicInt_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModuleContext; struct ModuleActivator; /** * \ingroup MicroServices */ class ModulePrivate { public: /** * Construct a new module based on a ModuleInfo object. */ ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info); virtual ~ModulePrivate(); void RemoveModuleResources(); CoreModuleContext* const coreCtx; /** * Module version */ ModuleVersion version; ModuleInfo info; ModuleResourceContainer resourceContainer; /** * ModuleContext for the module */ ModuleContext* moduleContext; ModuleActivator* moduleActivator; ModuleManifest moduleManifest; std::string baseStoragePath; std::string storagePath; Module* const q; private: void InitializeResources(); static AtomicInt idCounter; // purposely not implemented ModulePrivate(const ModulePrivate&); ModulePrivate& operator=(const ModulePrivate&); }; US_END_NAMESPACE #endif // USMODULEPRIVATE_H diff --git a/Modules/CppMicroServices/core/src/module/usModuleRegistry.cpp b/Modules/CppMicroServices/core/src/module/usModuleRegistry.cpp index d70a4d4616..b59e19d059 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleRegistry.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleRegistry.cpp @@ -1,224 +1,224 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleRegistry.h" #include "usModule.h" #include "usModuleInfo.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usModuleInitialization.h" #include "usCoreModuleContext_p.h" #include "usGetModuleContext.h" #include "usStaticInit_p.h" #include #include US_BEGIN_NAMESPACE typedef US_UNORDERED_MAP_TYPE ModuleMap; US_GLOBAL_STATIC(CoreModuleContext, coreModuleContext) template struct ModuleDeleter { void operator()(GlobalStatic& globalStatic) const { ModuleMap* moduleMap = globalStatic.pointer; for (ModuleMap::const_iterator i = moduleMap->begin(); i != moduleMap->end(); ++i) { delete i->second; } DefaultGlobalStaticDeleter defaultDeleter; defaultDeleter(globalStatic); } }; /** * Table of all installed modules in this framework. * Key is the module id. */ US_GLOBAL_STATIC_WITH_DELETER(ModuleMap, modules, ModuleDeleter) /** * Lock for protecting the modules object */ US_GLOBAL_STATIC(Mutex, modulesLock) /** * Lock for protecting the register count */ US_GLOBAL_STATIC(Mutex, countLock) void ModuleRegistry::Register(ModuleInfo* info) { static long regCount = 0; if (info->id > 0) { // The module was already registered Module* module = nullptr; { MutexLock lock(*modulesLock()); module = modules()->operator[](info->name); assert(module != nullptr); } module->Start(); } else { Module* module = nullptr; // check if the module is reloaded { MutexLock lock(*modulesLock()); ModuleMap* map = modules(); for (ModuleMap::const_iterator i = map->begin(); i != map->end(); ++i) { if (i->second->GetLocation() == info->location && i->second->GetName() == info->name) { module = i->second; info->id = module->GetModuleId(); } } } if (!module) { module = new Module(); countLock()->Lock(); info->id = ++regCount; assert(info->id == 1 ? info->name == "CppMicroServices" : true); countLock()->Unlock(); module->Init(coreModuleContext(), info); MutexLock lock(*modulesLock()); ModuleMap* map = modules(); map->insert(std::make_pair(info->name, module)); } else { module->Init(coreModuleContext(), info); } module->Start(); } } void ModuleRegistry::UnRegister(const ModuleInfo* info) { if (info->id > 1) { Module* curr = nullptr; { MutexLock lock(*modulesLock()); curr = modules()->operator[](info->name); assert(curr != nullptr); } curr->Stop(); } } Module* ModuleRegistry::GetModule(long id) { MutexLock lock(*modulesLock()); ModuleMap::const_iterator iter = modules()->begin(); ModuleMap::const_iterator iterEnd = modules()->end(); for (; iter != iterEnd; ++iter) { if (iter->second->GetModuleId() == id) { return iter->second; } } return nullptr; } Module* ModuleRegistry::GetModule(const std::string& name) { MutexLock lock(*modulesLock()); ModuleMap::const_iterator iter = modules()->find(name); if (iter != modules()->end()) { return iter->second; } return nullptr; } std::vector ModuleRegistry::GetModules() { MutexLock lock(*modulesLock()); std::vector result; ModuleMap* map = modules(); ModuleMap::const_iterator iter = map->begin(); ModuleMap::const_iterator iterEnd = map->end(); for (; iter != iterEnd; ++iter) { result.push_back(iter->second); } return result; } std::vector ModuleRegistry::GetLoadedModules() { MutexLock lock(*modulesLock()); std::vector result; ModuleMap::const_iterator iter = modules()->begin(); ModuleMap::const_iterator iterEnd = modules()->end(); for (; iter != iterEnd; ++iter) { if (iter->second->IsLoaded()) { result.push_back(iter->second); } } return result; } // Control the static initialization order for several core objects struct StaticInitializationOrder { StaticInitializationOrder() { ModuleSettings::GetLogLevel(); modulesLock(); countLock(); modules(); coreModuleContext(); } }; static StaticInitializationOrder _staticInitializationOrder; US_END_NAMESPACE // We initialize the CppMicroService module after making sure // that all other global statics have been initialized above US_INITIALIZE_MODULE diff --git a/Modules/CppMicroServices/core/src/module/usModuleResource.cpp b/Modules/CppMicroServices/core/src/module/usModuleResource.cpp index 7485267b3f..2470563beb 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleResource.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleResource.cpp @@ -1,289 +1,289 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleResource.h" #include "usAtomicInt_p.h" #include "usModuleResourceContainer_p.h" #include "usModuleInfo.h" #include US_BEGIN_NAMESPACE class ModuleResourcePrivate { public: ModuleResourcePrivate(const ModuleResourceContainer* rc) : resourceContainer(rc) , ref(1) {} void InitFilePath(const std::string& file); const ModuleResourceContainer* const resourceContainer; ModuleResourceContainer::Stat stat; std::string fileName; std::string path; mutable std::vector children; mutable std::vector childNodes; /** * Reference count for implicitly shared private implementation. */ AtomicInt ref; }; void ModuleResourcePrivate::InitFilePath(const std::string& file) { std::string normalizedFile = file; if (normalizedFile.empty() || normalizedFile[0] != '/') { normalizedFile = '/' + normalizedFile; } std::string rawPath; std::size_t index = normalizedFile.find_last_of('/'); if (index == std::string::npos) { fileName = normalizedFile; } else if (index < normalizedFile.size()-1) { fileName = normalizedFile.substr(index+1); rawPath = normalizedFile.substr(0,index+1); } else { rawPath = normalizedFile; } // remove duplicate / std::string::value_type lastChar = 0; for (std::size_t i = 0; i < rawPath.size(); ++i) { if (rawPath[i] == '/' && lastChar == '/') { continue; } lastChar = rawPath[i]; path.push_back(lastChar); } if (path.empty()) { path.push_back('/'); } } ModuleResource::ModuleResource() : d(new ModuleResourcePrivate(nullptr)) { } ModuleResource::ModuleResource(const ModuleResource &resource) : d(resource.d) { d->ref.Ref(); } ModuleResource::ModuleResource(const std::string& file, const ModuleResourceContainer& resourceContainer) : d(new ModuleResourcePrivate(&resourceContainer)) { d->InitFilePath(file); d->stat.filePath = d->resourceContainer->GetModuleInfo()->name + d->path + d->fileName; d->resourceContainer->GetStat(d->stat); } ModuleResource::ModuleResource(int index, const ModuleResourceContainer& resourceContainer) : d(new ModuleResourcePrivate(&resourceContainer)) { d->resourceContainer->GetStat(index, d->stat); d->InitFilePath(d->stat.filePath.substr(d->resourceContainer->GetModuleInfo()->name.size())); } ModuleResource::~ModuleResource() { if (!d->ref.Deref()) delete d; } ModuleResource& ModuleResource::operator =(const ModuleResource& resource) { ModuleResourcePrivate* curr_d = d; d = resource.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } bool ModuleResource::operator <(const ModuleResource& resource) const { return this->GetResourcePath() < resource.GetResourcePath(); } bool ModuleResource::operator ==(const ModuleResource& resource) const { return d->resourceContainer == resource.d->resourceContainer && this->GetResourcePath() == resource.GetResourcePath(); } bool ModuleResource::operator !=(const ModuleResource &resource) const { return !(*this == resource); } bool ModuleResource::IsValid() const { return d->resourceContainer && d->resourceContainer->IsValid() && d->stat.index > -1; } ModuleResource::operator bool_type() const { return IsValid() ? &ModuleResource::d : nullptr; } std::string ModuleResource::GetName() const { return d->fileName; } std::string ModuleResource::GetPath() const { return d->path; } std::string ModuleResource::GetResourcePath() const { return d->path + d->fileName; } std::string ModuleResource::GetBaseName() const { return d->fileName.substr(0, d->fileName.find_first_of('.')); } std::string ModuleResource::GetCompleteBaseName() const { return d->fileName.substr(0, d->fileName.find_last_of('.')); } std::string ModuleResource::GetSuffix() const { std::size_t index = d->fileName.find_last_of('.'); return index < d->fileName.size()-1 ? d->fileName.substr(index+1) : std::string(""); } std::string ModuleResource::GetCompleteSuffix() const { std::size_t index = d->fileName.find_first_of('.'); return index < d->fileName.size()-1 ? d->fileName.substr(index+1) : std::string(""); } bool ModuleResource::IsDir() const { return d->stat.isDir; } bool ModuleResource::IsFile() const { return !d->stat.isDir; } std::vector ModuleResource::GetChildren() const { if (!IsValid() || !IsDir()) return d->children; if (d->children.empty()) { d->resourceContainer->GetChildren(d->stat.filePath, true, d->children, d->childNodes); } return d->children; } std::vector ModuleResource::GetChildResources() const { std::vector childResources; if (!IsValid() || !IsDir()) return childResources; if (d->childNodes.empty()) { d->resourceContainer->GetChildren(this->GetResourcePath(), true, d->children, d->childNodes); } for (std::vector::const_iterator iter = d->childNodes.begin(), iterEnd = d->childNodes.end(); iter != iterEnd; ++iter) { childResources.push_back(ModuleResource(static_cast(*iter), *d->resourceContainer)); } return childResources; } int ModuleResource::GetSize() const { return d->stat.uncompressedSize; } time_t ModuleResource::GetLastModified() const { return d->stat.modifiedTime; } std::size_t ModuleResource::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; return US_HASH_FUNCTION(std::string, d->resourceContainer->GetModuleInfo()->name + this->GetResourcePath()); } void* ModuleResource::GetData() const { if (!IsValid()) return nullptr; void* data = d->resourceContainer->GetData(d->stat.index); if (data == nullptr) { US_WARN << "Error uncompressing resource data for " << this->GetResourcePath() << " from " << d->resourceContainer->GetModuleInfo()->location; } return data; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ModuleResource& resource) { return os << resource.GetResourcePath(); } diff --git a/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer.cpp b/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer.cpp index 456ccf590a..3ffe225092 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer.cpp @@ -1,287 +1,287 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleResourceBuffer_p.h" #include "us_stdint.h" #include #include #include #ifdef US_PLATFORM_WINDOWS #define DATA_NEEDS_NEWLINE_CONVERSION 1 #undef REMOVE_LAST_NEWLINE_IN_TEXT_MODE #else #undef DATA_NEEDS_NEWLINE_CONVERSION #define REMOVE_LAST_NEWLINE_IN_TEXT_MODE 1 #endif US_BEGIN_NAMESPACE class ModuleResourceBufferPrivate { public: ModuleResourceBufferPrivate(void* data, std::size_t size, const char* begin, std::ios_base::openmode mode) : begin(begin) , end(begin + size) , current(begin) , mode(mode) , uncompressedData(reinterpret_cast(data)) #ifdef DATA_NEEDS_NEWLINE_CONVERSION , pos(0) #endif { } ~ModuleResourceBufferPrivate() { free(uncompressedData); } const char* const begin; const char* const end; const char* current; const std::ios_base::openmode mode; unsigned char* uncompressedData; #ifdef DATA_NEEDS_NEWLINE_CONVERSION // records the stream position ignoring CR characters std::streambuf::pos_type pos; #endif }; ModuleResourceBuffer::ModuleResourceBuffer(void* data, std::size_t _size, std::ios_base::openmode mode) : d(nullptr) { assert(_size < static_cast(std::numeric_limits::max())); // assert(data != nullptr); char* begin = reinterpret_cast(data); std::size_t size = _size; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (data != nullptr && !(mode & std::ios_base::binary) && begin[0] == '\r') { ++begin; --size; } #endif #ifdef REMOVE_LAST_NEWLINE_IN_TEXT_MODE if (data != nullptr && !(mode & std::ios_base::binary) && begin[size-1] == '\n') { --size; } #endif d = new ModuleResourceBufferPrivate(data, size, begin, mode); } ModuleResourceBuffer::~ModuleResourceBuffer() { delete d; } ModuleResourceBuffer::int_type ModuleResourceBuffer::underflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current + 1 == d->end) { return traits_type::eof(); } c = d->current[1]; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::uflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current++; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current == d->end) { return traits_type::eof(); } c = *d->current++; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current++); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::pbackfail(int_type ch) { int backOffset = -1; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (!(d->mode & std::ios_base::binary)) { while ((d->current - backOffset) >= d->begin && d->current[backOffset] == '\r') { --backOffset; } // d->begin always points to a character != '\r' } #endif if (d->current == d->begin || (ch != traits_type::eof() && ch != d->current[backOffset])) { return traits_type::eof(); } d->current += backOffset; return traits_type::to_int_type(*d->current); } std::streamsize ModuleResourceBuffer::showmanyc() { assert(d->current <= d->end); #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streamsize ssize = 0; std::size_t chunkSize = d->end - d->current; for (std::size_t i = 0; i < chunkSize; ++i) { if (d->current[i] != '\r') { ++ssize; } } return ssize; #else return d->end - d->current; #endif } std::streambuf::pos_type ModuleResourceBuffer::seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*which*/) { #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streambuf::off_type step = 1; if (way == std::ios_base::beg) { d->current = d->begin; } else if (way == std::ios_base::end) { d->current = d->end; step = -1; } if (!(d->mode & std::ios_base::binary)) { if (way == std::ios_base::beg) { d->pos = 0; } else if (way == std::ios_base::end) { d->current -= 1; } std::streambuf::off_type i = 0; // scan through off amount of characters excluding '\r' while (i != off) { if (*d->current != '\r') { i += step; d->pos += step; } d->current += step; } // adjust the position in case of a "backwards" seek if (way == std::ios_base::end) { // fix pointer from previous while loop d->current += 1; d->pos = 0; i = 0; const std::streampos currInternalPos = d->current - d->begin; while (i != currInternalPos) { if (d->begin[i] != '\r') { d->pos += 1; } ++i; } } } else { d->current += off; d->pos = d->current - d->begin; } return d->pos; #else if (way == std::ios_base::beg) { d->current = d->begin + off; return off; } else if (way == std::ios_base::cur) { d->current += off; return d->current - d->begin; } else { d->current = d->end + off; return d->current - d->begin; } #endif } std::streambuf::pos_type ModuleResourceBuffer::seekpos(std::streambuf::pos_type sp, std::ios_base::openmode /*which*/) { return this->seekoff(sp, std::ios_base::beg); } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer_p.h b/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer_p.h index 63fa6f2911..e4b8a42a9f 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer_p.h +++ b/Modules/CppMicroServices/core/src/module/usModuleResourceBuffer_p.h @@ -1,68 +1,68 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULERESOURCEBUFFER_P_H #define USMODULERESOURCEBUFFER_P_H #include #include US_BEGIN_NAMESPACE class ModuleResourceBufferPrivate; class US_Core_EXPORT ModuleResourceBuffer: public std::streambuf { public: explicit ModuleResourceBuffer(void* data, std::size_t size, std::ios_base::openmode mode); ~ModuleResourceBuffer() override; private: int_type underflow() override; int_type uflow() override; int_type pbackfail(int_type ch) override; std::streamsize showmanyc() override; pos_type seekoff (off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; pos_type seekpos (pos_type sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; // purposely not implemented ModuleResourceBuffer(const ModuleResourceBuffer&); ModuleResourceBuffer& operator=(const ModuleResourceBuffer&); private: ModuleResourceBufferPrivate* d; }; US_END_NAMESPACE #endif // USMODULERESOURCEBUFFER_P_H diff --git a/Modules/CppMicroServices/core/src/module/usModuleResourceContainer.cpp b/Modules/CppMicroServices/core/src/module/usModuleResourceContainer.cpp index 6068e9900a..0ece7a461e 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleResourceContainer.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleResourceContainer.cpp @@ -1,229 +1,229 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleResourceContainer_p.h" #include "usModuleInfo.h" #include "usModuleUtils_p.h" #include "usModuleResource.h" #include "usLog_p.h" #include "miniz.h" #include #include #include #include US_BEGIN_NAMESPACE struct ModuleResourceContainerPrivate { ModuleResourceContainerPrivate(const ModuleInfo* moduleInfo) : m_ModuleInfo(moduleInfo) , m_IsValid(false) , m_ZipArchive() {} typedef std::pair NameIndexPair; struct PairComp { bool operator()(const NameIndexPair& p1, const NameIndexPair& p2) const { return p1.first < p2.first; } }; typedef std::set SetType; void InitSortedEntries() { if (m_SortedEntries.empty()) { mz_uint numFiles = mz_zip_reader_get_num_files(&m_ZipArchive); for (mz_uint fileIndex = 0; fileIndex < numFiles; ++fileIndex) { char fileName[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; mz_zip_reader_get_filename(&m_ZipArchive, fileIndex, fileName, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE); m_SortedEntries.insert(std::make_pair(std::string(fileName), fileIndex)); } } } const ModuleInfo* m_ModuleInfo; bool m_IsValid; mz_zip_archive m_ZipArchive; std::set m_SortedEntries; }; ModuleResourceContainer::ModuleResourceContainer(const ModuleInfo* moduleInfo) : d(new ModuleResourceContainerPrivate(moduleInfo)) { if (mz_zip_reader_init_file(&d->m_ZipArchive, moduleInfo->location.c_str(), 0)) { d->m_IsValid = true; } else { US_DEBUG << "Could not init zip archive for module " << moduleInfo->name; } } ModuleResourceContainer::~ModuleResourceContainer() { if (IsValid()) { mz_zip_reader_end(&d->m_ZipArchive); } delete d; } bool ModuleResourceContainer::IsValid() const { return d->m_IsValid; } bool ModuleResourceContainer::GetStat(ModuleResourceContainer::Stat& stat) const { if (IsValid()) { int fileIndex = mz_zip_reader_locate_file(&d->m_ZipArchive, stat.filePath.c_str(), nullptr, 0); if (fileIndex >= 0) { return GetStat(fileIndex, stat); } } return false; } bool ModuleResourceContainer::GetStat(int index, ModuleResourceContainer::Stat& stat) const { if (IsValid()) { if (index >= 0) { mz_zip_archive_file_stat zipStat; if (!mz_zip_reader_file_stat(&d->m_ZipArchive, index, &zipStat)) { return false; } stat.index = index; stat.filePath = zipStat.m_filename; stat.isDir = mz_zip_reader_is_file_a_directory(&d->m_ZipArchive, index) ? true : false; stat.modifiedTime = zipStat.m_time; // This will limit the size info from uint64 to uint32 on 32-bit // architectures. We don't care because we assume resources > 2GB // don't make sense to be embedded in a module anyway. assert(zipStat.m_comp_size < INT_MAX); assert(zipStat.m_uncomp_size < INT_MAX); stat.uncompressedSize = static_cast(zipStat.m_uncomp_size); return true; } } return false; } void* ModuleResourceContainer::GetData(int index) const { return mz_zip_reader_extract_to_heap(&d->m_ZipArchive, index, nullptr, 0); } const ModuleInfo*ModuleResourceContainer::GetModuleInfo() const { return d->m_ModuleInfo; } void ModuleResourceContainer::GetChildren(const std::string& resourcePath, bool relativePaths, std::vector& names, std::vector& indices) const { d->InitSortedEntries(); ModuleResourceContainerPrivate::SetType::const_iterator iter = d->m_SortedEntries.find(std::make_pair(resourcePath, 0)); if (iter == d->m_SortedEntries.end()) { return; } for (++iter; iter != d->m_SortedEntries.end(); ++iter) { if (resourcePath.size() > iter->first.size()) break; if (iter->first.compare(0, resourcePath.size(), resourcePath) == 0) { std::size_t pos = iter->first.find_first_of('/', resourcePath.size()); if (pos == std::string::npos || pos == iter->first.size()-1) { if (relativePaths) { names.push_back(iter->first.substr(resourcePath.size())); } else { names.push_back(iter->first); } indices.push_back(iter->second); } } } } void ModuleResourceContainer::FindNodes(const std::string& path, const std::string& filePattern, bool recurse, std::vector& resources) const { std::vector names; std::vector indices; this->GetChildren(path, true, names, indices); for(std::size_t i = 0, s = names.size(); i < s; ++i) { if (*names[i].rbegin() == '/' && recurse) { this->FindNodes(path + names[i], filePattern, recurse, resources); } if (this->Matches(names[i], filePattern)) { resources.push_back(ModuleResource(indices[i], *this)); } } } bool ModuleResourceContainer::Matches(const std::string& name, const std::string& filePattern) const { // short-cut if (filePattern == "*") return true; std::stringstream ss(filePattern); std::string tok; std::size_t pos = 0; while(std::getline(ss, tok, '*')) { std::size_t index = name.find(tok, pos); if (index == std::string::npos) return false; pos = index + tok.size(); } return true; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleResourceContainer_p.h b/Modules/CppMicroServices/core/src/module/usModuleResourceContainer_p.h index 9692c25ceb..f215bcfafe 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleResourceContainer_p.h +++ b/Modules/CppMicroServices/core/src/module/usModuleResourceContainer_p.h @@ -1,88 +1,88 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULERESOURCECONTAINER_P_H #define USMODULERESOURCECONTAINER_P_H #include "usGlobalConfig.h" #include "us_stdint.h" #include #include #include US_BEGIN_NAMESPACE struct ModuleInfo; class ModuleResource; struct ModuleResourceContainerPrivate; class ModuleResourceContainer { public: ModuleResourceContainer(const ModuleInfo* moduleInfo); ~ModuleResourceContainer(); struct Stat { Stat() : index(-1) , uncompressedSize(0) , modifiedTime(0) , isDir(false) {} std::string filePath; int index; int uncompressedSize; time_t modifiedTime; bool isDir; }; bool IsValid() const; bool GetStat(Stat& stat) const; bool GetStat(int index, Stat& stat) const; void* GetData(int index) const; const ModuleInfo* GetModuleInfo() const; void GetChildren(const std::string& resourcePath, bool relativePaths, std::vector& names, std::vector& indices) const; void FindNodes(const std::string& path, const std::string& filePattern, bool recurse, std::vector& resources) const; private: bool Matches(const std::string& name, const std::string& filePattern) const; ModuleResourceContainerPrivate* d; }; US_END_NAMESPACE #endif // USMODULERESOURCECONTAINER_P_H diff --git a/Modules/CppMicroServices/core/src/module/usModuleResourceStream.cpp b/Modules/CppMicroServices/core/src/module/usModuleResourceStream.cpp index 21b84b4382..7f2d5814e5 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleResourceStream.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleResourceStream.cpp @@ -1,39 +1,39 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleResourceStream.h" #include "usModuleResource.h" // 'this' used in base member initializer list US_MSVC_PUSH_DISABLE_WARNING(4355) US_BEGIN_NAMESPACE ModuleResourceStream::ModuleResourceStream(const ModuleResource& resource, std::ios_base::openmode mode) : ModuleResourceBuffer(resource.GetData(), resource.GetSize(), mode | std::ios_base::in) , std::istream(this) { } US_END_NAMESPACE US_MSVC_POP_WARNING diff --git a/Modules/CppMicroServices/core/src/module/usModuleSettings.cpp b/Modules/CppMicroServices/core/src/module/usModuleSettings.cpp index cf3176d306..8d9b38aad6 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleSettings.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleSettings.cpp @@ -1,189 +1,189 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleSettings.h" #include "usThreads_p.h" #include "usStaticInit_p.h" #include #include #include #include #include US_BEGIN_NAMESPACE namespace { std::string RemoveTrailingPathSeparator(const std::string& in) { #ifdef US_PLATFORM_WINDOWS const char separator = '\\'; #else const char separator = '/'; #endif if (in.empty()) return in; std::string::const_iterator lastChar = --in.end(); while (lastChar != in.begin() && std::isspace(*lastChar)) lastChar--; if (*lastChar != separator) lastChar++; std::string::const_iterator firstChar = in.begin(); while (firstChar < lastChar && std::isspace(*firstChar)) firstChar++; return std::string(firstChar, lastChar); } } std::string ModuleSettings::CURRENT_MODULE_PATH() { static const std::string var = "us_current_module_path"; return var; } struct ModuleSettingsPrivate : public MultiThreaded<> { ModuleSettingsPrivate() : autoLoadPaths() #ifdef US_ENABLE_AUTOLOADING_SUPPORT , autoLoadingEnabled(true) #else , autoLoadingEnabled(false) #endif , autoLoadingDisabled(false) , logLevel(DebugMsg) { autoLoadPaths.insert(ModuleSettings::CURRENT_MODULE_PATH()); char* envPaths = getenv("US_AUTOLOAD_PATHS"); if (envPaths != nullptr) { std::stringstream ss(envPaths); std::string envPath; #ifdef US_PLATFORM_WINDOWS const char separator = ';'; #else const char separator = ':'; #endif while (std::getline(ss, envPath, separator)) { std::string normalizedEnvPath = RemoveTrailingPathSeparator(envPath); if (!normalizedEnvPath.empty()) { extraPaths.insert(normalizedEnvPath); } } } if (getenv("US_DISABLE_AUTOLOADING")) { autoLoadingDisabled = true; } } std::set autoLoadPaths; std::set extraPaths; bool autoLoadingEnabled; bool autoLoadingDisabled; std::string storagePath; MsgType logLevel; }; US_GLOBAL_STATIC(ModuleSettingsPrivate, moduleSettingsPrivate) bool ModuleSettings::IsThreadingSupportEnabled() { #ifdef US_ENABLE_THREADING_SUPPORT return true; #else return false; #endif } bool ModuleSettings::IsAutoLoadingEnabled() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); #ifdef US_ENABLE_AUTOLOADING_SUPPORT return !moduleSettingsPrivate()->autoLoadingDisabled && moduleSettingsPrivate()->autoLoadingEnabled; #else return false; #endif } void ModuleSettings::SetAutoLoadingEnabled(bool enable) { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->autoLoadingEnabled = enable; } ModuleSettings::PathList ModuleSettings::GetAutoLoadPaths() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); ModuleSettings::PathList paths(moduleSettingsPrivate()->autoLoadPaths.begin(), moduleSettingsPrivate()->autoLoadPaths.end()); paths.insert(paths.end(), moduleSettingsPrivate()->extraPaths.begin(), moduleSettingsPrivate()->extraPaths.end()); std::sort(paths.begin(), paths.end()); paths.erase(std::unique(paths.begin(), paths.end()), paths.end()); return paths; } void ModuleSettings::SetAutoLoadPaths(const PathList& paths) { PathList normalizedPaths; normalizedPaths.resize(paths.size()); std::transform(paths.begin(), paths.end(), normalizedPaths.begin(), RemoveTrailingPathSeparator); US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->autoLoadPaths.clear(); moduleSettingsPrivate()->autoLoadPaths.insert(normalizedPaths.begin(), normalizedPaths.end()); } void ModuleSettings::AddAutoLoadPath(const std::string& path) { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->autoLoadPaths.insert(RemoveTrailingPathSeparator(path)); } void ModuleSettings::SetStoragePath(const std::string &path) { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->storagePath = RemoveTrailingPathSeparator(path); } std::string ModuleSettings::GetStoragePath() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); return moduleSettingsPrivate()->storagePath; } void ModuleSettings::SetLogLevel(MsgType level) { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->logLevel = level; } MsgType ModuleSettings::GetLogLevel() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); return moduleSettingsPrivate()->logLevel; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleUtils.cpp b/Modules/CppMicroServices/core/src/module/usModuleUtils.cpp index 8cf8e7fedb..29357cc58c 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleUtils.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleUtils.cpp @@ -1,171 +1,171 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usModuleUtils_p.h" #include #include #include US_BEGIN_NAMESPACE namespace { #ifdef US_BUILD_SHARED_LIBS const bool sharedLibMode = true; #else const bool sharedLibMode = false; #endif } #ifdef __GNUC__ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include std::string GetLibraryPath_impl(void* symbol) { Dl_info info; if (dladdr(symbol, &info)) { return info.dli_fname; } else { US_DEBUG << "GetLibraryPath_impl() failed for address " << symbol; } return ""; } void* GetSymbol_impl(const ModuleInfo& moduleInfo, const char* symbol) { // Clear the last error message dlerror(); void* selfHandle = nullptr; if (!sharedLibMode || moduleInfo.name == "main") { // Get the handle of the executable selfHandle = dlopen(nullptr, RTLD_LAZY); } else { selfHandle = dlopen(moduleInfo.location.c_str(), RTLD_LAZY); } if (selfHandle) { void* addr = dlsym(selfHandle, symbol); if (!addr) { const char* dlerrorMsg = dlerror(); if (dlerrorMsg) { US_DEBUG << "GetSymbol_impl() failed: " << dlerrorMsg; } } dlclose(selfHandle); return addr; } else { US_DEBUG << "GetSymbol_impl() dlopen() failed: " << dlerror(); } return nullptr; } #elif _WIN32 #include std::string GetLibraryPath_impl(void *symbol) { HMODULE handle = 0; BOOL handleError = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast(symbol), &handle); if (!handleError) { // Test US_DEBUG << "GetLibraryPath_impl():GetModuleHandle() " << GetLastErrorStr(); return ""; } char modulePath[512]; if (GetModuleFileName(handle, modulePath, 512)) { return modulePath; } US_DEBUG << "GetLibraryPath_impl():GetModuleFileName() " << GetLastErrorStr(); return ""; } void* GetSymbol_impl(const ModuleInfo& moduleInfo, const char* symbol) { HMODULE handle = nullptr; if (!sharedLibMode || moduleInfo.name == "main") { handle = GetModuleHandle(nullptr); } else { handle = GetModuleHandle(moduleInfo.location.c_str()); } if (!handle) { US_DEBUG << "GetSymbol_impl():GetModuleHandle() " << GetLastErrorStr(); return 0; } void* addr = (void*)GetProcAddress(handle, symbol); if (!addr) { US_DEBUG << "GetSymbol_impl():GetProcAddress(handle," << symbol << ") " << GetLastErrorStr(); } return addr; } #else std::string GetLibraryPath_impl(void*) { return ""; } void* GetSymbol_impl(const ModuleInfo&, const char* symbol) { return 0; } #endif std::string ModuleUtils::GetLibraryPath(void* symbol) { return GetLibraryPath_impl(symbol); } void* ModuleUtils::GetSymbol(const ModuleInfo& module, const char* symbol) { return GetSymbol_impl(module, symbol); } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/module/usModuleUtils_p.h b/Modules/CppMicroServices/core/src/module/usModuleUtils_p.h index c5291e22f6..5915f9a9f5 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleUtils_p.h +++ b/Modules/CppMicroServices/core/src/module/usModuleUtils_p.h @@ -1,52 +1,52 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEUTILS_H #define USMODULEUTILS_H #include #include #define US_STR_(x) #x #define US_STR(x) US_STR_(x) #define US_CONCAT_(x,y) x ## y #define US_CONCAT(x,y) US_CONCAT_(x,y) US_BEGIN_NAMESPACE struct ModuleInfo; /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. */ struct US_Core_EXPORT ModuleUtils { static std::string GetLibraryPath(void* symbol); static void* GetSymbol(const ModuleInfo& module, const char* symbol); }; US_END_NAMESPACE #endif // USMODULEUTILS_H diff --git a/Modules/CppMicroServices/core/src/module/usModuleVersion.cpp b/Modules/CppMicroServices/core/src/module/usModuleVersion.cpp index 6ecc56ed03..a62d5bddd5 100644 --- a/Modules/CppMicroServices/core/src/module/usModuleVersion.cpp +++ b/Modules/CppMicroServices/core/src/module/usModuleVersion.cpp @@ -1,275 +1,275 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usModuleVersion.h" #include #include #include #include #include US_BEGIN_NAMESPACE 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::stringstream ss; ss << majorVersion << SEPARATOR << minorVersion << SEPARATOR << microVersion; if (!qualifier.empty()) { ss << SEPARATOR << qualifier; } return ss.str(); } 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; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ModuleVersion& v) { return os << v.ToString(); } diff --git a/Modules/CppMicroServices/core/src/service/usLDAPExpr.cpp b/Modules/CppMicroServices/core/src/service/usLDAPExpr.cpp index 0d7a3ecd78..7c93465f78 100644 --- a/Modules/CppMicroServices/core/src/service/usLDAPExpr.cpp +++ b/Modules/CppMicroServices/core/src/service/usLDAPExpr.cpp @@ -1,809 +1,809 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usLDAPExpr_p.h" #include "usAny.h" #include "usServicePropertiesImpl_p.h" #include #include #include #include #include #include #include US_BEGIN_NAMESPACE namespace LDAPExprConstants { static LDAPExpr::Byte WILDCARD() { static LDAPExpr::Byte b = std::numeric_limits::max(); return b; } static const std::string& WILDCARD_STRING() { static std::string s(1, WILDCARD()); return s; } static const std::string& nullptrQ() { static std::string s = "Null query"; return s; } static const std::string& GARBAGE() { static std::string s = "Trailing garbage"; return s; } static const std::string& EOS() { static std::string s = "Unexpected end of query"; return s; } static const std::string& MALFORMED() { static std::string s = "Malformed query"; return s; } static const std::string& OPERATOR() { static std::string s = "Undefined operator"; return s; } } bool stricomp(const std::string::value_type& v1, const std::string::value_type& v2) { return ::tolower(v1) == ::tolower(v2); } class LDAPExprData : public SharedData { public: LDAPExprData( int op, const std::vector& args ) : m_operator(op), m_args(args), m_attrName(), m_attrValue() { } LDAPExprData( int op, std::string attrName, const std::string& attrValue ) : m_operator(op), m_args(), m_attrName(attrName), m_attrValue(attrValue) { } LDAPExprData( const LDAPExprData& other ) : SharedData(other), m_operator(other.m_operator), m_args(other.m_args), m_attrName(other.m_attrName), m_attrValue(other.m_attrValue) { } int m_operator; std::vector m_args; std::string m_attrName; std::string m_attrValue; }; LDAPExpr::LDAPExpr() : d() { } LDAPExpr::LDAPExpr( const std::string &filter ) : d() { ParseState ps(filter); try { LDAPExpr expr = ParseExpr(ps); if (!Trim(ps.rest()).empty()) { ps.error(LDAPExprConstants::GARBAGE() + " '" + ps.rest() + "'"); } d = expr.d; } catch (const std::out_of_range&) { ps.error(LDAPExprConstants::EOS()); } } LDAPExpr::LDAPExpr( int op, const std::vector& args ) : d(new LDAPExprData(op, args)) { } LDAPExpr::LDAPExpr( int op, const std::string &attrName, const std::string &attrValue ) : d(new LDAPExprData(op, attrName, attrValue)) { } LDAPExpr::LDAPExpr( const LDAPExpr& other ) : d(other.d) { } LDAPExpr& LDAPExpr::operator=(const LDAPExpr& other) { d = other.d; return *this; } LDAPExpr::~LDAPExpr() { } std::string LDAPExpr::Trim(std::string str) { str.erase(0, str.find_first_not_of(' ')); str.erase(str.find_last_not_of(' ')+1); return str; } bool LDAPExpr::GetMatchedObjectClasses(ObjectClassSet& objClasses) const { if (d->m_operator == EQ) { if (d->m_attrName.length() == ServiceConstants::OBJECTCLASS().length() && std::equal(d->m_attrName.begin(), d->m_attrName.end(), ServiceConstants::OBJECTCLASS().begin(), stricomp) && d->m_attrValue.find(LDAPExprConstants::WILDCARD()) == std::string::npos) { objClasses.insert( d->m_attrValue ); return true; } return false; } else if (d->m_operator == AND) { bool result = false; for (std::size_t i = 0; i < d->m_args.size( ); i++) { LDAPExpr::ObjectClassSet r; if (d->m_args[i].GetMatchedObjectClasses(r)) { result = true; if (objClasses.empty()) { objClasses = r; } else { // if AND op and classes in several operands, // then only the intersection is possible. LDAPExpr::ObjectClassSet::iterator it1 = objClasses.begin(); LDAPExpr::ObjectClassSet::iterator it2 = r.begin(); while ( (it1 != objClasses.end()) && (it2 != r.end()) ) { if (*it1 < *it2) { objClasses.erase(it1++); } else if (*it2 < *it1) { ++it2; } else { // *it1 == *it2 ++it1; ++it2; } } // Anything left in set_1 from here on did not appear in set_2, // so we remove it. objClasses.erase(it1, objClasses.end()); } } } return result; } else if (d->m_operator == OR) { for (std::size_t i = 0; i < d->m_args.size( ); i++) { LDAPExpr::ObjectClassSet r; if (d->m_args[i].GetMatchedObjectClasses(r)) { std::copy(r.begin(), r.end(), std::inserter(objClasses, objClasses.begin())); } else { objClasses.clear(); return false; } } return true; } return false; } std::string LDAPExpr::ToLower(const std::string& str) { std::string lowerStr(str); std::transform(str.begin(), str.end(), lowerStr.begin(), ::tolower); return lowerStr; } bool LDAPExpr::IsSimple(const StringList& keywords, LocalCache& cache, bool matchCase ) const { if (cache.empty()) { cache.resize(keywords.size()); } if (d->m_operator == EQ) { StringList::const_iterator index; if ((index = std::find(keywords.begin(), keywords.end(), matchCase ? d->m_attrName : ToLower(d->m_attrName))) != keywords.end() && d->m_attrValue.find_first_of(LDAPExprConstants::WILDCARD()) == std::string::npos) { cache[index - keywords.begin()] = StringList(1, d->m_attrValue); return true; } } else if (d->m_operator == OR) { for (std::size_t i = 0; i < d->m_args.size( ); i++) { if (!d->m_args[i].IsSimple(keywords, cache, matchCase)) return false; } return true; } return false; } bool LDAPExpr::IsNull() const { return !d; } bool LDAPExpr::Query( const std::string& filter, const ServicePropertiesImpl& pd) { return LDAPExpr(filter).Evaluate(pd, false); } bool LDAPExpr::Evaluate( const ServicePropertiesImpl& p, bool matchCase ) const { if ((d->m_operator & SIMPLE) != 0) { // try case sensitive match first int index = p.FindCaseSensitive(d->m_attrName); if (index < 0 && !matchCase) index = p.Find(d->m_attrName); return index < 0 ? false : Compare(p.Value(index), d->m_operator, d->m_attrValue); } else { // (d->m_operator & COMPLEX) != 0 switch (d->m_operator) { case AND: for (std::size_t i = 0; i < d->m_args.size(); i++) { if (!d->m_args[i].Evaluate(p, matchCase)) return false; } return true; case OR: for (std::size_t i = 0; i < d->m_args.size(); i++) { if (d->m_args[i].Evaluate(p, matchCase)) return true; } return false; case NOT: return !d->m_args[0].Evaluate(p, matchCase); default: return false; // Cannot happen } } } bool LDAPExpr::Compare( const Any& obj, int op, const std::string& s ) const { if (obj.Empty()) return false; if (op == EQ && s == LDAPExprConstants::WILDCARD_STRING()) return true; try { const std::type_info& objType = obj.Type(); if (objType == typeid(std::string)) { return CompareString(ref_any_cast(obj), op, s); } else if (objType == typeid(std::vector)) { const std::vector& list = ref_any_cast >(obj); for (std::size_t it = 0; it != list.size(); it++) { if (CompareString(list[it], op, s)) return true; } } else if (objType == typeid(std::list)) { const std::list& list = ref_any_cast >(obj); for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) { if (CompareString(*it, op, s)) return true; } } else if (objType == typeid(char)) { return CompareString(std::string(1, ref_any_cast(obj)), op, s); } else if (objType == typeid(bool)) { if (op==LE || op==GE) return false; std::string boolVal = any_cast(obj) ? "true" : "false"; return std::equal(s.begin(), s.end(), boolVal.begin(), stricomp); } else if (objType == typeid(short)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(long long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned char)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned short)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(unsigned long long int)) { return CompareIntegralType(obj, op, s); } else if (objType == typeid(float)) { errno = 0; char* endptr = nullptr; double sFloat = strtod(s.c_str(), &endptr); if ((errno == ERANGE && (sFloat == 0 || sFloat == HUGE_VAL || sFloat == -HUGE_VAL)) || (errno != 0 && sFloat == 0) || endptr == s.c_str()) { return false; } double floatVal = static_cast(any_cast(obj)); switch(op) { case LE: return floatVal <= sFloat; case GE: return floatVal >= sFloat; default: /*APPROX and EQ*/ double diff = floatVal - sFloat; return (diff < std::numeric_limits::epsilon()) && (diff > -std::numeric_limits::epsilon()); } } else if (objType == typeid(double)) { errno = 0; char* endptr = nullptr; double sDouble = strtod(s.c_str(), &endptr); if ((errno == ERANGE && (sDouble == 0 || sDouble == HUGE_VAL || sDouble == -HUGE_VAL)) || (errno != 0 && sDouble == 0) || endptr == s.c_str()) { return false; } double doubleVal = any_cast(obj); switch(op) { case LE: return doubleVal <= sDouble; case GE: return doubleVal >= sDouble; default: /*APPROX and EQ*/ double diff = doubleVal - sDouble; return (diff < std::numeric_limits::epsilon()) && (diff > -std::numeric_limits::epsilon()); } } else if (objType == typeid(std::vector)) { const std::vector& list = ref_any_cast >(obj); for (std::size_t it = 0; it != list.size(); it++) { if (Compare(list[it], op, s)) return true; } } } catch (...) { // This might happen if a std::string-to-datatype conversion fails // Just consider it a false match and ignore the exception } return false; } template bool LDAPExpr::CompareIntegralType(const Any& obj, const int op, const std::string& s) const { errno = 0; char* endptr = nullptr; long longInt = strtol(s.c_str(), &endptr, 10); if ((errno == ERANGE && (longInt == std::numeric_limits::max() || longInt == std::numeric_limits::min())) || (errno != 0 && longInt == 0) || endptr == s.c_str()) { return false; } T sInt = static_cast(longInt); T intVal = any_cast(obj); switch(op) { case LE: return intVal <= sInt; case GE: return intVal >= sInt; default: /*APPROX and EQ*/ return intVal == sInt; } } bool LDAPExpr::CompareString( const std::string& s1, int op, const std::string& s2 ) { switch(op) { case LE: return s1.compare(s2) <= 0; case GE: return s1.compare(s2) >= 0; case EQ: return PatSubstr(s1,s2); case APPROX: return FixupString(s2) == FixupString(s1); default: return false; } } std::string LDAPExpr::FixupString( const std::string& s ) { std::string sb; sb.reserve(s.size()); std::size_t len = s.length(); for(std::size_t i=0; im_operator std::vector v; do { v.push_back(ParseExpr(ps)); ps.skipWhite(); } while (ps.peek() == '('); std::size_t n = v.size(); if (!ps.prefix(")") || n == 0 || (op == NOT && n > 1)) ps.error(LDAPExprConstants::MALFORMED()); return LDAPExpr(op, v); } LDAPExpr LDAPExpr::ParseSimple( ParseState &ps ) { std::string attrName = ps.getAttributeName(); if (attrName.empty()) ps.error(LDAPExprConstants::MALFORMED()); int op = 0; if (ps.prefix("=")) op = EQ; else if (ps.prefix("<=")) op = LE; else if(ps.prefix(">=")) op = GE; else if(ps.prefix("~=")) op = APPROX; else { // System.out.println("undef op='" + ps.peek() + "'"); ps.error(LDAPExprConstants::OPERATOR()); // Does not return } std::string attrValue = ps.getAttributeValue(); if (!ps.prefix(")")) ps.error(LDAPExprConstants::MALFORMED()); return LDAPExpr(op, attrName, attrValue); } const std::string LDAPExpr::ToString() const { std::string res; res.append("("); if ((d->m_operator & SIMPLE) != 0) { res.append(d->m_attrName); switch (d->m_operator) { case EQ: res.append("="); break; case LE: res.append("<="); break; case GE: res.append(">="); break; case APPROX: res.append("~="); break; } for (std::size_t i = 0; i < d->m_attrValue.length(); i++) { Byte c = d->m_attrValue.at(i); if (c == '(' || c == ')' || c == '*' || c == '\\') { res.append(1, '\\'); } else if (c == LDAPExprConstants::WILDCARD()) { c = '*'; } res.append(1, c); } } else { switch (d->m_operator) { case AND: res.append("&"); break; case OR: res.append("|"); break; case NOT: res.append("!"); break; } for (std::size_t i = 0; i < d->m_args.size(); i++) { res.append(d->m_args[i].ToString()); } } res.append(")"); return res; } LDAPExpr::ParseState::ParseState( const std::string& str ) : m_pos(0), m_str() { if (str.empty()) { error(LDAPExprConstants::nullptrQ()); } m_str = str; } bool LDAPExpr::ParseState::prefix( const std::string& pre ) { std::string::iterator startIter = m_str.begin() + m_pos; if (!std::equal(pre.begin(), pre.end(), startIter)) return false; m_pos += pre.size(); return true; } char LDAPExpr::ParseState::peek() { if ( m_pos >= m_str.size() ) { throw std::out_of_range( "LDAPExpr" ); } return m_str.at(m_pos); } void LDAPExpr::ParseState::skip( int n ) { m_pos += n; } std::string LDAPExpr::ParseState::rest() const { return m_str.substr(m_pos); } void LDAPExpr::ParseState::skipWhite() { while (std::isspace(peek())) { m_pos++; } } std::string LDAPExpr::ParseState::getAttributeName() { std::size_t start = m_pos; std::size_t n = 0; bool nIsSet = false; for(;; m_pos++) { Byte c = peek(); if (c == '(' || c == ')' || c == '<' || c == '>' || c == '=' || c == '~') { break; } else if (!std::isspace(c)) { n = m_pos - start + 1; nIsSet = true; } } if (!nIsSet) { return std::string(); } return m_str.substr(start, n); } std::string LDAPExpr::ParseState::getAttributeValue() { std::string sb; bool exit = false; while( !exit ) { Byte c = peek( ); switch(c) { case '(': case ')': exit = true; break; case '*': sb.append(1, LDAPExprConstants::WILDCARD()); break; case '\\': sb.append(1, m_str.at(++m_pos)); break; default: sb.append(1, c); break; } if ( !exit ) { m_pos++; } } return sb; } void LDAPExpr::ParseState::error( const std::string &m ) const { std::string errorStr = m + ": " + (m_str.empty() ? "" : m_str.substr(m_pos)); throw std::invalid_argument(errorStr); } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usLDAPExpr_p.h b/Modules/CppMicroServices/core/src/service/usLDAPExpr_p.h index 9264239350..3d709800da 100644 --- a/Modules/CppMicroServices/core/src/service/usLDAPExpr_p.h +++ b/Modules/CppMicroServices/core/src/service/usLDAPExpr_p.h @@ -1,217 +1,217 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USLDAPEXPR_H #define USLDAPEXPR_H #include #include "usSharedData.h" #include #include US_BEGIN_NAMESPACE class Any; class LDAPExprData; class ServicePropertiesImpl; /** * This class is not part of the public API. */ class LDAPExpr { public: const static int AND = 0; const static int OR = 1; const static int NOT = 2; const static int EQ = 4; const static int LE = 8; const static int GE = 16; const static int APPROX = 32; const static int COMPLEX = AND | OR | NOT; const static int SIMPLE = EQ | LE | GE | APPROX; typedef char Byte; typedef std::vector StringList; typedef std::vector LocalCache; typedef US_UNORDERED_SET_TYPE ObjectClassSet; /** * Creates an invalid LDAPExpr object. Use with care. * * @see IsNull() */ LDAPExpr(); LDAPExpr(const std::string& filter); LDAPExpr(const LDAPExpr& other); LDAPExpr& operator=(const LDAPExpr& other); ~LDAPExpr(); /** * Get object class set matched by this LDAP expression. This will not work * with wildcards and NOT expressions. If a set can not be determined return false. * * \param objClasses The set of matched classes will be added to objClasses. * \return If the set cannot be determined, false is returned, true otherwise. */ bool GetMatchedObjectClasses(ObjectClassSet& objClasses) const; /** * Checks if this LDAP expression is "simple". The definition of * a simple filter is: *

    *
  • (name=value) is simple if * name is a member of the provided keywords, * and value does not contain a wildcard character;
  • *
  • (| EXPR+ ) is simple if all EXPR * expressions are simple;
  • *
  • No other expressions are simple.
  • *
* If the filter is found to be simple, the cache is * filled with mappings from the provided keywords to lists * of attribute values. The keyword-value-pairs are the ones that * satisfy this expression, for the given keywords. * * @param keywords The keywords to look for. * @param cache An array (indexed by the keyword indexes) of lists to * fill in with values saturating this expression. * @return true if this expression is simple, * false otherwise. */ bool IsSimple( const StringList& keywords, LocalCache& cache, bool matchCase) const; /** * Returns true if this instance is invalid, i.e. it was * constructed using LDAPExpr(). * * @return true if the expression is invalid, * false otherwise. */ bool IsNull() const; //! static bool Query(const std::string& filter, const ServicePropertiesImpl& pd); //! Evaluate this LDAP filter. bool Evaluate(const ServicePropertiesImpl& p, bool matchCase) const; //! const std::string ToString() const; private: //! Contains the current parser position and parsing utility methods. class ParseState { private: std::size_t m_pos; std::string m_str; public: ParseState(const std::string& str); //! Move m_pos to remove the prefix \a pre bool prefix(const std::string& pre); /** Peek a char at m_pos \note If index out of bounds, throw exception */ LDAPExpr::Byte peek(); //! Increment m_pos by n void skip(int n); //! return string from m_pos until the end std::string rest() const; //! Move m_pos until there's no spaces void skipWhite(); //! Get string until special chars. Move m_pos std::string getAttributeName(); //! Get string and convert * to WILDCARD std::string getAttributeValue(); //! Throw InvalidSyntaxException exception void error(const std::string& m) const; }; //! LDAPExpr(int op, const std::vector& args); //! LDAPExpr(int op, const std::string& attrName, const std::string& attrValue); //! static LDAPExpr ParseExpr(ParseState& ps); //! static LDAPExpr ParseSimple(ParseState& ps); static std::string Trim(std::string str); static std::string ToLower(const std::string& str); //! bool Compare(const Any& obj, int op, const std::string& s) const; //! template bool CompareIntegralType(const Any& obj, const int op, const std::string& s) const; //! static bool CompareString(const std::string& s1, int op, const std::string& s2); //! static std::string FixupString(const std::string &s); //! static bool PatSubstr(const std::string& s, const std::string& pat); //! static bool PatSubstr(const std::string& s, int si, const std::string& pat, int pi); //! Shared pointer SharedDataPointer d; }; US_END_NAMESPACE #endif // USLDAPEXPR_H diff --git a/Modules/CppMicroServices/core/src/service/usLDAPFilter.cpp b/Modules/CppMicroServices/core/src/service/usLDAPFilter.cpp index b755633f62..96b94699c3 100644 --- a/Modules/CppMicroServices/core/src/service/usLDAPFilter.cpp +++ b/Modules/CppMicroServices/core/src/service/usLDAPFilter.cpp @@ -1,121 +1,121 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usLDAPFilter.h" #include "usLDAPExpr_p.h" #include "usServicePropertiesImpl_p.h" #include "usServiceReference.h" #include "usServiceReferenceBasePrivate.h" #include US_BEGIN_NAMESPACE class LDAPFilterData : public SharedData { public: LDAPFilterData() : ldapExpr() {} LDAPFilterData(const std::string& filter) : ldapExpr(filter) {} LDAPFilterData(const LDAPFilterData& other) : SharedData(other), ldapExpr(other.ldapExpr) {} LDAPExpr ldapExpr; }; LDAPFilter::LDAPFilter() : d(nullptr) { } LDAPFilter::LDAPFilter(const std::string& filter) : d(nullptr) { 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_type() const { return d.ConstData() != nullptr ? &LDAPFilter::d : nullptr; } bool LDAPFilter::Match(const ServiceReferenceBase& reference) const { return d->ldapExpr.Evaluate(reference.d->GetProperties(), true); } bool LDAPFilter::Match(const ServiceProperties& dictionary) const { return d->ldapExpr.Evaluate(ServicePropertiesImpl(dictionary), false); } bool LDAPFilter::MatchCase(const ServiceProperties& dictionary) const { return d->ldapExpr.Evaluate(ServicePropertiesImpl(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; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const LDAPFilter& filter) { return os << filter.ToString(); } diff --git a/Modules/CppMicroServices/core/src/service/usServiceEvent.cpp b/Modules/CppMicroServices/core/src/service/usServiceEvent.cpp index 2c8521a416..4e36ba6c3e 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceEvent.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceEvent.cpp @@ -1,130 +1,130 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usServiceEvent.h" #include "usServiceProperties.h" US_BEGIN_NAMESPACE class ServiceEventData : public SharedData { public: ServiceEventData(const ServiceEvent::Type& type, const ServiceReferenceBase& reference) : type(type), reference(reference) { } ServiceEventData(const ServiceEventData& other) : SharedData(other), type(other.type), reference(other.reference) { } const ServiceEvent::Type type; const ServiceReferenceBase reference; private: // purposely not implemented ServiceEventData& operator=(const ServiceEventData&); }; ServiceEvent::ServiceEvent() : d(nullptr) { } ServiceEvent::~ServiceEvent() { } bool ServiceEvent::IsNull() const { return !d; } ServiceEvent::ServiceEvent(Type type, const ServiceReferenceBase& reference) : d(new ServiceEventData(type, reference)) { } ServiceEvent::ServiceEvent(const ServiceEvent& other) : d(other.d) { } ServiceEvent& ServiceEvent::operator=(const ServiceEvent& other) { d = other.d; return *this; } ServiceReferenceU ServiceEvent::GetServiceReference() const { return d->reference; } ServiceEvent::Type ServiceEvent::GetType() const { return d->type; } std::ostream& operator<<(std::ostream& os, const ServiceEvent::Type& type) { switch(type) { case ServiceEvent::MODIFIED: return os << "MODIFIED"; case ServiceEvent::MODIFIED_ENDMATCH: return os << "MODIFIED_ENDMATCH"; case ServiceEvent::REGISTERED: return os << "REGISTERED"; case ServiceEvent::UNREGISTERING: return os << "UNREGISTERING"; default: return os << "unknown service event type (" << static_cast(type) << ")"; } } std::ostream& operator<<(std::ostream& os, const ServiceEvent& event) { if (event.IsNull()) return os << "NONE"; os << event.GetType(); ServiceReferenceU sr = event.GetServiceReference(); if (sr) { // Some events will not have a service reference long int sid = any_cast(sr.GetProperty(ServiceConstants::SERVICE_ID())); os << " " << sid; Any classes = sr.GetProperty(ServiceConstants::OBJECTCLASS()); os << " objectClass=" << classes.ToString() << ")"; } return os; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceEventListenerHook.cpp b/Modules/CppMicroServices/core/src/service/usServiceEventListenerHook.cpp index 484fa27042..0ecfd2cde6 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceEventListenerHook.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceEventListenerHook.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServiceEventListenerHook.h" US_BEGIN_NAMESPACE ServiceEventListenerHook::~ServiceEventListenerHook() { } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceException.cpp b/Modules/CppMicroServices/core/src/service/usServiceException.cpp index 20beb9ad22..d3fb1fd96a 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceException.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceException.cpp @@ -1,59 +1,59 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServiceException.h" #include US_BEGIN_NAMESPACE 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; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ServiceException& exc) { return os << "ServiceException: " << exc.what(); } diff --git a/Modules/CppMicroServices/core/src/service/usServiceFindHook.cpp b/Modules/CppMicroServices/core/src/service/usServiceFindHook.cpp index f2307a9a7d..812e14070f 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceFindHook.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceFindHook.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServiceFindHook.h" US_BEGIN_NAMESPACE ServiceFindHook::~ServiceFindHook() { } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceHooks.cpp b/Modules/CppMicroServices/core/src/service/usServiceHooks.cpp index 29f35310b6..3c43813f15 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceHooks.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceHooks.cpp @@ -1,286 +1,286 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usServiceHooks_p.h" #include "usGetModuleContext.h" #include "usCoreModuleContext_p.h" #include "usServiceEventListenerHook.h" #include "usServiceFindHook.h" #include "usServiceListenerHook.h" #include "usServiceReferenceBasePrivate.h" US_BEGIN_NAMESPACE ServiceHooks::ServiceHooks(CoreModuleContext* coreCtx) : coreCtx(coreCtx) , listenerHookTracker(nullptr) , bOpen(false) { } ServiceHooks::~ServiceHooks() { this->Close(); } ServiceHooks::TrackedType ServiceHooks::AddingService(const ServiceReferenceType& reference) { ServiceListenerHook* lh = GetModuleContext()->GetService(reference); try { lh->Added(coreCtx->listeners.GetListenerInfoCollection()); } catch (const std::exception& e) { US_WARN << "Failed to call listener hook #" << reference.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": " << e.what(); } catch (...) { US_WARN << "Failed to call listener hook #" << reference.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": unknown exception type"; } return lh; } void ServiceHooks::ModifiedService(const ServiceReferenceType& /*reference*/, TrackedType /*service*/) { // noop } void ServiceHooks::RemovedService(const ServiceReferenceType& reference, TrackedType /*service*/) { GetModuleContext()->UngetService(reference); } void ServiceHooks::Open() { US_UNUSED(Lock(this)); listenerHookTracker = new ServiceTracker(GetModuleContext(), this); listenerHookTracker->Open(); bOpen = true; } void ServiceHooks::Close() { US_UNUSED(Lock(this)); if (listenerHookTracker) { listenerHookTracker->Close(); delete listenerHookTracker; listenerHookTracker = nullptr; } bOpen = false; } bool ServiceHooks::IsOpen() const { US_UNUSED(Lock(this)); return bOpen; } void ServiceHooks::FilterServiceReferences(ModuleContext* mc, const std::string& service, const std::string& filter, std::vector& refs) { std::vector srl; coreCtx->services.Get_unlocked(us_service_interface_iid(), srl); if (!srl.empty()) { ShrinkableVector filtered(refs); std::sort(srl.begin(), srl.end()); for (std::vector::reverse_iterator fhrIter = srl.rbegin(), fhrEnd = srl.rend(); fhrIter != fhrEnd; ++fhrIter) { ServiceReference sr = fhrIter->GetReference(); ServiceFindHook* const fh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); if (fh != nullptr) { try { fh->Find(mc, service, filter, filtered); } catch (const std::exception& e) { US_WARN << "Failed to call find hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": " << e.what(); } catch (...) { US_WARN << "Failed to call find hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": unknown exception type"; } } } } } void ServiceHooks::FilterServiceEventReceivers(const ServiceEvent& evt, ServiceListeners::ServiceListenerEntries& receivers) { std::vector eventListenerHooks; coreCtx->services.Get_unlocked(us_service_interface_iid(), eventListenerHooks); if (!eventListenerHooks.empty()) { std::sort(eventListenerHooks.begin(), eventListenerHooks.end()); std::map > listeners; for (ServiceListeners::ServiceListenerEntries::iterator sleIter = receivers.begin(), sleEnd = receivers.end(); sleIter != sleEnd; ++sleIter) { listeners[sleIter->GetModuleContext()].push_back(*sleIter); } std::map > shrinkableListeners; for (std::map >::iterator iter = listeners.begin(), iterEnd = listeners.end(); iter != iterEnd; ++iter) { shrinkableListeners.insert(std::make_pair(iter->first, ShrinkableVector(iter->second))); } ShrinkableMap > filtered(shrinkableListeners); for(std::vector::reverse_iterator sriIter = eventListenerHooks.rbegin(), sriEnd = eventListenerHooks.rend(); sriIter != sriEnd; ++sriIter) { ServiceReference sr = sriIter->GetReference(); ServiceEventListenerHook* elh = reinterpret_cast(sr.d->GetService(GetModuleContext()->GetModule())); if(elh != nullptr) { try { elh->Event(evt, filtered); } catch(const std::exception& e) { US_WARN << "Failed to call event hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": " << e.what(); } catch(...) { US_WARN << "Failed to call event hook #" << sr.GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": unknown exception type"; } } } receivers.clear(); for(std::map >::iterator iter = listeners.begin(), iterEnd = listeners.end(); iter != iterEnd; ++iter) { receivers.insert(iter->second.begin(), iter->second.end()); } } } void ServiceHooks::HandleServiceListenerReg(const ServiceListenerEntry& sle) { if(!IsOpen() || listenerHookTracker->Size() == 0) { return; } std::vector > srl = listenerHookTracker->GetServiceReferences(); if (!srl.empty()) { std::sort(srl.begin(), srl.end()); std::vector set; set.push_back(sle); for (std::vector >::reverse_iterator srIter = srl.rbegin(), srEnd = srl.rend(); srIter != srEnd; ++srIter) { ServiceListenerHook* lh = listenerHookTracker->GetService(*srIter); try { lh->Added(set); } catch (const std::exception& e) { US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": " << e.what(); } catch (...) { US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": unknown exception"; } } } } void ServiceHooks::HandleServiceListenerUnreg(const ServiceListenerEntry& sle) { if(IsOpen()) { std::vector set; set.push_back(sle); HandleServiceListenerUnreg(set); } } void ServiceHooks::HandleServiceListenerUnreg(const std::vector& set) { if(!IsOpen() || listenerHookTracker->Size() == 0) { return; } std::vector > srl = listenerHookTracker->GetServiceReferences(); if (!srl.empty()) { std::vector lis; for (std::vector::const_iterator sleIter = set.begin(), sleEnd = set.end(); sleIter != sleEnd; ++sleIter) { lis.push_back(*sleIter); } std::sort(srl.begin(), srl.end()); for (std::vector >::reverse_iterator srIter = srl.rbegin(), srEnd = srl.rend(); srIter != srEnd; ++srIter) { ServiceListenerHook* const lh = listenerHookTracker->GetService(*srIter); try { lh->Removed(lis); } catch (const std::exception& e) { US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": " << e.what(); } catch (...) { US_WARN << "Failed to call listener hook #" << srIter->GetProperty(ServiceConstants::SERVICE_ID()).ToString() << ": unknown exception type"; } } } } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceHooks_p.h b/Modules/CppMicroServices/core/src/service/usServiceHooks_p.h index a7f0546edb..28753febe0 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceHooks_p.h +++ b/Modules/CppMicroServices/core/src/service/usServiceHooks_p.h @@ -1,73 +1,73 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEHOOKS_P_H #define USSERVICEHOOKS_P_H #include "usServiceTracker.h" #include "usServiceListeners_p.h" US_BEGIN_NAMESPACE struct ServiceListenerHook; class ServiceHooks : private MultiThreaded<>, private ServiceTrackerCustomizer { private: CoreModuleContext* coreCtx; ServiceTracker* listenerHookTracker; bool bOpen; TrackedType AddingService(const ServiceReferenceType& reference) override; void ModifiedService(const ServiceReferenceType& reference, TrackedType service) override; void RemovedService(const ServiceReferenceType& reference, TrackedType service) override; public: ServiceHooks(CoreModuleContext* coreCtx); ~ServiceHooks() override; void Open(); void Close(); bool IsOpen() const; void FilterServiceReferences(ModuleContext* mc, const std::string& service, const std::string& filter, std::vector& refs); void FilterServiceEventReceivers(const ServiceEvent& evt, ServiceListeners::ServiceListenerEntries& receivers); void HandleServiceListenerReg(const ServiceListenerEntry& sle); void HandleServiceListenerUnreg(const ServiceListenerEntry& sle); void HandleServiceListenerUnreg(const std::vector& set); }; US_END_NAMESPACE #endif // USSERVICEHOOKS_P_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceListenerEntry.cpp b/Modules/CppMicroServices/core/src/service/usServiceListenerEntry.cpp index f281c846fb..bf886845cd 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceListenerEntry.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceListenerEntry.cpp @@ -1,148 +1,148 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usServiceListenerEntry_p.h" #include "usServiceListenerHook_p.h" #include US_BEGIN_NAMESPACE class ServiceListenerEntryData : public ServiceListenerHook::ListenerInfoData { public: ServiceListenerEntryData(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& l, void* data, const std::string& filter) : ServiceListenerHook::ListenerInfoData(mc, l, data, filter) , ldap() , hashValue(0) { if (!filter.empty()) { ldap = LDAPExpr(filter); } } ~ServiceListenerEntryData() override { } LDAPExpr ldap; /** * The elements of "simple" filters are cached, for easy lookup. * * The grammar for simple filters is as follows: * *
    * Simple = '(' attr '=' value ')'
    *        | '(' '|' Simple+ ')'
    * 
* where attr is one of Constants#OBJECTCLASS, * Constants#SERVICE_ID or Constants#SERVICE_PID, and * value must not contain a wildcard character. *

* The index of the vector determines which key the cache is for * (see ServiceListenerState#hashedKeys). For each key, there is * a vector pointing out the values which are accepted by this * ServiceListenerEntry's filter. This cache is maintained to make * it easy to remove this service listener. */ LDAPExpr::LocalCache local_cache; std::size_t hashValue; private: // purposely not implemented ServiceListenerEntryData(const ServiceListenerEntryData&); ServiceListenerEntryData& operator=(const ServiceListenerEntryData&); }; ServiceListenerEntry::ServiceListenerEntry(const ServiceListenerEntry& other) : ServiceListenerHook::ListenerInfo(other) { } ServiceListenerEntry::ServiceListenerEntry(const ServiceListenerHook::ListenerInfo& info) : ServiceListenerHook::ListenerInfo(info) { assert(info.d); } ServiceListenerEntry::~ServiceListenerEntry() { } ServiceListenerEntry& ServiceListenerEntry::operator=(const ServiceListenerEntry& other) { d = other.d; return *this; } void ServiceListenerEntry::SetRemoved(bool removed) const { d->bRemoved = removed; } ServiceListenerEntry::ServiceListenerEntry(ModuleContext* mc, const ServiceListener& l, void* data, const std::string& filter) : ServiceListenerHook::ListenerInfo(new ServiceListenerEntryData(mc, l, data, filter)) { } const LDAPExpr& ServiceListenerEntry::GetLDAPExpr() const { return static_cast(d.Data())->ldap; } LDAPExpr::LocalCache& ServiceListenerEntry::GetLocalCache() const { return static_cast(d.Data())->local_cache; } void ServiceListenerEntry::CallDelegate(const ServiceEvent& event) const { d->listener(event); } bool ServiceListenerEntry::operator==(const ServiceListenerEntry& other) const { return ((d->mc == nullptr || other.d->mc == nullptr) || d->mc == other.d->mc) && (d->data == other.d->data) && ServiceListenerCompare()(d->listener, other.d->listener); } std::size_t ServiceListenerEntry::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; if (static_cast(d.Data())->hashValue == 0) { static_cast(d.Data())->hashValue = ((US_HASH_FUNCTION(ModuleContext*, d->mc) ^ (US_HASH_FUNCTION(void*, d->data) << 1)) >> 1) ^ (US_HASH_FUNCTION(US_SERVICE_LISTENER_FUNCTOR, d->listener) << 1); } return static_cast(d.Data())->hashValue; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceListenerEntry_p.h b/Modules/CppMicroServices/core/src/service/usServiceListenerEntry_p.h index 1fa9d11dc1..27e4943e32 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceListenerEntry_p.h +++ b/Modules/CppMicroServices/core/src/service/usServiceListenerEntry_p.h @@ -1,79 +1,79 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICELISTENERENTRY_H #define USSERVICELISTENERENTRY_H #include #include #include #include "usLDAPExpr_p.h" US_BEGIN_NAMESPACE class Module; class ServiceListenerEntryData; /** * Data structure for saving service listener info. Contains * the optional service listener filter, in addition to the info * in ListenerEntry. */ class ServiceListenerEntry : public ServiceListenerHook::ListenerInfo { public: typedef US_SERVICE_LISTENER_FUNCTOR ServiceListener; ServiceListenerEntry(const ServiceListenerEntry& other); ServiceListenerEntry(const ServiceListenerHook::ListenerInfo& info); ~ServiceListenerEntry(); ServiceListenerEntry& operator=(const ServiceListenerEntry& other); void SetRemoved(bool removed) const; ServiceListenerEntry(ModuleContext* mc, const ServiceListener& l, void* data, const std::string& filter = ""); const LDAPExpr& GetLDAPExpr() const; LDAPExpr::LocalCache& GetLocalCache() const; void CallDelegate(const ServiceEvent& event) const; bool operator==(const ServiceListenerEntry& other) const; std::size_t Hash() const; }; US_END_NAMESPACE US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceListenerEntry)) return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USSERVICELISTENERENTRY_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceListenerHook.cpp b/Modules/CppMicroServices/core/src/service/usServiceListenerHook.cpp index 90615efba0..c82b006313 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceListenerHook.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceListenerHook.cpp @@ -1,96 +1,96 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usServiceListenerHook.h" #include "usServiceListenerHook_p.h" US_BEGIN_NAMESPACE ServiceListenerHook::~ServiceListenerHook() { } ServiceListenerHook::ListenerInfoData::ListenerInfoData( ModuleContext* mc, const ServiceListenerEntry::ServiceListener& l, void* data, const std::string& filter) : mc(mc) , listener(l) , data(data) , filter(filter) , bRemoved(false) { } ServiceListenerHook::ListenerInfoData::~ListenerInfoData() { } ServiceListenerHook::ListenerInfo::ListenerInfo(ListenerInfoData* data) : d(data) { } ServiceListenerHook::ListenerInfo::ListenerInfo() : d(nullptr) { } ServiceListenerHook::ListenerInfo::ListenerInfo(const ListenerInfo& other) : d(other.d) { } ServiceListenerHook::ListenerInfo::~ListenerInfo() { } ServiceListenerHook::ListenerInfo& ServiceListenerHook::ListenerInfo::operator=(const ListenerInfo& other) { d = other.d; return *this; } bool ServiceListenerHook::ListenerInfo::IsNull() const { return !d; } ModuleContext* ServiceListenerHook::ListenerInfo::GetModuleContext() const { return d->mc; } std::string ServiceListenerHook::ListenerInfo::GetFilter() const { return d->filter; } bool ServiceListenerHook::ListenerInfo::IsRemoved() const { return d->bRemoved; } bool ServiceListenerHook::ListenerInfo::operator==(const ListenerInfo& other) const { return d == other.d; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceListenerHook_p.h b/Modules/CppMicroServices/core/src/service/usServiceListenerHook_p.h index 22050a3c78..21929bd411 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceListenerHook_p.h +++ b/Modules/CppMicroServices/core/src/service/usServiceListenerHook_p.h @@ -1,48 +1,48 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICELISTENERHOOK_P_H #define USSERVICELISTENERHOOK_P_H #include "usServiceListenerHook.h" #include "usServiceListenerEntry_p.h" #include "usSharedData.h" US_BEGIN_NAMESPACE class ServiceListenerHook::ListenerInfoData : public SharedData { public: ListenerInfoData(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& l, void* data, const std::string& filter); virtual ~ListenerInfoData(); ModuleContext* const mc; ServiceListenerEntry::ServiceListener listener; void* data; std::string filter; bool bRemoved; }; US_END_NAMESPACE #endif // USSERVICELISTENERHOOK_P_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceListeners.cpp b/Modules/CppMicroServices/core/src/service/usServiceListeners.cpp index e134fe8e27..b4f4bf51bd 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceListeners.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceListeners.cpp @@ -1,334 +1,334 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usUtils_p.h" #include "usServiceListeners_p.h" #include "usServiceReferenceBasePrivate.h" #include "usCoreModuleContext_p.h" #include "usModule.h" #include "usModuleContext.h" US_BEGIN_NAMESPACE const int ServiceListeners::OBJECTCLASS_IX = 0; const int ServiceListeners::SERVICE_ID_IX = 1; ServiceListeners::ServiceListeners(CoreModuleContext* coreCtx) : coreCtx(coreCtx) { hashedServiceKeys.push_back(ServiceConstants::OBJECTCLASS()); hashedServiceKeys.push_back(ServiceConstants::SERVICE_ID()); } void ServiceListeners::AddServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data, const std::string& filter) { US_UNUSED(Lock(this)); ServiceListenerEntry sle(mc, listener, data, filter); RemoveServiceListener_unlocked(sle); serviceSet.insert(sle); coreCtx->serviceHooks.HandleServiceListenerReg(sle); CheckSimple(sle); } void ServiceListeners::RemoveServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data) { ServiceListenerEntry entryToRemove(mc, listener, data); US_UNUSED(Lock(this)); RemoveServiceListener_unlocked(entryToRemove); } void ServiceListeners::RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove) { ServiceListenerEntries::const_iterator it = serviceSet.find(entryToRemove); if (it != serviceSet.end()) { it->SetRemoved(true); coreCtx->serviceHooks.HandleServiceListenerUnreg(*it); RemoveFromCache(*it); serviceSet.erase(it); } } void ServiceListeners::AddModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data) { MutexLock lock(moduleListenerMapMutex); ModuleListenerMap::value_type::second_type& listeners = moduleListenerMap[mc]; if (std::find_if(listeners.begin(), listeners.end(), std::bind(ModuleListenerCompare(), std::make_pair(listener, data), std::placeholders::_1)) == listeners.end()) { listeners.push_back(std::make_pair(listener, data)); } } void ServiceListeners::RemoveModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data) { MutexLock lock(moduleListenerMapMutex); moduleListenerMap[mc].remove_if(std::bind(ModuleListenerCompare(), std::make_pair(listener, data), std::placeholders::_1)); } void ServiceListeners::ModuleChanged(const ModuleEvent& evt) { ModuleListenerMap filteredModuleListeners; coreCtx->moduleHooks.FilterModuleEventReceivers(evt, filteredModuleListeners); for(ModuleListenerMap::iterator iter = filteredModuleListeners.begin(), end = filteredModuleListeners.end(); iter != end; ++iter) { for (ModuleListenerMap::mapped_type::iterator iter2 = iter->second.begin(), end2 = iter->second.end(); iter2 != end2; ++iter2) { try { (iter2->first)(evt); } catch (const std::exception& e) { US_WARN << "Module listener threw an exception: " << e.what(); } } } } void ServiceListeners::RemoveAllListeners(ModuleContext* mc) { { US_UNUSED(Lock(this)); for (ServiceListenerEntries::iterator it = serviceSet.begin(); it != serviceSet.end(); ) { if (it->GetModuleContext() == mc) { RemoveFromCache(*it); serviceSet.erase(it++); } else { ++it; } } } { MutexLock lock(moduleListenerMapMutex); moduleListenerMap.erase(mc); } } void ServiceListeners::HooksModuleStopped(ModuleContext* mc) { US_UNUSED(Lock(this)); std::vector entries; for (ServiceListenerEntries::iterator it = serviceSet.begin(); it != serviceSet.end(); ) { if (it->GetModuleContext() == mc) { entries.push_back(*it); } } coreCtx->serviceHooks.HandleServiceListenerUnreg(entries); } void ServiceListeners::ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt) { ServiceListenerEntries matchBefore; ServiceChanged(receivers, evt, matchBefore); } void ServiceListeners::ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt, ServiceListenerEntries& matchBefore) { int n = 0; if (!matchBefore.empty()) { for (ServiceListenerEntries::const_iterator l = receivers.begin(); l != receivers.end(); ++l) { matchBefore.erase(*l); } } for (ServiceListenerEntries::const_iterator l = receivers.begin(); l != receivers.end(); ++l) { if (!l->IsRemoved()) { try { ++n; l->CallDelegate(evt); } catch (...) { US_WARN << "Service listener" << " in " << l->GetModuleContext()->GetModule()->GetName() << " threw an exception!"; } } } //US_DEBUG << "Notified " << n << " listeners"; } void ServiceListeners::GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& set, bool lockProps) { US_UNUSED(Lock(this)); // Filter the original set of listeners ServiceListenerEntries receivers = serviceSet; coreCtx->serviceHooks.FilterServiceEventReceivers(evt, receivers); // Check complicated or empty listener filters for (std::list::const_iterator sse = complicatedListeners.begin(); sse != complicatedListeners.end(); ++sse) { if (receivers.count(*sse) == 0) continue; const LDAPExpr& ldapExpr = sse->GetLDAPExpr(); if (ldapExpr.IsNull() || ldapExpr.Evaluate(evt.GetServiceReference().d->GetProperties(), false)) { set.insert(*sse); } } //US_DEBUG << "Added " << set.size() << " out of " << n // << " listeners with complicated filters"; // Check the cache const std::vector c(any_cast > (evt.GetServiceReference().d->GetProperty(ServiceConstants::OBJECTCLASS(), lockProps))); for (std::vector::const_iterator objClass = c.begin(); objClass != c.end(); ++objClass) { AddToSet(set, receivers, OBJECTCLASS_IX, *objClass); } long service_id = any_cast(evt.GetServiceReference().d->GetProperty(ServiceConstants::SERVICE_ID(), lockProps)); std::stringstream ss; ss << service_id; AddToSet(set, receivers, SERVICE_ID_IX, ss.str()); } std::vector ServiceListeners::GetListenerInfoCollection() const { US_UNUSED(Lock(this)); std::vector result; result.reserve(serviceSet.size()); for (ServiceListenerEntries::const_iterator iter = serviceSet.begin(), iterEnd = serviceSet.end(); iter != iterEnd; ++iter) { result.push_back(*iter); } return result; } void ServiceListeners::RemoveFromCache(const ServiceListenerEntry& sle) { if (!sle.GetLocalCache().empty()) { for (std::size_t i = 0; i < hashedServiceKeys.size(); ++i) { CacheType& keymap = cache[i]; std::vector& l = sle.GetLocalCache()[i]; for (std::vector::const_iterator it = l.begin(); it != l.end(); ++it) { std::list& sles = keymap[*it]; sles.remove(sle); if (sles.empty()) { keymap.erase(*it); } } } } else { complicatedListeners.remove(sle); } } void ServiceListeners::CheckSimple(const ServiceListenerEntry& sle) { if (sle.GetLDAPExpr().IsNull()) { complicatedListeners.push_back(sle); } else { LDAPExpr::LocalCache local_cache; if (sle.GetLDAPExpr().IsSimple(hashedServiceKeys, local_cache, false)) { sle.GetLocalCache() = local_cache; for (std::size_t i = 0; i < hashedServiceKeys.size(); ++i) { for (std::vector::const_iterator it = local_cache[i].begin(); it != local_cache[i].end(); ++it) { std::list& sles = cache[i][*it]; sles.push_back(sle); } } } else { //US_DEBUG << "Too complicated filter: " << sle.GetFilter(); complicatedListeners.push_back(sle); } } } void ServiceListeners::AddToSet(ServiceListenerEntries& set, const ServiceListenerEntries& receivers, int cache_ix, const std::string& val) { std::list& l = cache[cache_ix][val]; if (!l.empty()) { //US_DEBUG << hashedServiceKeys[cache_ix] << " matches " << l.size(); for (std::list::const_iterator entry = l.begin(); entry != l.end(); ++entry) { if (receivers.count(*entry)) { set.insert(*entry); } } } else { //US_DEBUG << hashedServiceKeys[cache_ix] << " matches none"; } } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceListeners_p.h b/Modules/CppMicroServices/core/src/service/usServiceListeners_p.h index 34e2280f67..f1b11e091b 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceListeners_p.h +++ b/Modules/CppMicroServices/core/src/service/usServiceListeners_p.h @@ -1,181 +1,181 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICELISTENERS_H #define USSERVICELISTENERS_H #include #include #include #include #include "usServiceListenerEntry_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModuleContext; /** * Here we handle all listeners that modules have registered. * */ class ServiceListeners : private MultiThreaded<> { public: typedef US_MODULE_LISTENER_FUNCTOR ModuleListener; typedef US_UNORDERED_MAP_TYPE > > ModuleListenerMap; ModuleListenerMap moduleListenerMap; Mutex moduleListenerMapMutex; typedef US_UNORDERED_MAP_TYPE > CacheType; typedef US_UNORDERED_SET_TYPE ServiceListenerEntries; private: std::vector hashedServiceKeys; static const int OBJECTCLASS_IX; // = 0; static const int SERVICE_ID_IX; // = 1; /* Service listeners with complicated or empty filters */ std::list complicatedListeners; /* Service listeners with "simple" filters are cached. */ CacheType cache[2]; ServiceListenerEntries serviceSet; CoreModuleContext* coreCtx; public: ServiceListeners(CoreModuleContext* coreCtx); /** * Add a new service listener. If an old one exists, and it has the * same owning module, the old listener is removed first. * * @param mc The module context adding this listener. * @param listener The service listener to add. * @param data Additional data to distinguish ServiceListener objects. * @param filter An LDAP filter string to check when a service is modified. * @exception org.osgi.framework.InvalidSyntaxException * If the filter is not a correct LDAP expression. */ void AddServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data, const std::string& filter); /** * Remove service listener from current framework. Silently ignore * if listener doesn't exist. If listener is registered more than * once remove all instances. * * @param mc The module context who wants to remove listener. * @param listener Object to remove. * @param data Additional data to distinguish ServiceListener objects. */ void RemoveServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data); /** * Add a new module listener. * * @param mc The module context adding this listener. * @param listener The module listener to add. * @param data Additional data to distinguish ModuleListener objects. */ void AddModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data); /** * Remove module listener from current framework. Silently ignore * if listener doesn't exist. * * @param mc The module context who wants to remove listener. * @param listener Object to remove. * @param data Additional data to distinguish ModuleListener objects. */ void RemoveModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data); void ModuleChanged(const ModuleEvent& evt); /** * Remove all listener registered by a module in the current framework. * * @param mc Module context which listeners we want to remove. */ void RemoveAllListeners(ModuleContext* mc); /** * Notify hooks that a module is about to be stopped * * @param mc Module context which listeners are about to be removed. */ void HooksModuleStopped(ModuleContext* mc); /** * Receive notification that a service has had a change occur in its lifecycle. * * @see org.osgi.framework.ServiceListener#serviceChanged */ void ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt, ServiceListenerEntries& matchBefore); void ServiceChanged(ServiceListenerEntries& receivers, const ServiceEvent& evt); /** * * */ void GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& listeners, bool lockProps = true); std::vector GetListenerInfoCollection() const; private: void RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove); /** * Remove all references to a service listener from the service listener * cache. */ void RemoveFromCache(const ServiceListenerEntry& sle); /** * Checks if the specified service listener's filter is simple enough * to cache. */ void CheckSimple(const ServiceListenerEntry& sle); void AddToSet(ServiceListenerEntries& set, const ServiceListenerEntries& receivers, int cache_ix, const std::string& val); }; US_END_NAMESPACE #endif // USSERVICELISTENERS_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceObjects.cpp b/Modules/CppMicroServices/core/src/service/usServiceObjects.cpp index 797c4b6ba2..eccea0a4e5 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceObjects.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceObjects.cpp @@ -1,210 +1,210 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usServiceObjects.h" #include "usServiceReferenceBasePrivate.h" #include US_BEGIN_NAMESPACE class ServiceObjectsBasePrivate { public: AtomicInt ref; ModuleContext* m_context; ServiceReferenceBase m_reference; // This is used by all ServiceObjects instances with S != void std::map m_serviceInstances; // This is used by ServiceObjects std::set m_serviceInterfaceMaps; ServiceObjectsBasePrivate(ModuleContext* context, const ServiceReferenceBase& reference) : m_context(context) , m_reference(reference) {} InterfaceMap GetServiceInterfaceMap() { InterfaceMap result; bool isPrototypeScope = m_reference.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(); if (isPrototypeScope) { result = m_reference.d->GetPrototypeService(m_context->GetModule()); } else { result = m_reference.d->GetServiceInterfaceMap(m_context->GetModule()); } return result; } }; ServiceObjectsBase::ServiceObjectsBase(ModuleContext* context, const ServiceReferenceBase& reference) : d(new ServiceObjectsBasePrivate(context, reference)) { if (!reference) { delete d; throw std::invalid_argument("The service reference is invalid"); } d->ref.Ref(); } void* ServiceObjectsBase::GetService() const { if (!d->m_reference) { return nullptr; } InterfaceMap im = d->GetServiceInterfaceMap(); void* result = im.find(d->m_reference.GetInterfaceId())->second; if (result) { d->m_serviceInstances.insert(std::make_pair(result, im)); } return result; } InterfaceMap ServiceObjectsBase::GetServiceInterfaceMap() const { InterfaceMap result; if (!d->m_reference) { return result; } result = d->GetServiceInterfaceMap(); if (!result.empty()) { d->m_serviceInterfaceMaps.insert(result); } return result; } void ServiceObjectsBase::UngetService(void* service) { if (service == nullptr) { return; } std::map::iterator serviceIter = d->m_serviceInstances.find(service); if (serviceIter == d->m_serviceInstances.end()) { throw std::invalid_argument("The provided service has not been retrieved via this ServiceObjects instance"); } if (!d->m_reference.d->UngetPrototypeService(d->m_context->GetModule(), serviceIter->second)) { US_WARN << "Ungetting service unsuccessful"; } else { d->m_serviceInstances.erase(serviceIter); } } void ServiceObjectsBase::UngetService(const InterfaceMap& interfaceMap) { if (interfaceMap.empty()) { return; } std::set::iterator serviceIter = d->m_serviceInterfaceMaps.find(interfaceMap); if (serviceIter == d->m_serviceInterfaceMaps.end()) { throw std::invalid_argument("The provided service has not been retrieved via this ServiceObjects instance"); } if (!d->m_reference.d->UngetPrototypeService(d->m_context->GetModule(), interfaceMap)) { US_WARN << "Ungetting service unsuccessful"; } else { d->m_serviceInterfaceMaps.erase(serviceIter); } } ServiceReferenceBase ServiceObjectsBase::GetReference() const { return d->m_reference; } ServiceObjectsBase::ServiceObjectsBase(const ServiceObjectsBase& other) : d(other.d) { d->ref.Ref(); } ServiceObjectsBase::~ServiceObjectsBase() { if (!d->ref.Deref()) { delete d; } } ServiceObjectsBase& ServiceObjectsBase::operator =(const ServiceObjectsBase& other) { ServiceObjectsBasePrivate* curr_d = d; d = other.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } InterfaceMap ServiceObjects::GetService() const { return this->ServiceObjectsBase::GetServiceInterfaceMap(); } void ServiceObjects::UngetService(const InterfaceMap& service) { this->ServiceObjectsBase::UngetService(service); } ServiceReferenceU ServiceObjects::GetServiceReference() const { return this->ServiceObjectsBase::GetReference(); } ServiceObjects::ServiceObjects(ModuleContext* context, const ServiceReferenceU& reference) : ServiceObjectsBase(context, reference) {} US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceProperties.cpp b/Modules/CppMicroServices/core/src/service/usServiceProperties.cpp index 699d8ff4bd..1266bf16fb 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceProperties.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceProperties.cpp @@ -1,82 +1,82 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServiceProperties.h" #include US_BEGIN_NAMESPACE const std::string& ServiceConstants::OBJECTCLASS() { static const std::string s("objectclass"); return s; } const std::string& ServiceConstants::SERVICE_ID() { static const std::string s("service.id"); return s; } const std::string& ServiceConstants::SERVICE_RANKING() { static const std::string s("service.ranking"); return s; } const std::string& ServiceConstants::SERVICE_SCOPE() { static const std::string s("service.scope"); return s; } const std::string& ServiceConstants::SCOPE_SINGLETON() { static const std::string s("singleton"); return s; } const std::string& ServiceConstants::SCOPE_MODULE() { static const std::string s("module"); return s; } const std::string& ServiceConstants::SCOPE_PROTOTYPE() { static const std::string s("prototype"); return s; } US_END_NAMESPACE US_USE_NAMESPACE // make sure all static locals get constructed, so that they // can be used in destructors of global statics. std::string tmp1 = ServiceConstants::OBJECTCLASS(); std::string tmp2 = ServiceConstants::SERVICE_ID(); std::string tmp3 = ServiceConstants::SERVICE_RANKING(); std::string tmp4 = ServiceConstants::SERVICE_SCOPE(); std::string tmp5 = ServiceConstants::SCOPE_SINGLETON(); std::string tmp6 = ServiceConstants::SCOPE_MODULE(); std::string tmp7 = ServiceConstants::SCOPE_PROTOTYPE(); diff --git a/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl.cpp b/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl.cpp index 05d9976192..bdc2380da5 100644 --- a/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl.cpp +++ b/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl.cpp @@ -1,105 +1,105 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServicePropertiesImpl_p.h" #include #include #ifdef US_PLATFORM_WINDOWS #include #define ci_compare strnicmp #else #include #define ci_compare strncasecmp #endif US_BEGIN_NAMESPACE Any ServicePropertiesImpl::emptyAny; ServicePropertiesImpl::ServicePropertiesImpl(const ServiceProperties& p) { if (p.size() > static_cast(std::numeric_limits::max())) { throw std::runtime_error("ServiceProperties object contains too many keys"); } keys.reserve(p.size()); values.reserve(p.size()); for (ServiceProperties::const_iterator iter = p.begin(); iter != p.end(); ++iter) { if (Find(iter->first) > -1) { std::string msg = "ServiceProperties object contains case variants of the key: "; msg += iter->first; throw std::runtime_error(msg.c_str()); } keys.push_back(iter->first); values.push_back(iter->second); } } const Any& ServicePropertiesImpl::Value(const std::string& key) const { int i = Find(key); if (i < 0) return emptyAny; return values[i]; } const Any& ServicePropertiesImpl::Value(int index) const { if (index < 0 || static_cast(index) >= values.size()) return emptyAny; return values[static_cast(index)]; } int ServicePropertiesImpl::Find(const std::string& key) const { for (std::size_t i = 0; i < keys.size(); ++i) { if (ci_compare(key.c_str(), keys[i].c_str(), key.size()) == 0) { return static_cast(i); } } return -1; } int ServicePropertiesImpl::FindCaseSensitive(const std::string& key) const { for (std::size_t i = 0; i < keys.size(); ++i) { if (key == keys[i]) { return static_cast(i); } } return -1; } const std::vector& ServicePropertiesImpl::Keys() const { return keys; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl_p.h b/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl_p.h index de4bf3de17..1f1ca8b90e 100644 --- a/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl_p.h +++ b/Modules/CppMicroServices/core/src/service/usServicePropertiesImpl_p.h @@ -1,55 +1,55 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USSERVICEPROPERTIESIMPL_P_H #define USSERVICEPROPERTIESIMPL_P_H #include "usServiceProperties.h" US_BEGIN_NAMESPACE class ServicePropertiesImpl { public: explicit ServicePropertiesImpl(const ServiceProperties& props); const Any& Value(const std::string& key) const; const Any& Value(int index) const; int Find(const std::string& key) const; int FindCaseSensitive(const std::string& key) const; const std::vector& Keys() const; private: std::vector keys; std::vector values; static Any emptyAny; }; US_END_NAMESPACE #endif // USSERVICEPROPERTIESIMPL_P_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceReferenceBase.cpp b/Modules/CppMicroServices/core/src/service/usServiceReferenceBase.cpp index 9c67052051..a36fff34ef 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceReferenceBase.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceReferenceBase.cpp @@ -1,221 +1,221 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usServiceReferenceBase.h" #include "usServiceReferenceBasePrivate.h" #include "usServiceRegistrationBasePrivate.h" #include "usModule.h" #include "usModulePrivate.h" #include US_BEGIN_NAMESPACE ServiceReferenceBase::ServiceReferenceBase() : d(new ServiceReferenceBasePrivate(nullptr)) { } ServiceReferenceBase::ServiceReferenceBase(const ServiceReferenceBase& ref) : d(ref.d) { d->ref.Ref(); } ServiceReferenceBase::ServiceReferenceBase(ServiceRegistrationBasePrivate* reg) : d(new ServiceReferenceBasePrivate(reg)) { } void ServiceReferenceBase::SetInterfaceId(const std::string& interfaceId) { if (d->ref > 1) { // detach d->ref.Deref(); d = new ServiceReferenceBasePrivate(d->registration); } d->interfaceId = interfaceId; } ServiceReferenceBase::operator bool_type() const { return GetModule() != nullptr ? &ServiceReferenceBase::d : nullptr; } ServiceReferenceBase& ServiceReferenceBase::operator=(int null) { if (null == 0) { if (!d->ref.Deref()) delete d; d = new ServiceReferenceBasePrivate(nullptr); } return *this; } ServiceReferenceBase::~ServiceReferenceBase() { if (!d->ref.Deref()) delete d; } Any ServiceReferenceBase::GetProperty(const std::string& key) const { MutexLock lock(d->registration->propsLock); return d->registration->properties.Value(key); } void ServiceReferenceBase::GetPropertyKeys(std::vector& keys) const { MutexLock lock(d->registration->propsLock); const std::vector& ks = d->registration->properties.Keys(); keys.assign(ks.begin(), ks.end()); } Module* ServiceReferenceBase::GetModule() const { if (d->registration == nullptr || d->registration->module == nullptr) { return nullptr; } return d->registration->module->q; } void ServiceReferenceBase::GetUsingModules(std::vector& modules) const { MutexLock lock(d->registration->propsLock); ServiceRegistrationBasePrivate::ModuleToRefsMap::const_iterator end = d->registration->dependents.end(); for (ServiceRegistrationBasePrivate::ModuleToRefsMap::const_iterator iter = d->registration->dependents.begin(); iter != end; ++iter) { modules.push_back(iter->first); } } bool ServiceReferenceBase::operator<(const ServiceReferenceBase& reference) const { if (!(*this)) { return true; } if (!reference) { return false; } const Any anyR1 = GetProperty(ServiceConstants::SERVICE_RANKING()); const Any anyR2 = reference.GetProperty(ServiceConstants::SERVICE_RANKING()); assert(anyR1.Empty() || anyR1.Type() == typeid(int)); assert(anyR2.Empty() || anyR2.Type() == typeid(int)); const int r1 = anyR1.Empty() ? 0 : *any_cast(&anyR1); const int r2 = anyR2.Empty() ? 0 : *any_cast(&anyR2); if (r1 != r2) { // use ranking if ranking differs return r1 < r2; } else { const Any anyId1 = GetProperty(ServiceConstants::SERVICE_ID()); const Any anyId2 = reference.GetProperty(ServiceConstants::SERVICE_ID()); assert(anyId1.Type() == typeid(long int)); assert(anyId2.Type() == typeid(long int)); const long int id1 = *any_cast(&anyId1); const long int id2 = *any_cast(&anyId2); // otherwise compare using IDs, // is less than if it has a higher ID. return id2 < id1; } } bool ServiceReferenceBase::operator==(const ServiceReferenceBase& reference) const { return d->registration == reference.d->registration; } ServiceReferenceBase& ServiceReferenceBase::operator=(const ServiceReferenceBase& reference) { ServiceReferenceBasePrivate* curr_d = d; d = reference.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } bool ServiceReferenceBase::IsConvertibleTo(const std::string& interfaceId) const { return d->IsConvertibleTo(interfaceId); } std::string ServiceReferenceBase::GetInterfaceId() const { return d->interfaceId; } std::size_t ServiceReferenceBase::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; return US_HASH_FUNCTION(ServiceRegistrationBasePrivate*, this->d->registration); } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ServiceReferenceBase& serviceRef) { if (serviceRef) { assert(serviceRef.GetModule() != nullptr); os << "Reference for service object registered from " << serviceRef.GetModule()->GetName() << " " << serviceRef.GetModule()->GetVersion() << " ("; std::vector keys; serviceRef.GetPropertyKeys(keys); size_t keySize = keys.size(); for(size_t i = 0; i < keySize; ++i) { os << keys[i] << "=" << serviceRef.GetProperty(keys[i]).ToString(); if (i < keySize-1) os << ","; } os << ")"; } else { os << "Invalid service reference"; } return os; } diff --git a/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.cpp b/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.cpp index 0a560ef5c7..be676e82e9 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.cpp @@ -1,320 +1,320 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServiceReferenceBasePrivate.h" #include "usServiceFactory.h" #include "usServiceException.h" #include "usServiceRegistry_p.h" #include "usServiceRegistrationBasePrivate.h" #include "usModule.h" #include "usModulePrivate.h" #include #include #ifdef _MSC_VER #pragma warning(disable:4503) // decorated name length exceeded, name was truncated #endif US_BEGIN_NAMESPACE ServiceReferenceBasePrivate::ServiceReferenceBasePrivate(ServiceRegistrationBasePrivate* reg) : ref(1), registration(reg) { if(registration) registration->ref.Ref(); } ServiceReferenceBasePrivate::~ServiceReferenceBasePrivate() { if (registration && !registration->ref.Deref()) delete registration; } InterfaceMap ServiceReferenceBasePrivate::GetServiceFromFactory(Module* module, ServiceFactory* factory, bool isModuleScope) { assert(factory && "Factory service pointer is nullptr"); InterfaceMap s; try { InterfaceMap smap = factory->GetService(module, ServiceRegistrationBase(registration)); if (smap.empty()) { US_WARN << "ServiceFactory produced null"; return smap; } const std::vector& classes = ref_any_cast >(registration->properties.Value(ServiceConstants::OBJECTCLASS())); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { if (smap.find(*i) == smap.end() && *i != "org.cppmicroservices.factory") { US_WARN << "ServiceFactory produced an object " "that did not implement: " << (*i); smap.clear(); return smap; } } s = smap; if (isModuleScope) { registration->moduleServiceInstance.insert(std::make_pair(module, smap)); } else { registration->prototypeServiceInstances[module].push_back(smap); } } catch (...) { US_WARN << "ServiceFactory threw an exception"; s.clear(); } return s; } InterfaceMap ServiceReferenceBasePrivate::GetPrototypeService(Module* module) { InterfaceMap s; { MutexLock lock(registration->propsLock); if (registration->available) { ServiceFactory* factory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); s = GetServiceFromFactory(module, factory, false); } } return s; } void* ServiceReferenceBasePrivate::GetService(Module* module) { void* s = nullptr; { MutexLock lock(registration->propsLock); if (registration->available) { ServiceFactory* serviceFactory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); const int count = registration->dependents[module]; if (count == 0) { if (serviceFactory) { const InterfaceMap im = GetServiceFromFactory(module, serviceFactory, true); s = im.find(interfaceId)->second; } else { s = registration->GetService(interfaceId); } } else { if (serviceFactory) { // return the already produced instance s = registration->moduleServiceInstance[module][interfaceId]; } else { s = registration->GetService(interfaceId); } } if (s) { registration->dependents[module] = count + 1; } } } return s; } InterfaceMap ServiceReferenceBasePrivate::GetServiceInterfaceMap(Module* module) { InterfaceMap s; { MutexLock lock(registration->propsLock); if (registration->available) { ServiceFactory* serviceFactory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); const int count = registration->dependents[module]; if (count == 0) { if (serviceFactory) { s = GetServiceFromFactory(module, serviceFactory, true); } else { s = registration->service; } } else { if (serviceFactory) { // return the already produced instance s = registration->moduleServiceInstance[module]; } else { s = registration->service; } } if (!s.empty()) { registration->dependents[module] = count + 1; } } } return s; } bool ServiceReferenceBasePrivate::UngetPrototypeService(Module* module, const InterfaceMap& service) { MutexLock lock(registration->propsLock); ServiceRegistrationBasePrivate::ModuleToServicesMap::iterator iter = registration->prototypeServiceInstances.find(module); if (iter == registration->prototypeServiceInstances.end()) { return false; } std::list& prototypeServiceMaps = iter->second; for (std::list::iterator imIter = prototypeServiceMaps.begin(); imIter != prototypeServiceMaps.end(); ++imIter) { if (service == *imIter) { try { ServiceFactory* sf = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); sf->UngetService(module, ServiceRegistrationBase(registration), service); } catch (const std::exception& /*e*/) { US_WARN << "ServiceFactory threw an exception"; } prototypeServiceMaps.erase(imIter); if (prototypeServiceMaps.empty()) { registration->prototypeServiceInstances.erase(iter); } return true; } } return false; } bool ServiceReferenceBasePrivate::UngetService(Module* module, bool checkRefCounter) { MutexLock lock(registration->propsLock); bool hadReferences = false; bool removeService = false; int count= registration->dependents[module]; if (count > 0) { hadReferences = true; } if(checkRefCounter) { if (count > 1) { registration->dependents[module] = count - 1; } else if(count == 1) { removeService = true; } } else { removeService = true; } if (removeService) { InterfaceMap sfi = registration->moduleServiceInstance[module]; registration->moduleServiceInstance.erase(module); if (!sfi.empty()) { try { ServiceFactory* sf = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); sf->UngetService(module, ServiceRegistrationBase(registration), sfi); } catch (const std::exception& /*e*/) { US_WARN << "ServiceFactory threw an exception"; } } registration->dependents.erase(module); } return hadReferences && removeService; } const ServicePropertiesImpl& ServiceReferenceBasePrivate::GetProperties() const { return registration->properties; } Any ServiceReferenceBasePrivate::GetProperty(const std::string& key, bool lock) const { if (lock) { MutexLock lock(registration->propsLock); return registration->properties.Value(key); } else { return registration->properties.Value(key); } } bool ServiceReferenceBasePrivate::IsConvertibleTo(const std::string& interfaceId) const { return registration ? registration->service.find(interfaceId) != registration->service.end() : false; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.h b/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.h index 77804c7b46..f3a0be1ca9 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.h +++ b/Modules/CppMicroServices/core/src/service/usServiceReferenceBasePrivate.h @@ -1,152 +1,152 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USSERVICEREFERENCEBASEPRIVATE_H #define USSERVICEREFERENCEBASEPRIVATE_H #include "usAtomicInt_p.h" #include "usServiceInterface.h" #include US_BEGIN_NAMESPACE class Any; class Module; class ServicePropertiesImpl; class ServiceRegistrationBasePrivate; class ServiceReferenceBasePrivate; /** * \ingroup MicroServices */ class ServiceReferenceBasePrivate { public: ServiceReferenceBasePrivate(ServiceRegistrationBasePrivate* reg); ~ServiceReferenceBasePrivate(); /** * Get the service object. * * @param module requester of service. * @return Service requested or null in case of failure. */ void* GetService(Module* module); InterfaceMap GetServiceInterfaceMap(Module* module); /** * Get new service instance. * * @param module requester of service. * @return Service requested or null in case of failure. */ InterfaceMap GetPrototypeService(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 removed or false if only reference counter was * decremented. */ bool UngetService(Module* module, bool checkRefCounter); /** * Unget prototype scope service objects. * * @param module Module who wants to remove a prototype scope service. * @param service The prototype scope service pointer. * @return \c true if the service was removed, \c false otherwise. */ bool UngetPrototypeService(Module* module, void* service); bool UngetPrototypeService(Module* module, const InterfaceMap& service); /** * Get all properties registered with this service. * * @return A ServiceProperties object containing properties or being empty * if service has been removed. */ const ServicePropertiesImpl& GetProperties() const; /** * 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 must continue 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. * @param lock If true, access of the properties of the service * referenced by this ServiceReference object will be * synchronized. * @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, bool lock) const; bool IsConvertibleTo(const std::string& interfaceId) const; /** * Reference count for implicitly shared private implementation. */ AtomicInt ref; /** * Link to registration object for this reference. */ ServiceRegistrationBasePrivate* const registration; /** * The service interface id for this reference. */ std::string interfaceId; private: InterfaceMap GetServiceFromFactory(Module* module, ServiceFactory* factory, bool isModuleScope); // purposely not implemented ServiceReferenceBasePrivate(const ServiceReferenceBasePrivate&); ServiceReferenceBasePrivate& operator=(const ServiceReferenceBasePrivate&); }; US_END_NAMESPACE #endif // USSERVICEREFERENCEBASEPRIVATE_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceRegistrationBase.cpp b/Modules/CppMicroServices/core/src/service/usServiceRegistrationBase.cpp index 033457ed0a..c4ff4f1f30 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceRegistrationBase.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceRegistrationBase.cpp @@ -1,271 +1,271 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServiceRegistrationBase.h" #include "usServiceRegistrationBasePrivate.h" #include "usServiceListenerEntry_p.h" #include "usServiceRegistry_p.h" #include "usServiceFactory.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" #include US_BEGIN_NAMESPACE ServiceRegistrationBase::ServiceRegistrationBase() : d(nullptr) { } ServiceRegistrationBase::ServiceRegistrationBase(const ServiceRegistrationBase& reg) : d(reg.d) { if (d) d->ref.Ref(); } ServiceRegistrationBase::ServiceRegistrationBase(ServiceRegistrationBasePrivate* registrationPrivate) : d(registrationPrivate) { if (d) d->ref.Ref(); } ServiceRegistrationBase::ServiceRegistrationBase(ModulePrivate* module, const InterfaceMap& service, const ServicePropertiesImpl& props) : d(new ServiceRegistrationBasePrivate(module, service, props)) { } ServiceRegistrationBase::operator bool_type() const { return d != nullptr ? &ServiceRegistrationBase::d : nullptr; } ServiceRegistrationBase& ServiceRegistrationBase::operator=(int null) { if (null == 0) { if (d && !d->ref.Deref()) { delete d; } d = nullptr; } return *this; } ServiceRegistrationBase::~ServiceRegistrationBase() { if (d && !d->ref.Deref()) delete d; } ServiceReferenceBase ServiceRegistrationBase::GetReference(const std::string& interfaceId) const { if (!d) throw std::logic_error("ServiceRegistrationBase object invalid"); if (!d->available) throw std::logic_error("Service is unregistered"); ServiceReferenceBase ref = d->reference; ref.SetInterfaceId(interfaceId); return ref; } void ServiceRegistrationBase::SetProperties(const ServiceProperties& props) { if (!d) throw std::logic_error("ServiceRegistrationBase object invalid"); MutexLock lock(d->eventLock); ServiceEvent modifiedEndMatchEvent(ServiceEvent::MODIFIED_ENDMATCH, d->reference); ServiceListeners::ServiceListenerEntries before; // TBD, optimize the locking of services { //MutexLock lock2(d->module->coreCtx->globalFwLock); if (d->available) { // NYI! Optimize the MODIFIED_ENDMATCH code int old_rank = 0; int new_rank = 0; std::vector classes; { MutexLock lock3(d->propsLock); { const Any& any = d->properties.Value(ServiceConstants::SERVICE_RANKING()); if (any.Type() == typeid(int)) old_rank = any_cast(any); } d->module->coreCtx->listeners.GetMatchingServiceListeners(modifiedEndMatchEvent, before, false); classes = ref_any_cast >(d->properties.Value(ServiceConstants::OBJECTCLASS())); long int sid = any_cast(d->properties.Value(ServiceConstants::SERVICE_ID())); d->properties = ServiceRegistry::CreateServiceProperties(props, classes, false, false, sid); { const Any& any = d->properties.Value(ServiceConstants::SERVICE_RANKING()); if (any.Type() == typeid(int)) new_rank = any_cast(any); } } if (old_rank != new_rank) { d->module->coreCtx->services.UpdateServiceRegistrationOrder(*this, classes); } } else { throw std::logic_error("Service is unregistered"); } } ServiceEvent modifiedEvent(ServiceEvent::MODIFIED, d->reference); ServiceListeners::ServiceListenerEntries matchingListeners; d->module->coreCtx->listeners.GetMatchingServiceListeners(modifiedEvent, matchingListeners); d->module->coreCtx->listeners.ServiceChanged(matchingListeners, modifiedEvent, before); d->module->coreCtx->listeners.ServiceChanged(before, modifiedEndMatchEvent); } void ServiceRegistrationBase::Unregister() { if (!d) throw std::logic_error("ServiceRegistrationBase object invalid"); if (d->unregistering) return; // Silently ignore redundant unregistration. { MutexLock lock(d->eventLock); if (d->unregistering) return; d->unregistering = true; if (d->available) { if (d->module) { d->module->coreCtx->services.RemoveServiceRegistration(*this); } } else { throw std::logic_error("Service is unregistered"); } } if (d->module) { ServiceListeners::ServiceListenerEntries listeners; ServiceEvent unregisteringEvent(ServiceEvent::UNREGISTERING, d->reference); d->module->coreCtx->listeners.GetMatchingServiceListeners(unregisteringEvent, listeners); d->module->coreCtx->listeners.ServiceChanged( listeners, unregisteringEvent); } { MutexLock lock(d->eventLock); { MutexLock lock2(d->propsLock); d->available = false; InterfaceMap::const_iterator factoryIter = d->service.find("org.cppmicroservices.factory"); if (d->module && factoryIter != d->service.end()) { ServiceFactory* serviceFactory = reinterpret_cast(factoryIter->second); ServiceRegistrationBasePrivate::ModuleToServicesMap::const_iterator end = d->prototypeServiceInstances.end(); // unget all prototype services for (ServiceRegistrationBasePrivate::ModuleToServicesMap::const_iterator i = d->prototypeServiceInstances.begin(); i != end; ++i) { for (std::list::const_iterator listIter = i->second.begin(); listIter != i->second.end(); ++listIter) { const InterfaceMap& service = *listIter; try { // NYI, don't call inside lock serviceFactory->UngetService(i->first, *this, service); } catch (const std::exception& /*ue*/) { US_WARN << "ServiceFactory UngetService implementation threw an exception"; } } } // unget module scope services ServiceRegistrationBasePrivate::ModuleToServiceMap::const_iterator moduleEnd = d->moduleServiceInstance.end(); for (ServiceRegistrationBasePrivate::ModuleToServiceMap::const_iterator i = d->moduleServiceInstance.begin(); i != moduleEnd; ++i) { try { // NYI, don't call inside lock serviceFactory->UngetService(i->first, *this, i->second); } catch (const std::exception& /*ue*/) { US_WARN << "ServiceFactory UngetService implementation threw an exception"; } } } d->module = nullptr; d->dependents.clear(); d->service.clear(); d->prototypeServiceInstances.clear(); d->moduleServiceInstance.clear(); // increment the reference count, since "d->reference" was used originally // to keep d alive. d->ref.Ref(); d->reference = 0; d->unregistering = false; } } } bool ServiceRegistrationBase::operator<(const ServiceRegistrationBase& o) const { if ((!d && !o.d) || !o.d) return false; if (!d) return true; return d->reference <(o.d->reference); } bool ServiceRegistrationBase::operator==(const ServiceRegistrationBase& registration) const { return d == registration.d; } ServiceRegistrationBase& ServiceRegistrationBase::operator=(const ServiceRegistrationBase& registration) { ServiceRegistrationBasePrivate* curr_d = d; d = registration.d; if (d) d->ref.Ref(); if (curr_d && !curr_d->ref.Deref()) delete curr_d; return *this; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.cpp b/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.cpp index 8e89eb9ede..0e300c0552 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.cpp @@ -1,76 +1,76 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usServiceRegistrationBasePrivate.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4355) #endif US_BEGIN_NAMESPACE ServiceRegistrationBasePrivate::ServiceRegistrationBasePrivate( ModulePrivate* module, const InterfaceMap& service, const ServicePropertiesImpl& props) : ref(0), service(service), module(module), reference(this), properties(props), available(true), unregistering(false) { // The reference counter is initialized to 0 because it will be // incremented by the "reference" member. } ServiceRegistrationBasePrivate::~ServiceRegistrationBasePrivate() { } bool ServiceRegistrationBasePrivate::IsUsedByModule(Module* p) const { return (dependents.find(p) != dependents.end()) || (prototypeServiceInstances.find(p) != prototypeServiceInstances.end()); } const InterfaceMap& ServiceRegistrationBasePrivate::GetInterfaces() const { return service; } void* ServiceRegistrationBasePrivate::GetService(const std::string& interfaceId) const { if (interfaceId.empty() && service.size() > 0) { return service.begin()->second; } InterfaceMap::const_iterator iter = service.find(interfaceId); if (iter != service.end()) { return iter->second; } return nullptr; } US_END_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif diff --git a/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.h b/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.h index 5ac69b9545..c683900d49 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.h +++ b/Modules/CppMicroServices/core/src/service/usServiceRegistrationBasePrivate.h @@ -1,149 +1,149 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEREGISTRATIONBASEPRIVATE_H #define USSERVICEREGISTRATIONBASEPRIVATE_H #include "usServiceInterface.h" #include "usServiceReference.h" #include "usServicePropertiesImpl_p.h" #include "usAtomicInt_p.h" US_BEGIN_NAMESPACE class ModulePrivate; class ServiceRegistrationBase; /** * \ingroup MicroServices */ class ServiceRegistrationBasePrivate { protected: friend class ServiceRegistrationBase; // The ServiceReferenceBasePrivate class holds a pointer to a // ServiceRegistrationBasePrivate instance and needs to manipulate // its reference count. This way it can keep the ServiceRegistrationBasePrivate // instance alive and keep returning service properties for // unregistered service instances. friend class ServiceReferenceBasePrivate; /** * Reference count for implicitly shared private implementation. */ AtomicInt ref; /** * Service or ServiceFactory object. */ InterfaceMap service; public: typedef US_UNORDERED_MAP_TYPE ModuleToRefsMap; typedef US_UNORDERED_MAP_TYPE ModuleToServiceMap; typedef US_UNORDERED_MAP_TYPE > ModuleToServicesMap; /** * Modules dependent on this service. Integer is used as * reference counter, counting number of unbalanced getService(). */ ModuleToRefsMap dependents; /** * Object instances that a prototype factory has produced. */ ModuleToServicesMap prototypeServiceInstances; /** * Object instance with module scope that a factory may have produced. */ ModuleToServiceMap moduleServiceInstance; /** * Module registering this service. */ ModulePrivate* module; /** * Reference object to this service registration. */ ServiceReferenceBase reference; /** * Service properties. */ ServicePropertiesImpl properties; /** * Is service available. I.e., if true then holders * of a ServiceReference for the service are allowed to get it. */ volatile bool available; /** * Avoid recursive unregistrations. I.e., if true then * unregistration of this service has started but is not yet * finished. */ volatile bool unregistering; /** * Lock object for synchronous event delivery. */ Mutex eventLock; // needs to be recursive Mutex propsLock; ServiceRegistrationBasePrivate(ModulePrivate* module, const InterfaceMap& service, const ServicePropertiesImpl& props); ~ServiceRegistrationBasePrivate(); /** * Check if a module uses this service * * @param p Module to check * @return true if module uses this service */ bool IsUsedByModule(Module* m) const; const InterfaceMap& GetInterfaces() const; void* GetService(const std::string& interfaceId) const; private: // purposely not implemented ServiceRegistrationBasePrivate(const ServiceRegistrationBasePrivate&); ServiceRegistrationBasePrivate& operator=(const ServiceRegistrationBasePrivate&); }; US_END_NAMESPACE #endif // USSERVICEREGISTRATIONBASEPRIVATE_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceRegistry.cpp b/Modules/CppMicroServices/core/src/service/usServiceRegistry.cpp index 023e7e574d..2131432c47 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceRegistry.cpp +++ b/Modules/CppMicroServices/core/src/service/usServiceRegistry.cpp @@ -1,338 +1,338 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include "usServiceRegistry_p.h" #include "usServiceFactory.h" #include "usPrototypeServiceFactory.h" #include "usServiceRegistry_p.h" #include "usServiceRegistrationBasePrivate.h" #include "usModulePrivate.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE ServicePropertiesImpl ServiceRegistry::CreateServiceProperties(const ServiceProperties& in, const std::vector& classes, bool isFactory, bool isPrototypeFactory, long sid) { static long nextServiceID = 1; ServiceProperties props(in); if (!classes.empty()) { props.insert(std::make_pair(ServiceConstants::OBJECTCLASS(), classes)); } props.insert(std::make_pair(ServiceConstants::SERVICE_ID(), sid != -1 ? sid : nextServiceID++)); if (isPrototypeFactory) { props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_PROTOTYPE())); } else if (isFactory) { props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_MODULE())); } else { props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_SINGLETON())); } return ServicePropertiesImpl(props); } ServiceRegistry::ServiceRegistry(CoreModuleContext* coreCtx) : core(coreCtx) { } ServiceRegistry::~ServiceRegistry() { Clear(); } void ServiceRegistry::Clear() { services.clear(); serviceRegistrations.clear(); classServices.clear(); core = nullptr; } ServiceRegistrationBase ServiceRegistry::RegisterService(ModulePrivate* module, const InterfaceMap& service, const ServiceProperties& properties) { if (service.empty()) { throw std::invalid_argument("Can't register empty InterfaceMap as a service"); } // Check if we got a service factory bool isFactory = service.count("org.cppmicroservices.factory") > 0; bool isPrototypeFactory = (isFactory ? dynamic_cast(reinterpret_cast(service.find("org.cppmicroservices.factory")->second)) != nullptr : false); std::vector classes; // Check if service implements claimed classes and that they exist. for (InterfaceMap::const_iterator i = service.begin(); i != service.end(); ++i) { if (i->first.empty() || (!isFactory && i->second == nullptr)) { throw std::invalid_argument("Can't register as null class"); } classes.push_back(i->first); } ServiceRegistrationBase res(module, service, CreateServiceProperties(properties, classes, isFactory, isPrototypeFactory)); { MutexLock lock(mutex); services.insert(std::make_pair(res, classes)); serviceRegistrations.push_back(res); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::vector& s = classServices[*i]; std::vector::iterator ip = std::lower_bound(s.begin(), s.end(), res); s.insert(ip, res); } } ServiceReferenceBase r = res.GetReference(std::string()); ServiceListeners::ServiceListenerEntries listeners; ServiceEvent registeredEvent(ServiceEvent::REGISTERED, r); module->coreCtx->listeners.GetMatchingServiceListeners(registeredEvent, listeners); module->coreCtx->listeners.ServiceChanged(listeners, registeredEvent); return res; } void ServiceRegistry::UpdateServiceRegistrationOrder(const ServiceRegistrationBase& sr, const std::vector& classes) { MutexLock lock(mutex); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::vector& s = classServices[*i]; s.erase(std::remove(s.begin(), s.end(), sr), s.end()); s.insert(std::lower_bound(s.begin(), s.end(), sr), sr); } } void ServiceRegistry::Get(const std::string& clazz, std::vector& serviceRegs) const { MutexLock lock(mutex); Get_unlocked(clazz, serviceRegs); } void ServiceRegistry::Get_unlocked(const std::string& clazz, std::vector& serviceRegs) const { MapClassServices::const_iterator i = classServices.find(clazz); if (i != classServices.end()) { serviceRegs = i->second; } } ServiceReferenceBase ServiceRegistry::Get(ModulePrivate* module, const std::string& clazz) const { MutexLock lock(mutex); try { std::vector srs; Get_unlocked(clazz, "", module, srs); US_DEBUG << "get service ref " << clazz << " for module " << module->info.name << " = " << srs.size() << " refs"; if (!srs.empty()) { return srs.back(); } } catch (const std::invalid_argument& ) { } return ServiceReferenceBase(); } void ServiceRegistry::Get(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::vector& res) const { MutexLock lock(mutex); Get_unlocked(clazz, filter, module, res); } void ServiceRegistry::Get_unlocked(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::vector& res) const { std::vector::const_iterator s; std::vector::const_iterator send; std::vector v; LDAPExpr ldap; if (clazz.empty()) { if (!filter.empty()) { ldap = LDAPExpr(filter); LDAPExpr::ObjectClassSet matched; if (ldap.GetMatchedObjectClasses(matched)) { v.clear(); for(LDAPExpr::ObjectClassSet::const_iterator className = matched.begin(); className != matched.end(); ++className) { MapClassServices::const_iterator i = classServices.find(*className); if (i != classServices.end()) { std::copy(i->second.begin(), i->second.end(), std::back_inserter(v)); } } if (!v.empty()) { s = v.begin(); send = v.end(); } else { return; } } else { s = serviceRegistrations.begin(); send = serviceRegistrations.end(); } } else { s = serviceRegistrations.begin(); send = serviceRegistrations.end(); } } else { MapClassServices::const_iterator it = classServices.find(clazz); if (it != classServices.end()) { s = it->second.begin(); send = it->second.end(); } else { return; } if (!filter.empty()) { ldap = LDAPExpr(filter); } } for (; s != send; ++s) { ServiceReferenceBase sri = s->GetReference(clazz); if (filter.empty() || ldap.Evaluate(s->d->properties, false)) { res.push_back(sri); } } if (!res.empty()) { if (module != nullptr) { core->serviceHooks.FilterServiceReferences(module->moduleContext, clazz, filter, res); } else { core->serviceHooks.FilterServiceReferences(nullptr, clazz, filter, res); } } } void ServiceRegistry::RemoveServiceRegistration(const ServiceRegistrationBase& sr) { MutexLock lock(mutex); assert(sr.d->properties.Value(ServiceConstants::OBJECTCLASS()).Type() == typeid(std::vector)); const std::vector& classes = ref_any_cast >( sr.d->properties.Value(ServiceConstants::OBJECTCLASS())); services.erase(sr); serviceRegistrations.erase(std::remove(serviceRegistrations.begin(), serviceRegistrations.end(), sr), serviceRegistrations.end()); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { std::vector& s = classServices[*i]; if (s.size() > 1) { s.erase(std::remove(s.begin(), s.end(), sr), s.end()); } else { classServices.erase(*i); } } } void ServiceRegistry::GetRegisteredByModule(ModulePrivate* p, std::vector& res) const { MutexLock lock(mutex); for (std::vector::const_iterator i = serviceRegistrations.begin(); i != serviceRegistrations.end(); ++i) { if (i->d->module == p) { res.push_back(*i); } } } void ServiceRegistry::GetUsedByModule(Module* p, std::vector& res) const { MutexLock lock(mutex); for (std::vector::const_iterator i = serviceRegistrations.begin(); i != serviceRegistrations.end(); ++i) { if (i->d->IsUsedByModule(p)) { res.push_back(*i); } } } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceRegistry_p.h b/Modules/CppMicroServices/core/src/service/usServiceRegistry_p.h index e91aaabf9a..7f0d74e277 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceRegistry_p.h +++ b/Modules/CppMicroServices/core/src/service/usServiceRegistry_p.h @@ -1,189 +1,189 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICEREGISTRY_H #define USSERVICEREGISTRY_H #include "usServiceInterface.h" #include "usServiceRegistration.h" #include "usThreads_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModulePrivate; class ServicePropertiesImpl; /** * Here we handle all the CppMicroServices services that are registered. */ class ServiceRegistry { public: typedef Mutex MutexType; mutable MutexType mutex; /** * Creates a new ServiceProperties object containing in * with the keys converted to lower case. * * @param classes A list of class names which will be added to the * created ServiceProperties object under the key * ModuleConstants::OBJECTCLASS. * @param sid A service id which will be used instead of a default one. */ static ServicePropertiesImpl CreateServiceProperties(const ServiceProperties& in, const std::vector& classes = std::vector(), bool isFactory = false, bool isPrototypeFactory = false, long sid = -1); typedef US_UNORDERED_MAP_TYPE > MapServiceClasses; typedef US_UNORDERED_MAP_TYPE > MapClassServices; /** * All registered services in the current framework. * Mapping of registered service to class names under which * the service is registerd. */ MapServiceClasses services; std::vector serviceRegistrations; /** * Mapping of classname to registered service. * The List of registered services are ordered with the highest * ranked service first. */ MapClassServices classServices; CoreModuleContext* core; ServiceRegistry(CoreModuleContext* coreCtx); ~ServiceRegistry(); void Clear(); /** * Register a service in the framework wide register. * * @param module The module registering the service. * @param classes The class names under which the service can be located. * @param service The service object. * @param properties The properties for this service. * @return A ServiceRegistration object. * @exception std::invalid_argument If one of the following is true: *

    *
  • The service object is 0.
  • *
  • The service parameter is not a ServiceFactory or an * instance of all the named classes in the classes parameter.
  • *
*/ ServiceRegistrationBase RegisterService(ModulePrivate* module, const InterfaceMap& service, const ServiceProperties& properties); /** * Service ranking changed, reorder registered services * according to ranking. * * @param serviceRegistration The ServiceRegistrationPrivate object. * @param rank New rank of object. */ void UpdateServiceRegistrationOrder(const ServiceRegistrationBase& sr, const std::vector& classes); /** * Get all services implementing a certain class. * Only used internally by the framework. * * @param clazz The class name of the requested service. * @return A sorted list of {@link ServiceRegistrationPrivate} objects. */ void Get(const std::string& clazz, std::vector& serviceRegs) const; /** * Get a service implementing a certain class. * * @param module The module requesting reference * @param clazz The class name of the requested service. * @return A {@link ServiceReference} object. */ ServiceReferenceBase Get(ModulePrivate* module, const std::string& clazz) const; /** * Get all services implementing a certain class and then * filter these with a property filter. * * @param clazz The class name of requested service. * @param filter The property filter. * @param module The module requesting reference. * @return A list of {@link ServiceReference} object. */ void Get(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::vector& serviceRefs) const; /** * Remove a registered service. * * @param sr The ServiceRegistration object that is registered. */ void RemoveServiceRegistration(const ServiceRegistrationBase& sr) ; /** * Get all services that a module has registered. * * @param p The module * @return A set of {@link ServiceRegistration} objects */ void GetRegisteredByModule(ModulePrivate* m, std::vector& serviceRegs) const; /** * Get all services that a module uses. * * @param p The module * @return A set of {@link ServiceRegistration} objects */ void GetUsedByModule(Module* m, std::vector& serviceRegs) const; private: friend class ServiceHooks; void Get_unlocked(const std::string& clazz, std::vector& serviceRegs) const; void Get_unlocked(const std::string& clazz, const std::string& filter, ModulePrivate* module, std::vector& serviceRefs) const; // purposely not implemented ServiceRegistry(const ServiceRegistry&); ServiceRegistry& operator=(const ServiceRegistry&); }; US_END_NAMESPACE #endif // USSERVICEREGISTRY_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceTracker.tpp b/Modules/CppMicroServices/core/src/service/usServiceTracker.tpp index 04f12e7454..6db7508887 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceTracker.tpp +++ b/Modules/CppMicroServices/core/src/service/usServiceTracker.tpp @@ -1,464 +1,464 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usServiceTrackerPrivate.h" #include "usTrackedService_p.h" #include "usServiceException.h" #include "usModuleContext.h" #include #include #include US_BEGIN_NAMESPACE template ServiceTracker::~ServiceTracker() { Close(); delete d; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4355) #endif template ServiceTracker::ServiceTracker(ModuleContext* context, const ServiceReferenceType& reference, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, reference, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const std::string& clazz, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, clazz, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const LDAPFilter& filter, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, filter, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext *context, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, us_service_interface_iid(), customizer)) { std::string clazz = us_service_interface_iid(); if (clazz.empty()) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); } #ifdef _MSC_VER #pragma warning(pop) #endif template void ServiceTracker::Open() { _TrackedService* t; { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); if (d->trackedService) { return; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::Open: " << d->filter; t = new _TrackedService(this, d->customizer); { US_UNUSED(typename _TrackedService::Lock(*t)); try { d->context->AddServiceListener(t, &_TrackedService::ServiceChanged, d->listenerFilter); std::vector references; if (!d->trackClass.empty()) { references = d->GetInitialReferences(d->trackClass, std::string()); } else { if (d->trackReference.GetModule() != nullptr) { references.push_back(d->trackReference); } else { /* user supplied filter */ references = d->GetInitialReferences(std::string(), (d->listenerFilter.empty()) ? d->filter.ToString() : d->listenerFilter); } } /* set tracked with the initial references */ t->SetInitial(references); } catch (const std::invalid_argument& e) { throw std::runtime_error(std::string("unexpected std::invalid_argument exception: ") + e.what()); } } d->trackedService = t; } /* Call tracked outside of synchronized region */ t->TrackInitial(); /* process the initial references */ } template void ServiceTracker::Close() { _TrackedService* outgoing; std::vector references; { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); outgoing = d->trackedService; if (outgoing == nullptr) { return; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::close:" << d->filter; outgoing->Close(); references = GetServiceReferences(); d->trackedService = nullptr; try { d->context->RemoveServiceListener(outgoing, &_TrackedService::ServiceChanged); } catch (const std::logic_error& /*e*/) { /* In case the context was stopped. */ } } d->Modified(); /* clear the cache */ { US_UNUSED(typename _TrackedService::Lock(outgoing)); outgoing->NotifyAll(); /* wake up any waiters */ } for(typename std::vector::const_iterator ref = references.begin(); ref != references.end(); ++ref) { outgoing->Untrack(*ref, ServiceEvent()); } if (d->DEBUG_OUTPUT) { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); if ((d->cachedReference.GetModule() == nullptr) && !TTT::IsValid(d->cachedService)) { US_DEBUG(true) << "ServiceTracker::close[cached cleared]:" << d->filter; } } delete outgoing; d->trackedService = nullptr; } template typename ServiceTracker::T ServiceTracker::WaitForService(unsigned long timeoutMillis) { T object = GetService(); while (!TTT::IsValid(object)) { _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return TTT::DefaultValue(); } { US_UNUSED(typename _TrackedService::Lock(t)); if (t->Size() == 0) { t->Wait(timeoutMillis); } } object = GetService(); } return object; } template std::vector::ServiceReferenceType> ServiceTracker::GetServiceReferences() const { std::vector refs; _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return refs; } { US_UNUSED(typename _TrackedService::Lock(t)); d->GetServiceReferences_unlocked(refs, t); } return refs; } template typename ServiceTracker::ServiceReferenceType ServiceTracker::GetServiceReference() const { ServiceReferenceType reference; { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); reference = d->cachedReference; } if (reference.GetModule() != nullptr) { US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getServiceReference[cached]:" << d->filter; return reference; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getServiceReference:" << d->filter; std::vector references = GetServiceReferences(); std::size_t length = references.size(); if (length == 0) { /* if no service is being tracked */ throw ServiceException("No service is being tracked"); } typename std::vector::const_iterator selectedRef = references.begin(); if (length > 1) { /* if more than one service, select highest ranking */ std::vector rankings(length); int count = 0; int maxRanking = std::numeric_limits::min(); typename std::vector::const_iterator refIter = references.begin(); for (std::size_t i = 0; i < length; i++) { Any rankingAny = refIter->GetProperty(ServiceConstants::SERVICE_RANKING()); int ranking = 0; if (rankingAny.Type() == typeid(int)) { ranking = any_cast(rankingAny); } rankings[i] = ranking; if (ranking > maxRanking) { selectedRef = refIter; maxRanking = ranking; count = 1; } else { if (ranking == maxRanking) { count++; } } ++refIter; } if (count > 1) { /* if still more than one service, select lowest id */ long int minId = std::numeric_limits::max(); refIter = references.begin(); for (std::size_t i = 0; i < length; i++) { if (rankings[i] == maxRanking) { Any idAny = refIter->GetProperty(ServiceConstants::SERVICE_ID()); long int id = 0; if (idAny.Type() == typeid(long int)) { id = any_cast(idAny); } if (id < minId) { selectedRef = refIter; minId = id; } } ++refIter; } } } { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); d->cachedReference = *selectedRef; return d->cachedReference; } } template typename ServiceTracker::T ServiceTracker::GetService(const ServiceReferenceType& reference) const { _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return TTT::DefaultValue(); } { US_UNUSED(typename _TrackedService::Lock(t)); return t->GetCustomizedObject(reference); } } template std::vector::T> ServiceTracker::GetServices() const { std::vector services; _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return services; } { US_UNUSED(typename _TrackedService::Lock(t)); std::vector references; d->GetServiceReferences_unlocked(references, t); for(typename std::vector::const_iterator ref = references.begin(); ref != references.end(); ++ref) { services.push_back(t->GetCustomizedObject(*ref)); } } return services; } template typename ServiceTracker::T ServiceTracker::GetService() const { { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); const T& service = d->cachedService; if (TTT::IsValid(service)) { US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getService[cached]:" << d->filter; return service; } } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getService:" << d->filter; try { ServiceReferenceType reference = GetServiceReference(); if (reference.GetModule() == nullptr) { return TTT::DefaultValue(); } { US_UNUSED(typename _ServiceTrackerPrivate::Lock(d)); return d->cachedService = GetService(reference); } } catch (const ServiceException&) { return TTT::DefaultValue(); } } template void ServiceTracker::Remove(const ServiceReferenceType& reference) { _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return; } t->Untrack(reference, ServiceEvent()); } template int ServiceTracker::Size() const { _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return 0; } { US_UNUSED(typename _TrackedService::Lock(t)); return static_cast(t->Size()); } } template int ServiceTracker::GetTrackingCount() const { _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return -1; } { US_UNUSED(typename _TrackedService::Lock(t)); return t->GetTrackingCount(); } } template void ServiceTracker::GetTracked(TrackingMap& map) const { _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return; } { US_UNUSED(typename _TrackedService::Lock(t)); t->CopyEntries(map); } } template bool ServiceTracker::IsEmpty() const { _TrackedService* t = d->Tracked(); if (t == nullptr) { /* if ServiceTracker is not open */ return true; } { US_UNUSED(typename _TrackedService::Lock(t)); return t->IsEmpty(); } } template typename ServiceTracker::T ServiceTracker::AddingService(const ServiceReferenceType& reference) { return TTT::ConvertToTrackedType(d->context->GetService(reference)); } template void ServiceTracker::ModifiedService(const ServiceReferenceType& /*reference*/, T /*service*/) { /* do nothing */ } template void ServiceTracker::RemovedService(const ServiceReferenceType& reference, T /*service*/) { d->context->UngetService(reference); } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.h b/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.h index 282798710a..d03e6bb255 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.h +++ b/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.h @@ -1,172 +1,172 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICETRACKERPRIVATE_H #define USSERVICETRACKERPRIVATE_H #include "usServiceReference.h" #include "usLDAPFilter.h" US_BEGIN_NAMESPACE /** * \ingroup MicroServices */ template class ServiceTrackerPrivate : MultiThreaded<> { public: typedef typename TTT::TrackedType T; ServiceTrackerPrivate(ServiceTracker* st, ModuleContext* context, const ServiceReference& reference, ServiceTrackerCustomizer* customizer); ServiceTrackerPrivate(ServiceTracker* st, ModuleContext* context, const std::string& clazz, ServiceTrackerCustomizer* customizer); ServiceTrackerPrivate(ServiceTracker* st, ModuleContext* context, const LDAPFilter& filter, ServiceTrackerCustomizer* customizer); ~ServiceTrackerPrivate(); /** * Returns the list of initial ServiceReferences that will be * tracked by this ServiceTracker. * * @param className The class name with which the service was registered, or * null for all services. * @param filterString The filter criteria or null for all * services. * @return The list of initial ServiceReferences. * @throws std::invalid_argument If the specified filterString has an * invalid syntax. */ std::vector > GetInitialReferences(const std::string& className, const std::string& filterString); void GetServiceReferences_unlocked(std::vector >& refs, TrackedService* t) const; /* set this to true to compile in debug messages */ static const bool DEBUG_OUTPUT; // = false; /** * The Module Context used by this ServiceTracker. */ ModuleContext* const context; /** * The filter used by this ServiceTracker which specifies the * search criteria for the services to track. */ LDAPFilter filter; /** * The ServiceTrackerCustomizer for this tracker. */ ServiceTrackerCustomizer* customizer; /** * Filter string for use when adding the ServiceListener. If this field is * set, then certain optimizations can be taken since we don't have a user * supplied filter. */ std::string listenerFilter; /** * Class name to be tracked. If this field is set, then we are tracking by * class name. */ std::string trackClass; /** * Reference to be tracked. If this field is set, then we are tracking a * single ServiceReference. */ ServiceReference trackReference; /** * Tracked services: ServiceReference -> customized Object and * ServiceListenerEntry object */ TrackedService* trackedService; /** * Accessor method for the current TrackedService object. This method is only * intended to be used by the unsynchronized methods which do not modify the * trackedService field. * * @return The current Tracked object. */ TrackedService* Tracked() const; /** * Called by the TrackedService object whenever the set of tracked services is * modified. Clears the cache. */ /* * This method must not be synchronized since it is called by TrackedService while * TrackedService is synchronized. We don't want synchronization interactions * between the listener thread and the user thread. */ void Modified(); /** * Cached ServiceReference for getServiceReference. */ mutable ServiceReference cachedReference; /** * Cached service object for GetService. */ mutable T cachedService; private: inline ServiceTracker* q_func() { return static_cast *>(q_ptr); } inline const ServiceTracker* q_func() const { return static_cast *>(q_ptr); } friend class ServiceTracker; ServiceTracker * const q_ptr; }; US_END_NAMESPACE #include "usServiceTrackerPrivate.tpp" #endif // USSERVICETRACKERPRIVATE_H diff --git a/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.tpp b/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.tpp index 616eec9fe1..940c71f102 100644 --- a/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.tpp +++ b/Modules/CppMicroServices/core/src/service/usServiceTrackerPrivate.tpp @@ -1,155 +1,155 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usTrackedService_p.h" #include "usModuleContext.h" #include "usLDAPFilter.h" #include US_BEGIN_NAMESPACE template const bool ServiceTrackerPrivate::DEBUG_OUTPUT = true; template ServiceTrackerPrivate::ServiceTrackerPrivate( ServiceTracker* st, ModuleContext* context, const ServiceReference& reference, ServiceTrackerCustomizer* customizer) : context(context), customizer(customizer), trackReference(reference), trackedService(nullptr), cachedReference(), cachedService(TTT::DefaultValue()), q_ptr(st) { this->customizer = customizer ? customizer : q_func(); std::stringstream ss; ss << "(" << ServiceConstants::SERVICE_ID() << "=" << any_cast(reference.GetProperty(ServiceConstants::SERVICE_ID())) << ")"; this->listenerFilter = ss.str(); 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(), trackedService(nullptr), cachedReference(), cachedService(TTT::DefaultValue()), q_ptr(st) { this->customizer = customizer ? customizer : q_func(); this->listenerFilter = std::string("(") + US_PREPEND_NAMESPACE(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(), trackedService(nullptr), cachedReference(), cachedService(TTT::DefaultValue()), q_ptr(st) { this->customizer = customizer ? customizer : q_func(); if (context == nullptr) { throw std::invalid_argument("The module context cannot be null."); } } template ServiceTrackerPrivate::~ServiceTrackerPrivate() { } template std::vector > ServiceTrackerPrivate::GetInitialReferences( const std::string& className, const std::string& filterString) { std::vector > result; std::vector refs = context->GetServiceReferences(className, filterString); for(std::vector::const_iterator iter = refs.begin(); iter != refs.end(); ++iter) { ServiceReference ref(*iter); if (ref) { result.push_back(ref); } } return result; } template void ServiceTrackerPrivate::GetServiceReferences_unlocked(std::vector >& refs, TrackedService* t) const { if (t->Size() == 0) { return; } t->GetTracked(refs); } template TrackedService* ServiceTrackerPrivate::Tracked() const { return trackedService; } template void ServiceTrackerPrivate::Modified() { cachedReference = 0; /* clear cached value */ TTT::Dispose(cachedService); /* clear cached value */ US_DEBUG(DEBUG_OUTPUT) << "ServiceTracker::Modified(): " << filter; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usTrackedService.tpp b/Modules/CppMicroServices/core/src/service/usTrackedService.tpp index 6cef9feec1..39293f9e5d 100644 --- a/Modules/CppMicroServices/core/src/service/usTrackedService.tpp +++ b/Modules/CppMicroServices/core/src/service/usTrackedService.tpp @@ -1,128 +1,128 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ US_BEGIN_NAMESPACE template TrackedService::TrackedService(ServiceTracker* serviceTracker, ServiceTrackerCustomizer* customizer) : serviceTracker(serviceTracker), customizer(customizer) { } template void TrackedService::ServiceChanged(const ServiceEvent event) { /* * Check if we had a delayed call (which could happen when we * close). */ if (this->closed) { return; } ServiceReference reference = event.GetServiceReference(InterfaceType()); US_DEBUG(serviceTracker->d->DEBUG_OUTPUT) << "TrackedService::ServiceChanged[" << event.GetType() << "]: " << reference; if (!reference) { return; } switch (event.GetType()) { case ServiceEvent::REGISTERED : case ServiceEvent::MODIFIED : { if (!serviceTracker->d->listenerFilter.empty()) { // service listener added with filter this->Track(reference, event); /* * If the customizer throws an unchecked exception, it * is safe to let it propagate */ } else { // service listener added without filter if (serviceTracker->d->filter.Match(reference)) { this->Track(reference, event); /* * If the customizer throws an unchecked exception, * it is safe to let it propagate */ } else { this->Untrack(reference, event); /* * If the customizer throws an unchecked exception, * it is safe to let it propagate */ } } break; } case ServiceEvent::MODIFIED_ENDMATCH : case ServiceEvent::UNREGISTERING : this->Untrack(reference, event); /* * If the customizer throws an unchecked exception, it is * safe to let it propagate */ break; } } template void TrackedService::Modified() { Superclass::Modified(); /* increment the modification count */ serviceTracker->d->Modified(); } template typename TrackedService::T TrackedService::CustomizerAdding(ServiceReference item, const ServiceEvent& /*related*/) { return customizer->AddingService(item); } template void TrackedService::CustomizerModified(ServiceReference item, const ServiceEvent& /*related*/, T object) { customizer->ModifiedService(item, object); } template void TrackedService::CustomizerRemoved(ServiceReference item, const ServiceEvent& /*related*/, T object) { customizer->RemovedService(item, object); } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/service/usTrackedServiceListener_p.h b/Modules/CppMicroServices/core/src/service/usTrackedServiceListener_p.h index 17847259a3..a147ada055 100644 --- a/Modules/CppMicroServices/core/src/service/usTrackedServiceListener_p.h +++ b/Modules/CppMicroServices/core/src/service/usTrackedServiceListener_p.h @@ -1,51 +1,51 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USTRACKEDSERVICELISTENER_H #define USTRACKEDSERVICELISTENER_H #include "usServiceEvent.h" US_BEGIN_NAMESPACE /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. */ struct TrackedServiceListener { virtual ~TrackedServiceListener() {} /** * 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; }; US_END_NAMESPACE #endif // USTRACKEDSERVICELISTENER_H diff --git a/Modules/CppMicroServices/core/src/service/usTrackedService_p.h b/Modules/CppMicroServices/core/src/service/usTrackedService_p.h index f589353944..6cd601a12e 100644 --- a/Modules/CppMicroServices/core/src/service/usTrackedService_p.h +++ b/Modules/CppMicroServices/core/src/service/usTrackedService_p.h @@ -1,110 +1,110 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USTRACKEDSERVICE_H #define USTRACKEDSERVICE_H #include "usTrackedServiceListener_p.h" #include "usModuleAbstractTracked_p.h" #include "usServiceEvent.h" US_BEGIN_NAMESPACE /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. */ template class TrackedService : public TrackedServiceListener, public ModuleAbstractTracked, TTT, ServiceEvent> { public: typedef typename TTT::TrackedType T; 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) override; private: typedef ModuleAbstractTracked, TTT, ServiceEvent> Superclass; ServiceTracker* serviceTracker; ServiceTrackerCustomizer* customizer; /** * Increment the tracking count and tell the tracker there was a * modification. * * @GuardedBy this */ void Modified() override; /** * 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) override; /** * 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) override ; /** * 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) override ; }; US_END_NAMESPACE #include "usTrackedService.tpp" #endif // USTRACKEDSERVICE_H diff --git a/Modules/CppMicroServices/core/src/util/usAny.cpp b/Modules/CppMicroServices/core/src/util/usAny.cpp index e1ae1e5ce0..d93864bfd5 100644 --- a/Modules/CppMicroServices/core/src/util/usAny.cpp +++ b/Modules/CppMicroServices/core/src/util/usAny.cpp @@ -1,46 +1,46 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usAny.h" US_BEGIN_NAMESPACE std::string any_value_to_string(const Any& any) { return any.ToString(); } std::string any_value_to_json(const Any& val) { return val.ToJSON(); } std::string any_value_to_json(const std::string& val) { return '"' + val + '"'; } std::string any_value_to_json(bool val) { return val ? "true" : "false"; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/util/usAtomicInt_p.h b/Modules/CppMicroServices/core/src/util/usAtomicInt_p.h index 6cdf4ad46a..ad4c026708 100644 --- a/Modules/CppMicroServices/core/src/util/usAtomicInt_p.h +++ b/Modules/CppMicroServices/core/src/util/usAtomicInt_p.h @@ -1,79 +1,79 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USATOMICINT_H #define USATOMICINT_H #include #include "usThreads_p.h" US_BEGIN_NAMESPACE /** * This class acts as an atomic integer. * * The integer value represented by this class can be incremented * and decremented atomically. This is often useful in reference * counting scenarios to minimize locking overhead in multi-threaded * environments. */ class AtomicInt : private AtomicCounter { public: AtomicInt(int value = 0) : AtomicCounter(value) {} /** * Increase the reference count atomically by 1. * * \return true if the new value is unequal to zero, false * otherwise. */ inline bool Ref() const { return AtomicIncrement() != 0; } /** * Decrease the reference count atomically by 1. * * \return true if the new value is unequal to zero, false * otherwise. */ inline bool Deref() const { return AtomicDecrement() != 0; } /** * Returns the current value. * */ inline operator int() const { IntType curr(0); AtomicAssign(curr); return curr; } }; US_END_NAMESPACE #endif // USATOMICINT_H diff --git a/Modules/CppMicroServices/core/src/util/usLDAPProp.cpp b/Modules/CppMicroServices/core/src/util/usLDAPProp.cpp index a7e1c0c916..e7f8686457 100644 --- a/Modules/CppMicroServices/core/src/util/usLDAPProp.cpp +++ b/Modules/CppMicroServices/core/src/util/usLDAPProp.cpp @@ -1,136 +1,136 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usLDAPProp.h" #include US_BEGIN_NAMESPACE LDAPPropExpr::LDAPPropExpr(const std::string& expr) : m_ldapExpr(expr) {} LDAPPropExpr& LDAPPropExpr::operator!() { if (m_ldapExpr.empty()) return *this; m_ldapExpr = "(!" + m_ldapExpr + ")"; return *this; } LDAPPropExpr::operator std::string() const { return m_ldapExpr; } bool LDAPPropExpr::IsNull() const { return m_ldapExpr.empty(); } LDAPProp::LDAPProp(const std::string& property) : m_property(property) { if (m_property.empty()) throw std::invalid_argument("property must not be empty"); } LDAPPropExpr LDAPProp::operator==(const std::string& s) const { if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + "=" + s + ")"); } LDAPPropExpr LDAPProp::operator==(const us::Any& any) const { return operator==(any.ToString()); } LDAPProp::operator LDAPPropExpr () const { return LDAPPropExpr("(" + m_property + "=*)"); } LDAPPropExpr LDAPProp::operator!() const { return LDAPPropExpr("(!(" + m_property + "=*))"); } LDAPPropExpr LDAPProp::operator!=(const std::string& s) const { if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(!(" + m_property + "=" + s + "))"); } LDAPPropExpr LDAPProp::operator!=(const us::Any& any) const { return operator!=(any.ToString()); } LDAPPropExpr LDAPProp::operator>=(const std::string& s) const { if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + ">=" + s + ")"); } LDAPPropExpr LDAPProp::operator>=(const us::Any& any) const { return operator>=(any.ToString()); } LDAPPropExpr LDAPProp::operator<=(const std::string& s) const { if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + "<=" + s + ")"); } LDAPPropExpr LDAPProp::operator<=(const us::Any& any) const { return operator<=(any.ToString()); } LDAPPropExpr LDAPProp::Approx(const std::string& s) const { if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + "~=" + s + ")"); } LDAPPropExpr LDAPProp::Approx(const us::Any& any) const { return Approx(any.ToString()); } US_END_NAMESPACE us::LDAPPropExpr operator&&(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right) { if (left.IsNull()) return right; if (right.IsNull()) return left; return us::LDAPPropExpr("(&" + static_cast(left) + static_cast(right) + ")"); } us::LDAPPropExpr operator||(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right) { if (left.IsNull()) return right; if (right.IsNull()) return left; return us::LDAPPropExpr("(|" + static_cast(left) + static_cast(right) + ")"); } diff --git a/Modules/CppMicroServices/core/src/util/usListenerFunctors_p.h b/Modules/CppMicroServices/core/src/util/usListenerFunctors_p.h index 6578eb7ed4..d2ffe910b2 100644 --- a/Modules/CppMicroServices/core/src/util/usListenerFunctors_p.h +++ b/Modules/CppMicroServices/core/src/util/usListenerFunctors_p.h @@ -1,88 +1,88 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USLISTENERFUNCTORS_P_H #define USLISTENERFUNCTORS_P_H #include #include #include #include #ifdef US_HAVE_STD_FUNCTION #ifdef US_HAVE_FUNCTIONAL_H #include #elif defined(US_HAVE_TR1_FUNCTIONAL_H) #include #endif #define US_FUNCTION_TYPE std::function #elif defined(US_HAVE_TR1_FUNCTION) #ifdef US_HAVE_TR1_FUNCTIONAL_H #include #elif defined(US_HAVE_FUNCTIONAL_H) #include #endif #define US_FUNCTION_TYPE std::tr1::function #endif #define US_MODULE_LISTENER_FUNCTOR US_FUNCTION_TYPE #define US_SERVICE_LISTENER_FUNCTOR US_FUNCTION_TYPE US_BEGIN_NAMESPACE template US_MODULE_LISTENER_FUNCTOR ModuleListenerMemberFunctor(X* x, void (X::*memFn)(const US_PREPEND_NAMESPACE(ModuleEvent))) { return std::bind(std::mem_fn(memFn), x, std::placeholders::_1); } struct ModuleListenerCompare { bool operator()(const std::pair& p1, const std::pair& p2) const { return p1.second == p2.second && p1.first.target() == p2.first.target(); } }; template US_SERVICE_LISTENER_FUNCTOR ServiceListenerMemberFunctor(X* x, void (X::*memFn)(const US_PREPEND_NAMESPACE(ServiceEvent))) { return std::bind(std::mem_fn(memFn), x, std::placeholders::_1); } struct ServiceListenerCompare { bool operator()(const US_SERVICE_LISTENER_FUNCTOR& f1, const US_SERVICE_LISTENER_FUNCTOR& f2) const { return f1.target() == f2.target(); } }; US_END_NAMESPACE US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_SERVICE_LISTENER_FUNCTOR) void(*targetFunc)(const US_PREPEND_NAMESPACE(ServiceEvent)&) = arg.target(); void* targetPtr = nullptr; std::memcpy(&targetPtr, &targetFunc, sizeof(void*)); return US_HASH_FUNCTION(void*, targetPtr); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USLISTENERFUNCTORS_P_H diff --git a/Modules/CppMicroServices/core/src/util/usLog_p.h b/Modules/CppMicroServices/core/src/util/usLog_p.h index 533027b6a0..a31632709b 100644 --- a/Modules/CppMicroServices/core/src/util/usLog_p.h +++ b/Modules/CppMicroServices/core/src/util/usLog_p.h @@ -1,94 +1,94 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USLOG_P_H #define USLOG_P_H #include #include #include #include US_BEGIN_NAMESPACE US_Core_EXPORT void message_output(MsgType, const char* buf); struct LogMsg { LogMsg(MsgType t, const char* file, int ln, const char* func) : type(t), enabled(true), buffer() { buffer << "In " << func << " at " << file << ":" << ln << " : "; } LogMsg() : type(DebugMsg), enabled(false), buffer() {} LogMsg(const LogMsg& other) : type(other.type), enabled(other.enabled), buffer() {} ~LogMsg() { if(enabled) message_output(type, buffer.str().c_str()); } template LogMsg& operator<<(T t) { if (enabled) buffer << t; return *this; } LogMsg& operator()(bool flag) { this->enabled = flag; return *this; } private: MsgType type; bool enabled; std::stringstream buffer; }; US_END_NAMESPACE #if defined(US_ENABLE_DEBUG_OUTPUT) #define US_DEBUG (US_PREPEND_NAMESPACE(ModuleSettings)::GetLogLevel() > US_PREPEND_NAMESPACE(DebugMsg) ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(DebugMsg), __FILE__, __LINE__, __FUNCTION__)) #else #define US_DEBUG true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() #endif #if !defined(US_NO_INFO_OUTPUT) #define US_INFO (US_PREPEND_NAMESPACE(ModuleSettings)::GetLogLevel() > US_PREPEND_NAMESPACE(InfoMsg) ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(InfoMsg), __FILE__, __LINE__, __FUNCTION__)) #else #define US_INFO true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() #endif #if !defined(US_NO_WARNING_OUTPUT) #define US_WARN (US_PREPEND_NAMESPACE(ModuleSettings)::GetLogLevel() > US_PREPEND_NAMESPACE(WarningMsg) ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(WarningMsg), __FILE__, __LINE__, __FUNCTION__)) #else #define US_WARN true ? US_PREPEND_NAMESPACE(LogMsg)() : US_PREPEND_NAMESPACE(LogMsg)() #endif #define US_ERROR US_PREPEND_NAMESPACE(LogMsg)(US_PREPEND_NAMESPACE(ErrorMsg), __FILE__, __LINE__, __FUNCTION__) #endif // USLOG_P_H diff --git a/Modules/CppMicroServices/core/src/util/usSharedLibrary.cpp b/Modules/CppMicroServices/core/src/util/usSharedLibrary.cpp index 032946d706..6e8acb7447 100644 --- a/Modules/CppMicroServices/core/src/util/usSharedLibrary.cpp +++ b/Modules/CppMicroServices/core/src/util/usSharedLibrary.cpp @@ -1,273 +1,273 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usSharedLibrary.h" #include #include #include #include #if defined(US_PLATFORM_POSIX) #include #elif defined(US_PLATFORM_WINDOWS) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #else #error Unsupported platform #endif US_BEGIN_NAMESPACE #ifdef US_PLATFORM_POSIX static const char PATH_SEPARATOR = '/'; #else static const char PATH_SEPARATOR = '\\'; #endif class SharedLibraryPrivate : public SharedData { public: SharedLibraryPrivate() : m_Handle(nullptr) #ifdef US_PLATFORM_WINDOWS , m_Suffix(".dll") #elif defined(US_PLATFORM_APPLE) , m_Suffix(".dylib") , m_Prefix("lib") #else , m_Suffix(".so") , m_Prefix("lib") #endif {} void* m_Handle; std::string m_Name; std::string m_Path; std::string m_FilePath; std::string m_Suffix; std::string m_Prefix; }; SharedLibrary::SharedLibrary() : d(new SharedLibraryPrivate) { } SharedLibrary::SharedLibrary(const SharedLibrary& other) : d(other.d) { } SharedLibrary::SharedLibrary(const std::string& libPath, const std::string& name) : d(new SharedLibraryPrivate) { d->m_Name = name; d->m_Path = libPath; } SharedLibrary::SharedLibrary(const std::string& absoluteFilePath) : d(new SharedLibraryPrivate) { d->m_FilePath = absoluteFilePath; SetFilePath(absoluteFilePath); } SharedLibrary::~SharedLibrary() { } SharedLibrary& SharedLibrary::operator =(const SharedLibrary& other) { d = other.d; return *this; } void SharedLibrary::Load(int flags) { if (d->m_Handle) throw std::logic_error(std::string("Library already loaded: ") + GetFilePath()); std::string libPath = GetFilePath(); #ifdef US_PLATFORM_POSIX d->m_Handle = dlopen(libPath.c_str(), flags); if (!d->m_Handle) { const char* err = dlerror(); throw std::runtime_error(err ? std::string(err) : (std::string("Error loading ") + libPath)); } #else d->m_Handle = LoadLibrary(libPath.c_str()); if (!d->m_Handle) { std::string errMsg = "Loading "; errMsg.append(libPath).append("failed with error: ").append(GetLastErrorStr()); throw std::runtime_error(errMsg); } #endif } void SharedLibrary::Load() { #ifdef US_PLATFORM_POSIX #ifdef US_GCC_RTTI_WORKAROUND_NEEDED Load(RTLD_LAZY | RTLD_GLOBAL); #else Load(RTLD_LAZY | RTLD_LOCAL); #endif #else Load(0); #endif } void SharedLibrary::Unload() { if (d->m_Handle) { #ifdef US_PLATFORM_POSIX if (dlclose(d->m_Handle)) { const char* err = dlerror(); throw std::runtime_error(err ? std::string(err) : (std::string("Error unloading ") + GetLibraryPath())); } #else if (!FreeLibrary((HMODULE)d->m_Handle)) { std::string errMsg = "Unloading "; errMsg.append(GetLibraryPath()).append("failed with error: ").append(GetLastErrorStr()); throw std::runtime_error(errMsg); } #endif d->m_Handle = nullptr; } } void SharedLibrary::SetName(const std::string& name) { if (IsLoaded() || !d->m_FilePath.empty()) return; d.Detach(); d->m_Name = name; } std::string SharedLibrary::GetName() const { return d->m_Name; } std::string SharedLibrary::GetFilePath(const std::string& name) const { if (!d->m_FilePath.empty()) return d->m_FilePath; return GetLibraryPath() + PATH_SEPARATOR + GetPrefix() + name + GetSuffix(); } void SharedLibrary::SetFilePath(const std::string& absoluteFilePath) { if (IsLoaded()) return; d.Detach(); d->m_FilePath = absoluteFilePath; std::string name = d->m_FilePath; std::size_t pos = d->m_FilePath.find_last_of(PATH_SEPARATOR); if (pos != std::string::npos) { d->m_Path = d->m_FilePath.substr(0, pos); name = d->m_FilePath.substr(pos+1); } else { d->m_Path.clear(); } if (name.size() >= d->m_Prefix.size() && name.compare(0, d->m_Prefix.size(), d->m_Prefix) == 0) { name = name.substr(d->m_Prefix.size()); } if (name.size() >= d->m_Suffix.size() && name.compare(name.size()-d->m_Suffix.size(), d->m_Suffix.size(), d->m_Suffix) == 0) { name = name.substr(0, name.size()-d->m_Suffix.size()); } d->m_Name = name; } std::string SharedLibrary::GetFilePath() const { return GetFilePath(d->m_Name); } void SharedLibrary::SetLibraryPath(const std::string& path) { if (IsLoaded() || !d->m_FilePath.empty()) return; d.Detach(); d->m_Path = path; } std::string SharedLibrary::GetLibraryPath() const { return d->m_Path; } void SharedLibrary::SetSuffix(const std::string& suffix) { if (IsLoaded() || !d->m_FilePath.empty()) return; d.Detach(); d->m_Suffix = suffix; } std::string SharedLibrary::GetSuffix() const { return d->m_Suffix; } void SharedLibrary::SetPrefix(const std::string& prefix) { if (IsLoaded() || !d->m_FilePath.empty()) return; d.Detach(); d->m_Prefix = prefix; } std::string SharedLibrary::GetPrefix() const { return d->m_Prefix; } void* SharedLibrary::GetHandle() const { return d->m_Handle; } bool SharedLibrary::IsLoaded() const { return d->m_Handle != nullptr; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/util/usStaticInit_p.h b/Modules/CppMicroServices/core/src/util/usStaticInit_p.h index 72011ff32b..c52a02c45e 100644 --- a/Modules/CppMicroServices/core/src/util/usStaticInit_p.h +++ b/Modules/CppMicroServices/core/src/util/usStaticInit_p.h @@ -1,171 +1,171 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ /*============================================================================ Extracted from qglobal.h from Qt 4.7.3 and adapted for CppMicroServices. Original copyright (c) Nokia Corporation. Usage covered by the GNU Lesser General Public License version 2.1 -(http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and the Nokia Qt +(https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and the Nokia Qt LGPL Exception version 1.1 (file LGPL_EXCEPTION.txt in Qt 4.7.3 package). ============================================================================*/ #ifndef US_STATIC_INIT_H #define US_STATIC_INIT_H #include "usThreads_p.h" US_BEGIN_NAMESPACE // POD for US_GLOBAL_STATIC template class GlobalStatic : public MultiThreaded<> { public: GlobalStatic(T* p = nullptr, bool destroyed = false) : pointer(p), destroyed(destroyed) {} T* pointer; bool destroyed; private: // purposely not implemented GlobalStatic(const GlobalStatic&); GlobalStatic& operator=(const GlobalStatic&); }; template struct DefaultGlobalStaticDeleter { void operator()(GlobalStatic& globalStatic) const { delete globalStatic.pointer; globalStatic.pointer = nullptr; globalStatic.destroyed = true; } }; // Created as a function-local static to delete a GlobalStatic template class Deleter = DefaultGlobalStaticDeleter> class GlobalStaticDeleter { public: GlobalStatic &globalStatic; GlobalStaticDeleter(GlobalStatic &_globalStatic) : globalStatic(_globalStatic) { } inline ~GlobalStaticDeleter() { Deleter deleter; deleter(globalStatic); } }; US_END_NAMESPACE #define US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static US_PREPEND_NAMESPACE(GlobalStatic)& this_##NAME() \ { \ static US_PREPEND_NAMESPACE(GlobalStatic) l; \ return l; \ } #define US_GLOBAL_STATIC(TYPE, NAME) \ US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE; \ bool ok = false; \ { \ US_PREPEND_NAMESPACE(GlobalStatic)::Lock lock(this_##NAME()); \ US_UNUSED(lock); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ } \ if (!ok) \ delete x; \ else \ static US_PREPEND_NAMESPACE(GlobalStaticDeleter) cleanup(this_##NAME()); \ } \ return this_##NAME().pointer; \ } #define US_GLOBAL_STATIC_WITH_DELETER(TYPE, NAME, DELETER) \ US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE; \ bool ok = false; \ { \ US_PREPEND_NAMESPACE(GlobalStatic)::Lock lock(this_##NAME()); \ US_UNUSED(lock); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ } \ if (!ok) \ delete x; \ else \ static US_PREPEND_NAMESPACE(GlobalStaticDeleter) cleanup(this_##NAME()); \ } \ return this_##NAME().pointer; \ } #define US_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ US_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE ARGS; \ bool ok = false; \ { \ US_PREPEND_NAMESPACE(GlobalStatic)::Lock lock(this_##NAME()); \ US_UNUSED(lock); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ } \ if (!ok) \ delete x; \ else \ static US_PREPEND_NAMESPACE(GlobalStaticDeleter) cleanup(this_##NAME()); \ } \ return this_##NAME().pointer; \ } #endif // US_STATIC_INIT_H diff --git a/Modules/CppMicroServices/core/src/util/usThreads_p.h b/Modules/CppMicroServices/core/src/util/usThreads_p.h index 9eaeca1d4e..c6f1f5afc8 100644 --- a/Modules/CppMicroServices/core/src/util/usThreads_p.h +++ b/Modules/CppMicroServices/core/src/util/usThreads_p.h @@ -1,329 +1,329 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTHREADINGMODEL_H #define USTHREADINGMODEL_H #include #ifdef US_ENABLE_THREADING_SUPPORT // Atomic compiler intrinsics #if defined(US_PLATFORM_APPLE) // OSAtomic.h optimizations only used in 10.5 and later, deprecated in 10.12 #include #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 && MAC_OS_X_VERSION_MAX_ALLOWED < 101200 #include #define US_ATOMIC_OPTIMIZATION_APPLE #endif #elif defined(__GLIBCPP__) || defined(__GLIBCXX__) #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) # include #else # include #endif #define US_ATOMIC_OPTIMIZATION_GNUC #endif // Mutex support #ifdef US_PLATFORM_WINDOWS #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef NOMINMAX #define NOMINMAX #endif #include #define US_THREADS_MUTEX(x) HANDLE (x); #define US_THREADS_MUTEX_INIT(x) #define US_THREADS_MUTEX_CTOR(x) : x(::CreateMutex(nullptr, FALSE, nullptr)) #define US_THREADS_MUTEX_DELETE(x) ::CloseHandle (x) #define US_THREADS_MUTEX_LOCK(x) ::WaitForSingleObject (x, INFINITE) #define US_THREADS_MUTEX_UNLOCK(x) ::ReleaseMutex (x) #define US_THREADS_LONG LONG #define US_ATOMIC_OPTIMIZATION #define US_ATOMIC_INCREMENT(x) IntType n = InterlockedIncrement(x) #define US_ATOMIC_DECREMENT(x) IntType n = InterlockedDecrement(x) #define US_ATOMIC_ASSIGN(l, r) InterlockedExchange(l, r) #elif defined(US_PLATFORM_POSIX) #include #define US_THREADS_MUTEX(x) pthread_mutex_t x; #define US_THREADS_MUTEX_INIT(x) ::pthread_mutex_init(&x, 0) #define US_THREADS_MUTEX_CTOR(x) : x() #define US_THREADS_MUTEX_DELETE(x) ::pthread_mutex_destroy (&x) #define US_THREADS_MUTEX_LOCK(x) ::pthread_mutex_lock (&x) #define US_THREADS_MUTEX_UNLOCK(x) ::pthread_mutex_unlock (&x) #define US_ATOMIC_OPTIMIZATION #if defined(US_ATOMIC_OPTIMIZATION_APPLE) #if defined (__LP64__) && __LP64__ #define US_THREADS_LONG volatile int64_t #define US_ATOMIC_INCREMENT(x) IntType n = OSAtomicIncrement64Barrier(x) #define US_ATOMIC_DECREMENT(x) IntType n = OSAtomicDecrement64Barrier(x) #define US_ATOMIC_ASSIGN(l, v) OSAtomicCompareAndSwap64Barrier(*l, v, l) #else #define US_THREADS_LONG volatile int32_t #define US_ATOMIC_INCREMENT(x) IntType n = OSAtomicIncrement32Barrier(x) #define US_ATOMIC_DECREMENT(x) IntType n = OSAtomicDecrement32Barrier(x) #define US_ATOMIC_ASSIGN(l, v) OSAtomicCompareAndSwap32Barrier(*l, v, l) #endif #elif defined(US_ATOMIC_OPTIMIZATION_GNUC) #define US_THREADS_LONG _Atomic_word #define US_ATOMIC_INCREMENT(x) IntType n = __sync_add_and_fetch(x, 1) #define US_ATOMIC_DECREMENT(x) IntType n = __sync_add_and_fetch(x, -1) #define US_ATOMIC_ASSIGN(l, v) __sync_val_compare_and_swap(l, *l, v) #else #define US_THREADS_LONG long #undef US_ATOMIC_OPTIMIZATION #define US_ATOMIC_INCREMENT(x) m_AtomicMtx.Lock(); \ IntType n = ++(*x); \ m_AtomicMtx.Unlock() #define US_ATOMIC_DECREMENT(x) m_AtomicMtx.Lock(); \ IntType n = --(*x); \ m_AtomicMtx.Unlock() #define US_ATOMIC_ASSIGN(l, v) m_AtomicMtx.Lock(); \ *l = v; \ m_AtomicMtx.Unlock() #endif #endif #else // single threaded #define US_THREADS_MUTEX(x) #define US_THREADS_MUTEX_INIT(x) #define US_THREADS_MUTEX_CTOR(x) #define US_THREADS_MUTEX_DELETE(x) #define US_THREADS_MUTEX_LOCK(x) #define US_THREADS_MUTEX_UNLOCK(x) #define US_THREADS_LONG int #define US_ATOMIC_INCREMENT(x) IntType n = ++(*x); #define US_ATOMIC_DECREMENT(x) IntType n = --(*x); #define US_ATOMIC_ASSIGN(l, r) *l = r; #endif US_BEGIN_NAMESPACE class Mutex { public: Mutex() US_THREADS_MUTEX_CTOR(m_Mtx) { US_THREADS_MUTEX_INIT(m_Mtx); } ~Mutex() { US_THREADS_MUTEX_DELETE(m_Mtx); } void Lock() { US_THREADS_MUTEX_LOCK(m_Mtx); } void Unlock() { US_THREADS_MUTEX_UNLOCK(m_Mtx); } private: template friend class WaitCondition; // Copy-constructor not implemented. Mutex(const Mutex &); // Copy-assignement operator not implemented. Mutex & operator = (const Mutex &); US_THREADS_MUTEX(m_Mtx) }; class MutexLock { public: typedef Mutex MutexType; MutexLock(MutexType& mtx) : m_Mtx(&mtx) { m_Mtx->Lock(); } ~MutexLock() { m_Mtx->Unlock(); } private: MutexType* m_Mtx; // purposely not implemented MutexLock(const MutexLock&); MutexLock& operator=(const MutexLock&); }; class AtomicCounter { public: typedef US_THREADS_LONG IntType; AtomicCounter(int value = 0) : m_Counter(value) {} IntType AtomicIncrement() const { US_ATOMIC_INCREMENT(&m_Counter); return n; } IntType AtomicIncrement(volatile IntType& lval) const { US_ATOMIC_INCREMENT(&lval); return n; } IntType AtomicDecrement() const { US_ATOMIC_DECREMENT(&m_Counter); return n; } IntType AtomicDecrement(volatile IntType& lval) const { US_ATOMIC_DECREMENT(&lval); return n; } void AtomicAssign(volatile IntType& lval) const { US_ATOMIC_ASSIGN(&lval, m_Counter); } void AtomicAssign(volatile IntType& lval, const IntType val) const { US_ATOMIC_ASSIGN(&lval, val); } mutable IntType m_Counter; private: #if !defined(US_ATOMIC_OPTIMIZATION) mutable Mutex m_AtomicMtx; #endif }; class MutexLockingStrategy { public: MutexLockingStrategy() #ifdef US_ENABLE_THREADING_SUPPORT : m_Mtx() #endif {} MutexLockingStrategy(const MutexLockingStrategy&) #ifdef US_ENABLE_THREADING_SUPPORT : m_Mtx() #endif {} class Lock; friend class Lock; class Lock { public: #ifdef US_ENABLE_THREADING_SUPPORT // Lock object explicit Lock(const MutexLockingStrategy& host) : m_Host(host) { m_Host.m_Mtx.Lock(); } // Lock object explicit Lock(const MutexLockingStrategy* host) : m_Host(*host) { m_Host.m_Mtx.Lock(); } // Unlock object ~Lock() { m_Host.m_Mtx.Unlock(); } #else explicit Lock(const MutexLockingStrategy&) {} explicit Lock(const MutexLockingStrategy*) {} #endif private: // private by design Lock(); Lock(const Lock&); Lock& operator=(const Lock&); #ifdef US_ENABLE_THREADING_SUPPORT const MutexLockingStrategy& m_Host; #endif }; protected: #ifdef US_ENABLE_THREADING_SUPPORT mutable Mutex m_Mtx; #endif }; class NoLockingStrategy { }; US_END_NAMESPACE #include US_BEGIN_NAMESPACE template class WaitConditionStrategy = NoWaitCondition > class MultiThreaded : public LockingStrategy, public WaitConditionStrategy > { friend class WaitConditionStrategy >; }; US_END_NAMESPACE #endif // USTHREADINGMODEL_H diff --git a/Modules/CppMicroServices/core/src/util/usUtils.cpp b/Modules/CppMicroServices/core/src/util/usUtils.cpp index 4e01fb9ef0..507d6d2e70 100644 --- a/Modules/CppMicroServices/core/src/util/usUtils.cpp +++ b/Modules/CppMicroServices/core/src/util/usUtils.cpp @@ -1,350 +1,350 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usUtils_p.h" #include "usLog_p.h" #include "usModuleInfo.h" #include "usModuleSettings.h" #include #include #include #include #include #ifdef US_PLATFORM_POSIX #include #include #include #include #else #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include "dirent_win32.h" #endif //------------------------------------------------------------------- // Module auto-loading //------------------------------------------------------------------- namespace { #if !defined(US_PLATFORM_LINUX) std::string library_suffix() { #ifdef US_PLATFORM_WINDOWS return ".dll"; #elif defined(US_PLATFORM_APPLE) return ".dylib"; #else return ".so"; #endif } #endif #ifdef US_PLATFORM_POSIX const char DIR_SEP = '/'; bool load_impl(const std::string& modulePath) { void* handle = dlopen(modulePath.c_str(), RTLD_NOW | RTLD_LOCAL); if (handle == nullptr) { US_WARN << dlerror(); } return (handle != nullptr); } #elif defined(US_PLATFORM_WINDOWS) const char DIR_SEP = '\\'; bool load_impl(const std::string& modulePath) { void* handle = LoadLibrary(modulePath.c_str()); if (handle == nullptr) { US_WARN << us::GetLastErrorStr(); } return (handle != nullptr); } #else #ifdef US_ENABLE_AUTOLOADING_SUPPORT #error "Missing load_impl implementation for this platform." #else bool load_impl(const std::string&) { return false; } #endif #endif } US_BEGIN_NAMESPACE std::vector AutoLoadModulesFromPath(const std::string& absoluteBasePath, const std::string& subDir) { std::vector loadedModules; std::string loadPath = absoluteBasePath + DIR_SEP + subDir; DIR* dir = opendir(loadPath.c_str()); #ifdef CMAKE_INTDIR // Try intermediate output directories if (dir == nullptr) { std::size_t indexOfLastSeparator = absoluteBasePath.find_last_of(DIR_SEP); if (indexOfLastSeparator != std::string::npos) { std::string intermediateDir = absoluteBasePath.substr(indexOfLastSeparator+1); bool equalSubDir = intermediateDir.size() == std::strlen(CMAKE_INTDIR); for (std::size_t i = 0; equalSubDir && i < intermediateDir.size(); ++i) { if (std::tolower(intermediateDir[i]) != std::tolower(CMAKE_INTDIR[i])) { equalSubDir = false; } } if (equalSubDir) { loadPath = absoluteBasePath.substr(0, indexOfLastSeparator+1) + subDir + DIR_SEP + CMAKE_INTDIR; dir = opendir(loadPath.c_str()); } } } #endif if (dir != nullptr) { struct dirent *ent = nullptr; while ((ent = readdir(dir)) != nullptr) { bool loadFile = true; #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type != DT_UNKNOWN && ent->d_type != DT_REG) { loadFile = false; } #endif std::string entryFileName(ent->d_name); // On Linux, library file names can have version numbers appended. On other platforms, we // check the file ending. This could be refined for Linux in the future. #if !defined(US_PLATFORM_LINUX) if (entryFileName.rfind(library_suffix()) != (entryFileName.size() - library_suffix().size())) { loadFile = false; } #endif if (!loadFile) continue; std::string libPath = loadPath; if (!libPath.empty() && libPath.find_last_of(DIR_SEP) != libPath.size() -1) { libPath += DIR_SEP; } libPath += entryFileName; US_DEBUG << "Auto-loading module " << libPath; if (!load_impl(libPath)) { US_WARN << "Auto-loading of module " << libPath << " failed."; } else { loadedModules.push_back(libPath); } } closedir(dir); } return loadedModules; } std::vector AutoLoadModules(const ModuleInfo& moduleInfo) { std::vector loadedModules; if (moduleInfo.autoLoadDir.empty()) { return loadedModules; } ModuleSettings::PathList autoLoadPaths = ModuleSettings::GetAutoLoadPaths(); std::size_t indexOfLastSeparator = moduleInfo.location.find_last_of(DIR_SEP); std::string moduleBasePath = moduleInfo.location.substr(0, indexOfLastSeparator); for (ModuleSettings::PathList::iterator i = autoLoadPaths.begin(); i != autoLoadPaths.end(); ++i) { if (*i == ModuleSettings::CURRENT_MODULE_PATH()) { // Load all modules from a directory located relative to this modules location // and named after this modules library name. *i = moduleBasePath; } } // We could have introduced a duplicate above, so remove it. std::sort(autoLoadPaths.begin(), autoLoadPaths.end()); autoLoadPaths.erase(std::unique(autoLoadPaths.begin(), autoLoadPaths.end()), autoLoadPaths.end()); for (ModuleSettings::PathList::iterator i = autoLoadPaths.begin(); i != autoLoadPaths.end(); ++i) { if (i->empty()) continue; std::vector paths = AutoLoadModulesFromPath(*i, moduleInfo.autoLoadDir); loadedModules.insert(loadedModules.end(), paths.begin(), paths.end()); } return loadedModules; } US_END_NAMESPACE //------------------------------------------------------------------- // Error handling //------------------------------------------------------------------- US_BEGIN_NAMESPACE std::string GetLastErrorStr() { #ifdef US_PLATFORM_POSIX return std::string(strerror(errno)); #else // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, nullptr ); std::string errMsg((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return errMsg; #endif } static MsgHandler handler = nullptr; MsgHandler installMsgHandler(MsgHandler h) { MsgHandler old = handler; handler = h; return old; } void message_output(MsgType msgType, const char *buf) { if (handler) { (*handler)(msgType, buf); } else { fprintf(stderr, "%s\n", buf); fflush(stderr); } if (msgType == ErrorMsg) { #if defined(_MSC_VER) && !defined(NDEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) // get the current report mode int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW); _CrtSetReportMode(_CRT_ERROR, reportMode); int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, CppMicroServices_VERSION_STR, buf); if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW) return; // ignore else if (ret == 1) _CrtDbgBreak(); #endif #ifdef US_PLATFORM_POSIX abort(); // trap; generates core dump #else exit(1); // goodbye cruel world #endif } } #ifdef US_HAVE_CXXABI_H #include #endif US_Core_EXPORT ::std::string GetDemangledName(const ::std::type_info& typeInfo) { ::std::string result; #ifdef US_HAVE_CXXABI_H int status = 0; char* demangled = abi::__cxa_demangle(typeInfo.name(), nullptr, nullptr, &status); if (demangled && status == 0) { result = demangled; free(demangled); } #elif defined(US_PLATFORM_WINDOWS) const char* demangled = typeInfo.name(); if (demangled != nullptr) { result = demangled; // remove "struct" qualifiers std::size_t pos = 0; while (pos != std::string::npos) { if ((pos = result.find("struct ", pos)) != std::string::npos) { result = result.substr(0, pos) + result.substr(pos + 7); pos += 8; } } // remove "class" qualifiers pos = 0; while (pos != std::string::npos) { if ((pos = result.find("class ", pos)) != std::string::npos) { result = result.substr(0, pos) + result.substr(pos + 6); pos += 7; } } } #else (void)typeInfo; #endif return result; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/src/util/usUtils_p.h b/Modules/CppMicroServices/core/src/util/usUtils_p.h index 34e2bc3a00..216e0f84e0 100644 --- a/Modules/CppMicroServices/core/src/util/usUtils_p.h +++ b/Modules/CppMicroServices/core/src/util/usUtils_p.h @@ -1,53 +1,53 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USUTILS_H #define USUTILS_H #include #include #include //------------------------------------------------------------------- // Module auto-loading //------------------------------------------------------------------- US_BEGIN_NAMESPACE struct ModuleInfo; std::vector AutoLoadModules(const ModuleInfo& moduleInfo); US_END_NAMESPACE //------------------------------------------------------------------- // Error handling //------------------------------------------------------------------- US_BEGIN_NAMESPACE US_Core_EXPORT std::string GetLastErrorStr(); US_END_NAMESPACE #endif // USUTILS_H diff --git a/Modules/CppMicroServices/core/src/util/usWaitCondition_p.h b/Modules/CppMicroServices/core/src/util/usWaitCondition_p.h index f58201eb69..a020bd1391 100644 --- a/Modules/CppMicroServices/core/src/util/usWaitCondition_p.h +++ b/Modules/CppMicroServices/core/src/util/usWaitCondition_p.h @@ -1,378 +1,376 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 USWAITCONDITION_P_H #define USWAITCONDITION_P_H #include "usCoreConfig.h" #include "usLog_p.h" #include "usUtils_p.h" #include "usThreads_p.h" #ifdef US_PLATFORM_POSIX #include #include #endif US_BEGIN_NAMESPACE /** * \brief A thread synchronization object used to suspend execution until some * condition on shared data is met. * * A thread calls Wait() to suspend its execution until the condition is * met. Each call to Notify() from an executing thread will then cause a single * waiting thread to be released. A call to Notify() means, "signal * that the condition is true." NotifyAll() releases all threads waiting on * the condition variable. * * The WaitCondition implementation is consistent with the standard * definition and use of condition variables in pthreads and other common * thread libraries. * * IMPORTANT: A condition variable always requires an associated mutex * object. The mutex object is used to avoid a dangerous race condition when * Wait() and Notify() are called simultaneously from two different * threads. * * On systems using pthreads, this implementation abstracts the * standard calls to the pthread condition variable. On Win32 * systems, there is no system provided condition variable. This * class implements a condition variable using a critical section, a * semphore, an event and a number of counters. The implementation is * almost an extract translation of the implementation presented by * Douglas C Schmidt and Irfan Pyarali in "Strategies for Implementing - * POSIX Condition Variables on Win32". This article can be found at - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - * + * POSIX Condition Variables on Win32". */ template class WaitCondition { public: WaitCondition(); ~WaitCondition(); bool Wait(unsigned long time = 0); /** Notify that the condition is true and release one waiting thread */ void Notify(); /** Notify that the condition is true and release all waiting threads */ void NotifyAll(); private: // purposely not implemented WaitCondition(const WaitCondition& other); const WaitCondition& operator=(const WaitCondition&); #ifdef US_ENABLE_THREADING_SUPPORT /** Suspend execution of this thread until the condition is signaled. The * argument is a SimpleMutex object that must be locked prior to calling * this method. */ bool Wait(Mutex& mutex, unsigned long time = 0); bool Wait(Mutex* mutex, unsigned long time = 0); #ifdef US_PLATFORM_POSIX pthread_cond_t m_WaitCondition; #else int m_NumberOfWaiters; // number of waiting threads CRITICAL_SECTION m_NumberOfWaitersLock; // Serialize access to // m_NumberOfWaiters HANDLE m_Semaphore; // Semaphore to queue threads HANDLE m_WaitersAreDone; // Auto-reset event used by the // broadcast/signal thread to // wait for all the waiting // threads to wake up and // release the semaphore std::size_t m_WasNotifyAll; // Keeps track of whether we // were broadcasting or signaling #endif #endif // US_ENABLE_THREADING_SUPPORT }; template class NoWaitCondition { public: NoWaitCondition() {} private: // purposely not implemented NoWaitCondition(const NoWaitCondition& other); const NoWaitCondition& operator=(const NoWaitCondition&); }; // ------------------------------------------------------------------------ // WaitCondition implementation // ------------------------------------------------------------------------ #ifdef US_ENABLE_THREADING_SUPPORT template WaitCondition::WaitCondition() { #ifdef US_PLATFORM_POSIX pthread_cond_init(&m_WaitCondition, nullptr); #else m_NumberOfWaiters = 0; m_WasNotifyAll = 0; m_Semaphore = CreateSemaphore(0, // no security 0, // initial value 0x7fffffff, // max count 0); // unnamed InitializeCriticalSection(&m_NumberOfWaitersLock); m_WaitersAreDone = CreateEvent(0, // no security FALSE, // auto-reset FALSE, // non-signaled initially 0 ); // unnamed #endif } template WaitCondition::~WaitCondition() { #ifdef US_PLATFORM_POSIX pthread_cond_destroy(&m_WaitCondition); #else CloseHandle(m_Semaphore); CloseHandle(m_WaitersAreDone); DeleteCriticalSection(&m_NumberOfWaitersLock); #endif } template bool WaitCondition::Wait(unsigned long time) { return this->Wait(static_cast(this)->m_Mtx, time); } template void WaitCondition::Notify() { #ifdef US_PLATFORM_POSIX pthread_cond_signal(&m_WaitCondition); #else EnterCriticalSection(&m_NumberOfWaitersLock); int haveWaiters = m_NumberOfWaiters > 0; LeaveCriticalSection(&m_NumberOfWaitersLock); // if there were not any waiters, then this is a no-op if (haveWaiters) { ReleaseSemaphore(m_Semaphore, 1, 0); } #endif } template void WaitCondition::NotifyAll() { #ifdef US_PLATFORM_POSIX pthread_cond_broadcast(&m_WaitCondition); #else // This is needed to ensure that m_NumberOfWaiters and m_WasNotifyAll are // consistent EnterCriticalSection(&m_NumberOfWaitersLock); int haveWaiters = 0; if (m_NumberOfWaiters > 0) { // We are broadcasting, even if there is just one waiter... // Record that we are broadcasting, which helps optimize Notify() // for the non-broadcast case m_WasNotifyAll = 1; haveWaiters = 1; } if (haveWaiters) { // Wake up all waiters atomically ReleaseSemaphore(m_Semaphore, m_NumberOfWaiters, 0); LeaveCriticalSection(&m_NumberOfWaitersLock); // Wait for all the awakened threads to acquire the counting // semaphore WaitForSingleObject(m_WaitersAreDone, INFINITE); // This assignment is ok, even without the m_NumberOfWaitersLock held // because no other waiter threads can wake up to access it. m_WasNotifyAll = 0; } else { LeaveCriticalSection(&m_NumberOfWaitersLock); } #endif } template bool WaitCondition::Wait(Mutex* mutex, unsigned long timeoutMillis) { return Wait(*mutex, timeoutMillis); } template bool WaitCondition::Wait(Mutex& mutex, unsigned long timeoutMillis) { #ifdef US_PLATFORM_POSIX struct timespec ts, * pts = nullptr; if (timeoutMillis) { pts = &ts; struct timeval tv; int error = gettimeofday(&tv, nullptr); if (error) { US_ERROR << "gettimeofday error: " << GetLastErrorStr(); return false; } ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; ts.tv_sec += timeoutMillis / 1000; ts.tv_nsec += (timeoutMillis % 1000) * 1000000; ts.tv_sec += ts.tv_nsec / 1000000000; ts.tv_nsec = ts.tv_nsec % 1000000000; } if (pts) { int error = pthread_cond_timedwait(&m_WaitCondition, &mutex.m_Mtx, pts); if (error == 0) { return true; } else { if (error != ETIMEDOUT) { US_ERROR << "pthread_cond_timedwait error: " << GetLastErrorStr(); } return false; } } else { int error = pthread_cond_wait(&m_WaitCondition, &mutex.m_Mtx); if (error) { US_ERROR << "pthread_cond_wait error: " << GetLastErrorStr(); return false; } return true; } #else // Avoid race conditions EnterCriticalSection(&m_NumberOfWaitersLock); m_NumberOfWaiters++; LeaveCriticalSection(&m_NumberOfWaitersLock); DWORD dw; bool result = true; // This call atomically releases the mutex and waits on the // semaphore until signaled dw = SignalObjectAndWait(mutex.m_Mtx, m_Semaphore, timeoutMillis ? timeoutMillis : INFINITE, FALSE); if (dw == WAIT_TIMEOUT) { result = false; } else if (dw == WAIT_FAILED) { result = false; US_ERROR << "SignalObjectAndWait failed: " << GetLastErrorStr(); } // Reacquire lock to avoid race conditions EnterCriticalSection(&m_NumberOfWaitersLock); // We're no longer waiting.... m_NumberOfWaiters--; // Check to see if we're the last waiter after the broadcast int lastWaiter = m_WasNotifyAll && m_NumberOfWaiters == 0; LeaveCriticalSection(&m_NumberOfWaitersLock); // If we're the last waiter thread during this particular broadcast // then let the other threads proceed if (lastWaiter) { // This call atomically signals the m_WaitersAreDone event and waits // until it can acquire the external mutex. This is required to // ensure fairness dw = SignalObjectAndWait(m_WaitersAreDone, mutex.m_Mtx, INFINITE, FALSE); if (result && dw == WAIT_FAILED) { result = false; US_ERROR << "SignalObjectAndWait failed: " << GetLastErrorStr(); } } else { // Always regain the external mutex since that's the guarentee we // give to our callers dw = WaitForSingleObject(mutex.m_Mtx, INFINITE); if (result && dw == WAIT_FAILED) { result = false; US_ERROR << "SignalObjectAndWait failed: " << GetLastErrorStr(); } } return result; #endif } #else template WaitCondition::WaitCondition() {} template WaitCondition::~WaitCondition() {} template bool WaitCondition::Wait(unsigned long) { return true; } template void WaitCondition::Notify() {} template void WaitCondition::NotifyAll() {} #endif US_END_NAMESPACE #endif // USWAITCONDITION_P_H diff --git a/Modules/CppMicroServices/core/test/modules/libA/usTestModuleA.cpp b/Modules/CppMicroServices/core/test/modules/libA/usTestModuleA.cpp index 556c1acb04..761c53c507 100644 --- a/Modules/CppMicroServices/core/test/modules/libA/usTestModuleA.cpp +++ b/Modules/CppMicroServices/core/test/modules/libA/usTestModuleA.cpp @@ -1,77 +1,77 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usTestModuleAService.h" #include #include #include US_BEGIN_NAMESPACE struct TestModuleA : public TestModuleAService { TestModuleA(ModuleContext* mc) { US_INFO << "Registering TestModuleAService"; sr = mc->RegisterService(this); } void Unregister() { if (sr) { sr.Unregister(); sr = 0; } } private: ServiceRegistration sr; }; class TestModuleAActivator : public ModuleActivator { public: TestModuleAActivator() : s(nullptr) {} ~TestModuleAActivator() override { delete s; } void Load(ModuleContext* context) override { s = new TestModuleA(context); } void Unload(ModuleContext*) override { } private: TestModuleA* s; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleAActivator)) diff --git a/Modules/CppMicroServices/core/test/modules/libA/usTestModuleAService.h b/Modules/CppMicroServices/core/test/modules/libA/usTestModuleAService.h index d7a5ec7dfb..a868692a01 100644 --- a/Modules/CppMicroServices/core/test/modules/libA/usTestModuleAService.h +++ b/Modules/CppMicroServices/core/test/modules/libA/usTestModuleAService.h @@ -1,38 +1,38 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTMODULEASERVICE_H #define USTESTMODULEASERVICE_H #include #include US_BEGIN_NAMESPACE struct TestModuleAService { virtual ~TestModuleAService() {} }; US_END_NAMESPACE #endif // USTESTMODULEASERVICE_H diff --git a/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2.cpp b/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2.cpp index 13fc6a192a..77f546454a 100644 --- a/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2.cpp +++ b/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2.cpp @@ -1,76 +1,76 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usTestModuleA2Service.h" #include #include US_BEGIN_NAMESPACE struct TestModuleA2 : public TestModuleA2Service { TestModuleA2(ModuleContext* mc) { US_INFO << "Registering TestModuleA2Service"; sr = mc->RegisterService(this); } void Unregister() { if (sr) { sr.Unregister(); } } private: ServiceRegistration sr; }; class TestModuleA2Activator : public ModuleActivator { public: TestModuleA2Activator() : s(nullptr) {} ~TestModuleA2Activator() override { delete s; } void Load(ModuleContext* context) override { s = new TestModuleA2(context); } void Unload(ModuleContext* /*context*/) override { s->Unregister(); } private: TestModuleA2* s; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleA2Activator)) diff --git a/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2Service.h b/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2Service.h index 8323712fd0..e975c4e817 100644 --- a/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2Service.h +++ b/Modules/CppMicroServices/core/test/modules/libA2/usTestModuleA2Service.h @@ -1,38 +1,38 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTMODULEA2SERVICE_H #define USTESTMODULEA2SERVICE_H #include #include US_BEGIN_NAMESPACE struct TestModuleA2Service { virtual ~TestModuleA2Service() {} }; US_END_NAMESPACE #endif // USTESTMODULEA2SERVICE_H diff --git a/Modules/CppMicroServices/core/test/modules/libAL/libAL_1/usTestModuleAL_1.cpp b/Modules/CppMicroServices/core/test/modules/libAL/libAL_1/usTestModuleAL_1.cpp index d2892ff0a8..aecb75f978 100644 --- a/Modules/CppMicroServices/core/test/modules/libAL/libAL_1/usTestModuleAL_1.cpp +++ b/Modules/CppMicroServices/core/test/modules/libAL/libAL_1/usTestModuleAL_1.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include US_BEGIN_NAMESPACE struct US_ABI_EXPORT TestModuleAL_1_Dummy { }; US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/test/modules/libAL/usTestModuleAL.cpp b/Modules/CppMicroServices/core/test/modules/libAL/usTestModuleAL.cpp index d5d6b61c24..1d4f6923a2 100644 --- a/Modules/CppMicroServices/core/test/modules/libAL/usTestModuleAL.cpp +++ b/Modules/CppMicroServices/core/test/modules/libAL/usTestModuleAL.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include US_BEGIN_NAMESPACE struct TestModuleAL_Dummy { }; US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/test/modules/libAL2/libAL2_1/usTestModuleAL2_1.cpp b/Modules/CppMicroServices/core/test/modules/libAL2/libAL2_1/usTestModuleAL2_1.cpp index 4f8dd1fcfc..ad5fcf9ee4 100644 --- a/Modules/CppMicroServices/core/test/modules/libAL2/libAL2_1/usTestModuleAL2_1.cpp +++ b/Modules/CppMicroServices/core/test/modules/libAL2/libAL2_1/usTestModuleAL2_1.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include US_BEGIN_NAMESPACE struct US_ABI_EXPORT TestModuleAL2_1_Dummy { }; US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/test/modules/libAL2/usTestModuleAL2.cpp b/Modules/CppMicroServices/core/test/modules/libAL2/usTestModuleAL2.cpp index 139f18cc11..d27c443589 100644 --- a/Modules/CppMicroServices/core/test/modules/libAL2/usTestModuleAL2.cpp +++ b/Modules/CppMicroServices/core/test/modules/libAL2/usTestModuleAL2.cpp @@ -1,30 +1,30 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include US_BEGIN_NAMESPACE struct TestModuleAL2_Dummy { }; US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleB.cpp b/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleB.cpp index afb095675b..e01576e1bc 100644 --- a/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleB.cpp +++ b/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleB.cpp @@ -1,66 +1,66 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usTestModuleBService.h" #include #include #include US_BEGIN_NAMESPACE struct TestModuleB : public TestModuleBService { TestModuleB(ModuleContext* mc) { US_INFO << "Registering TestModuleBService"; mc->RegisterService(this); } }; class TestModuleBActivator : public ModuleActivator { public: TestModuleBActivator() : s(nullptr) {} ~TestModuleBActivator() override { delete s; } void Load(ModuleContext* context) override { s = new TestModuleB(context); } void Unload(ModuleContext*) override { } private: TestModuleB* s; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleBActivator)) US_IMPORT_MODULE(TestModuleImportedByB) diff --git a/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleBService.h b/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleBService.h index 084912a926..d3b82ce5ef 100644 --- a/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleBService.h +++ b/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleBService.h @@ -1,38 +1,38 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTMODULEBSERVICE_H #define USTESTMODULEBSERVICE_H #include #include US_BEGIN_NAMESPACE struct TestModuleBService { virtual ~TestModuleBService() {} }; US_END_NAMESPACE #endif // USTESTMODULEASERVICE_H diff --git a/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp b/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp index 80f6a7bb91..25096f0609 100644 --- a/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp +++ b/Modules/CppMicroServices/core/test/modules/libBWithStatic/usTestModuleImportedByB.cpp @@ -1,64 +1,64 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usTestModuleBService.h" #include #include US_BEGIN_NAMESPACE struct TestModuleImportedByB : public TestModuleBService { TestModuleImportedByB(ModuleContext* mc) { US_INFO << "Registering TestModuleImportedByB"; mc->RegisterService(this); } }; class TestModuleImportedByBActivator : public ModuleActivator { public: TestModuleImportedByBActivator() : s(nullptr) {} ~TestModuleImportedByBActivator() override { delete s; } void Load(ModuleContext* context) override { s = new TestModuleImportedByB(context); } void Unload(ModuleContext*) override { } private: TestModuleImportedByB* s; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleImportedByBActivator)) diff --git a/Modules/CppMicroServices/core/test/modules/libH/usTestModuleH.cpp b/Modules/CppMicroServices/core/test/modules/libH/usTestModuleH.cpp index 1effdf75de..ad522d7766 100644 --- a/Modules/CppMicroServices/core/test/modules/libH/usTestModuleH.cpp +++ b/Modules/CppMicroServices/core/test/modules/libH/usTestModuleH.cpp @@ -1,140 +1,140 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include US_BEGIN_NAMESPACE struct TestModuleH { virtual ~TestModuleH() {} }; struct TestModuleH2 { virtual ~TestModuleH2() {} }; class TestProduct : public TestModuleH { // Module* caller; public: TestProduct(Module* /*caller*/) //: caller(caller) {} }; class TestProduct2 : public TestProduct, public TestModuleH2 { public: TestProduct2(Module* caller) : TestProduct(caller) {} }; class TestModuleHPrototypeServiceFactory : public PrototypeServiceFactory { std::map > fcbind; // Map calling module with implementation public: InterfaceMap GetService(Module* caller, const ServiceRegistrationBase& /*sReg*/) override { std::cout << "GetService (prototype) in H" << std::endl; TestProduct2* product = new TestProduct2(caller); fcbind[caller->GetModuleId()].push_back(product); return MakeInterfaceMap(product); } void UngetService(Module* caller, const ServiceRegistrationBase& /*sReg*/, const InterfaceMap& service) override { TestProduct2* product = dynamic_cast(ExtractInterface(service)); delete product; fcbind[caller->GetModuleId()].remove(product); } }; class TestModuleHActivator : public ModuleActivator, public ServiceFactory { std::string thisServiceName; ServiceRegistration factoryService; ServiceRegistration prototypeFactoryService; ModuleContext* mc; std::map fcbind; // Map calling module with implementation TestModuleHPrototypeServiceFactory prototypeFactory; public: TestModuleHActivator() : thisServiceName(us_service_interface_iid()) , mc(nullptr) {} void Load(ModuleContext* mc) override { std::cout << "start in H" << std::endl; this->mc = mc; factoryService = mc->RegisterService(this); prototypeFactoryService = mc->RegisterService(static_cast(&prototypeFactory)); } void Unload(ModuleContext* /*mc*/) override { factoryService.Unregister(); } InterfaceMap GetService(Module* caller, const ServiceRegistrationBase& /*sReg*/) override { std::cout << "GetService in H" << std::endl; TestProduct* product = new TestProduct(caller); fcbind.insert(std::make_pair(caller->GetModuleId(), product)); return MakeInterfaceMap(product); } void UngetService(Module* caller, const ServiceRegistrationBase& /*sReg*/, const InterfaceMap& service) override { TestModuleH* product = ExtractInterface(service); delete product; fcbind.erase(caller->GetModuleId()); } }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(us::TestModuleHActivator) diff --git a/Modules/CppMicroServices/core/test/modules/libM/usTestModuleM.cpp b/Modules/CppMicroServices/core/test/modules/libM/usTestModuleM.cpp index aef358ac73..74340ba8b4 100644 --- a/Modules/CppMicroServices/core/test/modules/libM/usTestModuleM.cpp +++ b/Modules/CppMicroServices/core/test/modules/libM/usTestModuleM.cpp @@ -1,43 +1,43 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include US_BEGIN_NAMESPACE class TestModuleMActivator : public ModuleActivator { public: void Load(ModuleContext*) override { } void Unload(ModuleContext*) override { } }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleMActivator)) diff --git a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleS.cpp b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleS.cpp index f8d444d48b..f3fcce94f9 100644 --- a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleS.cpp +++ b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleS.cpp @@ -1,142 +1,142 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "../../usServiceControlInterface.h" #include "usTestModuleSService0.h" #include "usTestModuleSService1.h" #include "usTestModuleSService2.h" #include "usTestModuleSService3.h" #include #include #include US_BEGIN_NAMESPACE class TestModuleS : public ServiceControlInterface, public TestModuleSService0, public TestModuleSService1, public TestModuleSService2, public TestModuleSService3 { public: TestModuleS(ModuleContext* mc) : mc(mc) { for(int i = 0; i <= 3; ++i) { servregs.push_back(ServiceRegistrationU()); } sreg = mc->RegisterService(this); sciReg = mc->RegisterService(this); } virtual const char* GetNameOfClass() const { return "TestModuleS"; } void ServiceControl(int offset, const std::string& operation, int ranking) override { if (0 <= offset && offset <= 3) { if (operation == "register") { if (!servregs[offset]) { std::stringstream servicename; servicename << SERVICE << offset; InterfaceMap ifm; ifm.insert(std::make_pair(servicename.str(), static_cast(this))); ServiceProperties props; props.insert(std::make_pair(ServiceConstants::SERVICE_RANKING(), Any(ranking))); servregs[offset] = mc->RegisterService(ifm, props); } } if (operation == "unregister") { if (servregs[offset]) { ServiceRegistrationU sr1 = servregs[offset]; sr1.Unregister(); servregs[offset] = 0; } } } } void Unregister() { if (sreg) { sreg.Unregister(); } if (sciReg) { sciReg.Unregister(); } } private: static const std::string SERVICE; // = "us::TestModuleSService" ModuleContext* mc; std::vector servregs; ServiceRegistration sreg; ServiceRegistration sciReg; }; const std::string TestModuleS::SERVICE = "us::TestModuleSService"; class TestModuleSActivator : public ModuleActivator { public: TestModuleSActivator() : s(nullptr) {} ~TestModuleSActivator() override { delete s; } void Load(ModuleContext* context) override { s = new TestModuleS(context); } void Unload(ModuleContext* /*context*/) override { #ifndef US_BUILD_SHARED_LIBS s->Unregister(); #endif } private: TestModuleS* s; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(TestModuleSActivator)) diff --git a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService0.h b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService0.h index c37a109410..44dc7f1d99 100644 --- a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService0.h +++ b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService0.h @@ -1,37 +1,37 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTMODULESSERVICE0_H #define USTESTMODULESSERVICE0_H #include US_BEGIN_NAMESPACE struct TestModuleSService0 { virtual ~TestModuleSService0() {} }; US_END_NAMESPACE #endif // USTESTMODULESSERVICE0_H diff --git a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService1.h b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService1.h index ac37600bfd..ffeb2df967 100644 --- a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService1.h +++ b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService1.h @@ -1,37 +1,37 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTMODULESSERVICE1_H #define USTESTMODULESSERVICE1_H #include US_BEGIN_NAMESPACE struct TestModuleSService1 { virtual ~TestModuleSService1() {} }; US_END_NAMESPACE #endif // USTESTMODULESSERVICE1_H diff --git a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService2.h b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService2.h index c43989d016..c03f19853a 100644 --- a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService2.h +++ b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService2.h @@ -1,37 +1,37 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTMODULESSERVICE2_H #define USTESTMODULESSERVICE2_H #include US_BEGIN_NAMESPACE struct TestModuleSService2 { virtual ~TestModuleSService2() {} }; US_END_NAMESPACE #endif // USTESTMODULESSERVICE0_H diff --git a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService3.h b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService3.h index 2be388b717..76b31a3392 100644 --- a/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService3.h +++ b/Modules/CppMicroServices/core/test/modules/libS/usTestModuleSService3.h @@ -1,37 +1,37 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTMODULESSERVICE3_H #define USTESTMODULESSERVICE3_H #include US_BEGIN_NAMESPACE struct TestModuleSService3 { virtual ~TestModuleSService3() {} }; US_END_NAMESPACE #endif // USTESTMODULESSERVICE0_H diff --git a/Modules/CppMicroServices/core/test/modules/libSL1/usActivatorSL1.cpp b/Modules/CppMicroServices/core/test/modules/libSL1/usActivatorSL1.cpp index d6d38ba2e4..8cd577392b 100644 --- a/Modules/CppMicroServices/core/test/modules/libSL1/usActivatorSL1.cpp +++ b/Modules/CppMicroServices/core/test/modules/libSL1/usActivatorSL1.cpp @@ -1,106 +1,106 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include "usFooService.h" US_BEGIN_NAMESPACE class ActivatorSL1 : public ModuleActivator, public ModulePropsInterface, public ServiceTrackerCustomizer { public: ActivatorSL1() : tracker(nullptr), context(nullptr) { } ~ActivatorSL1() override { delete tracker; } void Load(ModuleContext* context) override { this->context = context; InterfaceMap im = MakeInterfaceMap(this); im.insert(std::make_pair(std::string("ActivatorSL1"), this)); sr = context->RegisterService(im); delete tracker; tracker = new FooTracker(context, this); tracker->Open(); } void Unload(ModuleContext* /*context*/) override { tracker->Close(); } const Properties& GetProperties() const override { return props; } FooService* AddingService(const ServiceReferenceType& reference) override { props["serviceAdded"] = true; FooService* fooService = context->GetService(reference); fooService->foo(); return fooService; } void ModifiedService(const ServiceReferenceType& /*reference*/, FooService* /*service*/) override {} void RemovedService(const ServiceReferenceType& /*reference*/, FooService* /*service*/) override { props["serviceRemoved"] = true; } private: ModulePropsInterface::Properties props; ServiceRegistrationU sr; typedef ServiceTracker FooTracker; FooTracker* tracker; ModuleContext* context; }; // ActivatorSL1 US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(ActivatorSL1)) diff --git a/Modules/CppMicroServices/core/test/modules/libSL1/usFooService.h b/Modules/CppMicroServices/core/test/modules/libSL1/usFooService.h index 3e3d12096d..5dafcd78a6 100644 --- a/Modules/CppMicroServices/core/test/modules/libSL1/usFooService.h +++ b/Modules/CppMicroServices/core/test/modules/libSL1/usFooService.h @@ -1,38 +1,38 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USFOOSERVICE_H #define USFOOSERVICE_H #include US_BEGIN_NAMESPACE struct FooService { virtual ~FooService() {} virtual void foo() = 0; }; US_END_NAMESPACE #endif // USFOOSERVICE_H diff --git a/Modules/CppMicroServices/core/test/modules/libSL3/usActivatorSL3.cpp b/Modules/CppMicroServices/core/test/modules/libSL3/usActivatorSL3.cpp index e1b49c68e7..4fc9a59fef 100644 --- a/Modules/CppMicroServices/core/test/modules/libSL3/usActivatorSL3.cpp +++ b/Modules/CppMicroServices/core/test/modules/libSL3/usActivatorSL3.cpp @@ -1,99 +1,99 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include US_BEGIN_NAMESPACE class ActivatorSL3 : public ModuleActivator, public ModulePropsInterface, public ServiceTrackerCustomizer { public: ActivatorSL3() : tracker(nullptr), context(nullptr) {} ~ActivatorSL3() override { delete tracker; } void Load(ModuleContext* context) override { this->context = context; InterfaceMap im = MakeInterfaceMap(this); im.insert(std::make_pair(std::string("ActivatorSL3"), this)); sr = context->RegisterService(im); delete tracker; tracker = new FooTracker(context, this); tracker->Open(); } void Unload(ModuleContext* /*context*/) override { tracker->Close(); } const ModulePropsInterface::Properties& GetProperties() const override { return props; } FooService* AddingService(const ServiceReferenceType& reference) override { props["serviceAdded"] = true; US_INFO << "SL3: Adding reference =" << reference; FooService* fooService = context->GetService(reference); fooService->foo(); return fooService; } void ModifiedService(const ServiceReferenceType& /*reference*/, FooService* /*service*/) override { } void RemovedService(const ServiceReferenceType& reference, FooService* /*service*/) override { props["serviceRemoved"] = true; US_INFO << "SL3: Removing reference =" << reference; } private: typedef ServiceTracker FooTracker; FooTracker* tracker; ModuleContext* context; ServiceRegistrationU sr; ModulePropsInterface::Properties props; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(ActivatorSL3)) diff --git a/Modules/CppMicroServices/core/test/modules/libSL4/usActivatorSL4.cpp b/Modules/CppMicroServices/core/test/modules/libSL4/usActivatorSL4.cpp index e31548d537..f1e5a1c52a 100644 --- a/Modules/CppMicroServices/core/test/modules/libSL4/usActivatorSL4.cpp +++ b/Modules/CppMicroServices/core/test/modules/libSL4/usActivatorSL4.cpp @@ -1,64 +1,64 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include US_BEGIN_NAMESPACE class ActivatorSL4 : public ModuleActivator, public FooService { public: ~ActivatorSL4() override { } void foo() override { US_INFO << "TestModuleSL4: Doing foo"; } void Load(ModuleContext* context) override { sr = context->RegisterService(this); US_INFO << "TestModuleSL4: Registered " << sr; } void Unload(ModuleContext* /*context*/) override { } private: ServiceRegistration sr; }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(US_PREPEND_NAMESPACE(ActivatorSL4)) diff --git a/Modules/CppMicroServices/core/test/usAnyTest.cpp b/Modules/CppMicroServices/core/test/usAnyTest.cpp index 137db91e44..6b6406eaf2 100644 --- a/Modules/CppMicroServices/core/test/usAnyTest.cpp +++ b/Modules/CppMicroServices/core/test/usAnyTest.cpp @@ -1,147 +1,147 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include "usTestingMacros.h" #include US_USE_NAMESPACE int usAnyTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("AnyTest"); Any anyBool = true; US_TEST_CONDITION(anyBool.Type() == typeid(bool), "Any[bool].Type()") US_TEST_CONDITION(any_cast(anyBool) == true, "any_cast()") US_TEST_CONDITION(anyBool.ToString() == "1", "Any[bool].ToString()") US_TEST_CONDITION(anyBool.ToJSON() == "true", "Any[bool].ToJSON()") anyBool = false; US_TEST_CONDITION(anyBool.ToString() == "0", "Any[bool].ToString()") US_TEST_CONDITION(anyBool.ToJSON() == "false", "Any[bool].ToJSON()") Any anyInt = 13; US_TEST_CONDITION(anyInt.Type() == typeid(int), "Any[int].Type()") US_TEST_CONDITION(any_cast(anyInt) == 13, "any_cast()") US_TEST_CONDITION(anyInt.ToString() == "13", "Any[int].ToString()") US_TEST_CONDITION(anyInt.ToJSON() == "13", "Any[int].ToJSON()") Any anyChar = 'a'; US_TEST_CONDITION(anyChar.Type() == typeid(char), "Any[char].Type()") US_TEST_CONDITION(any_cast(anyChar) == 'a', "any_cast()") US_TEST_CONDITION(anyChar.ToString() == "a", "Any[char].ToString()") US_TEST_CONDITION(anyChar.ToJSON() == "a", "Any[char].ToJSON()") Any anyFloat = 0.2f; US_TEST_CONDITION(anyFloat.Type() == typeid(float), "Any[float].Type()") US_TEST_CONDITION(any_cast(anyFloat) - 0.2f < std::numeric_limits::epsilon(), "any_cast()") US_TEST_CONDITION(anyFloat.ToString() == "0.2", "Any[float].ToString()") US_TEST_CONDITION(anyFloat.ToString() == "0.2", "Any[float].ToJSON()") Any anyDouble = 0.5; US_TEST_CONDITION(anyDouble.Type() == typeid(double), "Any[double].Type()") US_TEST_CONDITION(any_cast(anyDouble) - 0.5 < std::numeric_limits::epsilon(), "any_cast()") US_TEST_CONDITION(anyDouble.ToString() == "0.5", "Any[double].ToString()") US_TEST_CONDITION(anyDouble.ToString() == "0.5", "Any[double].ToJSON()") Any anyString = std::string("hello"); US_TEST_CONDITION(anyString.Type() == typeid(std::string), "Any[std::string].Type()") US_TEST_CONDITION(any_cast(anyString) == "hello", "any_cast()") US_TEST_CONDITION(anyString.ToString() == "hello", "Any[std::string].ToString()") US_TEST_CONDITION(anyString.ToJSON() == "\"hello\"", "Any[std::string].ToJSON()") std::vector vecInts; vecInts.push_back(1); vecInts.push_back(2); Any anyVectorOfInts = vecInts; US_TEST_CONDITION(anyVectorOfInts.Type() == typeid(std::vector), "Any[std::vector].Type()") US_TEST_CONDITION(any_cast >(anyVectorOfInts) == vecInts, "any_cast>()") US_TEST_CONDITION(anyVectorOfInts.ToString() == "[1,2]", "Any[std::vector].ToString()") US_TEST_CONDITION(anyVectorOfInts.ToJSON() == "[1,2]", "Any[std::vector].ToJSON()") std::list listInts; listInts.push_back(1); listInts.push_back(2); Any anyListOfInts = listInts; US_TEST_CONDITION(anyListOfInts.Type() == typeid(std::list), "Any[std::list].Type()") US_TEST_CONDITION(any_cast >(anyListOfInts) == listInts, "any_cast>()") US_TEST_CONDITION(anyListOfInts.ToString() == "[1,2]", "Any[std::list].ToString()") US_TEST_CONDITION(anyListOfInts.ToJSON() == "[1,2]", "Any[std::list].ToJSON()") std::set setInts; setInts.insert(1); setInts.insert(2); Any anySetOfInts = setInts; US_TEST_CONDITION(anySetOfInts.Type() == typeid(std::set), "Any[std::set].Type()") US_TEST_CONDITION(any_cast >(anySetOfInts) == setInts, "any_cast>()") US_TEST_CONDITION(anySetOfInts.ToString() == "[1,2]", "Any[std::set].ToString()") US_TEST_CONDITION(anySetOfInts.ToJSON() == "[1,2]", "Any[std::set].ToJSON()") std::vector vecAny; vecAny.push_back(1); vecAny.push_back(std::string("hello")); Any anyVectorOfAnys = vecAny; US_TEST_CONDITION(anyVectorOfAnys.Type() == typeid(std::vector), "Any[std::vector].Type()") US_TEST_CONDITION(anyVectorOfAnys.ToString() == "[1,hello]", "Any[std::vector].ToString()") US_TEST_CONDITION(anyVectorOfAnys.ToJSON() == "[1,\"hello\"]", "Any[std::vector].ToJSON()") std::list listAny; listAny.push_back(1); listAny.push_back(std::string("hello")); Any anyListOfAnys = listAny; US_TEST_CONDITION(anyListOfAnys.Type() == typeid(std::list), "Any[std::list].Type()") US_TEST_CONDITION(anyListOfAnys.ToString() == "[1,hello]", "Any[std::list].ToString()") US_TEST_CONDITION(anyListOfAnys.ToJSON() == "[1,\"hello\"]", "Any[std::list].ToJSON()") std::map map1; map1["one"] = 1; map1["two"] = 2; Any anyMap1 = map1; US_TEST_CONDITION(anyMap1.Type() == typeid(std::map), "Any[std::map].Type()") US_TEST_CONDITION((any_cast >(anyMap1) == map1), "any_cast>()") US_TEST_CONDITION(anyMap1.ToString() == "{one : 1, two : 2}", "Any[std::map].ToString()") US_TEST_CONDITION(anyMap1.ToJSON() == "{\"one\" : 1, \"two\" : 2}", "Any[std::map].ToJSON()") std::map map2; map2[1] = 0.3; map2[3] = std::string("bye"); Any anyMap2 = map2; US_TEST_CONDITION(anyMap2.Type() == typeid(std::map), "Any[std::map].Type()") US_TEST_CONDITION(anyMap2.ToString() == "{1 : 0.3, 3 : bye}", "Any[std::map].ToString()") US_TEST_CONDITION(anyMap2.ToJSON() == "{\"1\" : 0.3, \"3\" : \"bye\"}", "Any[std::map].ToJSON()") std::map map3; map3["number"] = 5; std::vector numbers; numbers.push_back(9); numbers.push_back(8); numbers.push_back(7); map3["vector"] = numbers; map3["map"] = map2; Any anyMap3 = map3; US_TEST_CONDITION(anyMap3.Type() == typeid(std::map), "Any[std::map].Type()") US_TEST_CONDITION(anyMap3.ToString() == "{map : {1 : 0.3, 3 : bye}, number : 5, vector : [9,8,7]}", "Any[std::map].ToString()") US_TEST_CONDITION(anyMap3.ToJSON() == "{\"map\" : {\"1\" : 0.3, \"3\" : \"bye\"}, \"number\" : 5, \"vector\" : [9,8,7]}", "Any[std::map].ToJSON()") US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usLDAPFilterTest.cpp b/Modules/CppMicroServices/core/test/usLDAPFilterTest.cpp index 9e9f74ea2f..e9149e2a2c 100644 --- a/Modules/CppMicroServices/core/test/usLDAPFilterTest.cpp +++ b/Modules/CppMicroServices/core/test/usLDAPFilterTest.cpp @@ -1,169 +1,169 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include "usTestingMacros.h" #include US_USE_NAMESPACE int TestParsing() { // WELL FORMED Expr try { US_TEST_OUTPUT(<< "Parsing (cn=Babs Jensen)") LDAPFilter ldap( "(cn=Babs Jensen)" ); US_TEST_OUTPUT(<< "Parsing (!(cn=Tim Howes))") ldap = LDAPFilter( "(!(cn=Tim Howes))" ); US_TEST_OUTPUT(<< "Parsing " << std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=Person)(|(sn=Jensen)(cn=Babs J*)))") ldap = LDAPFilter( std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=Person)(|(sn=Jensen)(cn=Babs J*)))" ); US_TEST_OUTPUT(<< "Parsing (o=univ*of*mich*)") ldap = LDAPFilter( "(o=univ*of*mich*)" ); } catch (const std::invalid_argument& e) { US_TEST_OUTPUT(<< e.what()); return EXIT_FAILURE; } // MALFORMED Expr try { US_TEST_OUTPUT( << "Parsing malformed expr: cn=Babs Jensen)") LDAPFilter ldap( "cn=Babs Jensen)" ); return EXIT_FAILURE; } catch (const std::invalid_argument&) { } return EXIT_SUCCESS; } int TestEvaluate() { // EVALUATE try { LDAPFilter ldap( "(Cn=Babs Jensen)" ); ServiceProperties props; bool eval = false; // Several values props["cn"] = std::string("Babs Jensen"); props["unused"] = std::string("Jansen"); US_TEST_OUTPUT(<< "Evaluating expr: " << ldap.ToString()) eval = ldap.Match(props); if (!eval) { return EXIT_FAILURE; } // WILDCARD ldap = LDAPFilter( "(cn=Babs *)" ); props.clear(); props["cn"] = std::string("Babs Jensen"); US_TEST_OUTPUT(<< "Evaluating wildcard expr: " << ldap.ToString()) eval = ldap.Match(props); if ( !eval ) { return EXIT_FAILURE; } // NOT FOUND ldap = LDAPFilter( "(cn=Babs *)" ); props.clear(); props["unused"] = std::string("New"); US_TEST_OUTPUT(<< "Expr not found test: " << ldap.ToString()) eval = ldap.Match(props); if ( eval ) { return EXIT_FAILURE; } // std::vector with integer values ldap = 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; US_TEST_OUTPUT(<< "Evaluating vector expr: " << ldap.ToString()) eval = ldap.Match(props); if (!eval) { return EXIT_FAILURE; } // wrong case ldap = LDAPFilter( "(cN=Babs *)" ); props.clear(); props["cn"] = std::string("Babs Jensen"); US_TEST_OUTPUT(<< "Evaluating case sensitive expr: " << ldap.ToString()) eval = ldap.MatchCase(props); if (eval) { return EXIT_FAILURE; } } catch (const std::invalid_argument& e) { US_TEST_OUTPUT( << e.what() ) return EXIT_FAILURE; } return EXIT_SUCCESS; } void TestLDAPExpressions() { LDAPFilter filter( LDAPProp("bla") == "jo" && !(LDAPProp("ha") == 1) && (LDAPProp("presence") || !LDAPProp("absence")) && LDAPProp("le") <= 4.1 && LDAPProp("ge") >= -3 && LDAPProp("approx").Approx("Approx") ); const std::string filterStr = "(&(&(&(&(&(bla=jo)(!(ha=1)))(|(presence=*)(!(absence=*))))(le<=4.1))(ge>=-3))(approx~=Approx))"; US_TEST_CONDITION(filter.ToString() == filterStr, "test generated filter string") std::string emptyValue; std::string someValue = "some"; std::string filter1 = LDAPProp("key2") == someValue && LDAPProp("key3"); std::string filter2 = LDAPProp("key2") == someValue && (LDAPProp("key1") == emptyValue || LDAPProp("key3")); US_TEST_CONDITION(filter1 == filter2, "test null expressions") } int usLDAPFilterTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("LDAPFilterTest"); TestLDAPExpressions(); US_TEST_CONDITION(TestParsing() == EXIT_SUCCESS, "Parsing LDAP expressions: ") US_TEST_CONDITION(TestEvaluate() == EXIT_SUCCESS, "Evaluating LDAP expressions: ") US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usLogTest.cpp b/Modules/CppMicroServices/core/test/usLogTest.cpp index ea9b601b04..bfde61535a 100644 --- a/Modules/CppMicroServices/core/test/usLogTest.cpp +++ b/Modules/CppMicroServices/core/test/usLogTest.cpp @@ -1,177 +1,177 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include "usTestingMacros.h" US_USE_NAMESPACE static int lastMsgType = -1; static std::string lastMsg; void handleMessages(MsgType type, const char* msg) { lastMsgType = type; lastMsg.assign(msg); } void resetLastMsg() { lastMsgType = -1; lastMsg.clear(); } void logMsg(MsgType msgType, int logLevel) { resetLastMsg(); std::string logMsg; switch (msgType) { case DebugMsg: { logMsg = "Debug msg"; US_DEBUG << logMsg; #if !defined(US_ENABLE_DEBUG_OUTPUT) if (logLevel == DebugMsg) logLevel = InfoMsg; #endif break; } case InfoMsg: { logMsg = "Info msg"; US_INFO << logMsg; break; } case WarningMsg: { logMsg = "Warning msg"; US_WARN << logMsg; break; } case ErrorMsg: { // Skip error messages logLevel = 100; break; } } if (msgType >= logLevel) { US_TEST_CONDITION(lastMsgType == msgType && lastMsg.find(logMsg) != std::string::npos, "Testing for logged message") } else { US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing for skipped log message") } } void testLogMessages() { // Use the default message handler installMsgHandler(nullptr); { US_DEBUG << "Msg"; US_DEBUG(false) << "Msg"; US_INFO << "Msg"; US_INFO(false) << "Msg"; US_WARN << "Msg"; US_WARN(false) << "Msg"; } US_TEST_CONDITION(lastMsg.empty(), "Testing default message handler"); resetLastMsg(); installMsgHandler(handleMessages); { US_DEBUG << "Msg"; } #if !defined(US_ENABLE_DEBUG_OUTPUT) US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing suppressed debug message") #else US_TEST_CONDITION(lastMsgType == 0 && lastMsg.find("Msg") != std::string::npos, "Testing debug message") #endif resetLastMsg(); { US_DEBUG(false) << "No msg"; } US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing disabled debug message") resetLastMsg(); { US_INFO << "Info msg"; } US_TEST_CONDITION(lastMsgType == 1 && lastMsg.find("Info msg") != std::string::npos, "Testing informational message") resetLastMsg(); { US_WARN << "Warn msg"; } US_TEST_CONDITION(lastMsgType == 2 && lastMsg.find("Warn msg") != std::string::npos, "Testing warning message") resetLastMsg(); // We cannot test US_ERROR since it will call abort(). installMsgHandler(nullptr); { US_INFO << "Info msg"; } US_TEST_CONDITION(lastMsgType == -1 && lastMsg.empty(), "Testing message handler reset") resetLastMsg(); } void testLogLevels() { installMsgHandler(handleMessages); MsgType logLevel = ModuleSettings::GetLogLevel(); US_TEST_CONDITION_REQUIRED(logLevel == DebugMsg, "Default log level") logMsg(DebugMsg, logLevel); logMsg(InfoMsg, logLevel); logMsg(WarningMsg, logLevel); logMsg(ErrorMsg, logLevel); for (int level = ErrorMsg; level >= 0; --level) { ModuleSettings::SetLogLevel(static_cast(level)); logMsg(DebugMsg, level); logMsg(InfoMsg, level); logMsg(WarningMsg, level); logMsg(ErrorMsg, level); } installMsgHandler(nullptr); resetLastMsg(); } int usLogTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("DebugOutputTest"); testLogMessages(); testLogLevels(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usModuleAutoLoadTest.cpp b/Modules/CppMicroServices/core/test/usModuleAutoLoadTest.cpp index 2a252a1fe6..a4035230cc 100644 --- a/Modules/CppMicroServices/core/test/usModuleAutoLoadTest.cpp +++ b/Modules/CppMicroServices/core/test/usModuleAutoLoadTest.cpp @@ -1,175 +1,175 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include #include "usTestUtilModuleListener.h" #include "usTestingMacros.h" #include US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif void testDefaultAutoLoadPath(bool autoLoadEnabled) { ModuleContext* mc = GetModuleContext(); assert(mc); TestModuleListener listener; ModuleListenerRegistrationHelper listenerReg(mc, &listener, &TestModuleListener::ModuleChanged); SharedLibrary libAL(LIB_PATH, "TestModuleAL"); try { libAL.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } Module* moduleAL = ModuleRegistry::GetModule("TestModuleAL"); US_TEST_CONDITION_REQUIRED(moduleAL != nullptr, "Test for existing module TestModuleAL") US_TEST_CONDITION(moduleAL->GetName() == "TestModuleAL", "Test module name") // check the listeners for events std::vector pEvts; pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL)); Any loadedModules = moduleAL->GetProperty(Module::PROP_AUTOLOADED_MODULES()); Module* moduleAL_1 = ModuleRegistry::GetModule("TestModuleAL_1"); if (autoLoadEnabled) { US_TEST_CONDITION_REQUIRED(moduleAL_1 != nullptr, "Test for existing auto-loaded module TestModuleAL_1") US_TEST_CONDITION(moduleAL_1->GetName() == "TestModuleAL_1", "Test module name") US_TEST_CONDITION_REQUIRED(!loadedModules.Empty(), "Test for PROP_AUTOLOADED_MODULES property") US_TEST_CONDITION_REQUIRED(loadedModules.Type() == typeid(std::vector), "Test for PROP_AUTOLOADED_MODULES property type") std::vector loadedModulesVec = any_cast >(loadedModules); US_TEST_CONDITION_REQUIRED(loadedModulesVec.size() == 1, "Test for PROP_AUTOLOADED_MODULES vector size") US_TEST_CONDITION_REQUIRED(loadedModulesVec[0] == moduleAL_1->GetLocation(), "Test for PROP_AUTOLOADED_MODULES vector content") pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL_1)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL_1)); } else { US_TEST_CONDITION_REQUIRED(moduleAL_1 == nullptr, "Test for non-existing auto-loaded module TestModuleAL_1") US_TEST_CONDITION_REQUIRED(loadedModules.Empty(), "Test for empty PROP_AUTOLOADED_MODULES property") } pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL)); US_TEST_CONDITION(listener.CheckListenerEvents(pEvts), "Test for unexpected events"); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); libAL.Unload(); } void testCustomAutoLoadPath() { ModuleContext* mc = GetModuleContext(); assert(mc); TestModuleListener listener; try { mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); throw; } SharedLibrary libAL2(LIB_PATH, "TestModuleAL2"); try { libAL2.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } Module* moduleAL2 = ModuleRegistry::GetModule("TestModuleAL2"); US_TEST_CONDITION_REQUIRED(moduleAL2 != nullptr, "Test for existing module TestModuleAL2") US_TEST_CONDITION(moduleAL2->GetName() == "TestModuleAL2", "Test module name") // check the listeners for events std::vector pEvts; pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL2)); Module* moduleAL2_1 = ModuleRegistry::GetModule("TestModuleAL2_1"); #ifdef US_ENABLE_AUTOLOADING_SUPPORT US_TEST_CONDITION_REQUIRED(moduleAL2_1 != nullptr, "Test for existing auto-loaded module TestModuleAL2_1") US_TEST_CONDITION(moduleAL2_1->GetName() == "TestModuleAL2_1", "Test module name") pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleAL2_1)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL2_1)); #else US_TEST_CONDITION_REQUIRED(moduleAL2_1 == nullptr, "Test for non-existing aut-loaded module TestModuleAL2_1") #endif pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleAL2)); US_TEST_CONDITION(listener.CheckListenerEvents(pEvts), "Test for unexpected events"); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); } } // end unnamed namespace int usModuleAutoLoadTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleLoaderTest"); ModuleSettings::SetAutoLoadingEnabled(false); testDefaultAutoLoadPath(false); ModuleSettings::SetAutoLoadingEnabled(true); testDefaultAutoLoadPath(true); testCustomAutoLoadPath(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usModuleHooksTest.cpp b/Modules/CppMicroServices/core/test/usModuleHooksTest.cpp index e9b05620f4..172798fda2 100644 --- a/Modules/CppMicroServices/core/test/usModuleHooksTest.cpp +++ b/Modules/CppMicroServices/core/test/usModuleHooksTest.cpp @@ -1,194 +1,194 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif class TestModuleListener { public: void ModuleChanged(const ModuleEvent moduleEvent) { this->events.push_back(moduleEvent); } std::vector events; }; class TestModuleFindHook : public ModuleFindHook { public: void Find(const ModuleContext* /*context*/, ShrinkableVector& modules) override { for (ShrinkableVector::iterator i = modules.begin(); i != modules.end();) { if ((*i)->GetName() == "TestModuleA") { i = modules.erase(i); } else { ++i; } } } }; class TestModuleEventHook : public ModuleEventHook { public: void Event(const ModuleEvent& event, ShrinkableVector& contexts) override { if (event.GetType() == ModuleEvent::LOADING || event.GetType() == ModuleEvent::UNLOADING) { contexts.erase(std::remove(contexts.begin(), contexts.end(), GetModuleContext()), contexts.end()); } } }; void TestFindHook() { SharedLibrary libA(LIB_PATH, "TestModuleA"); #ifdef US_BUILD_SHARED_LIBS try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #endif Module* moduleA = GetModuleContext()->GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != nullptr, "Test for existing module TestModuleA") US_TEST_CONDITION(moduleA->GetName() == "TestModuleA", "Test module name") US_TEST_CONDITION(moduleA->IsLoaded() == true, "Test if loaded correctly"); long moduleAId = moduleA->GetModuleId(); US_TEST_CONDITION_REQUIRED(moduleAId > 0, "Test for valid module id") US_TEST_CONDITION_REQUIRED(GetModuleContext()->GetModule(moduleAId) != nullptr, "Test for non-filtered GetModule(long) result") TestModuleFindHook findHook; ServiceRegistration findHookReg = GetModuleContext()->RegisterService(&findHook); US_TEST_CONDITION_REQUIRED(GetModuleContext()->GetModule(moduleAId) == nullptr, "Test for filtered GetModule(long) result") std::vector modules = GetModuleContext()->GetModules(); for (std::vector::iterator i = modules.begin(); i != modules.end(); ++i) { if((*i)->GetName() == "TestModuleA") { US_TEST_FAILED_MSG(<< "TestModuleA not filtered from GetModules()") } } findHookReg.Unregister(); libA.Unload(); } #ifdef US_BUILD_SHARED_LIBS void TestEventHook() { TestModuleListener moduleListener; GetModuleContext()->AddModuleListener(&moduleListener, &TestModuleListener::ModuleChanged); SharedLibrary libA(LIB_PATH, "TestModuleA"); try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 2, "Test for received load module events") libA.Unload(); US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 4, "Test for received unload module events") TestModuleEventHook eventHook; ServiceRegistration eventHookReg = GetModuleContext()->RegisterService(&eventHook); moduleListener.events.clear(); try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 1, "Test for filtered load module events") US_TEST_CONDITION_REQUIRED(moduleListener.events[0].GetType() == ModuleEvent::LOADED, "Test for LOADED event") libA.Unload(); US_TEST_CONDITION_REQUIRED(moduleListener.events.size() == 2, "Test for filtered unload module events") US_TEST_CONDITION_REQUIRED(moduleListener.events[1].GetType() == ModuleEvent::UNLOADED, "Test for UNLOADED event") eventHookReg.Unregister(); GetModuleContext()->RemoveModuleListener(&moduleListener, &TestModuleListener::ModuleChanged); } #endif } // end unnamed namespace int usModuleHooksTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleHooksTest"); TestFindHook(); #ifdef US_BUILD_SHARED_LIBS TestEventHook(); #endif US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usModuleManifestTest.cpp b/Modules/CppMicroServices/core/test/usModuleManifestTest.cpp index 51f201efdc..01164d649b 100644 --- a/Modules/CppMicroServices/core/test/usModuleManifestTest.cpp +++ b/Modules/CppMicroServices/core/test/usModuleManifestTest.cpp @@ -1,96 +1,96 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif } // end unnamed namespace int usModuleManifestTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleManifestTest"); SharedLibrary target(LIB_PATH, "TestModuleM"); #ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } #endif Module* moduleM = ModuleRegistry::GetModule("TestModuleM"); US_TEST_CONDITION_REQUIRED(moduleM != nullptr, "Test for existing module TestModuleM") US_TEST_CONDITION(moduleM->GetProperty(Module::PROP_NAME()).ToString() == "TestModuleM", "Module name") US_TEST_CONDITION(moduleM->GetName() == "TestModuleM", "Module name 2") US_TEST_CONDITION(moduleM->GetProperty(Module::PROP_DESCRIPTION()).ToString() == "My Module description", "Module description") US_TEST_CONDITION(moduleM->GetLocation() == moduleM->GetProperty(Module::PROP_LOCATION()).ToString(), "Module location") US_TEST_CONDITION(moduleM->GetProperty(Module::PROP_VERSION()).ToString() == "1.0.0", "Module version") US_TEST_CONDITION(moduleM->GetVersion() == ModuleVersion(1,0,0), "Module version 2") Any anyVector = moduleM->GetProperty("vector"); US_TEST_CONDITION_REQUIRED(anyVector.Type() == typeid(std::vector), "vector type") std::vector& vec = ref_any_cast >(anyVector); US_TEST_CONDITION_REQUIRED(vec.size() == 3, "vector size") US_TEST_CONDITION_REQUIRED(vec[0].Type() == typeid(std::string), "vector 0 type") US_TEST_CONDITION_REQUIRED(vec[0].ToString() == "first", "vector 0 value") US_TEST_CONDITION_REQUIRED(vec[1].Type() == typeid(int), "vector 1 type") US_TEST_CONDITION_REQUIRED(any_cast(vec[1]) == 2, "vector 1 value") Any anyMap = moduleM->GetProperty("map"); US_TEST_CONDITION_REQUIRED(anyMap.Type() == typeid(std::map), "map type") std::map& m = ref_any_cast >(anyMap); US_TEST_CONDITION_REQUIRED(m.size() == 3, "map size") US_TEST_CONDITION_REQUIRED(m["string"].Type() == typeid(std::string), "map 0 type") US_TEST_CONDITION_REQUIRED(m["string"].ToString() == "hi", "map 0 value") US_TEST_CONDITION_REQUIRED(m["number"].Type() == typeid(int), "map 1 type") US_TEST_CONDITION_REQUIRED(any_cast(m["number"]) == 4, "map 1 value") US_TEST_CONDITION_REQUIRED(m["list"].Type() == typeid(std::vector), "map 2 type") US_TEST_CONDITION_REQUIRED(any_cast >(m["list"]).size() == 2, "map 2 value size") target.Unload(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usModulePropsInterface.h b/Modules/CppMicroServices/core/test/usModulePropsInterface.h index 7755ea9cbd..26eefd32ab 100644 --- a/Modules/CppMicroServices/core/test/usModulePropsInterface.h +++ b/Modules/CppMicroServices/core/test/usModulePropsInterface.h @@ -1,42 +1,42 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USMODULEPROPSINTERFACE_H #define USMODULEPROPSINTERFACE_H #include #include US_BEGIN_NAMESPACE struct ModulePropsInterface { typedef ServiceProperties Properties; virtual ~ModulePropsInterface() {} virtual const Properties& GetProperties() const = 0; }; US_END_NAMESPACE #endif // USMODULEPROPSINTERFACE_H diff --git a/Modules/CppMicroServices/core/test/usModuleResourceTest.cpp b/Modules/CppMicroServices/core/test/usModuleResourceTest.cpp index 0cced3fc62..0246b864b7 100644 --- a/Modules/CppMicroServices/core/test/usModuleResourceTest.cpp +++ b/Modules/CppMicroServices/core/test/usModuleResourceTest.cpp @@ -1,483 +1,483 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include #include "usTestingMacros.h" #include #include #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif US_USE_NAMESPACE namespace { // Please confirm that a character count differing from the following targets is not due to // a misconfiguration of your versioning software (Correct line endings for your system) // See issue #18 ( https://github.com/saschazelzer/CppMicroServices/issues/18 ) void checkResourceInfo(const ModuleResource& res, const std::string& path, const std::string& baseName, const std::string& completeBaseName, const std::string& suffix, const std::string& completeSuffix, int size, bool children = false) { US_TEST_CONDITION_REQUIRED(res.IsValid(), "Valid resource") US_TEST_CONDITION(res.GetBaseName() == baseName, "GetBaseName()") US_TEST_CONDITION(res.GetChildren().empty() == !children, "No children") US_TEST_CONDITION(res.GetCompleteBaseName() == completeBaseName, "GetCompleteBaseName()") US_TEST_CONDITION(res.GetName() == completeBaseName + "." + suffix, "GetName()") US_TEST_CONDITION(res.GetResourcePath() == path + completeBaseName + "." + suffix, "GetResourcePath()") US_TEST_CONDITION(res.GetPath() == path, "GetPath()") US_TEST_CONDITION(res.GetSize() == size, "Data size") US_TEST_CONDITION(res.GetSuffix() == suffix, "Suffix") US_TEST_CONDITION(res.GetCompleteSuffix() == completeSuffix, "Complete suffix") } void testTextResource(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(12); const std::string fileData = "foo and\nbar\n"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); rs.clear(); rs.seekg(0); US_TEST_CONDITION_REQUIRED(rs.tellg() == std::streampos(0), "Move to start") US_TEST_CONDITION_REQUIRED(rs.good(), "Start re-reading"); std::vector lines; std::string line; while (std::getline(rs, line)) { lines.push_back(line); } US_TEST_CONDITION_REQUIRED(lines.size() > 1, "Number of lines") US_TEST_CONDITION(lines[0] == "foo and", "Check first line") US_TEST_CONDITION(lines[1] == "bar", "Check second line") } void testTextResourceAsBinary(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(16); const std::string fileData = "foo and\r\nbar\r\n\r\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #endif ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testInvalidResource(Module* module) { ModuleResource res = module->GetResource("invalid"); US_TEST_CONDITION_REQUIRED(res.IsValid() == false, "Check invalid resource") US_TEST_CONDITION(res.GetName().empty(), "Check empty name") US_TEST_CONDITION(res.GetPath().empty(), "Check empty path") US_TEST_CONDITION(res.GetResourcePath().empty(), "Check empty resource path") US_TEST_CONDITION(res.GetBaseName().empty(), "Check empty base name") US_TEST_CONDITION(res.GetCompleteBaseName().empty(), "Check empty complete base name") US_TEST_CONDITION(res.GetSuffix().empty(), "Check empty suffix") US_TEST_CONDITION(res.GetChildren().empty(), "Check empty children") US_TEST_CONDITION(res.GetSize() == 0, "Check zero size") ModuleResourceStream rs(res); US_TEST_CONDITION(rs.good() == true, "Check invalid resource stream") rs.ignore(); US_TEST_CONDITION(rs.good() == false, "Check invalid resource stream") US_TEST_CONDITION(rs.eof() == true, "Check invalid resource stream") } void testSpecialCharacters(Module* module) { ModuleResource res = module->GetResource("special_chars.dummy.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 56, false); const std::streampos ssize(54); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)\n"; #else checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 54, false); const std::streampos ssize(53); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios_base::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios_base::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testBinaryResource(Module* module) { ModuleResource res = module->GetResource("/icons/cppmicroservices.png"); checkResourceInfo(res, "/icons/", "cppmicroservices", "cppmicroservices", "png", "png", 2598, false); ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios_base::end); std::streampos resLength = rs.tellg(); rs.seekg(0); std::ifstream png(US_CORE_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/cppmicroservices.png", std::ifstream::in | std::ifstream::binary); US_TEST_CONDITION_REQUIRED(png.is_open(), "Open reference file") png.seekg(0, std::ios_base::end); std::streampos pngLength = png.tellg(); png.seekg(0); US_TEST_CONDITION(res.GetSize() == resLength, "Check resource size") US_TEST_CONDITION_REQUIRED(resLength == pngLength, "Compare sizes") char c1 = 0; char c2 = 0; bool isEqual = true; int count = 0; while (png.get(c1) && rs.get(c2)) { ++count; if (c1 != c2) { isEqual = false; break; } } US_TEST_CONDITION_REQUIRED(count == pngLength, "Check if everything was read"); US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); US_TEST_CONDITION(png.eof(), "EOF check"); } void testCompressedResource(Module* module) { ModuleResource res = module->GetResource("/icons/compressable.bmp"); checkResourceInfo(res, "/icons/", "compressable", "compressable", "bmp", "bmp", 300122, false); ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios_base::end); std::streampos resLength = rs.tellg(); rs.seekg(0); std::ifstream bmp(US_CORE_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/compressable.bmp", std::ifstream::in | std::ifstream::binary); US_TEST_CONDITION_REQUIRED(bmp.is_open(), "Open reference file") bmp.seekg(0, std::ios_base::end); std::streampos bmpLength = bmp.tellg(); bmp.seekg(0); US_TEST_CONDITION(300122 == resLength, "Check resource size") US_TEST_CONDITION_REQUIRED(resLength == bmpLength, "Compare sizes") char c1 = 0; char c2 = 0; bool isEqual = true; int count = 0; while (bmp.get(c1) && rs.get(c2)) { ++count; if (c1 != c2) { isEqual = false; break; } } US_TEST_CONDITION_REQUIRED(count == bmpLength, "Check if everything was read"); US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); US_TEST_CONDITION(bmp.eof(), "EOF check"); } struct ResourceComparator { bool operator()(const ModuleResource& mr1, const ModuleResource& mr2) const { return mr1 < mr2; } }; void testResourceTree(Module* module) { ModuleResource res = module->GetResource(""); US_TEST_CONDITION(res.GetResourcePath() == "/", "Check root file path") US_TEST_CONDITION(res.IsDir() == true, "Check type") std::vector children = res.GetChildren(); std::sort(children.begin(), children.end()); US_TEST_CONDITION_REQUIRED(children.size() == 5, "Check child count") US_TEST_CONDITION(children[0] == "foo.txt", "Check child name") US_TEST_CONDITION(children[1] == "foo2.txt", "Check child name") US_TEST_CONDITION(children[2] == "icons/", "Check child name") US_TEST_CONDITION(children[3] == "special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(children[4] == "test.xml", "Check child name") US_TEST_CONDITION(module->FindResources("!$noexist=?", std::string(), "true").empty(), "Check not existant path"); ModuleResource readme = module->GetResource("/icons/readme.txt"); US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") ModuleResource icons = module->GetResource("icons/"); US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") children = icons.GetChildren(); US_TEST_CONDITION_REQUIRED(children.size() == 3, "Check icons child count") std::sort(children.begin(), children.end()); US_TEST_CONDITION(children[0] == "compressable.bmp", "Check child name") US_TEST_CONDITION(children[1] == "cppmicroservices.png", "Check child name") US_TEST_CONDITION(children[2] == "readme.txt", "Check child name") ResourceComparator resourceComparator; // find all .txt files std::vector nodes = module->FindResources("", "*.txt", false); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 3, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo2.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") nodes = module->FindResources("", "*.txt", true); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 4, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo2.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/icons/readme.txt", "Check child name") US_TEST_CONDITION(nodes[3].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") // find all resources nodes = module->FindResources("", "", true); US_TEST_CONDITION(nodes.size() == 8, "Total resource number") nodes = module->FindResources("", "**", true); US_TEST_CONDITION(nodes.size() == 8, "Total resource number") // test pattern matching nodes.clear(); nodes = module->FindResources("/icons", "*micro*.png", false); US_TEST_CONDITION(nodes.size() == 1 && nodes[0].GetResourcePath() == "/icons/cppmicroservices.png", "Check file pattern matches") nodes.clear(); nodes = module->FindResources("", "*.txt", true); US_TEST_CONDITION(nodes.size() == 4, "Check recursive pattern matches") } void testResourceOperators(Module* module) { ModuleResource invalid = module->GetResource("invalid"); ModuleResource foo = module->GetResource("foo.txt"); US_TEST_CONDITION_REQUIRED(foo.IsValid() && foo, "Check valid resource") ModuleResource foo2(foo); US_TEST_CONDITION(foo == foo, "Check equality operator") US_TEST_CONDITION(foo == foo2, "Check copy constructor and equality operator") US_TEST_CONDITION(foo != invalid, "Check inequality with invalid resource") ModuleResource xml = module->GetResource("/test.xml"); US_TEST_CONDITION_REQUIRED(xml.IsValid() && xml, "Check valid resource") US_TEST_CONDITION(foo != xml, "Check inequality") US_TEST_CONDITION(foo < xml, "Check operator<") // check operator< by using a set std::set resources; resources.insert(foo); resources.insert(foo); resources.insert(xml); US_TEST_CONDITION(resources.size() == 2, "Check operator< with set") // check hash function specialization US_UNORDERED_SET_TYPE resources2; resources2.insert(foo); resources2.insert(foo); resources2.insert(xml); US_TEST_CONDITION(resources2.size() == 2, "Check operator< with unordered set") // check operator<< std::ostringstream oss; oss << foo; US_TEST_CONDITION(oss.str() == foo.GetResourcePath(), "Check operator<<") } void testResourceFromExecutable(Module* module) { ModuleResource resource = module->GetResource("usTestResource.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid executable resource") std::string line; ModuleResourceStream rs(resource); std::getline(rs, line); US_TEST_CONDITION(line == "meant to be compiled into the test driver", "Check executable resource content") } void testResourcesFrom(const std::string& moduleName) { #ifdef US_BUILD_SHARED_LIBS SharedLibrary libR(LIB_PATH, moduleName); try { libR.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #endif Module* moduleR = ModuleRegistry::GetModule(moduleName); US_TEST_CONDITION_REQUIRED(moduleR != nullptr, "Test for existing module") US_TEST_CONDITION(moduleR->GetName() == moduleName, "Test module name") US_TEST_CONDITION(moduleR->FindResources("", "*.txt", true).size() == 2, "Resource count") #ifdef US_BUILD_SHARED_LIBS libR.Unload(); #endif } } // end unnamed namespace int usModuleResourceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleResourceTest"); ModuleContext* mc = GetModuleContext(); assert(mc); #ifdef US_BUILD_SHARED_LIBS SharedLibrary libR(LIB_PATH, "TestModuleR"); try { libR.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #endif Module* moduleR = ModuleRegistry::GetModule("TestModuleR"); US_TEST_CONDITION_REQUIRED(moduleR != nullptr, "Test for existing module TestModuleR") US_TEST_CONDITION(moduleR->GetName() == "TestModuleR", "Test module name") testInvalidResource(moduleR); testResourceFromExecutable(mc->GetModule()); testResourceTree(moduleR); testResourceOperators(moduleR); testTextResource(moduleR); testTextResourceAsBinary(moduleR); testSpecialCharacters(moduleR); testBinaryResource(moduleR); testCompressedResource(moduleR); ModuleResource foo = moduleR->GetResource("foo.txt"); US_TEST_CONDITION(foo.IsValid() == true, "Valid resource") #ifdef US_BUILD_SHARED_LIBS libR.Unload(); US_TEST_CONDITION(foo.IsValid() == true, "Still valid resource") #endif testResourcesFrom("TestModuleRL"); testResourcesFrom("TestModuleRA"); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usModuleTest.cpp b/Modules/CppMicroServices/core/test/usModuleTest.cpp index 683ad97c37..713d16e17f 100644 --- a/Modules/CppMicroServices/core/test/usModuleTest.cpp +++ b/Modules/CppMicroServices/core/test/usModuleTest.cpp @@ -1,350 +1,350 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include "usTestUtilModuleListener.h" #include "usTestDriverActivator.h" #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '\\'; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; static const char PATH_SEPARATOR = '/'; #endif // Check that the executable's activator was loaded and called void frame01() { US_TEST_CONDITION_REQUIRED(TestDriverActivator::LoadCalled(), "ModuleActivator::Load() called for executable") } // Verify that the same member function pointers registered as listeners // with different receivers works. void frame02a() { ModuleContext* mc = GetModuleContext(); TestModuleListener listener1; TestModuleListener listener2; try { mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); mc->AddModuleListener(&listener2, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "module listener registration failed " << ise.what() << " : frameSL02a:FAIL" ); } SharedLibrary target(LIB_PATH, "TestModuleA"); #ifdef US_BUILD_SHARED_LIBS // Start the test target try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } #endif Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != nullptr, "Test for existing module TestModuleA") std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; US_TEST_CONDITION(listener1.CheckListenerEvents(pEvts, seEvts), "Check first module listener") US_TEST_CONDITION(listener2.CheckListenerEvents(pEvts, seEvts), "Check second module listener") mc->RemoveModuleListener(&listener1, &TestModuleListener::ModuleChanged); mc->RemoveModuleListener(&listener2, &TestModuleListener::ModuleChanged); target.Unload(); } // Verify information from the ModuleInfo struct void frame005a(ModuleContext* mc) { Module* m = mc->GetModule(); // check expected headers US_TEST_CONDITION("main" == m->GetName(), "Test module name") US_TEST_CONDITION(ModuleVersion(0,1,0) == m->GetVersion(), "Test test driver module version") US_TEST_CONDITION(ModuleVersion(CppMicroServices_MAJOR_VERSION, CppMicroServices_MINOR_VERSION, CppMicroServices_PATCH_VERSION) == ModuleRegistry::GetModule(1)->GetVersion(), "Test CppMicroServices version") } // Get context id, location and status of the module void frame010a(ModuleContext* mc) { Module* m = mc->GetModule(); long int contextid = m->GetModuleId(); US_DEBUG << "CONTEXT ID:" << contextid; std::string location = m->GetLocation(); US_DEBUG << "LOCATION:" << location; US_TEST_CONDITION(!location.empty(), "Test for non-empty module location") US_TEST_CONDITION(m->IsLoaded(), "Test for loaded flag") US_TEST_CONDITION(ModuleSettings::GetStoragePath().empty(), "Test for empty base storage path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("").empty(), "Test for empty data path") US_TEST_CONDITION(m->GetModuleContext()->GetDataFile("bla").empty(), "Test for empty data file path") } //---------------------------------------------------------------------------- //Test result of GetService(ServiceReference()). Should throw std::invalid_argument void frame018a(ModuleContext* mc) { try { mc->GetService(ServiceReferenceU()); US_DEBUG << "Got service object, expected std::invalid_argument exception"; US_TEST_FAILED_MSG(<< "Got service object, excpected std::invalid_argument exception") } catch (const std::invalid_argument& ) {} catch (...) { US_TEST_FAILED_MSG(<< "Got wrong exception, expected std::invalid_argument") } } // Load libA and check that it exists and that the service it registers exists, // also check that the expected events occur and that the storage paths are correct void frame020a(ModuleContext* mc, TestModuleListener& listener, #ifdef US_BUILD_SHARED_LIBS SharedLibrary& libA) { try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #else SharedLibrary& /*libA*/) { #endif ModuleSettings::SetStoragePath(std::string("/tmp") + PATH_SEPARATOR); US_TEST_CONDITION(ModuleSettings::GetStoragePath() == "/tmp", "Test for valid base storage path") Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != nullptr, "Test for existing module TestModuleA") US_TEST_CONDITION(moduleA->GetName() == "TestModuleA", "Test module name") std::cout << moduleA->GetModuleContext()->GetDataFile("") << std::endl; std::stringstream ss; ss << moduleA->GetModuleId(); const std::string baseStoragePath = std::string("/tmp") + PATH_SEPARATOR + ss.str() + "_TestModuleA" + PATH_SEPARATOR; US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("") == baseStoragePath, "Test for valid data path") US_TEST_CONDITION(moduleA->GetModuleContext()->GetDataFile("bla") == baseStoragePath + "bla", "Test for valid data file path") // Check if libA registered the expected service try { ServiceReferenceU sr1 = mc->GetServiceReference("us::TestModuleAService"); InterfaceMap o1 = mc->GetService(sr1); US_TEST_CONDITION(!o1.empty(), "Test if service object found"); try { US_TEST_CONDITION(mc->UngetService(sr1), "Test if Service UnGet returns true"); } catch (const std::logic_error& le) { US_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) } // check the listeners for events std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } catch (const ServiceException& /*se*/) { US_TEST_FAILED_MSG(<< "test module, expected service not found"); } US_TEST_CONDITION(moduleA->IsLoaded() == true, "Test if loaded correctly"); } // Unload libA and check for correct events void frame030b(ModuleContext* mc, TestModuleListener& listener, SharedLibrary& libA) { Module* moduleA = ModuleRegistry::GetModule("TestModuleA"); US_TEST_CONDITION_REQUIRED(moduleA != nullptr, "Test for non-null module") ServiceReferenceU sr1 = mc->GetServiceReference("us::TestModuleAService"); US_TEST_CONDITION(sr1, "Test for valid service reference") try { libA.Unload(); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleA->IsLoaded() == false, "Test for unloaded state") #endif } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) } std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleA)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleA)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, sr1)); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } struct LocalListener { void ServiceChanged(const ServiceEvent) {} }; // Add a service listener with a broken LDAP filter to Get an exception void frame045a(ModuleContext* mc) { LocalListener sListen1; std::string brokenFilter = "A broken LDAP filter"; try { mc->AddServiceListener(&sListen1, &LocalListener::ServiceChanged, brokenFilter); } catch (const std::invalid_argument& /*ia*/) { //assertEquals("InvalidSyntaxException.GetFilter should be same as input string", brokenFilter, ise.GetFilter()); } catch (...) { US_TEST_FAILED_MSG(<< "test module, wrong exception on broken LDAP filter:"); } } } // end unnamed namespace int usModuleTest(int /*argc*/, char* /*argv*/[]) { //US_TEST_BEGIN("ModuleTest"); std::vector modules = ModuleRegistry::GetModules(); for (std::vector::iterator iter = modules.begin(), iterEnd = modules.end(); iter != iterEnd; ++iter) { std::cout << "----- " << (*iter)->GetName() << std::endl; } frame01(); frame02a(); ModuleContext* mc = GetModuleContext(); TestModuleListener listener; try { mc->AddModuleListener(&listener, &TestModuleListener::ModuleChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); throw; } try { mc->AddServiceListener(&listener, &TestModuleListener::ServiceChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); throw; } frame005a(mc); frame010a(mc); frame018a(mc); SharedLibrary libA(LIB_PATH, "TestModuleA"); frame020a(mc, listener, libA); frame030b(mc, listener, libA); frame045a(mc); mc->RemoveModuleListener(&listener, &TestModuleListener::ModuleChanged); mc->RemoveServiceListener(&listener, &TestModuleListener::ServiceChanged); //US_TEST_END() return 0; } diff --git a/Modules/CppMicroServices/core/test/usServiceControlInterface.h b/Modules/CppMicroServices/core/test/usServiceControlInterface.h index 07b09b39ec..2811e61fb9 100644 --- a/Modules/CppMicroServices/core/test/usServiceControlInterface.h +++ b/Modules/CppMicroServices/core/test/usServiceControlInterface.h @@ -1,43 +1,43 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USSERVICECONTROLINTERFACE_H #define USSERVICECONTROLINTERFACE_H #include #include #include US_BEGIN_NAMESPACE struct ServiceControlInterface { virtual ~ServiceControlInterface() {} virtual void ServiceControl(int service, const std::string& operation, int ranking) = 0; }; US_END_NAMESPACE #endif // USSERVICECONTROLINTERFACE_H diff --git a/Modules/CppMicroServices/core/test/usServiceFactoryTest.cpp b/Modules/CppMicroServices/core/test/usServiceFactoryTest.cpp index 2c3cf29f73..15ff92cd6e 100644 --- a/Modules/CppMicroServices/core/test/usServiceFactoryTest.cpp +++ b/Modules/CppMicroServices/core/test/usServiceFactoryTest.cpp @@ -1,231 +1,231 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif } // end unnamed namespace US_BEGIN_NAMESPACE struct TestModuleH { virtual ~TestModuleH() {} }; struct TestModuleH2 { virtual ~TestModuleH2() {} }; US_END_NAMESPACE void TestServiceFactoryModuleScope() { // Install and start test module H, a service factory and test that the methods // in that interface works. SharedLibrary target(LIB_PATH, "TestModuleH"); #ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what()) } #endif Module* moduleH = ModuleRegistry::GetModule("TestModuleH"); US_TEST_CONDITION_REQUIRED(moduleH != nullptr, "Test for existing module TestModuleH") std::vector registeredRefs = moduleH->GetRegisteredServices(); US_TEST_CONDITION_REQUIRED(registeredRefs.size() == 2, "# of registered services") US_TEST_CONDITION(registeredRefs[0].GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_MODULE(), "service scope") US_TEST_CONDITION(registeredRefs[1].GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") ModuleContext* mc = GetModuleContext(); // Check that a service reference exist const ServiceReferenceU sr1 = mc->GetServiceReference("us::TestModuleH"); US_TEST_CONDITION_REQUIRED(sr1, "Service shall be present.") US_TEST_CONDITION(sr1.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_MODULE(), "service scope") InterfaceMap service = mc->GetService(sr1); US_TEST_CONDITION_REQUIRED(service.size() >= 1, "GetService()") InterfaceMap::const_iterator serviceIter = service.find("us::TestModuleH"); US_TEST_CONDITION_REQUIRED(serviceIter != service.end(), "GetService()") US_TEST_CONDITION_REQUIRED(serviceIter->second != nullptr, "GetService()") InterfaceMap service2 = mc->GetService(sr1); US_TEST_CONDITION(service == service2, "Same service pointer") std::vector usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") US_TEST_CONDITION(usedRefs[0] == sr1, "service ref in use") InterfaceMap service3 = moduleH->GetModuleContext()->GetService(sr1); US_TEST_CONDITION(service != service3, "Different service pointer") US_TEST_CONDITION(moduleH->GetModuleContext()->UngetService(sr1), "UngetService()") US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == false, "ungetService()") US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == true, "ungetService()") target.Unload(); } void TestServiceFactoryPrototypeScope() { // Install and start test module H, a service factory and test that the methods // in that interface works. SharedLibrary target(LIB_PATH, "TestModuleH"); #ifdef US_BUILD_SHARED_LIBS try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what()) } Module* moduleH = ModuleRegistry::GetModule("TestModuleH"); US_TEST_CONDITION_REQUIRED(moduleH != nullptr, "Test for existing module TestModuleH") #endif ModuleContext* mc = GetModuleContext(); // Check that a service reference exist const ServiceReference sr1 = mc->GetServiceReference(); US_TEST_CONDITION_REQUIRED(sr1, "Service shall be present.") US_TEST_CONDITION(sr1.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") ServiceObjects svcObjects = mc->GetServiceObjects(sr1); TestModuleH2* prototypeServiceH2 = svcObjects.GetService(); const ServiceReferenceU sr1void = mc->GetServiceReference(us_service_interface_iid()); ServiceObjects svcObjectsVoid = mc->GetServiceObjects(sr1void); InterfaceMap prototypeServiceH2Void = svcObjectsVoid.GetService(); US_TEST_CONDITION_REQUIRED(prototypeServiceH2Void.find(us_service_interface_iid()) != prototypeServiceH2Void.end(), "ServiceObjects::GetService()") #ifdef US_BUILD_SHARED_LIBS // There should be only one service in use US_TEST_CONDITION_REQUIRED(mc->GetModule()->GetServicesInUse().size() == 1, "services in use") #endif TestModuleH2* moduleScopeService = mc->GetService(sr1); US_TEST_CONDITION_REQUIRED(moduleScopeService && moduleScopeService != prototypeServiceH2, "GetService()") US_TEST_CONDITION_REQUIRED(prototypeServiceH2 != prototypeServiceH2Void.find(us_service_interface_iid())->second, "GetService()") svcObjectsVoid.UngetService(prototypeServiceH2Void); TestModuleH2* moduleScopeService2 = mc->GetService(sr1); US_TEST_CONDITION(moduleScopeService == moduleScopeService2, "Same service pointer") #ifdef US_BUILD_SHARED_LIBS std::vector usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") US_TEST_CONDITION(usedRefs[0] == sr1, "service ref in use") #endif std::string filter = "(" + ServiceConstants::SERVICE_ID() + "=" + sr1.GetProperty(ServiceConstants::SERVICE_ID()).ToString() + ")"; const ServiceReference sr2 = mc->GetServiceReferences(filter).front(); US_TEST_CONDITION_REQUIRED(sr2, "Service shall be present.") US_TEST_CONDITION(sr2.GetProperty(ServiceConstants::SERVICE_SCOPE()).ToString() == ServiceConstants::SCOPE_PROTOTYPE(), "service scope") US_TEST_CONDITION(any_cast(sr2.GetProperty(ServiceConstants::SERVICE_ID())) == any_cast(sr1.GetProperty(ServiceConstants::SERVICE_ID())), "same service id") try { svcObjects.UngetService(moduleScopeService2); US_TEST_FAILED_MSG(<< "std::invalid_argument exception expected") } catch (const std::invalid_argument&) { // this is expected } #ifdef US_BUILD_SHARED_LIBS // There should still be only one service in use usedRefs = mc->GetModule()->GetServicesInUse(); US_TEST_CONDITION_REQUIRED(usedRefs.size() == 1, "services in use") #endif ServiceObjects svcObjects2 = svcObjects; ServiceObjects svcObjects3 = mc->GetServiceObjects(sr1); try { svcObjects3.UngetService(prototypeServiceH2); US_TEST_FAILED_MSG(<< "std::invalid_argument exception expected") } catch (const std::invalid_argument&) { // this is expected } svcObjects2.UngetService(prototypeServiceH2); prototypeServiceH2 = svcObjects2.GetService(); TestModuleH2* prototypeServiceH2_2 = svcObjects3.GetService(); US_TEST_CONDITION_REQUIRED(prototypeServiceH2_2 && prototypeServiceH2_2 != prototypeServiceH2, "prototype service") svcObjects2.UngetService(prototypeServiceH2); svcObjects3.UngetService(prototypeServiceH2_2); US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == false, "ungetService()") US_TEST_CONDITION_REQUIRED(mc->UngetService(sr1) == true, "ungetService()") target.Unload(); } int usServiceFactoryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceFactoryTest"); TestServiceFactoryModuleScope(); TestServiceFactoryPrototypeScope(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usServiceHooksTest.cpp b/Modules/CppMicroServices/core/test/usServiceHooksTest.cpp index 3818374da0..46b4ed2a44 100644 --- a/Modules/CppMicroServices/core/test/usServiceHooksTest.cpp +++ b/Modules/CppMicroServices/core/test/usServiceHooksTest.cpp @@ -1,414 +1,414 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif class TestServiceListener { public: void ServiceChanged(const ServiceEvent serviceEvent) { this->events.push_back(serviceEvent); } std::vector events; }; class TestServiceEventListenerHook : public ServiceEventListenerHook { private: int id; public: TestServiceEventListenerHook(int id) : id(id) { } typedef ShrinkableMap > MapType; void Event(const ServiceEvent& /*event*/, MapType& listeners) override { US_TEST_CONDITION_REQUIRED(listeners.size() > 0 && listeners.find(GetModuleContext()) != listeners.end(), "Check listener content"); ShrinkableVector& listenerInfos = listeners[GetModuleContext()]; // listener count should be 2 because the event listener hooks are called with // the list of listeners before filtering them according to ther LDAP filter if (id == 1) { #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(listenerInfos.size() == 2, "2 service listeners expected"); #else US_TEST_CONDITION(listenerInfos.size() >= 2, "2 service listeners expected"); #endif US_TEST_CONDITION(listenerInfos[0].IsRemoved() == false, "Listener is not removed"); US_TEST_CONDITION(listenerInfos[1].IsRemoved() == false, "Listener is not removed"); US_TEST_CONDITION(!(listenerInfos[0] == listenerInfos[1]), "listener info inequality"); } else { // there is already one listener filtered out #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(listenerInfos.size() == 1, "1 service listener expected"); #else US_TEST_CONDITION(listenerInfos.size() >= 1, "1 service listener expected"); #endif US_TEST_CONDITION(listenerInfos[0].IsRemoved() == false, "Listener is not removed"); } if (listenerInfo.IsNull()) { listenerInfo = listenerInfos[0]; } else { US_TEST_CONDITION(listenerInfo == listenerInfos[0], "Equal listener info objects"); } // Remove the listener without a filter from the list for(ShrinkableVector::iterator infoIter = listenerInfos.begin(); infoIter != listenerInfos.end();) { if (infoIter->GetFilter().empty()) { infoIter = listenerInfos.erase(infoIter); } else { ++infoIter; } } #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(listenerInfos.size() == 1, "One listener with LDAP filter should remain"); #else US_TEST_CONDITION(listenerInfos.size() >= 1, "One listener with LDAP filter should remain"); #endif ordering.push_back(id); } ServiceListenerHook::ListenerInfo listenerInfo; static std::vector ordering; }; std::vector TestServiceEventListenerHook::ordering; class TestServiceFindHook : public ServiceFindHook { private: int id; public: TestServiceFindHook(int id) : id(id) { } void Find(const ModuleContext* context, const std::string& /*name*/, const std::string& /*filter*/, ShrinkableVector& references) override { US_TEST_CONDITION(context == GetModuleContext(), "Module context"); references.clear(); ordering.push_back(id); } static std::vector ordering; }; std::vector TestServiceFindHook::ordering; class TestServiceListenerHook : public ServiceListenerHook { private: int id; public: TestServiceListenerHook(int id) : id(id) { } void Added(const std::vector& listeners) override { for (std::vector::const_iterator iter = listeners.begin(); iter != listeners.end(); ++iter) { if (iter->IsRemoved() || iter->GetModuleContext() != GetModuleContext()) continue; listenerInfos.insert(*iter); lastAdded = listeners.back(); ordering.push_back(id); } } void Removed(const std::vector& listeners) override { for (std::vector::const_iterator iter = listeners.begin(); iter != listeners.end(); ++iter) { listenerInfos.erase(*iter); ordering.push_back(id*10); } lastRemoved = listeners.back(); } static std::vector ordering; US_UNORDERED_SET_TYPE listenerInfos; ListenerInfo lastAdded; ListenerInfo lastRemoved; }; std::vector TestServiceListenerHook::ordering; void TestEventListenerHook() { ModuleContext* context = GetModuleContext(); TestServiceListener serviceListener1; TestServiceListener serviceListener2; context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); context->AddServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged, LDAPProp(ServiceConstants::OBJECTCLASS()) == "bla"); TestServiceEventListenerHook serviceEventListenerHook1(1); ServiceProperties hookProps1; hookProps1[ServiceConstants::SERVICE_RANKING()] = 10; ServiceRegistration eventListenerHookReg1 = context->RegisterService(&serviceEventListenerHook1, hookProps1); TestServiceEventListenerHook serviceEventListenerHook2(2); ServiceProperties hookProps2; hookProps2[ServiceConstants::SERVICE_RANKING()] = 0; ServiceRegistration eventListenerHookReg2 = context->RegisterService(&serviceEventListenerHook2, hookProps2); std::vector expectedOrdering; expectedOrdering.push_back(1); expectedOrdering.push_back(1); expectedOrdering.push_back(2); US_TEST_CONDITION(serviceEventListenerHook1.ordering == expectedOrdering, "Event listener hook call order"); US_TEST_CONDITION(serviceListener1.events.empty(), "service event of service event listener hook"); US_TEST_CONDITION(serviceListener2.events.empty(), "no service event for filtered listener"); #ifdef US_BUILD_SHARED_LIBS SharedLibrary libA(LIB_PATH, "TestModuleA"); try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } expectedOrdering.push_back(1); expectedOrdering.push_back(2); US_TEST_CONDITION(serviceEventListenerHook1.ordering == expectedOrdering, "Event listener hook call order"); libA.Unload(); #endif US_TEST_CONDITION(serviceListener1.events.empty(), "no service event due to service event listener hook"); US_TEST_CONDITION(serviceListener2.events.empty(), "no service event for filtered listener due to service event listener hook"); eventListenerHookReg2.Unregister(); eventListenerHookReg1.Unregister(); context->RemoveServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); context->RemoveServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged); } void TestListenerHook() { ModuleContext* context = GetModuleContext(); TestServiceListener serviceListener1; TestServiceListener serviceListener2; context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); context->AddServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged, LDAPProp(ServiceConstants::OBJECTCLASS()) == "bla"); TestServiceListenerHook serviceListenerHook1(1); ServiceProperties hookProps1; hookProps1[ServiceConstants::SERVICE_RANKING()] = 0; ServiceRegistration listenerHookReg1 = context->RegisterService(&serviceListenerHook1, hookProps1); TestServiceListenerHook serviceListenerHook2(2); ServiceProperties hookProps2; hookProps2[ServiceConstants::SERVICE_RANKING()] = 10; ServiceRegistration listenerHookReg2 = context->RegisterService(&serviceListenerHook2, hookProps2); #ifdef US_BUILD_SHARED_LIBS // check if hooks got notified about the existing listeners US_TEST_CONDITION_REQUIRED(serviceListenerHook1.listenerInfos.size() == 2, "Notification about existing listeners") #endif const std::size_t listenerInfoSizeOld = serviceListenerHook1.listenerInfos.size() - 2; context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); ServiceListenerHook::ListenerInfo lastAdded = serviceListenerHook1.lastAdded; #ifdef US_BUILD_SHARED_LIBS std::vector expectedOrdering; expectedOrdering.push_back(1); expectedOrdering.push_back(1); expectedOrdering.push_back(2); expectedOrdering.push_back(2); expectedOrdering.push_back(20); expectedOrdering.push_back(10); expectedOrdering.push_back(2); expectedOrdering.push_back(1); US_TEST_CONDITION(serviceListenerHook1.ordering == expectedOrdering, "Listener hook call order"); #endif context->AddServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged, LDAPProp(ServiceConstants::OBJECTCLASS()) == "blub"); US_TEST_CONDITION(lastAdded == serviceListenerHook1.lastRemoved, "Same ListenerInfo object)"); US_TEST_CONDITION(!(lastAdded == serviceListenerHook1.lastAdded), "New ListenerInfo object)"); #ifdef US_BUILD_SHARED_LIBS expectedOrdering.push_back(20); expectedOrdering.push_back(10); expectedOrdering.push_back(2); expectedOrdering.push_back(1); US_TEST_CONDITION(serviceListenerHook1.ordering == expectedOrdering, "Listener hook call order"); #endif context->RemoveServiceListener(&serviceListener1, &TestServiceListener::ServiceChanged); context->RemoveServiceListener(&serviceListener2, &TestServiceListener::ServiceChanged); #ifdef US_BUILD_SHARED_LIBS expectedOrdering.push_back(20); expectedOrdering.push_back(10); expectedOrdering.push_back(20); expectedOrdering.push_back(10); US_TEST_CONDITION(serviceListenerHook1.ordering == expectedOrdering, "Listener hook call order"); #endif US_TEST_CONDITION_REQUIRED(serviceListenerHook1.listenerInfos.size() == listenerInfoSizeOld, "Removed listener infos") listenerHookReg2.Unregister(); listenerHookReg1.Unregister(); } void TestFindHook() { ModuleContext* context = GetModuleContext(); TestServiceFindHook serviceFindHook1(1); ServiceProperties hookProps1; hookProps1[ServiceConstants::SERVICE_RANKING()] = 0; ServiceRegistration findHookReg1 = context->RegisterService(&serviceFindHook1, hookProps1); TestServiceFindHook serviceFindHook2(2); ServiceProperties hookProps2; hookProps2[ServiceConstants::SERVICE_RANKING()] = 10; ServiceRegistration findHookReg2 = context->RegisterService(&serviceFindHook2, hookProps2); std::vector expectedOrdering; US_TEST_CONDITION(serviceFindHook1.ordering == expectedOrdering, "Find hook call order"); TestServiceListener serviceListener; context->AddServiceListener(&serviceListener, &TestServiceListener::ServiceChanged); #ifdef US_BUILD_SHARED_LIBS SharedLibrary libA(LIB_PATH, "TestModuleA"); try { libA.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } US_TEST_CONDITION(serviceListener.events.size() == 1, "Service registered"); #endif std::vector refs = context->GetServiceReferences("us::TestModuleAService"); US_TEST_CONDITION(refs.empty(), "Empty references"); ServiceReferenceU ref = context->GetServiceReference("us::TestModuleAService"); US_TEST_CONDITION(!ref, "Invalid reference (filtered out)"); expectedOrdering.push_back(2); expectedOrdering.push_back(1); expectedOrdering.push_back(2); expectedOrdering.push_back(1); US_TEST_CONDITION(serviceFindHook1.ordering == expectedOrdering, "Find hook call order"); findHookReg2.Unregister(); findHookReg1.Unregister(); refs = context->GetServiceReferences("us::TestModuleAService"); US_TEST_CONDITION(!refs.empty(), "Non-empty references"); ref = context->GetServiceReference("us::TestModuleAService"); US_TEST_CONDITION(ref, "Valid reference"); #ifdef US_BUILD_SHARED_LIBS libA.Unload(); #endif context->RemoveServiceListener(&serviceListener, &TestServiceListener::ServiceChanged); } } // end unnamed namespace int usServiceHooksTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceHooksTest"); TestListenerHook(); TestFindHook(); TestEventListenerHook(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usServiceListenerTest.cpp b/Modules/CppMicroServices/core/test/usServiceListenerTest.cpp index fe8ac3a2eb..cd80f8e2bb 100644 --- a/Modules/CppMicroServices/core/test/usServiceListenerTest.cpp +++ b/Modules/CppMicroServices/core/test/usServiceListenerTest.cpp @@ -1,565 +1,565 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include US_USE_NAMESPACE #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif class TestServiceListener { private: friend bool runLoadUnloadTest(const std::string&, int cnt, SharedLibrary&, const std::vector&); const bool checkUsingModules; std::vector events; bool teststatus; ModuleContext* mc; public: TestServiceListener(ModuleContext* mc, bool checkUsingModules = true) : checkUsingModules(checkUsingModules), events(), 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 ServiceEvent evt) { events.push_back(evt); US_TEST_OUTPUT( << "ServiceEvent: " << evt ); if (ServiceEvent::UNREGISTERING == evt.GetType()) { ServiceReferenceU 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 InterfaceMap service = mc->GetService(sr); sr.GetUsingModules(usingModules); // if (UNREGISTERSERVICE_VALID_DURING_UNREGISTERING) { // In this mode the service shall be obtainable during // unregistration. if (service.empty()) { teststatus = false; US_TEST_OUTPUT( << "*** Service should be available to ServiceListener " << "while handling unregistering event." ); } US_TEST_OUTPUT( << "Service (unreg): " << service.begin()->first << " -> " << service.begin()->second ); 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 = any_cast(sr.GetProperty(ServiceConstants::SERVICE_ID())); std::stringstream ss; ss << "(" << ServiceConstants::SERVICE_ID() << "=" << sid << ")"; std::vector srs = mc->GetServiceReferences("", ss.str()); if (srs.empty()) { US_TEST_OUTPUT( << "ServiceReference for UNREGISTERING service is not" " found in the service registry; ok." ); } else { teststatus = false; US_TEST_OUTPUT( << "*** ServiceReference for UNREGISTERING service," << sr << ", not found in the service registry; fail." ); US_TEST_OUTPUT( << "Found the following Service references:") ; for(std::vector::const_iterator sr = srs.begin(); sr != srs.end(); ++sr) { US_TEST_OUTPUT( << (*sr) ); } } } catch (const std::exception& e) { teststatus = false; US_TEST_OUTPUT( << "*** Unexpected excpetion when trying to lookup a" " service while it is in state UNREGISTERING: " << e.what() ); } } } void printUsingModules(const ServiceReferenceU& sr, const std::string& caption) { std::vector usingModules; sr.GetUsingModules(usingModules); US_TEST_OUTPUT( << (caption.empty() ? "Using modules: " : caption) ); for(std::vector::const_iterator module = usingModules.begin(); module != usingModules.end(); ++module) { US_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(); US_TEST_OUTPUT( << "Expected event type -- Actual event" ); for (std::size_t i=0; i < max; ++i) { ServiceEvent evt = i < events.size() ? events[i] : ServiceEvent(); if (i < eventTypes.size()) { US_TEST_OUTPUT( << " " << eventTypes[i] << "--" << evt ); } else { US_TEST_OUTPUT( << " " << "- NONE - " << "--" << evt ); } } } }; // end of class ServiceListener bool runLoadUnloadTest(const std::string& name, int cnt, SharedLibrary& target, const std::vector& events) { bool teststatus = true; ModuleContext* mc = GetModuleContext(); for (int i = 0; i < cnt && teststatus; ++i) { TestServiceListener sListen(mc); try { mc->AddServiceListener(&sListen, &TestServiceListener::serviceChanged); //mc->AddServiceListener(MessageDelegate1(&sListen, &ServiceListener::serviceChanged)); } catch (const std::logic_error& ise) { teststatus = false; US_TEST_FAILED_MSG( << "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; US_TEST_FAILED_MSG( << "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; US_TEST_FAILED_MSG( << "Failed to unload module, got exception: " << e.what() << " + in " << name << ":FAIL" ); } if (teststatus && !sListen.checkEvents(events)) { teststatus = false; US_TEST_FAILED_MSG( << "Service listener event notification error :" << name << ":FAIL" ); } try { mc->RemoveServiceListener(&sListen, &TestServiceListener::serviceChanged); teststatus &= sListen.teststatus; sListen.clearEvents(); } catch (const std::logic_error& ise) { teststatus = false; US_TEST_FAILED_MSG( << "service listener removal failed " << ise.what() << " :" << name << ":FAIL" ); } } return teststatus; } void frameSL02a() { ModuleContext* mc = GetModuleContext(); TestServiceListener listener1(mc); TestServiceListener listener2(mc); try { mc->RemoveServiceListener(&listener1, &TestServiceListener::serviceChanged); mc->AddServiceListener(&listener1, &TestServiceListener::serviceChanged); mc->RemoveServiceListener(&listener2, &TestServiceListener::serviceChanged); mc->AddServiceListener(&listener2, &TestServiceListener::serviceChanged); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "service listener registration failed " << ise.what() << " : frameSL02a:FAIL" ); } SharedLibrary target(LIB_PATH, "TestModuleA"); // Start the test target to get a service published. try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } std::vector events; events.push_back(ServiceEvent::REGISTERED); US_TEST_CONDITION(listener1.checkEvents(events), "Check first service listener") US_TEST_CONDITION(listener2.checkEvents(events), "Check second service listener") mc->RemoveServiceListener(&listener1, &TestServiceListener::serviceChanged); mc->RemoveServiceListener(&listener2, &TestServiceListener::serviceChanged); target.Unload(); } void frameSL05a() { std::vector events; events.push_back(ServiceEvent::REGISTERED); events.push_back(ServiceEvent::UNREGISTERING); SharedLibrary libA(LIB_PATH, "TestModuleA"); bool testStatus = runLoadUnloadTest("FrameSL05a", 1, libA, events); US_TEST_CONDITION(testStatus, "FrameSL05a") } void frameSL10a() { std::vector events; events.push_back(ServiceEvent::REGISTERED); events.push_back(ServiceEvent::UNREGISTERING); SharedLibrary libA2(LIB_PATH, "TestModuleA2"); bool testStatus = runLoadUnloadTest("FrameSL10a", 1, libA2, events); US_TEST_CONDITION(testStatus, "FrameSL10a") } void frameSL25a() { ModuleContext* mc = GetModuleContext(); TestServiceListener sListen(mc, false); try { mc->AddServiceListener(&sListen, &TestServiceListener::serviceChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); throw; } SharedLibrary libSL1(LIB_PATH, "TestModuleSL1"); SharedLibrary libSL3(LIB_PATH, "TestModuleSL3"); SharedLibrary libSL4(LIB_PATH, "TestModuleSL4"); std::vector expectedServiceEventTypes; // Startup expectedServiceEventTypes.push_back(ServiceEvent::REGISTERED); // at start of libSL1 expectedServiceEventTypes.push_back(ServiceEvent::REGISTERED); // FooService at start of libSL4 expectedServiceEventTypes.push_back(ServiceEvent::REGISTERED); // at start of libSL3 // Stop libSL4 expectedServiceEventTypes.push_back(ServiceEvent::UNREGISTERING); // FooService at first stop of libSL4 #ifdef US_BUILD_SHARED_LIBS // Shutdown expectedServiceEventTypes.push_back(ServiceEvent::UNREGISTERING); // at stop of libSL1 expectedServiceEventTypes.push_back(ServiceEvent::UNREGISTERING); // at stop of libSL3 #endif // Start libModuleTestSL1 to ensure that the Service interface is available. try { US_TEST_OUTPUT( << "Starting libModuleTestSL1: " << libSL1.GetFilePath() ); libSL1.Load(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); throw; } // Start libModuleTestSL4 that will require the serivce interface and publish // us::FooService try { US_TEST_OUTPUT( << "Starting libModuleTestSL4: " << libSL4.GetFilePath() ); libSL4.Load(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); throw; } // Start libModuleTestSL3 that will require the serivce interface and get the service try { US_TEST_OUTPUT( << "Starting libModuleTestSL3: " << libSL3.GetFilePath() ); libSL3.Load(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); throw; } // Check that libSL3 has been notified about the FooService. US_TEST_OUTPUT( << "Check that FooService is added to service tracker in libSL3" ); try { ServiceReferenceU libSL3SR = mc->GetServiceReference("ActivatorSL3"); InterfaceMap libSL3Activator = mc->GetService(libSL3SR); US_TEST_CONDITION_REQUIRED(!libSL3Activator.empty(), "ActivatorSL3 service != 0"); ServiceReference libSL3PropsI(libSL3SR); ModulePropsInterface* propsInterface = mc->GetService(libSL3PropsI); US_TEST_CONDITION_REQUIRED(propsInterface, "ModulePropsInterface != 0"); ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceAdded"); US_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceAdded"); Any serviceAddedField3 = i->second; US_TEST_CONDITION_REQUIRED(!serviceAddedField3.Empty() && any_cast(serviceAddedField3), "libSL3 notified about presence of FooService"); mc->UngetService(libSL3SR); } catch (const ServiceException& se) { US_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); } // Check that libSL1 has been notified about the FooService. US_TEST_OUTPUT( << "Check that FooService is added to service tracker in libSL1" ); try { ServiceReferenceU libSL1SR = mc->GetServiceReference("ActivatorSL1"); InterfaceMap libSL1Activator = mc->GetService(libSL1SR); US_TEST_CONDITION_REQUIRED(!libSL1Activator.empty(), "ActivatorSL1 service != 0"); ServiceReference libSL1PropsI(libSL1SR); ModulePropsInterface* propsInterface = mc->GetService(libSL1PropsI); US_TEST_CONDITION_REQUIRED(propsInterface, "Cast to ModulePropsInterface"); ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceAdded"); US_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceAdded"); Any serviceAddedField1 = i->second; US_TEST_CONDITION_REQUIRED(!serviceAddedField1.Empty() && any_cast(serviceAddedField1), "libSL1 notified about presence of FooService"); mc->UngetService(libSL1SR); } catch (const ServiceException& se) { US_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); } // Stop the service provider: libSL4 try { US_TEST_OUTPUT( << "Stop libSL4: " << libSL4.GetFilePath() ); libSL4.Unload(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to unload module, got exception:" << e.what() ); throw; } // Check that libSL3 has been notified about the removal of FooService. US_TEST_OUTPUT( << "Check that FooService is removed from service tracker in libSL3" ); try { ServiceReferenceU libSL3SR = mc->GetServiceReference("ActivatorSL3"); InterfaceMap libSL3Activator = mc->GetService(libSL3SR); US_TEST_CONDITION_REQUIRED(!libSL3Activator.empty(), "ActivatorSL3 service != 0"); ServiceReference libSL3PropsI(libSL3SR); ModulePropsInterface* propsInterface = mc->GetService(libSL3PropsI); US_TEST_CONDITION_REQUIRED(propsInterface, "Cast to ModulePropsInterface"); ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceRemoved"); US_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceRemoved"); Any serviceRemovedField3 = i->second; US_TEST_CONDITION(!serviceRemovedField3.Empty() && any_cast(serviceRemovedField3), "libSL3 notified about removal of FooService"); mc->UngetService(libSL3SR); } catch (const ServiceException& se) { US_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); } // Stop libSL1 try { US_TEST_OUTPUT( << "Stop libSL1:" << libSL1.GetFilePath() ); libSL1.Unload(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to unload module got exception" << e.what() ); throw; } // Stop pSL3 try { US_TEST_OUTPUT( << "Stop libSL3:" << libSL3.GetFilePath() ); libSL3.Unload(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to unload module got exception" << e.what() ); throw; } // Check service events seen by this class US_TEST_OUTPUT( << "Checking ServiceEvents(ServiceListener):" ); if (!sListen.checkEvents(expectedServiceEventTypes)) { US_TEST_FAILED_MSG( << "Service listener event notification error" ); } US_TEST_CONDITION_REQUIRED(sListen.getTestStatus(), "Service listener checks"); try { mc->RemoveServiceListener(&sListen, &TestServiceListener::serviceChanged); sListen.clearEvents(); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "service listener removal failed: " << ise.what() ); } } int usServiceListenerTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceListenerTest"); frameSL02a(); frameSL05a(); frameSL10a(); frameSL25a(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usServiceRegistryPerformanceTest.cpp b/Modules/CppMicroServices/core/test/usServiceRegistryPerformanceTest.cpp index f763e0cdf2..2ffa3f0998 100644 --- a/Modules/CppMicroServices/core/test/usServiceRegistryPerformanceTest.cpp +++ b/Modules/CppMicroServices/core/test/usServiceRegistryPerformanceTest.cpp @@ -1,428 +1,428 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usTestingMacros.h" #include #include US_USE_NAMESPACE #ifdef US_PLATFORM_APPLE #include #elif defined(US_PLATFORM_POSIX) #include #include #ifndef _POSIX_MONOTONIC_CLOCK #error Monotonic clock support missing on this POSIX platform #endif #elif defined(US_PLATFORM_WINDOWS) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef VC_EXTRA_LEAN #define VC_EXTRA_LEAN #endif #include #else #error High precision timer support nod available on this platform #endif #include class HighPrecisionTimer { public: inline HighPrecisionTimer(); inline void Start(); inline long long ElapsedMilli(); inline long long ElapsedMicro(); private: #ifdef US_PLATFORM_APPLE static double timeConvert; uint64_t startTime; #elif defined(US_PLATFORM_POSIX) timespec startTime; #elif defined(US_PLATFORM_WINDOWS) LARGE_INTEGER timerFrequency; LARGE_INTEGER startTime; #endif }; #ifdef US_PLATFORM_APPLE double HighPrecisionTimer::timeConvert = 0.0; inline HighPrecisionTimer::HighPrecisionTimer() : startTime(0) { if (timeConvert == 0) { mach_timebase_info_data_t timeBase; mach_timebase_info(&timeBase); timeConvert = static_cast(timeBase.numer) / static_cast(timeBase.denom) / 1000.0; } } inline void HighPrecisionTimer::Start() { startTime = mach_absolute_time(); } inline long long HighPrecisionTimer::ElapsedMilli() { uint64_t current = mach_absolute_time(); return static_cast(current - startTime) * timeConvert / 1000.0; } inline long long HighPrecisionTimer::ElapsedMicro() { uint64_t current = mach_absolute_time(); return static_cast(current - startTime) * timeConvert; } #elif defined(US_PLATFORM_POSIX) inline HighPrecisionTimer::HighPrecisionTimer() { startTime.tv_nsec = 0; startTime.tv_sec = 0; } inline void HighPrecisionTimer::Start() { clock_gettime(CLOCK_MONOTONIC, &startTime); } inline long long HighPrecisionTimer::ElapsedMilli() { timespec current; clock_gettime(CLOCK_MONOTONIC, ¤t); return (static_cast(current.tv_sec)*1000 + current.tv_nsec/1000/1000) - (static_cast(startTime.tv_sec)*1000 + startTime.tv_nsec/1000/1000); } inline long long HighPrecisionTimer::ElapsedMicro() { timespec current; clock_gettime(CLOCK_MONOTONIC, ¤t); return (static_cast(current.tv_sec)*1000*1000 + current.tv_nsec/1000) - (static_cast(startTime.tv_sec)*1000*1000 + startTime.tv_nsec/1000); } #elif defined(US_PLATFORM_WINDOWS) inline HighPrecisionTimer::HighPrecisionTimer() { if (!QueryPerformanceFrequency(&timerFrequency)) throw std::runtime_error("QueryPerformanceFrequency() failed"); } inline void HighPrecisionTimer::Start() { //DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0); QueryPerformanceCounter(&startTime); //SetThreadAffinityMask(GetCurrentThread(), oldmask); } inline long long HighPrecisionTimer::ElapsedMilli() { LARGE_INTEGER current; QueryPerformanceCounter(¤t); return (current.QuadPart - startTime.QuadPart) / (timerFrequency.QuadPart / 1000); } inline long long HighPrecisionTimer::ElapsedMicro() { LARGE_INTEGER current; QueryPerformanceCounter(¤t); return (current.QuadPart - startTime.QuadPart) / (timerFrequency.QuadPart / (1000*1000)); } #endif class MyServiceListener; struct IPerfTestService { virtual ~IPerfTestService() {} }; class ServiceRegistryPerformanceTest { private: friend class MyServiceListener; ModuleContext* mc; int nListeners; int nServices; std::size_t nRegistered; std::size_t nUnregistering; std::size_t nModified; std::vector > regs; std::vector listeners; std::vector services; public: ServiceRegistryPerformanceTest(ModuleContext* context); void InitTestCase(); void CleanupTestCase(); void TestAddListeners(); void TestRegisterServices(); void TestModifyServices(); void TestUnregisterServices(); private: std::ostream& Log() const { return std::cout; } void AddListeners(int n); void RegisterServices(int n); void ModifyServices(); void UnregisterServices(); }; class MyServiceListener { private: ServiceRegistryPerformanceTest* ts; public: MyServiceListener(ServiceRegistryPerformanceTest* ts) : ts(ts) { } void ServiceChanged(const ServiceEvent ev) { switch(ev.GetType()) { case ServiceEvent::REGISTERED: ts->nRegistered++; break; case ServiceEvent::UNREGISTERING: ts->nUnregistering++; break; case ServiceEvent::MODIFIED: ts->nModified++; break; default: break; } } }; ServiceRegistryPerformanceTest::ServiceRegistryPerformanceTest(ModuleContext* context) : mc(context) , nListeners(100) , nServices(1000) , nRegistered(0) , nUnregistering(0) , nModified(0) { } void ServiceRegistryPerformanceTest::InitTestCase() { Log() << "Initialize event counters\n"; nRegistered = 0; nUnregistering = 0; nModified = 0; } void ServiceRegistryPerformanceTest::CleanupTestCase() { Log() << "Remove all service listeners\n"; for(std::size_t i = 0; i < listeners.size(); i++) { try { MyServiceListener* l = listeners[i]; mc->RemoveServiceListener(l, &MyServiceListener::ServiceChanged); delete l; } catch (const std::exception& e) { Log() << e.what(); } } listeners.clear(); } void ServiceRegistryPerformanceTest::TestAddListeners() { AddListeners(nListeners); } void ServiceRegistryPerformanceTest::AddListeners(int n) { Log() << "adding " << n << " service listeners\n"; for(int i = 0; i < n; i++) { MyServiceListener* l = new MyServiceListener(this); try { listeners.push_back(l); mc->AddServiceListener(l, &MyServiceListener::ServiceChanged, "(perf.service.value>=0)"); } catch (const std::exception& e) { Log() << e.what(); } } Log() << "listener count=" << listeners.size() << "\n"; } void ServiceRegistryPerformanceTest::TestRegisterServices() { Log() << "Register services, and check that we get #of services (" << nServices << ") * #of listeners (" << nListeners << ") REGISTERED events\n"; Log() << "registering " << nServices << " services, listener count=" << listeners.size() << "\n"; HighPrecisionTimer t; t.Start(); RegisterServices(nServices); long long ms = t.ElapsedMilli(); Log() << "register took " << ms << "ms\n"; US_TEST_CONDITION_REQUIRED(nServices * listeners.size() == nRegistered, "# REGISTERED events must be same as # of registered services * # of listeners"); } void ServiceRegistryPerformanceTest::RegisterServices(int n) { class PerfTestService : public IPerfTestService { }; std::string pid("my.service."); for(int i = 0; i < n; i++) { ServiceProperties props; std::stringstream ss; ss << pid << i; props["service.pid"] = ss.str(); props["perf.service.value"] = i+1; PerfTestService* service = new PerfTestService(); services.push_back(service); ServiceRegistration reg = mc->RegisterService(service, props); regs.push_back(reg); } } void ServiceRegistryPerformanceTest::TestModifyServices() { Log() << "Modify all services, and check that we get #of services (" << nServices << ") * #of listeners (" << nListeners << ") MODIFIED events\n"; HighPrecisionTimer t; t.Start(); ModifyServices(); long long ms = t.ElapsedMilli(); Log() << "modify took " << ms << "ms\n"; US_TEST_CONDITION_REQUIRED(nServices * listeners.size() == nModified, "# MODIFIED events must be same as # of modified services * # of listeners"); } void ServiceRegistryPerformanceTest::ModifyServices() { Log() << "modifying " << regs.size() << " services, listener count=" << listeners.size() << "\n"; for(std::size_t i = 0; i < regs.size(); i++) { ServiceRegistration reg = regs[i]; ServiceProperties props; props["perf.service.value"] = i * 2; reg.SetProperties(props); } } void ServiceRegistryPerformanceTest::TestUnregisterServices() { Log() << "Unregister all services, and check that we get #of services (" << nServices << ") * #of listeners (" << nListeners << ") UNREGISTERING events\n"; HighPrecisionTimer t; t.Start(); UnregisterServices(); long long ms = t.ElapsedMilli(); Log() << "unregister took " << ms << "ms\n"; US_TEST_CONDITION_REQUIRED(nServices * listeners.size() == nUnregistering, "# UNREGISTERING events must be same as # of (un)registered services * # of listeners"); } void ServiceRegistryPerformanceTest::UnregisterServices() { Log() << "unregistering " << regs.size() << " services, listener count=" << listeners.size() << "\n"; for(std::size_t i = 0; i < regs.size(); i++) { ServiceRegistration reg = regs[i]; reg.Unregister(); } regs.clear(); } int usServiceRegistryPerformanceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceRegistryPerformanceTest") ServiceRegistryPerformanceTest perfTest(GetModuleContext()); perfTest.InitTestCase(); perfTest.TestAddListeners(); perfTest.TestRegisterServices(); perfTest.TestModifyServices(); perfTest.TestUnregisterServices(); perfTest.CleanupTestCase(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usServiceRegistryTest.cpp b/Modules/CppMicroServices/core/test/usServiceRegistryTest.cpp index c25fe315cf..0f39a6afae 100644 --- a/Modules/CppMicroServices/core/test/usServiceRegistryTest.cpp +++ b/Modules/CppMicroServices/core/test/usServiceRegistryTest.cpp @@ -1,140 +1,140 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include "usTestingMacros.h" #include #include #include #include US_USE_NAMESPACE struct ITestServiceA { virtual ~ITestServiceA() {} }; void TestServiceInterfaceId() { US_TEST_CONDITION(us_service_interface_iid() == "int", "Service interface id int") US_TEST_CONDITION(us_service_interface_iid() == "ITestServiceA", "Service interface id ITestServiceA") } void TestMultipleServiceRegistrations() { struct TestServiceA : public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; TestServiceA s2; ServiceRegistration reg1 = context->RegisterService(&s1); ServiceRegistration reg2 = context->RegisterService(&s2); std::vector > refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Testing for two registered ITestServiceA services") reg2.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.size() == 1, "Testing for one registered ITestServiceA services") reg1.Unregister(); refs = context->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(refs.empty(), "Testing for no ITestServiceA services") ServiceReference ref = context->GetServiceReference(); US_TEST_CONDITION_REQUIRED(!ref, "Testing for invalid service reference") } void TestServicePropertiesUpdate() { struct TestServiceA : public ITestServiceA { }; ModuleContext* context = GetModuleContext(); TestServiceA s1; ServiceProperties props; props["string"] = std::string("A std::string"); props["bool"] = false; const char* str = "A const char*"; props["const char*"] = str; ServiceRegistration reg1 = context->RegisterService(&s1, props); ServiceReference ref1 = context->GetServiceReference(); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 1, "Testing service count") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == false, "Testing bool property") // register second service with higher rank TestServiceA s2; ServiceProperties props2; props2[ServiceConstants::SERVICE_RANKING()] = 50; ServiceRegistration reg2 = context->RegisterService(&s2, props2); // Get the service with the highest rank, this should be s2. ServiceReference ref2 = context->GetServiceReference(); TestServiceA* service = dynamic_cast(context->GetService(ref2)); US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") props["bool"] = true; // change the service ranking props[ServiceConstants::SERVICE_RANKING()] = 100; reg1.SetProperties(props); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().size() == 2, "Testing service count") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty("bool")) == true, "Testing bool property") US_TEST_CONDITION_REQUIRED(any_cast(ref1.GetProperty(ServiceConstants::SERVICE_RANKING())) == 100, "Testing updated ranking") // Service with the highest ranking should now be s1 service = dynamic_cast(context->GetService(ref1)); US_TEST_CONDITION_REQUIRED(service == &s1, "Testing highest service rank") reg1.Unregister(); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count") service = dynamic_cast(context->GetService(ref2)); US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank") reg2.Unregister(); US_TEST_CONDITION_REQUIRED(context->GetServiceReferences().empty(), "Testing service count") } int usServiceRegistryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceRegistryTest"); TestServiceInterfaceId(); TestMultipleServiceRegistrations(); TestServicePropertiesUpdate(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usServiceTemplateTest.cpp b/Modules/CppMicroServices/core/test/usServiceTemplateTest.cpp index da83dfd118..9782180fea 100644 --- a/Modules/CppMicroServices/core/test/usServiceTemplateTest.cpp +++ b/Modules/CppMicroServices/core/test/usServiceTemplateTest.cpp @@ -1,208 +1,208 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include "usTestingMacros.h" struct Interface1 {}; struct Interface2 {}; struct Interface3 {}; struct MyService1 : public Interface1 {}; struct MyService2 : public Interface1, public Interface2 {}; struct MyService3 : public Interface1, public Interface2, public Interface3 {}; struct MyFactory1 : public us::ServiceFactory { std::map m_idToServiceMap; us::InterfaceMap GetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/) override { MyService1* s = new MyService1; m_idToServiceMap.insert(std::make_pair(module->GetModuleId(), s)); return us::MakeInterfaceMap(s); } void UngetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) override { std::map::iterator iter = m_idToServiceMap.find(module->GetModuleId()); if (iter != m_idToServiceMap.end()) { US_TEST_CONDITION(static_cast(iter->second) == us::ExtractInterface(service), "Compare service pointer") delete iter->second; m_idToServiceMap.erase(iter); } } }; struct MyFactory2 : public us::ServiceFactory { std::map m_idToServiceMap; us::InterfaceMap GetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/) override { MyService2* s = new MyService2; m_idToServiceMap.insert(std::make_pair(module->GetModuleId(), s)); return us::MakeInterfaceMap(s); } void UngetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) override { std::map::iterator iter = m_idToServiceMap.find(module->GetModuleId()); if (iter != m_idToServiceMap.end()) { US_TEST_CONDITION(static_cast(iter->second) == us::ExtractInterface(service), "Compare service pointer") delete iter->second; m_idToServiceMap.erase(iter); } } }; struct MyFactory3 : public us::ServiceFactory { std::map m_idToServiceMap; us::InterfaceMap GetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/) override { MyService3* s = new MyService3; m_idToServiceMap.insert(std::make_pair(module->GetModuleId(), s)); return us::MakeInterfaceMap(s); } void UngetService(us::Module* module, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) override { std::map::iterator iter = m_idToServiceMap.find(module->GetModuleId()); if (iter != m_idToServiceMap.end()) { US_TEST_CONDITION(static_cast(iter->second) == us::ExtractInterface(service), "Compare service pointer") delete iter->second; m_idToServiceMap.erase(iter); } } }; US_USE_NAMESPACE int usServiceTemplateTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceTemplateTest"); ModuleContext* mc = GetModuleContext(); // Register compile tests MyService1 s1; MyService2 s2; MyService3 s3; us::ServiceRegistration sr1 = mc->RegisterService(&s1); us::ServiceRegistration sr2 = mc->RegisterService(&s2); us::ServiceRegistration sr3 = mc->RegisterService(&s3); MyFactory1 f1; us::ServiceRegistration sfr1 = mc->RegisterService(&f1); MyFactory2 f2; us::ServiceRegistration sfr2 = mc->RegisterService(static_cast(&f2)); MyFactory3 f3; us::ServiceRegistration sfr3 = mc->RegisterService(static_cast(&f3)); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(mc->GetModule()->GetRegisteredServices().size() == 6, "# of reg services") #endif std::vector > s1refs = mc->GetServiceReferences(); US_TEST_CONDITION(s1refs.size() == 6, "# of interface1 regs") std::vector > s2refs = mc->GetServiceReferences(); US_TEST_CONDITION(s2refs.size() == 4, "# of interface2 regs") std::vector > s3refs = mc->GetServiceReferences(); US_TEST_CONDITION(s3refs.size() == 2, "# of interface3 regs") Interface1* i1 = mc->GetService(sr1.GetReference()); US_TEST_CONDITION(i1 == static_cast(&s1), "interface1 ptr") i1 = nullptr; US_TEST_CONDITION(mc->UngetService(sr1.GetReference()), "unget interface1 ptr") i1 = mc->GetService(sfr1.GetReference()); US_TEST_CONDITION(i1 == static_cast(f1.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface1 factory ptr") i1 = nullptr; US_TEST_CONDITION(mc->UngetService(sfr1.GetReference()), "unget interface1 factory ptr") i1 = mc->GetService(sr2.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(&s2), "interface1 ptr") i1 = nullptr; US_TEST_CONDITION(mc->UngetService(sr2.GetReference(InterfaceType())), "unget interface1 ptr") i1 = mc->GetService(sfr2.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(f2.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface1 factory ptr") i1 = nullptr; US_TEST_CONDITION(mc->UngetService(sfr2.GetReference(InterfaceType())), "unget interface1 factory ptr") Interface2* i2 = mc->GetService(sr2.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(&s2), "interface2 ptr") i2 = nullptr; US_TEST_CONDITION(mc->UngetService(sr2.GetReference(InterfaceType())), "unget interface2 ptr") i2 = mc->GetService(sfr2.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(f2.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface2 factory ptr") i2 = nullptr; US_TEST_CONDITION(mc->UngetService(sfr2.GetReference(InterfaceType())), "unget interface2 factory ptr") i1 = mc->GetService(sr3.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(&s3), "interface1 ptr") i1 = nullptr; US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceType())), "unget interface1 ptr") i1 = mc->GetService(sfr3.GetReference(InterfaceType())); US_TEST_CONDITION(i1 == static_cast(f3.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface1 factory ptr") i1 = nullptr; US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceType())), "unget interface1 factory ptr") i2 = mc->GetService(sr3.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(&s3), "interface2 ptr") i2 = nullptr; US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceType())), "unget interface2 ptr") i2 = mc->GetService(sfr3.GetReference(InterfaceType())); US_TEST_CONDITION(i2 == static_cast(f3.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface2 factory ptr") i2 = nullptr; US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceType())), "unget interface2 factory ptr") Interface3* i3 = mc->GetService(sr3.GetReference(InterfaceType())); US_TEST_CONDITION(i3 == static_cast(&s3), "interface3 ptr") i3 = nullptr; US_TEST_CONDITION(mc->UngetService(sr3.GetReference(InterfaceType())), "unget interface3 ptr") i3 = mc->GetService(sfr3.GetReference(InterfaceType())); US_TEST_CONDITION(i3 == static_cast(f3.m_idToServiceMap[mc->GetModule()->GetModuleId()]), "interface3 factory ptr") i3 = nullptr; US_TEST_CONDITION(mc->UngetService(sfr3.GetReference(InterfaceType())), "unget interface3 factory ptr") sr1.Unregister(); sr2.Unregister(); sr3.Unregister(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usServiceTrackerTest.cpp b/Modules/CppMicroServices/core/test/usServiceTrackerTest.cpp index 38d4dccaad..a6cb2f70ef 100644 --- a/Modules/CppMicroServices/core/test/usServiceTrackerTest.cpp +++ b/Modules/CppMicroServices/core/test/usServiceTrackerTest.cpp @@ -1,287 +1,287 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include #include "usServiceControlInterface.h" #include US_USE_NAMESPACE bool CheckConvertibility(const std::vector& refs, std::vector::const_iterator idBegin, std::vector::const_iterator idEnd) { std::vector ids; ids.assign(idBegin, idEnd); for (std::vector::const_iterator sri = refs.begin(); sri != refs.end(); ++sri) { for (std::vector::iterator idIter = ids.begin(); idIter != ids.end(); ++idIter) { if (sri->IsConvertibleTo(*idIter)) { ids.erase(idIter); break; } } } return ids.empty(); } struct MyInterfaceOne { virtual ~MyInterfaceOne() {} }; struct MyInterfaceTwo { virtual ~MyInterfaceTwo() {} }; class MyCustomizer : public us::ServiceTrackerCustomizer { public: MyCustomizer(us::ModuleContext* context) : m_context(context) {} MyInterfaceOne* AddingService(const ServiceReferenceType& reference) override { US_TEST_CONDITION_REQUIRED(reference, "AddingService() valid reference") return m_context->GetService(reference); } void ModifiedService(const ServiceReferenceType& reference, MyInterfaceOne* service) override { US_TEST_CONDITION(reference, "ModifiedService() valid reference") US_TEST_CONDITION(service, "ModifiedService() valid service") } void RemovedService(const ServiceReferenceType& reference, MyInterfaceOne* service) override { US_TEST_CONDITION(reference, "RemovedService() valid reference") US_TEST_CONDITION(service, "RemovedService() valid service") } private: us::ModuleContext* m_context; }; void TestFilterString() { us::ModuleContext* context = us::GetModuleContext(); MyCustomizer customizer(context); us::LDAPFilter filter("(" + us::ServiceConstants::SERVICE_ID() + ">=0)"); us::ServiceTracker tracker(context, filter, &customizer); tracker.Open(); struct MyServiceOne : public MyInterfaceOne {}; struct MyServiceTwo : public MyInterfaceTwo {}; MyServiceOne serviceOne; MyServiceTwo serviceTwo; ServiceRegistration reg1 = context->RegisterService(&serviceOne); ServiceRegistration reg2 = context->RegisterService(&serviceTwo); US_TEST_CONDITION(tracker.GetServiceReferences().size() == 1, "tracking count") reg1.Unregister(); reg2.Unregister(); } void TestServiceTracker() { #ifdef US_PLATFORM_WINDOWS const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif ModuleContext* mc = GetModuleContext(); SharedLibrary libS(LIB_PATH, "TestModuleS"); #ifdef US_BUILD_SHARED_LIBS // Start the test target to get a service published. try { libS.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() ); } #endif // 1. Create a ServiceTracker with ServiceTrackerCustomizer == null std::string s1("us::TestModuleSService"); ServiceReferenceU servref = mc->GetServiceReference(s1 + "0"); US_TEST_CONDITION_REQUIRED(servref != nullptr, "Test if registered service of id us::TestModuleSService0"); ServiceReference servCtrlRef = mc->GetServiceReference(); US_TEST_CONDITION_REQUIRED(servCtrlRef != nullptr, "Test if constrol service was registered"); ServiceControlInterface* serviceController = mc->GetService(servCtrlRef); US_TEST_CONDITION_REQUIRED(serviceController != nullptr, "Test valid service controller"); std::unique_ptr> st1(new ServiceTracker(mc, servref)); // 2. Check the size method with an unopened service tracker US_TEST_CONDITION_REQUIRED(st1->Size() == 0, "Test if size == 0"); // 3. Open the service tracker and see what it finds, // expect to find one instance of the implementation, // "org.cppmicroservices.TestModuleSService0" st1->Open(); std::vector sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 1, "Checking ServiceTracker size"); US_TEST_CONDITION_REQUIRED(s1 + "0" == sa2[0].GetInterfaceId(), "Checking service implementation name"); // 5. Close this service tracker st1->Close(); // 6. Check the size method, now when the servicetracker is closed US_TEST_CONDITION_REQUIRED(st1->Size() == 0, "Checking ServiceTracker size"); // 7. Check if we still track anything , we should get null sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.empty(), "Checking ServiceTracker size"); // 8. A new Servicetracker, this time with a filter for the object std::string fs = std::string("(") + ServiceConstants::OBJECTCLASS() + "=" + s1 + "*" + ")"; LDAPFilter f1(fs); st1.reset(new ServiceTracker(mc, f1)); // add a service serviceController->ServiceControl(1, "register", 7); // 9. Open the service tracker and see what it finds, // expect to find two instances of references to // "org.cppmicroservices.TestModuleSService*" // i.e. they refer to the same piece of code std::vector ids; ids.push_back((s1 + "0")); ids.push_back((s1 + "1")); ids.push_back((s1 + "2")); ids.push_back((s1 + "3")); st1->Open(); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 2, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.begin()+2), "Check for expected interface id [0]"); US_TEST_CONDITION_REQUIRED(sa2[1].IsConvertibleTo(s1 + "1"), "Check for expected interface id [1]"); // 10. Get libTestModuleS to register one more service and see if it appears serviceController->ServiceControl(2, "register", 1); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 3, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.begin()+3), "Check for expected interface id [2]"); // 11. Get libTestModuleS to register one more service and see if it appears serviceController->ServiceControl(3, "register", 2); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 4, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.end()), "Check for expected interface id [3]"); // 12. Get libTestModuleS to unregister one service and see if it disappears serviceController->ServiceControl(3, "unregister", 0); sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 3, "Checking service reference count"); // 13. Get the highest ranking service reference, it should have ranking 7 ServiceReferenceU h1 = st1->GetServiceReference(); int rank = any_cast(h1.GetProperty(ServiceConstants::SERVICE_RANKING())); US_TEST_CONDITION_REQUIRED(rank == 7, "Check service rank"); // 14. Get the service of the highest ranked service reference InterfaceMap o1 = st1->GetService(h1); US_TEST_CONDITION_REQUIRED(!o1.empty(), "Check for non-null service"); // 14a Get the highest ranked service, directly this time InterfaceMap o3 = st1->GetService(); US_TEST_CONDITION_REQUIRED(!o3.empty(), "Check for non-null service"); US_TEST_CONDITION_REQUIRED(o1 == o3, "Check for equal service instances"); // 15. Now release the tracking of that service and then try to get it // from the servicetracker, which should yield a null object serviceController->ServiceControl(1, "unregister", 7); InterfaceMap o2 = st1->GetService(h1); US_TEST_CONDITION_REQUIRED(o2.empty(), "Checkt that service is null"); // 16. Get all service objects this tracker tracks, it should be 2 std::vector ts1 = st1->GetServices(); US_TEST_CONDITION_REQUIRED(ts1.size() == 2, "Check service count"); // 17. Test the remove method. // First register another service, then remove it being tracked serviceController->ServiceControl(1, "register", 7); h1 = st1->GetServiceReference(); std::vector sa3 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa3.size() == 3, "Check service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa3, ids.begin(), ids.begin()+3), "Check for expected interface id [0]"); st1->Remove(h1); // remove tracking on one servref sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 2, "Check service reference count"); // 18. Test the addingService method,add a service reference // 19. Test the removedService method, remove a service reference // 20. Test the waitForService method InterfaceMap o9 = st1->WaitForService(50); US_TEST_CONDITION_REQUIRED(!o9.empty(), "Checking WaitForService method"); } int usServiceTrackerTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceTrackerTest") TestFilterString(); TestServiceTracker(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usSharedLibraryTest.cpp b/Modules/CppMicroServices/core/test/usSharedLibraryTest.cpp index b700afa6ff..5cde7ea228 100644 --- a/Modules/CppMicroServices/core/test/usSharedLibraryTest.cpp +++ b/Modules/CppMicroServices/core/test/usSharedLibraryTest.cpp @@ -1,118 +1,118 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include "usTestingMacros.h" #include "usTestingConfig.h" #include #include US_USE_NAMESPACE int usSharedLibraryTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("SharedLibraryTest"); #ifdef US_PLATFORM_WINDOWS const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; const std::string LIB_PREFIX = ""; const std::string LIB_SUFFIX = ".dll"; const char PATH_SEPARATOR = '\\'; #elif defined(US_PLATFORM_APPLE) const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; const std::string LIB_PREFIX = "lib"; const std::string LIB_SUFFIX = ".dylib"; const char PATH_SEPARATOR = '/'; #else const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; const std::string LIB_PREFIX = "lib"; const std::string LIB_SUFFIX = ".so"; const char PATH_SEPARATOR = '/'; #endif const std::string libAFilePath = LIB_PATH + PATH_SEPARATOR + LIB_PREFIX + "TestModuleA" + LIB_SUFFIX; SharedLibrary lib1(libAFilePath); US_TEST_CONDITION(lib1.GetFilePath() == libAFilePath, "Absolute file path") US_TEST_CONDITION(lib1.GetLibraryPath() == LIB_PATH, "Library path") US_TEST_CONDITION(lib1.GetName() == "TestModuleA", "Name") US_TEST_CONDITION(lib1.GetPrefix() == LIB_PREFIX, "Prefix") US_TEST_CONDITION(lib1.GetSuffix() == LIB_SUFFIX, "Suffix") lib1.SetName("bla"); US_TEST_CONDITION(lib1.GetName() == "TestModuleA", "Name after SetName()") lib1.SetLibraryPath("bla"); US_TEST_CONDITION(lib1.GetLibraryPath() == LIB_PATH, "Library path after SetLibraryPath()") lib1.SetPrefix("bla"); US_TEST_CONDITION(lib1.GetPrefix() == LIB_PREFIX, "Prefix after SetPrefix()") lib1.SetSuffix("bla"); US_TEST_CONDITION(lib1.GetSuffix() == LIB_SUFFIX, "Suffix after SetSuffix()") US_TEST_CONDITION(lib1.GetFilePath() == libAFilePath, "File path after setters") lib1.SetFilePath("bla"); US_TEST_CONDITION(lib1.GetFilePath() == "bla", "Invalid file path") US_TEST_CONDITION(lib1.GetLibraryPath().empty(), "Empty lib path") US_TEST_CONDITION(lib1.GetName() == "bla", "Invalid file name") US_TEST_CONDITION(lib1.GetPrefix() == LIB_PREFIX, "Invalid prefix") US_TEST_CONDITION(lib1.GetSuffix() == LIB_SUFFIX, "Invalid suffix") US_TEST_FOR_EXCEPTION(std::runtime_error, lib1.Load()) US_TEST_CONDITION(lib1.IsLoaded() == false, "Is loaded") US_TEST_CONDITION(lib1.GetHandle() == nullptr, "Handle") lib1.SetFilePath(libAFilePath); lib1.Load(); US_TEST_CONDITION(lib1.IsLoaded() == true, "Is loaded") US_TEST_CONDITION(lib1.GetHandle() != nullptr, "Handle") US_TEST_FOR_EXCEPTION(std::logic_error, lib1.Load()) lib1.SetFilePath("bla"); US_TEST_CONDITION(lib1.GetFilePath() == libAFilePath, "File path") lib1.Unload(); SharedLibrary lib2(LIB_PATH, "TestModuleA"); US_TEST_CONDITION(lib2.GetFilePath() == libAFilePath, "File path") lib2.SetPrefix(""); US_TEST_CONDITION(lib2.GetPrefix().empty(), "Lib prefix") US_TEST_CONDITION(lib2.GetFilePath() == LIB_PATH + PATH_SEPARATOR + "TestModuleA" + LIB_SUFFIX, "File path") SharedLibrary lib3 = lib2; US_TEST_CONDITION(lib3.GetFilePath() == lib2.GetFilePath(), "Compare file path") lib3.SetPrefix(LIB_PREFIX); US_TEST_CONDITION(lib3.GetFilePath() == libAFilePath, "Compare file path") lib3.Load(); US_TEST_CONDITION(lib3.IsLoaded(), "lib3 loaded") US_TEST_CONDITION(!lib2.IsLoaded(), "lib2 not loaded") lib1 = lib3; US_TEST_FOR_EXCEPTION(std::logic_error, lib1.Load()) lib2.SetPrefix(LIB_PREFIX); lib2.Load(); lib3.Unload(); US_TEST_CONDITION(!lib3.IsLoaded(), "lib3 unloaded") US_TEST_CONDITION(!lib1.IsLoaded(), "lib3 unloaded") lib2.Unload(); lib1.Unload(); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usStaticModuleResourceTest.cpp b/Modules/CppMicroServices/core/test/usStaticModuleResourceTest.cpp index c13f5c6481..1f5eb19632 100644 --- a/Modules/CppMicroServices/core/test/usStaticModuleResourceTest.cpp +++ b/Modules/CppMicroServices/core/test/usStaticModuleResourceTest.cpp @@ -1,146 +1,146 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include "usTestingMacros.h" #include "usTestingConfig.h" #include #include US_USE_NAMESPACE namespace { std::string GetResourceContent(const ModuleResource& resource) { std::string line; ModuleResourceStream rs(resource); std::getline(rs, line); return line; } struct ResourceComparator { bool operator()(const ModuleResource& mr1, const ModuleResource& mr2) const { return mr1 < mr2; } }; void testResourceOperators(Module* module) { std::vector resources = module->FindResources("", "res.txt", false); US_TEST_CONDITION_REQUIRED(resources.size() == 1, "Check resource count") } void testResourcesWithStaticImport(Module* module) { ModuleResource resource = module->GetResource("res.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid res.txt resource") std::string line = GetResourceContent(resource); US_TEST_CONDITION(line == "dynamic resource", "Check dynamic resource content") resource = module->GetResource("dynamic.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid dynamic.txt resource") line = GetResourceContent(resource); US_TEST_CONDITION(line == "dynamic", "Check dynamic resource content") resource = module->GetResource("static.txt"); US_TEST_CONDITION_REQUIRED(!resource.IsValid(), "Check in-valid static.txt resource") Module* importedByBModule = ModuleRegistry::GetModule("TestModuleImportedByB"); US_TEST_CONDITION_REQUIRED(importedByBModule != nullptr, "Check valid static module") resource = importedByBModule->GetResource("static.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid static.txt resource") line = GetResourceContent(resource); US_TEST_CONDITION(line == "static", "Check static resource content") std::vector resources = module->FindResources("", "*.txt", false); std::stable_sort(resources.begin(), resources.end(), ResourceComparator()); std::vector importedResources = importedByBModule->FindResources("", "*.txt", false); std::stable_sort(importedResources.begin(), importedResources.end(), ResourceComparator()); US_TEST_CONDITION(resources.size() == 2, "Check resource count") US_TEST_CONDITION(importedResources.size() == 2, "Check resource count") line = GetResourceContent(resources[0]); US_TEST_CONDITION(line == "dynamic", "Check dynamic.txt resource content") line = GetResourceContent(resources[1]); US_TEST_CONDITION(line == "dynamic resource", "Check res.txt (from importing module) resource content") line = GetResourceContent(importedResources[0]); US_TEST_CONDITION(line == "static resource", "Check res.txt (from imported module) resource content") line = GetResourceContent(importedResources[1]); US_TEST_CONDITION(line == "static", "Check static.txt (from importing module) resource content") } } // end unnamed namespace int usStaticModuleResourceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("StaticModuleResourceTest"); assert(GetModuleContext()); #ifdef US_BUILD_SHARED_LIBS #ifdef US_PLATFORM_WINDOWS const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif SharedLibrary libB(LIB_PATH, "TestModuleB"); try { libB.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #endif Module* module = ModuleRegistry::GetModule("TestModuleB"); US_TEST_CONDITION_REQUIRED(module != nullptr, "Test for existing module TestModuleB") US_TEST_CONDITION(module->GetName() == "TestModuleB", "Test module name") testResourceOperators(module); testResourcesWithStaticImport(module); ModuleResource resource = ModuleRegistry::GetModule("TestModuleImportedByB")->GetResource("static.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid static.txt resource") #ifdef US_BUILD_SHARED_LIBS libB.Unload(); US_TEST_CONDITION_REQUIRED(resource.IsValid() == true, "Check still valid static.txt resource") #endif US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp b/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp index 424ddd7c7f..ee433b74ed 100644 --- a/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp +++ b/Modules/CppMicroServices/core/test/usStaticModuleTest.cpp @@ -1,183 +1,183 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include #include #include #include #include "usTestUtilModuleListener.h" #include "usTestingMacros.h" #include "usTestingConfig.h" US_USE_NAMESPACE namespace { #ifdef US_PLATFORM_WINDOWS static const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else static const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif // Load libTestModuleB and check that it exists and that the service it registers exists, // also check that the expected events occur void frame020a(ModuleContext* mc, TestModuleListener& listener, #ifdef US_BUILD_SHARED_LIBS SharedLibrary& libB) { try { libB.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } #else SharedLibrary& /*libB*/) { #endif Module* moduleB = ModuleRegistry::GetModule("TestModuleB"); US_TEST_CONDITION_REQUIRED(moduleB != nullptr, "Test for existing module TestModuleB") Module* moduleImportedByB = ModuleRegistry::GetModule("TestModuleImportedByB"); US_TEST_CONDITION_REQUIRED(moduleImportedByB != nullptr, "Test for existing module TestModuleImportedByB") US_TEST_CONDITION(moduleB->GetName() == "TestModuleB", "Test module name") // Check if libB registered the expected service try { std::vector refs = mc->GetServiceReferences("us::TestModuleBService"); US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Test that both the service from the shared and imported library are regsitered"); InterfaceMap o1 = mc->GetService(refs.front()); US_TEST_CONDITION(!o1.empty(), "Test if first service object found"); InterfaceMap o2 = mc->GetService(refs.back()); US_TEST_CONDITION(!o2.empty(), "Test if second service object found"); try { US_TEST_CONDITION(mc->UngetService(refs.front()), "Test if Service UnGet for first service returns true"); US_TEST_CONDITION(mc->UngetService(refs.back()), "Test if Service UnGet for second service returns true"); } catch (const std::logic_error &le) { US_TEST_FAILED_MSG(<< "UnGetService exception: " << le.what()) } // check the listeners for events std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADING, moduleImportedByB)); pEvts.push_back(ModuleEvent(ModuleEvent::LOADED, moduleImportedByB)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, refs.back())); seEvts.push_back(ServiceEvent(ServiceEvent::REGISTERED, refs.front())); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } catch (const ServiceException& /*se*/) { US_TEST_FAILED_MSG(<< "test module, expected service not found"); } #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleB->IsLoaded() == true, "Test if loaded correctly"); #endif } // Unload libB and check for correct events void frame030b(ModuleContext* mc, TestModuleListener& listener, SharedLibrary& libB) { Module* moduleB = ModuleRegistry::GetModule("TestModuleB"); US_TEST_CONDITION_REQUIRED(moduleB != nullptr, "Test for non-null module") Module* moduleImportedByB = ModuleRegistry::GetModule("TestModuleImportedByB"); US_TEST_CONDITION_REQUIRED(moduleImportedByB != nullptr, "Test for non-null module") std::vector refs = mc->GetServiceReferences("us::TestModuleBService"); US_TEST_CONDITION(refs.front(), "Test for first valid service reference") US_TEST_CONDITION(refs.back(), "Test for second valid service reference") try { libB.Unload(); #ifdef US_BUILD_SHARED_LIBS US_TEST_CONDITION(moduleB->IsLoaded() == false, "Test for unloaded state") #endif } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "UnLoad module exception: " << e.what()) } std::vector pEvts; #ifdef US_BUILD_SHARED_LIBS pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleImportedByB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleImportedByB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADING, moduleB)); pEvts.push_back(ModuleEvent(ModuleEvent::UNLOADED, moduleB)); #endif std::vector seEvts; #ifdef US_BUILD_SHARED_LIBS seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, refs.front())); seEvts.push_back(ServiceEvent(ServiceEvent::UNREGISTERING, refs.back())); #endif US_TEST_CONDITION(listener.CheckListenerEvents(pEvts, seEvts), "Test for unexpected events"); } } // end unnamed namespace int usStaticModuleTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("StaticModuleTest"); ModuleContext* mc = GetModuleContext(); TestModuleListener listener; ModuleListenerRegistrationHelper ml(mc, &listener, &TestModuleListener::ModuleChanged); ServiceListenerRegistrationHelper sl(mc, &listener, &TestModuleListener::ServiceChanged); SharedLibrary libB(LIB_PATH, "TestModuleB"); frame020a(mc, listener, libB); frame030b(mc, listener, libB); US_TEST_END() } diff --git a/Modules/CppMicroServices/core/test/usTestDriverActivator.cpp b/Modules/CppMicroServices/core/test/usTestDriverActivator.cpp index 4f6a420f0f..ee9432a10c 100644 --- a/Modules/CppMicroServices/core/test/usTestDriverActivator.cpp +++ b/Modules/CppMicroServices/core/test/usTestDriverActivator.cpp @@ -1,69 +1,69 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usTestDriverActivator.h" #include "usModuleImport.h" US_BEGIN_NAMESPACE TestDriverActivator* TestDriverActivator::m_Instance = nullptr; TestDriverActivator::TestDriverActivator() : m_LoadCalled(false) { } bool TestDriverActivator::LoadCalled() { return m_Instance ? m_Instance->m_LoadCalled : false; } void TestDriverActivator::Load(ModuleContext*) { this->m_Instance = this; this->m_LoadCalled = true; } void TestDriverActivator::Unload(ModuleContext*) { this->m_Instance = nullptr; } US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(us::TestDriverActivator) #ifndef US_BUILD_SHARED_LIBS US_IMPORT_MODULE(CppMicroServices) US_IMPORT_MODULE(TestModuleA) US_IMPORT_MODULE(TestModuleA2) US_IMPORT_MODULE(TestModuleB) US_IMPORT_MODULE(TestModuleH) US_IMPORT_MODULE(TestModuleM) US_INITIALIZE_STATIC_MODULE(TestModuleR) US_INITIALIZE_STATIC_MODULE(TestModuleRL) US_INITIALIZE_STATIC_MODULE(TestModuleRA) US_IMPORT_MODULE(TestModuleS) US_IMPORT_MODULE(TestModuleSL1) US_IMPORT_MODULE(TestModuleSL3) US_IMPORT_MODULE(TestModuleSL4) US_IMPORT_MODULE(main) #endif diff --git a/Modules/CppMicroServices/core/test/usTestDriverActivator.h b/Modules/CppMicroServices/core/test/usTestDriverActivator.h index 97b0cda48d..5efc021bfd 100644 --- a/Modules/CppMicroServices/core/test/usTestDriverActivator.h +++ b/Modules/CppMicroServices/core/test/usTestDriverActivator.h @@ -1,49 +1,49 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTDRIVERACTIVATOR_H #define USTESTDRIVERACTIVATOR_H #include US_BEGIN_NAMESPACE class TestDriverActivator : public ModuleActivator { public: TestDriverActivator(); static bool LoadCalled(); void Load(ModuleContext*) override; void Unload(ModuleContext* ) override; private: static TestDriverActivator* m_Instance; bool m_LoadCalled; }; US_END_NAMESPACE #endif // USTESTDRIVERACTIVATOR_H diff --git a/Modules/CppMicroServices/core/test/usTestManager.cpp b/Modules/CppMicroServices/core/test/usTestManager.cpp index 1423d899da..46cd014368 100644 --- a/Modules/CppMicroServices/core/test/usTestManager.cpp +++ b/Modules/CppMicroServices/core/test/usTestManager.cpp @@ -1,59 +1,59 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include "usTestManager.h" US_BEGIN_NAMESPACE TestManager& TestManager::GetInstance() { static TestManager instance; return instance; } void TestManager::Initialize() { m_FailedTests = 0; m_PassedTests = 0; } int TestManager::NumberOfFailedTests() { return m_FailedTests; } int TestManager::NumberOfPassedTests() { return m_PassedTests; } void TestManager::TestFailed() { m_FailedTests++; } void TestManager::TestPassed() { m_PassedTests++; } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/test/usTestManager.h b/Modules/CppMicroServices/core/test/usTestManager.h index 44308228cb..63056319ef 100644 --- a/Modules/CppMicroServices/core/test/usTestManager.h +++ b/Modules/CppMicroServices/core/test/usTestManager.h @@ -1,57 +1,57 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef US_TESTMANAGER_H_INCLUDED #define US_TESTMANAGER_H_INCLUDED #include US_BEGIN_NAMESPACE class TestManager { public: TestManager() : m_FailedTests(0), m_PassedTests(0) {} virtual ~TestManager() {} static TestManager& GetInstance(); /** \brief Must be called at the beginning of a test run. */ void Initialize(); int NumberOfFailedTests(); int NumberOfPassedTests(); /** \brief Tell manager a subtest failed */ void TestFailed(); /** \brief Tell manager a subtest passed */ void TestPassed(); protected: int m_FailedTests; int m_PassedTests; }; US_END_NAMESPACE #endif // US_TESTMANAGER_H_INCLUDED diff --git a/Modules/CppMicroServices/core/test/usTestUtilModuleListener.cpp b/Modules/CppMicroServices/core/test/usTestUtilModuleListener.cpp index 75967289dc..71cb5fb779 100644 --- a/Modules/CppMicroServices/core/test/usTestUtilModuleListener.cpp +++ b/Modules/CppMicroServices/core/test/usTestUtilModuleListener.cpp @@ -1,160 +1,160 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://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 "usTestUtilModuleListener.h" #include "usUtils_p.h" US_BEGIN_NAMESPACE TestModuleListener::TestModuleListener() : serviceEvents(), moduleEvents() {} void TestModuleListener::ModuleChanged(const ModuleEvent event) { moduleEvents.push_back(event); US_DEBUG << "ModuleEvent:" << event; } void TestModuleListener::ServiceChanged(const ServiceEvent event) { serviceEvents.push_back(event); US_DEBUG << "ServiceEvent:" << event; } ModuleEvent TestModuleListener::GetModuleEvent() const { if (moduleEvents.empty()) { return ModuleEvent(); } return moduleEvents.back(); } ServiceEvent TestModuleListener::GetServiceEvent() const { if (serviceEvents.empty()) { return ServiceEvent(); } return serviceEvents.back(); } bool TestModuleListener::CheckListenerEvents( bool pexp, ModuleEvent::Type ptype, bool sexp, ServiceEvent::Type stype, Module* moduleX, ServiceReferenceU* servX) { std::vector pEvts; std::vector seEvts; if (pexp) pEvts.push_back(ModuleEvent(ptype, moduleX)); if (sexp) seEvts.push_back(ServiceEvent(stype, *servX)); return CheckListenerEvents(pEvts, seEvts); } bool TestModuleListener::CheckListenerEvents(const std::vector& pEvts) { bool listenState = true; // assume everything will work if (pEvts.size() != moduleEvents.size()) { listenState = false; US_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 ModuleEvent& pE = i < pEvts.size() ? pEvts[i] : ModuleEvent(); const ModuleEvent& pR = i < moduleEvents.size() ? moduleEvents[i] : ModuleEvent(); US_DEBUG << " " << pE << " - " << pR; } } else { for (std::size_t i = 0; i < pEvts.size(); ++i) { const ModuleEvent& pE = pEvts[i]; const ModuleEvent& pR = moduleEvents[i]; if (pE.GetType() != pR.GetType() || pE.GetModule() != pR.GetModule()) { listenState = false; US_DEBUG << "*** Wrong module event: " << pR << " expected " << pE; } } } moduleEvents.clear(); return listenState; } bool TestModuleListener::CheckListenerEvents(const std::vector& seEvts) { bool listenState = true; // assume everything will work if (seEvts.size() != serviceEvents.size()) { listenState = false; US_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 ServiceEvent& seE = i < seEvts.size() ? seEvts[i] : ServiceEvent(); const ServiceEvent& seR = i < serviceEvents.size() ? serviceEvents[i] : ServiceEvent(); US_DEBUG << " " << seE << " - " << seR; } } else { for (std::size_t i = 0; i < seEvts.size(); ++i) { const ServiceEvent& seE = seEvts[i]; const ServiceEvent& seR = serviceEvents[i]; if (seE.GetType() != seR.GetType() || (!(seE.GetServiceReference() == seR.GetServiceReference()))) { listenState = false; US_DEBUG << "*** Wrong service event: " << seR << " expected " << seE; } } } serviceEvents.clear(); return listenState; } bool TestModuleListener::CheckListenerEvents( const std::vector& pEvts, const std::vector& seEvts) { if (!CheckListenerEvents(pEvts)) return false; return CheckListenerEvents(seEvts); } US_END_NAMESPACE diff --git a/Modules/CppMicroServices/core/test/usTestUtilModuleListener.h b/Modules/CppMicroServices/core/test/usTestUtilModuleListener.h index 82dc0c4946..a52dcb0c8e 100644 --- a/Modules/CppMicroServices/core/test/usTestUtilModuleListener.h +++ b/Modules/CppMicroServices/core/test/usTestUtilModuleListener.h @@ -1,141 +1,141 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTUTILMODULELISTENER_H #define USTESTUTILMODULELISTENER_H #include "usModuleEvent.h" #include "usServiceEvent.h" #include "usModuleContext.h" #include "usTestingMacros.h" US_BEGIN_NAMESPACE class ModuleContext; class TestModuleListener { public: TestModuleListener(); void ModuleChanged(const ModuleEvent event); void ServiceChanged(const ServiceEvent event); ModuleEvent GetModuleEvent() const; ServiceEvent GetServiceEvent() const; bool CheckListenerEvents( bool pexp, ModuleEvent::Type ptype, bool sexp, ServiceEvent::Type stype, Module* moduleX, ServiceReferenceU* servX); bool CheckListenerEvents(const std::vector& pEvts); bool CheckListenerEvents(const std::vector& seEvts); bool CheckListenerEvents(const std::vector& pEvts, const std::vector& seEvts); private: std::vector serviceEvents; std::vector moduleEvents; }; template class ModuleListenerRegistrationHelper { public: typedef void(Receiver::*CallbackType)(const ModuleEvent); ModuleListenerRegistrationHelper(ModuleContext* context, Receiver* receiver, CallbackType callback) : context(context) , receiver(receiver) , callback(callback) { try { context->AddModuleListener(receiver, callback); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "module listener registration failed " << ise.what() ); throw; } } ~ModuleListenerRegistrationHelper() { context->RemoveModuleListener(receiver, callback); } private: ModuleContext* context; Receiver* receiver; CallbackType callback; }; template class ServiceListenerRegistrationHelper { public: typedef void(Receiver::*CallbackType)(const ServiceEvent); ServiceListenerRegistrationHelper(ModuleContext* context, Receiver* receiver, CallbackType callback) : context(context) , receiver(receiver) , callback(callback) { try { context->AddServiceListener(receiver, callback); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); throw; } } ~ServiceListenerRegistrationHelper() { context->RemoveServiceListener(receiver, callback); } private: ModuleContext* context; Receiver* receiver; CallbackType callback; }; US_END_NAMESPACE #endif // USTESTUTILMODULELISTENER_H diff --git a/Modules/CppMicroServices/core/test/usTestingMacros.h b/Modules/CppMicroServices/core/test/usTestingMacros.h index b415f8471a..036cc1cbd2 100644 --- a/Modules/CppMicroServices/core/test/usTestingMacros.h +++ b/Modules/CppMicroServices/core/test/usTestingMacros.h @@ -1,138 +1,138 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #ifndef USTESTINGMACROS_H_ #define USTESTINGMACROS_H_ #include #include #include #include #include "usTestManager.h" US_BEGIN_NAMESPACE /** \brief Indicate a failed test. */ class TestFailedException : public std::exception { public: TestFailedException() {} }; US_END_NAMESPACE /** * * \brief Output some text without generating a terminating newline. * * */ #define US_TEST_OUTPUT_NO_ENDL(x) \ std::cout x << std::flush; /** \brief Output some text. */ #define US_TEST_OUTPUT(x) \ US_TEST_OUTPUT_NO_ENDL(x << "\n") /** \brief Do some general test preparations. Must be called first in the main test function. */ #define US_TEST_BEGIN(testName) \ std::string usTestName(#testName); \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().Initialize(); \ try { /** \brief Fail and finish test with message MSG */ #define US_TEST_FAILED_MSG(MSG) \ US_TEST_OUTPUT(MSG) \ throw US_PREPEND_NAMESPACE(TestFailedException)(); /** \brief Must be called last in the main test function. */ #define US_TEST_END() \ } catch (const US_PREPEND_NAMESPACE(TestFailedException)&) { \ US_TEST_OUTPUT(<< "Further test execution skipped.") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ } catch (const std::exception& ex) { \ US_TEST_OUTPUT(<< "Exception occured " << ex.what()) \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ } \ if (US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfFailedTests() > 0) { \ US_TEST_OUTPUT(<< usTestName << ": [DONE FAILED] , subtests passed: " << \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfPassedTests() << " failed: " << \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfFailedTests() ) \ return EXIT_FAILURE; \ } else { \ US_TEST_OUTPUT(<< usTestName << ": " \ << US_PREPEND_NAMESPACE(TestManager)::GetInstance().NumberOfPassedTests() \ << " tests [DONE PASSED]") \ return EXIT_SUCCESS; \ } #define US_TEST_CONDITION(COND,MSG) \ US_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ US_TEST_OUTPUT(<< " [FAILED]\n" << "In " << __FILE__ \ << ", line " << __LINE__ \ << ": " #COND " : [FAILED]") \ } else { \ US_TEST_OUTPUT(<< " [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } #define US_TEST_CONDITION_REQUIRED(COND,MSG) \ US_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ US_TEST_FAILED_MSG(<< " [FAILED]\n" << " +--> in " << __FILE__ \ << ", line " << __LINE__ \ << ", expression is false: \"" #COND "\"") \ } else { \ US_TEST_OUTPUT(<< " [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } /** * \brief Begin block which should be checked for exceptions * * This macro, together with US_TEST_FOR_EXCEPTION_END, can be used * to test whether a code block throws an expected exception. The test FAILS if the * exception is NOT thrown. */ #define US_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ try { #define US_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestFailed(); \ US_TEST_OUTPUT( << "Expected an '" << #EXCEPTIONCLASS << "' exception. [FAILED]") \ } \ catch (const EXCEPTIONCLASS &) { \ US_TEST_OUTPUT(<< "Caught an expected '" << #EXCEPTIONCLASS \ << "' exception. [PASSED]") \ US_PREPEND_NAMESPACE(TestManager)::GetInstance().TestPassed(); \ } /** * \brief Simplified version of US_TEST_FOR_EXCEPTION_BEGIN / END for * a single statement */ #define US_TEST_FOR_EXCEPTION(EXCEPTIONCLASS, STATEMENT) \ US_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ STATEMENT ; \ US_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) #endif // USTESTINGMACROS_H_ diff --git a/Modules/CppMicroServices/doc/CMakeDoxygenFilter.cpp b/Modules/CppMicroServices/doc/CMakeDoxygenFilter.cpp index 98911ce407..f04f7f0d18 100644 --- a/Modules/CppMicroServices/doc/CMakeDoxygenFilter.cpp +++ b/Modules/CppMicroServices/doc/CMakeDoxygenFilter.cpp @@ -1,495 +1,495 @@ /*============================================================================ Library: CppMicroServices Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================================================*/ #include #include #include #include #include //-------------------------------------- // Utilitiy classes and functions //-------------------------------------- struct ci_char_traits : public std::char_traits // just inherit all the other functions // that we don't need to override { static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); } static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); } static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); } static bool gt(char c1, char c2) { return toupper(c1) > toupper(c2); } static int compare(const char* s1, const char* s2, std::size_t n) { while (n-- > 0) { if (lt(*s1, *s2)) return -1; if (gt(*s1, *s2)) return 1; ++s1; ++s2; } return 0; } static const char* find(const char* s, int n, char a) { while (n-- > 0 && toupper(*s) != toupper(a)) { ++s; } return s; } }; typedef std::basic_string ci_string; //-------------------------------------- // Lexer //-------------------------------------- class CMakeLexer { public: enum Token { TOK_EOF = -1, TOK_EOL = -2, // commands TOK_MACRO = -3, TOK_ENDMACRO = -4, TOK_FUNCTION = -5, TOK_ENDFUNCTION = -6, TOK_DOXYGEN_COMMENT = -7, TOK_SET = -8, TOK_STRING_LITERAL = -100, TOK_NUMBER_LITERAL = -102, // primary TOK_IDENTIFIER = -200 }; CMakeLexer(std::istream& is) : _lastChar(' '), _is(is), _line(1), _col(1) {} int getToken() { // skip whitespace while (isspace(_lastChar) && _lastChar != '\r' && _lastChar != '\n') { _lastChar = getChar(); } if (isalpha(_lastChar) || _lastChar == '_') { _identifier = _lastChar; while (isalnum(_lastChar = getChar()) || _lastChar == '-' || _lastChar == '_') { _identifier += _lastChar; } if (_identifier == "set") return TOK_SET; if (_identifier == "function") return TOK_FUNCTION; if (_identifier == "macro") return TOK_MACRO; if (_identifier == "endfunction") return TOK_ENDFUNCTION; if (_identifier == "endmacro") return TOK_ENDMACRO; return TOK_IDENTIFIER; } if (isdigit(_lastChar)) { // very lax!! number detection _identifier = _lastChar; while (isalnum(_lastChar = getChar()) || _lastChar == '.' || _lastChar == ',') { _identifier += _lastChar; } return TOK_NUMBER_LITERAL; } if (_lastChar == '#') { _lastChar = getChar(); if (_lastChar == '!') { // found a doxygen comment marker _identifier.clear(); _lastChar = getChar(); while (_lastChar != EOF && _lastChar != '\n' && _lastChar != '\r') { _identifier += _lastChar; _lastChar = getChar(); } return TOK_DOXYGEN_COMMENT; } // skip the comment while (_lastChar != EOF && _lastChar != '\n' && _lastChar != '\r') { _lastChar = getChar(); } } if (_lastChar == '"') { _lastChar = getChar(); _identifier.clear(); while (_lastChar != EOF && _lastChar != '"') { _identifier += _lastChar; _lastChar = getChar(); } // eat the closing " _lastChar = getChar(); return TOK_STRING_LITERAL; } // don't eat the EOF if (_lastChar == EOF) return TOK_EOF; // don't eat the EOL if (_lastChar == '\r' || _lastChar == '\n') { if (_lastChar == '\r') _lastChar = getChar(); if (_lastChar == '\n') _lastChar = getChar(); return TOK_EOL; } // return the character as its ascii value int thisChar = _lastChar; _lastChar = getChar(); return thisChar; } std::string getIdentifier() const { return std::string(_identifier.c_str()); } int curLine() const { return _line; } int curCol() const { return _col; } int getChar() { int c = _is.get(); updateLoc(c); return c; } private: void updateLoc(int c) { if (c == '\n' || c == '\r') { ++_line; _col = 1; } else { ++_col; } } ci_string _identifier; int _lastChar; std::istream& _is; int _line; int _col; }; //-------------------------------------- // Parser //-------------------------------------- class CMakeParser { public: CMakeParser(std::istream& is, std::ostream& os) : _os(os), _lexer(is), _curToken(CMakeLexer::TOK_EOF), _lastToken(CMakeLexer::TOK_EOF) { } int curToken() { return _curToken; } int nextToken() { _lastToken = _curToken; _curToken = _lexer.getToken(); while (_curToken == CMakeLexer::TOK_EOL) { // Try to preserve lines in output to allow correct line number referencing by doxygen. _os << std::endl; _curToken = _lexer.getToken(); } return _curToken; } void handleMacro() { if(!parseMacro()) { // skip token for error recovery nextToken(); } } void handleFunction() { if(!parseFunction()) { // skip token for error recovery nextToken(); } } void handleSet() { // SET(var ...) following a documentation block is assumed to be a variable declaration. if (_lastToken != CMakeLexer::TOK_DOXYGEN_COMMENT) { // No comment block before nextToken(); } else if(!parseSet()) { // skip token for error recovery nextToken(); } } void handleDoxygenComment() { _os << "///" << _lexer.getIdentifier(); nextToken(); } void handleTopLevelExpression() { // skip token nextToken(); } private: void printError(const char* str) { std::cerr << "Error: " << str << " (at line " << _lexer.curLine() << ", col " << _lexer.curCol() << ")"; } bool parseMacro() { if (nextToken() != '(') { printError("Expected '(' after MACRO"); return false; } nextToken(); std::string macroName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || macroName.empty()) { printError("Expected macro name"); return false; } _os << macroName << '('; if (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << _lexer.getIdentifier(); while (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << ", " << _lexer.getIdentifier(); } } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ");"; } // eat the ')' nextToken(); return true; } bool parseSet() { if (nextToken() != '(') { printError("Expected '(' after SET"); return false; } nextToken(); std::string variableName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || variableName.empty()) { printError("Expected variable name"); return false; } _os << "CMAKE_VARIABLE " << variableName; nextToken(); while ((curToken() == CMakeLexer::TOK_IDENTIFIER) || (curToken() == CMakeLexer::TOK_STRING_LITERAL) || (curToken() == CMakeLexer::TOK_NUMBER_LITERAL)) { nextToken(); } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ";"; } // eat the ')' nextToken(); return true; } bool parseFunction() { if (nextToken() != '(') { printError("Expected '(' after FUNCTION"); return false; } nextToken(); std::string funcName = _lexer.getIdentifier(); if (curToken() != CMakeLexer::TOK_IDENTIFIER || funcName.empty()) { printError("Expected function name"); return false; } _os << funcName << '('; if (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << _lexer.getIdentifier(); while (nextToken() == CMakeLexer::TOK_IDENTIFIER) { _os << ", " << _lexer.getIdentifier(); } } if (curToken() != ')') { printError("Missing expected ')'"); } else { _os << ");"; } // eat the ')' nextToken(); return true; } std::ostream& _os; CMakeLexer _lexer; int _curToken; int _lastToken; }; #define STRINGIFY(a) #a #define DOUBLESTRINGIFY(a) STRINGIFY(a) int main(int argc, char** argv) { assert(argc > 1); for (int i = 1; i < argc; ++i) { std::ifstream ifs(argv[i]); std::ostream& os = std::cout; #ifdef USE_NAMESPACE os << "namespace " << DOUBLESTRINGIFY(USE_NAMESPACE) << " {\n"; #endif CMakeParser parser(ifs, os); parser.nextToken(); while (ifs.good()) { switch (parser.curToken()) { case CMakeLexer::TOK_EOF: return ifs.get(); // eat EOF case CMakeLexer::TOK_MACRO: parser.handleMacro(); break; case CMakeLexer::TOK_FUNCTION: parser.handleFunction(); break; case CMakeLexer::TOK_SET: parser.handleSet(); break; case CMakeLexer::TOK_DOXYGEN_COMMENT: parser.handleDoxygenComment(); break; default: parser.handleTopLevelExpression(); break; } } #ifdef USE_NAMESPACE os << "}\n"; #endif } return EXIT_SUCCESS; } diff --git a/Modules/CppMicroServices/doc/doxygen/footer.html b/Modules/CppMicroServices/doc/doxygen/footer.html index ea6b6dac83..fdcb775e7c 100644 --- a/Modules/CppMicroServices/doc/doxygen/footer.html +++ b/Modules/CppMicroServices/doc/doxygen/footer.html @@ -1,4 +1,4 @@ -