diff --git a/Core/Code/CppMicroServices/src/module/usModule.cpp b/Core/Code/CppMicroServices/src/module/usModule.cpp index f31175e384..f2f37327f8 100644 --- a/Core/Code/CppMicroServices/src/module/usModule.cpp +++ b/Core/Code/CppMicroServices/src/module/usModule.cpp @@ -1,279 +1,279 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usModule.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usModulePrivate.h" #include "usModuleResource.h" #include "usModuleSettings.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE const std::string& Module::PROP_ID() { static const std::string s("module.id"); return s; } const std::string& Module::PROP_NAME() { static const std::string s("module.name"); return s; } const std::string& Module::PROP_LOCATION() { static const std::string s("module.location"); return s; } const std::string& Module::PROP_MODULE_DEPENDS() { static const std::string s("module.module_depends"); return s; } const std::string& Module::PROP_LIB_DEPENDS() { static const std::string s("module.lib_depends"); return s; } const std::string& Module::PROP_VERSION() { static const std::string s("module.version"); return s; } Module::Module() : d(0) { } Module::~Module() { delete d; } void Module::Init(CoreModuleContext* coreCtx, ModuleInfo* info) { ModulePrivate* mp = new ModulePrivate(this, coreCtx, info); std::swap(mp, d); delete mp; } void Module::Uninit() { if (d->moduleContext) { delete d->moduleContext; d->moduleContext = 0; } d->moduleActivator = 0; } bool Module::IsLoaded() const { return d->moduleContext != 0; } void Module::Start() { if (d->moduleContext) { US_WARN << "Module " << d->info.name << " already started."; return; } d->moduleContext = new ModuleContext(this->d); // try // { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADING, this)); // try to get a ModuleActivator instance if (d->info.activatorHook) { try { d->moduleActivator = d->info.activatorHook(); } catch (...) { US_ERROR << "Creating the module activator of " << d->info.name << " failed"; throw; } d->moduleActivator->Load(d->moduleContext); } d->StartStaticModules(); #ifdef US_ENABLE_AUTOLOADING_SUPPORT if (ModuleSettings::IsAutoLoadingEnabled()) { AutoLoadModules(d->info); } #endif d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADED, this)); // } // catch (...) // { // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); // d->RemoveModuleResources(); // delete d->moduleContext; // d->moduleContext = 0; // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); // US_ERROR << "Calling the module activator Load() method of " << d->info.name << " failed!"; // throw; // } } void Module::Stop() { if (d->moduleContext == 0) { US_WARN << "Module " << d->info.name << " already stopped."; return; } try { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); d->StopStaticModules(); if (d->moduleActivator) { d->moduleActivator->Unload(d->moduleContext); } } catch (...) { US_WARN << "Calling the module activator Unload() method of " << d->info.name << " failed!"; try { d->RemoveModuleResources(); } catch (...) {} delete d->moduleContext; d->moduleContext = 0; d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); throw; } d->RemoveModuleResources(); delete d->moduleContext; d->moduleContext = 0; d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); } ModuleContext* Module::GetModuleContext() const { return d->moduleContext; } long Module::GetModuleId() const { return d->info.id; } std::string Module::GetLocation() const { return d->info.location; } std::string Module::GetName() const { return d->info.name; } ModuleVersion Module::GetVersion() const { return d->version; } std::string Module::GetProperty(const std::string& key) const { if (d->properties.count(key) == 0) return ""; return d->properties[key]; } ModuleResource Module::GetResource(const std::string &name) const { ModuleResource result; - if (d->resourceTrees.empty()) return result; + if (d->resourceTreePtrs.empty()) return result; - for (std::size_t i = 0; i < d->resourceTrees.size(); ++i) + for (std::size_t i = 0; i < d->resourceTreePtrs.size(); ++i) { - if (!d->resourceTrees[i].IsValid()) continue; - result = ModuleResource(name, &d->resourceTrees[i]); + if (!d->resourceTreePtrs[i]->IsValid()) continue; + result = ModuleResource(name, d->resourceTreePtrs[i], d->resourceTreePtrs); if (result) return result; } return result; } std::vector Module::FindResources(const std::string& path, const std::string& filePattern, bool recurse) const { std::vector result; - if (d->resourceTrees.empty()) return result; + if (d->resourceTreePtrs.empty()) return result; - for (std::size_t i = 0; i < d->resourceTrees.size(); ++i) + for (std::size_t i = 0; i < d->resourceTreePtrs.size(); ++i) { - if (!d->resourceTrees[i].IsValid()) continue; + if (!d->resourceTreePtrs[i]->IsValid()) continue; std::vector nodes; - d->resourceTrees[i].FindNodes(path, filePattern, recurse, nodes); + d->resourceTreePtrs[i]->FindNodes(path, filePattern, recurse, nodes); for (std::vector::iterator nodeIter = nodes.begin(); nodeIter != nodes.end(); ++nodeIter) { - result.push_back(ModuleResource(*nodeIter, &d->resourceTrees[i])); + result.push_back(ModuleResource(*nodeIter, d->resourceTreePtrs[i], d->resourceTreePtrs)); } } return result; } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const Module& module) { os << "Module[" << "id=" << module.GetModuleId() << ", loc=" << module.GetLocation() << ", name=" << module.GetName() << "]"; return os; } std::ostream& operator<<(std::ostream& os, Module const * module) { return operator<<(os, *module); } diff --git a/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp b/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp index c88d8785fb..77e10d4464 100644 --- a/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp +++ b/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp @@ -1,243 +1,248 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usModulePrivate.h" #include "usModule.h" #include "usModuleActivator.h" #include "usModuleUtils_p.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistration.h" #include "usServiceReferencePrivate.h" #include #include #include US_BEGIN_NAMESPACE AtomicInt ModulePrivate::idCounter; ModulePrivate::ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info) : coreCtx(coreCtx) , info(*info) , moduleContext(0) , moduleActivator(0) , q(qq) { // Parse the statically imported module library names typedef const char*(*GetImportedModulesFunc)(void); std::string getImportedModulesSymbol("_us_get_imported_modules_for_"); getImportedModulesSymbol += this->info.libName; std::string location = this->info.location; if (this->info.libName.empty()) { /* make sure we retrieve symbols from the executable, if "libName" is empty */ location.clear(); } GetImportedModulesFunc getImportedModulesFunc = reinterpret_cast( ModuleUtils::GetSymbol(location, getImportedModulesSymbol.c_str())); if (getImportedModulesFunc != NULL) { std::string importedStaticModuleLibNames = getImportedModulesFunc(); std::istringstream iss(importedStaticModuleLibNames); std::copy(std::istream_iterator(iss), std::istream_iterator(), std::back_inserter >(this->staticModuleLibNames)); } InitializeResources(location); std::stringstream propId; propId << this->info.id; properties[Module::PROP_ID()] = propId.str(); std::stringstream propModuleDepends; std::stringstream propLibDepends; int counter = 0; int counter2 = 0; std::stringstream ss(this->info.moduleDeps); while (ss) { std::string moduleDep; ss >> moduleDep; if (!moduleDep.empty()) { Module* dep = ModuleRegistry::GetModule(moduleDep); if (dep) { requiresIds.push_back(dep->GetModuleId()); if (counter > 0) propModuleDepends << ", "; propModuleDepends << moduleDep; ++counter; } else { requiresLibs.push_back(moduleDep); if (counter2 > 0) propLibDepends << ", "; propLibDepends << moduleDep; ++counter2; } } } properties[Module::PROP_MODULE_DEPENDS()] = propModuleDepends.str(); properties[Module::PROP_LIB_DEPENDS()] = propLibDepends.str(); if (!this->info.version.empty()) { try { version = ModuleVersion(this->info.version); properties[Module::PROP_VERSION()] = this->info.version; } catch (const std::exception& e) { throw std::invalid_argument(std::string("CppMicroServices module does not specify a valid version identifier. Got exception: ") + e.what()); } } properties[Module::PROP_LOCATION()] = this->info.location; properties[Module::PROP_NAME()] = this->info.name; } ModulePrivate::~ModulePrivate() { delete moduleContext; + + for (std::size_t i = 0; i < this->resourceTreePtrs.size(); ++i) + { + delete resourceTreePtrs[i]; + } } void ModulePrivate::RemoveModuleResources() { coreCtx->listeners.RemoveAllListeners(moduleContext); std::list srs; coreCtx->services.GetRegisteredByModule(this, srs); for (std::list::iterator i = srs.begin(); i != srs.end(); ++i) { try { i->Unregister(); } catch (const std::logic_error& /*ignore*/) { // Someone has unregistered the service after stop completed. // This should not occur, but we don't want get stuck in // an illegal state so we catch it. } } srs.clear(); coreCtx->services.GetUsedByModule(q, srs); for (std::list::const_iterator i = srs.begin(); i != srs.end(); ++i) { i->GetReference().d->UngetService(q, false); } - for (std::size_t i = 0; i < resourceTrees.size(); ++i) + for (std::size_t i = 0; i < resourceTreePtrs.size(); ++i) { - resourceTrees[i].Invalidate(); + resourceTreePtrs[i]->Invalidate(); } } void ModulePrivate::StartStaticModules() { std::string location = this->info.location; if (this->info.libName.empty()) { /* make sure we retrieve symbols from the executable, if "libName" is empty */ location.clear(); } for (std::vector::iterator i = staticModuleLibNames.begin(); i != staticModuleLibNames.end(); ++i) { std::string staticActivatorSymbol = "_us_module_activator_instance_"; staticActivatorSymbol += *i; ModuleInfo::ModuleActivatorHook staticActivator = reinterpret_cast(ModuleUtils::GetSymbol(location, staticActivatorSymbol.c_str())); if (staticActivator) { US_DEBUG << "Loading static activator " << *i; staticActivators.push_back(staticActivator); staticActivator()->Load(moduleContext); } else { US_DEBUG << "Could not find an activator for the static module " << (*i) << ". It propably does not provide an activator on purpose.\n Or you either " "forgot a US_IMPORT_MODULE macro call in " << info.libName << " or to link " << (*i) << " to " << info.libName << "."; } } } void ModulePrivate::StopStaticModules() { for (std::list::iterator i = staticActivators.begin(); i != staticActivators.end(); ++i) { (*i)()->Unload(moduleContext); } } void ModulePrivate::InitializeResources(const std::string& location) { // Get the resource data from static modules and this module std::vector moduleLibNames; moduleLibNames.push_back(this->info.libName); moduleLibNames.insert(moduleLibNames.end(), this->staticModuleLibNames.begin(), this->staticModuleLibNames.end()); std::string initResourcesSymbolPrefix = "_us_init_resources_"; for (std::size_t i = 0; i < moduleLibNames.size(); ++i) { std::string initResourcesSymbol = initResourcesSymbolPrefix + moduleLibNames[i]; ModuleInfo::InitResourcesHook initResourcesFunc = reinterpret_cast( ModuleUtils::GetSymbol(location, initResourcesSymbol.c_str())); if (initResourcesFunc) { initResourcesFunc(&this->info); } } // Initialize this modules resource trees assert(this->info.resourceData.size() == this->info.resourceNames.size()); assert(this->info.resourceNames.size() == this->info.resourceTree.size()); for (std::size_t i = 0; i < this->info.resourceData.size(); ++i) { - resourceTrees.push_back(ModuleResourceTree(this->info.resourceTree[i], - this->info.resourceNames[i], - this->info.resourceData[i])); + resourceTreePtrs.push_back(new ModuleResourceTree(this->info.resourceTree[i], + this->info.resourceNames[i], + this->info.resourceData[i])); } } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/module/usModulePrivate.h b/Core/Code/CppMicroServices/src/module/usModulePrivate.h index 11c8e142e9..6d1f4e4a07 100644 --- a/Core/Code/CppMicroServices/src/module/usModulePrivate.h +++ b/Core/Code/CppMicroServices/src/module/usModulePrivate.h @@ -1,105 +1,105 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULEPRIVATE_H #define USMODULEPRIVATE_H #include #include #include "usModuleRegistry.h" #include "usModuleVersion.h" #include "usModuleInfo.h" #include "usModuleResourceTree_p.h" #include "usAtomicInt_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModuleContext; struct ModuleActivator; /** * \ingroup MicroServices */ class ModulePrivate { public: /** * Construct a new module based on a ModuleInfo object. */ ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info); virtual ~ModulePrivate(); void RemoveModuleResources(); void StartStaticModules(); void StopStaticModules(); CoreModuleContext* const coreCtx; std::vector requiresIds; std::vector requiresLibs; std::vector staticModuleLibNames; /** * Module version */ ModuleVersion version; ModuleInfo info; - std::vector resourceTrees; + std::vector resourceTreePtrs; /** * ModuleContext for the module */ ModuleContext* moduleContext; ModuleActivator* moduleActivator; std::map properties; Module* const q; private: void InitializeResources(const std::string& location); std::list staticActivators; static AtomicInt idCounter; // purposely not implemented ModulePrivate(const ModulePrivate&); ModulePrivate& operator=(const ModulePrivate&); }; US_END_NAMESPACE #endif // USMODULEPRIVATE_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleResource.cpp b/Core/Code/CppMicroServices/src/module/usModuleResource.cpp index fde16076a2..a81781b818 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResource.cpp +++ b/Core/Code/CppMicroServices/src/module/usModuleResource.cpp @@ -1,236 +1,242 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usModuleResource.h" #include "usAtomicInt_p.h" #include "usModuleResourceTree_p.h" #include US_BEGIN_NAMESPACE class ModuleResourcePrivate { public: ModuleResourcePrivate() - : resourceTree(NULL) + : associatedResourceTree(NULL) , node(-1) , size(0) , data(NULL) , isFile(false) , ref(1) {} std::string fileName; std::string path; std::string filePath; - ModuleResourceTree* resourceTree; + std::vector resourceTrees; + const ModuleResourceTree* associatedResourceTree; int node; int32_t size; const unsigned char* data; mutable std::vector children; bool isFile; /** * Reference count for implicitly shared private implementation. */ AtomicInt ref; }; ModuleResource::ModuleResource() : d(new ModuleResourcePrivate) { } ModuleResource::ModuleResource(const ModuleResource &resource) : d(resource.d) { d->ref.Ref(); } -ModuleResource::ModuleResource(const std::string& _file, ModuleResourceTree* resourceTree) +ModuleResource::ModuleResource(const std::string& _file, ModuleResourceTree* associatedResourceTree, + const std::vector& resourceTrees) : d(new ModuleResourcePrivate) { - d->resourceTree = resourceTree; + d->resourceTrees = resourceTrees; + d->associatedResourceTree = associatedResourceTree; std::string file = _file; if (file.empty()) file = "/"; if (file[0] != '/') file = std::string("/") + file; std::size_t index = file.find_last_of('/'); if (index < file.size()-1) { d->fileName = file.substr(index+1); } std::string rawPath = file.substr(0,index+1); // remove duplicate / std::string::value_type lastChar = 0; for (std::size_t i = 0; i < rawPath.size(); ++i) { if (rawPath[i] == '/' && lastChar == '/') { continue; } lastChar = rawPath[i]; d->path.push_back(lastChar); } d->filePath = d->path + d->fileName; - d->node = d->resourceTree->FindNode(GetFilePath()); + d->node = d->associatedResourceTree->FindNode(GetResourcePath()); if (d->node != -1) { - d->isFile = !resourceTree->IsDir(d->node); + d->isFile = !associatedResourceTree->IsDir(d->node); if (d->isFile) { - d->data = d->resourceTree->GetData(d->node, &d->size); + d->data = d->associatedResourceTree->GetData(d->node, &d->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->GetFilePath() < resource.GetFilePath(); } bool ModuleResource::operator ==(const ModuleResource& resource) const { return this->GetFilePath() == resource.GetFilePath(); } bool ModuleResource::operator !=(const ModuleResource &resource) const { return !(*this == resource); } bool ModuleResource::IsValid() const { - return d->resourceTree->IsValid() && d->node > -1; + return d->associatedResourceTree->IsValid() && d->node > -1; } ModuleResource::operator bool() const { return IsValid(); } std::string ModuleResource::GetFileName() const { return d->fileName; } std::string ModuleResource::GetPath() const { return d->path; } std::string ModuleResource::GetFilePath() const { return d->filePath; } 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(""); } bool ModuleResource::IsDir() const { return !d->isFile; } bool ModuleResource::IsFile() const { return d->isFile; } std::vector ModuleResource::GetChildren() const { if (d->isFile || !IsValid()) return d->children; if (!d->children.empty()) return d->children; - d->resourceTree->GetChildren(d->node, d->children); + for (std::size_t i = 0; i < d->resourceTrees.size(); ++i) + { + d->resourceTrees[i]->GetChildren(d->node, d->children); + } return d->children; } int ModuleResource::GetSize() const { return d->size; } const unsigned char* ModuleResource::GetData() const { if (!IsValid()) return NULL; return d->data; } std::size_t ModuleResource::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; return US_HASH_FUNCTION(std::string, this->GetFilePath()); } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ModuleResource& resource) { return os << resource.GetFilePath(); } diff --git a/Core/Code/CppMicroServices/src/module/usModuleResource.h b/Core/Code/CppMicroServices/src/module/usModuleResource.h index d15ccad560..feedbe4f7d 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResource.h +++ b/Core/Code/CppMicroServices/src/module/usModuleResource.h @@ -1,99 +1,100 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULERESOURCE_H #define USMODULERESOURCE_H #include #include #include US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class ModuleResourcePrivate; class ModuleResourceTree; class US_EXPORT ModuleResource { public: ModuleResource(); ModuleResource(const ModuleResource& resource); ~ModuleResource(); ModuleResource& operator=(const ModuleResource& resource); bool operator<(const ModuleResource& resource) const; bool operator==(const ModuleResource& resource) const; bool operator!=(const ModuleResource& resource) const; bool IsValid() const; operator bool() const; std::string GetFileName() const; std::string GetPath() const; std::string GetFilePath() const; std::string GetBaseName() const; std::string GetCompleteBaseName() const; std::string GetSuffix() const; bool IsDir() const; bool IsFile() const; std::vector GetChildren() const; int GetSize() const; const unsigned char* GetData() const; private: - ModuleResource(const std::string& file, ModuleResourceTree* resourceTree); + ModuleResource(const std::string& file, ModuleResourceTree* resourceTree, + const std::vector& resourceTrees); friend class Module; US_HASH_FUNCTION_FRIEND(ModuleResource); std::size_t Hash() const; ModuleResourcePrivate* d; }; US_END_NAMESPACE US_MSVC_POP_WARNING US_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