diff --git a/Modules/DICOMReader/include/mitkDICOMFileReaderSelector.h b/Modules/DICOMReader/include/mitkDICOMFileReaderSelector.h index bccf689505..1ec18d21e6 100644 --- a/Modules/DICOMReader/include/mitkDICOMFileReaderSelector.h +++ b/Modules/DICOMReader/include/mitkDICOMFileReaderSelector.h @@ -1,116 +1,116 @@ /*============================================================================ 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. ============================================================================*/ #ifndef mitkDICOMFileReaderSelector_h #define mitkDICOMFileReaderSelector_h #include "mitkDICOMFileReader.h" #include namespace mitk { /** \ingroup DICOMReaderModule \brief Simple best-reader selection. This class implements a process of comparing different DICOMFileReader%s and selecting the reader with the minimal number of mitk::Image%s in its output. The code found in this class can - just be used to select a reader using this simple strategy - be taken as an example of how to use DICOMFileReader%s To create a selection of potential readers, the class makes use of mitk::DICOMReaderConfigurator, i.e. DICOMFileReaderSelector also expects the configuration files/strings to be in the format expected by mitk::DICOMReaderConfigurator. Two convenience methods load "default" configurations from compiled-in resources: LoadBuiltIn3DConfigs() and LoadBuiltIn3DnTConfigs(). @remark If you use LoadBuiltIn3DConfigs() and LoadBuiltIn3DnTConfigs() you must ensure that the MitkDICOMReader module (and therefore its resources) is properly loaded. If the module is not available these methods will do nothing. - This can especially lead to problem if these methods are used in the scope - of anothers module's activator. + This can especially lead to problems if these methods are used in the scope + of another module's activator. */ class MITKDICOMREADER_EXPORT DICOMFileReaderSelector : public itk::LightObject { public: typedef std::list ReaderList; mitkClassMacroItkParent( DICOMFileReaderSelector, itk::LightObject ); itkNewMacro( DICOMFileReaderSelector ); /// \brief Add a configuration as expected by DICOMReaderConfigurator. /// Configs can only be reset by instantiating a new DICOMFileReaderSelector. void AddConfig(const std::string& xmlDescription); /// \brief Add a configuration as expected by DICOMReaderConfigurator. /// Configs can only be reset by instantiating a new DICOMFileReaderSelector. void AddConfigFile(const std::string& filename); /// \brief Add a configuration that is stored in the passed us::ModuleResourse. /// Configs can only be reset by instantiating a new DICOMFileReaderSelector. void AddConfigFromResource(us::ModuleResource& resource); /// \brief Add a whole pre-configured reader to the selection process. void AddFileReaderCanditate(DICOMFileReader::Pointer reader); /// \brief Load 3D image creating configurations from the MITK module system (see us::Module::FindResources()). /// For a default set of configurations, look into the directory Resources of the DICOMReader module. /// @remark If you use this function you must ensure that the MitkDICOMReader module(and therefore its resources) - /// is properly loaded. If the module is not available these method will do nothing. - /// This can especially lead to problem if these methods are used in the scope - /// of anothers module's activator. + /// is properly loaded. If the module is not available this function will do nothing. + /// This can especially lead to problem if this function is used in the scope + /// of another module's activator. void LoadBuiltIn3DConfigs(); /// \brief Load 3D+t image creating configurations from the MITK module system (see us::Module::FindResources()). /// For a default set of configurations, look into the directory Resources of the DICOMReader module. /// @remark If you use this function you must ensure that the MitkDICOMReader module(and therefore its resources) - /// is properly loaded. If the module is not available these method will do nothing. - /// This can especially lead to problem if these methods are used in the scope - /// of anothers module's activator. + /// is properly loaded. If the module is not available this function will do nothing. + /// This can especially lead to problem if this function is used in the scope + /// of another module's activator. void LoadBuiltIn3DnTConfigs(); /// \brief Return all the DICOMFileReader%s that are currently used for selection by this class. /// The readers returned by this method depend on what config files have been added earlier /// (or which of the built-in readers have been loaded) ReaderList GetAllConfiguredReaders() const; /// Input files void SetInputFiles(StringList filenames); /// Input files const StringList& GetInputFiles() const; /// Execute the analysis and selection process. The first reader with a minimal number of outputs will be returned. DICOMFileReader::Pointer GetFirstReaderWithMinimumNumberOfOutputImages(); protected: DICOMFileReaderSelector(); ~DICOMFileReaderSelector() override; void AddConfigsFromResources(const std::string& path); void AddConfigFromResource(const std::string& resourcename); private: StringList m_PossibleConfigurations; StringList m_InputFilenames; ReaderList m_Readers; }; } // namespace #endif // mitkDICOMFileReaderSelector_h diff --git a/Modules/DICOMReader/src/mitkDICOMTagsOfInterestAddHelper.cpp b/Modules/DICOMReader/src/mitkDICOMTagsOfInterestAddHelper.cpp index 209d0b9019..7eb96eb655 100644 --- a/Modules/DICOMReader/src/mitkDICOMTagsOfInterestAddHelper.cpp +++ b/Modules/DICOMReader/src/mitkDICOMTagsOfInterestAddHelper.cpp @@ -1,103 +1,118 @@ /*============================================================================ 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 "mitkDICOMTagsOfInterestAddHelper.h" #include #include "usModuleContext.h" +#include "usGetModuleContext.h" void mitk::DICOMTagsOfInterestAddHelper::Activate(us::ModuleContext* context, TagsOfInterestVector tags) { if (!m_Active && nullptr != context) { std::lock_guard lock(m_Mutex); m_Active = true; m_Context = context; m_TagsOfInterest = tags; // Listen for events pertaining to dictionary services. m_Context->AddServiceListener(this, &DICOMTagsOfInterestAddHelper::DICOMTagsOfInterestServiceChanged, std::string("(&(") + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + "))"); // Query for any service references matching any language. std::vector > refs = m_Context->GetServiceReferences(); if (!refs.empty()) { for (const auto& ref : refs) { this->RegisterTagsOfInterest(context->GetService(ref)); context->UngetService(ref); } } } } void mitk::DICOMTagsOfInterestAddHelper::Deactivate() { if (m_Active) { std::lock_guard lock(m_Mutex); m_Active = false; - try + if (nullptr != m_Context) { - if (nullptr != m_Context) + try { - m_Context->RemoveServiceListener(this, &DICOMTagsOfInterestAddHelper::DICOMTagsOfInterestServiceChanged); + m_Context->RemoveServiceListener(this, &DICOMTagsOfInterestAddHelper::DICOMTagsOfInterestServiceChanged); + } + catch (...) + { + MITK_WARN << "Was not able to remove service listener from module context."; } - } - catch (...) - { - MITK_WARN << "Was not able to remove service listener from module context."; } } } mitk::DICOMTagsOfInterestAddHelper::~DICOMTagsOfInterestAddHelper() { if (m_Active) { - MITK_WARN << "DICOMTagsOfInterestAddHelper was not deactivated correctly befor its destructor was called."; + MITK_ERROR << "DICOMTagsOfInterestAddHelper was not deactivated correctly befor its destructor was called."; + auto context = us::GetModuleContext(); + //we cannot trust m_Context at this point anymore and have no means to validate it. So try to get the own module context + //and to remove the listener via this context. + if (nullptr != context) + { + try + { + m_Context->RemoveServiceListener(this, &DICOMTagsOfInterestAddHelper::DICOMTagsOfInterestServiceChanged); + } + catch (...) + { + MITK_WARN << "Was not able to remove service listener from module context."; + } + } } } void mitk::DICOMTagsOfInterestAddHelper::RegisterTagsOfInterest(IDICOMTagsOfInterest* toiService) const { if (nullptr != toiService) { for (const auto& tag : m_TagsOfInterest) { toiService->AddTagOfInterest(tag); } } } void mitk::DICOMTagsOfInterestAddHelper::DICOMTagsOfInterestServiceChanged(const us::ServiceEvent event) { // If a DICOMTagsOfInterestService was registered, register all tags of interest. if (event.GetType() == us::ServiceEvent::REGISTERED) { if (nullptr != m_Context) { std::lock_guard lock(m_Mutex); // Get a reference to the service object. us::ServiceReference ref = event.GetServiceReference(); this->RegisterTagsOfInterest(m_Context->GetService(ref)); m_Context->UngetService(ref); } else { MITK_ERROR << "New DICOMTagsOfInterestService was registered, but no module context exists. Thus, no DICOM tags of interest where added."; } } } diff --git a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp index 97ba946471..907f5ab402 100644 --- a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp +++ b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp @@ -1,123 +1,123 @@ /*============================================================================ 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 "mitkDICOMReaderServicesActivator.h" #include "mitkAutoSelectingDICOMReaderService.h" #include "mitkManualSelectingDICOMReaderService.h" #include "mitkDICOMTagsOfInterestService.h" #include "mitkSimpleVolumeDICOMSeriesReaderService.h" #include "mitkCoreServices.h" #include "mitkPropertyPersistenceInfo.h" #include "mitkDICOMIOMetaInformationPropertyConstants.h" #include "mitkIPropertyPersistence.h" #include "mitkTemporoSpatialStringProperty.h" #include #include void AddPropertyPersistence(const mitk::PropertyKeyPath& propPath, bool temporoSpatial = false) { mitk::CoreServicePointer persistenceService(mitk::CoreServices::GetPropertyPersistence()); mitk::PropertyPersistenceInfo::Pointer info = mitk::PropertyPersistenceInfo::New(); if (propPath.IsExplicit()) { std::string name = mitk::PropertyKeyPathToPropertyName(propPath); std::string key = name; std::replace(key.begin(), key.end(), '.', '_'); info->SetNameAndKey(name, key); } else { std::string key = mitk::PropertyKeyPathToPersistenceKeyRegEx(propPath); std::string keyTemplate = mitk::PropertyKeyPathToPersistenceKeyTemplate(propPath); std::string propRegEx = mitk::PropertyKeyPathToPropertyRegEx(propPath); std::string propTemplate = mitk::PropertyKeyPathToPersistenceNameTemplate(propPath); info->UseRegEx(propRegEx, propTemplate, key, keyTemplate); } if (temporoSpatial) { info->SetDeserializationFunction(mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty); info->SetSerializationFunction(mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON); } persistenceService->AddInfo(info); } namespace mitk { void DICOMReaderServicesActivator::Load(us::ModuleContext* context) { m_Context = context; m_AutoSelectingDICOMReader = std::make_unique(); m_SimpleVolumeDICOMSeriesReader = std::make_unique(); m_DICOMTagsOfInterestService = std::make_unique(); context->RegisterService(m_DICOMTagsOfInterestService.get()); DICOMTagPathMapType tagmap = GetDefaultDICOMTagsOfInterest(); for (auto tag : tagmap) { m_DICOMTagsOfInterestService->AddTagOfInterest(tag.first); } //add properties that should be persistent (if possible/supported by the writer) AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_FILES(), true); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION()); AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING()); //We have to handle ManualSelectingDICOMSeriesReader different then the other - //readers. Reason: The reader uses in its constructor DICOMFileReaderSelector. + //readers. Reason: The reader uses DICOMFileReaderSelector in its constructor. //this class needs to access resources of MitkDICOMReader module, which might //not be initialized yet (that would lead to a crash, see i.a. T27553). Thus check if the module //is alreade loaded. If not, register a listener and create the reader as soon //as the module is available. auto dicomModule = us::ModuleRegistry::GetModule("MitkDICOMReader"); if (nullptr == dicomModule) { std::lock_guard lock(m_Mutex); // Listen for events of module life cycle. - m_Context->AddModuleListener(this, &DICOMReaderServicesActivator::OnModuleEvent); + m_Context->AddModuleListener(this, &DICOMReaderServicesActivator::EnsureManualSelectingDICOMSeriesReader); } else { m_ManualSelectingDICOMSeriesReader = std::make_unique(); } } void DICOMReaderServicesActivator::Unload(us::ModuleContext*) { } - void DICOMReaderServicesActivator::OnModuleEvent(const us::ModuleEvent event) + void DICOMReaderServicesActivator::EnsureManualSelectingDICOMSeriesReader(const us::ModuleEvent event) { //We have to handle ManualSelectingDICOMSeriesReader different then the other - //readers. For more details the the explinations in the constructor. + //readers. For more details see the explanations in the constructor. std::lock_guard lock(m_Mutex); if (nullptr == m_ManualSelectingDICOMSeriesReader && event.GetModule()->GetName()=="MitkDICOMReader" && event.GetType() == us::ModuleEvent::LOADED) { m_ManualSelectingDICOMSeriesReader = std::make_unique(); } } } US_EXPORT_MODULE_ACTIVATOR(mitk::DICOMReaderServicesActivator) diff --git a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.h b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.h index dda0bc4b40..ae6c9d4de1 100644 --- a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.h +++ b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.h @@ -1,50 +1,50 @@ /*============================================================================ 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. ============================================================================*/ #ifndef MITKDICOMREADERSERVICESACTIVATOR_H #define MITKDICOMREADERSERVICESACTIVATOR_H #include #include #include #include namespace mitk { struct IFileReader; class IDICOMTagsOfInterest; class DICOMReaderServicesActivator : public us::ModuleActivator { public: void Load(us::ModuleContext* context) override; void Unload(us::ModuleContext* context) override; private: - void OnModuleEvent(const us::ModuleEvent event); + void EnsureManualSelectingDICOMSeriesReader(const us::ModuleEvent event); std::unique_ptr m_AutoSelectingDICOMReader; std::unique_ptr m_ManualSelectingDICOMSeriesReader; std::unique_ptr m_SimpleVolumeDICOMSeriesReader; std::unique_ptr m_DICOMTagsOfInterestService; us::ModuleContext* m_Context; /**mutex to guard the module listening */ std::mutex m_Mutex; }; } #endif // MITKDICOMREADERSERVICESACTIVATOR_H