mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-08-30 04:15:10 +00:00
connection between 2 systems and bug fixes (#14)
This commit is contained in:
@@ -49,13 +49,14 @@ add_library(core_services SHARED
|
||||
"toml_parser_util.h"
|
||||
"installation_manifest.h"
|
||||
"installation_manifest.cpp"
|
||||
"../../global/tracefifo/trace_fifo.cpp"
|
||||
"local_shutdown_request.h"
|
||||
"iso_monitor.h"
|
||||
"iso_monitor.cpp"
|
||||
"installation_composer.h"
|
||||
"installation_composer.cpp"
|
||||
|
||||
"toml_parser/lexer_toml_token.h" "toml_parser/lexer_toml_token.cpp" "toml_parser/miscellaneous.h" "toml_parser/miscellaneous.cpp" "toml_parser/code_snippet.h" "toml_parser/code_snippet.cpp" "app_settings.h" "app_settings.cpp" "app_config_file.h" "app_config_file.cpp")
|
||||
"toml_parser/lexer_toml_token.h" "toml_parser/lexer_toml_token.cpp" "toml_parser/miscellaneous.h" "toml_parser/miscellaneous.cpp" "toml_parser/code_snippet.h" "toml_parser/code_snippet.cpp" "app_settings.h" "app_settings.cpp" "app_config_file.h" "app_config_file.cpp" "toml_parser/parser_node_indexer.h" "toml_parser/parser_node_indexer.cpp" "permission_control.h" "permission_control.cpp")
|
||||
|
||||
# Compiler settiings
|
||||
add_compile_definitions(SDV_NO_EXPORT_DEFINITION)
|
||||
|
||||
@@ -33,61 +33,6 @@ CAppConfig& GetAppConfig()
|
||||
return app_config;
|
||||
}
|
||||
|
||||
// GetCoreDirectory might have been redirected for unit tests.
|
||||
#ifndef GetCoreDirectory
|
||||
std::filesystem::path GetCoreDirectory()
|
||||
{
|
||||
static std::filesystem::path pathCoreDir;
|
||||
if (!pathCoreDir.empty())
|
||||
return pathCoreDir;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows specific
|
||||
std::wstring ssPath(32768, '\0');
|
||||
|
||||
MEMORY_BASIC_INFORMATION sMemInfo{};
|
||||
if (!VirtualQuery(&pathCoreDir, &sMemInfo, sizeof(sMemInfo)))
|
||||
return pathCoreDir;
|
||||
DWORD dwLength = GetModuleFileNameW(reinterpret_cast<HINSTANCE>(sMemInfo.AllocationBase), ssPath.data(), 32767);
|
||||
ssPath.resize(dwLength);
|
||||
pathCoreDir = std::filesystem::path(ssPath);
|
||||
return pathCoreDir.remove_filename();
|
||||
#elif __linux__
|
||||
// Read the maps file. It contains all loaded SOs.
|
||||
std::ifstream fstream("/proc/self/maps");
|
||||
std::stringstream sstreamMap;
|
||||
sstreamMap << fstream.rdbuf();
|
||||
std::string ssMap = sstreamMap.str();
|
||||
if (ssMap.empty())
|
||||
return pathCoreDir; // Some error
|
||||
|
||||
// Find the "core_services.sdv"
|
||||
size_t nPos = ssMap.find("core_services.sdv");
|
||||
if (nPos == std::string::npos)
|
||||
return pathCoreDir;
|
||||
size_t nEnd = nPos;
|
||||
|
||||
// Find the start... runbackwards until the beginning of the line and remember the earliest occurance of a slash
|
||||
size_t nBegin = 0;
|
||||
while (nPos && ssMap[nPos] != '\n')
|
||||
{
|
||||
if (ssMap[nPos] == '/')
|
||||
nBegin = nPos;
|
||||
nPos--;
|
||||
}
|
||||
if (!nBegin)
|
||||
nBegin = nPos;
|
||||
|
||||
// Return the path
|
||||
pathCoreDir = ssMap.substr(nBegin, nEnd - nBegin);
|
||||
|
||||
return pathCoreDir;
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
#endif // !defined GetCoreDirectory
|
||||
|
||||
bool CAppConfig::LoadInstallationManifests()
|
||||
{
|
||||
// Check for allowance
|
||||
@@ -96,13 +41,14 @@ bool CAppConfig::LoadInstallationManifests()
|
||||
{
|
||||
case sdv::app::EAppContext::main:
|
||||
case sdv::app::EAppContext::isolated:
|
||||
case sdv::app::EAppContext::external:
|
||||
case sdv::app::EAppContext::maintenance:
|
||||
bServerApp = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
std::filesystem::path pathCore = GetCoreDirectory();
|
||||
std::filesystem::path pathCore = GetAppSettings().GetFrameworkDir();
|
||||
std::filesystem::path pathExe = GetExecDirectory();
|
||||
std::filesystem::path pathInstall = GetAppSettings().GetInstallDir();
|
||||
|
||||
@@ -155,8 +101,8 @@ void CAppConfig::UnloadInstallatonManifests()
|
||||
|
||||
bool CAppConfig::LoadAppConfigs()
|
||||
{
|
||||
// Isolated applications do not load configurations
|
||||
if (GetAppSettings().IsIsolatedApplication()) return false;
|
||||
// Isolated and external applications do not load configurations
|
||||
if (GetAppSettings().IsIsolatedApplication() || GetAppSettings().IsExternalApplication()) return false;
|
||||
|
||||
// When running as server application, load the system configurations
|
||||
if (GetAppSettings().IsMainApplication() || GetAppSettings().IsMaintenanceApplication())
|
||||
@@ -243,6 +189,7 @@ sdv::core::EConfigProcessResult CAppConfig::ProcessConfig(/*in*/ const sdv::u8st
|
||||
{
|
||||
case sdv::app::EAppContext::main:
|
||||
case sdv::app::EAppContext::isolated:
|
||||
case sdv::app::EAppContext::external:
|
||||
case sdv::app::EAppContext::maintenance:
|
||||
return sdv::core::EConfigProcessResult::failed;
|
||||
default:
|
||||
@@ -275,7 +222,7 @@ sdv::core::EConfigProcessResult CAppConfig::ProcessConfig(/*in*/ const sdv::u8st
|
||||
//size_t nLoadable = 0;
|
||||
//size_t nNotLoadable = 0;
|
||||
//if (!GetAppSettings().IsMainApplication() && !GetAppSettings().IsIsolatedApplication() &&
|
||||
// !GetAppSettings().IsMaintenanceApplication())
|
||||
// !GetAppSettings().IsExternalApplication() && !GetAppSettings().IsMaintenanceApplication())
|
||||
//{
|
||||
// // Load all modules in the component section
|
||||
// auto ptrComponents = parser.Root().Direct("Component");
|
||||
@@ -394,7 +341,7 @@ sdv::core::EConfigProcessResult CAppConfig::ProcessConfig(/*in*/ const sdv::u8st
|
||||
// // loaded; get the module ID.
|
||||
// sdv::core::TObjectID tObjectID = 0;
|
||||
// if (!GetAppSettings().IsMainApplication() && !GetAppSettings().IsIsolatedApplication() &&
|
||||
// !GetAppSettings().IsMaintenanceApplication())
|
||||
// !GetAppSettings().IsExternalApplication() && !GetAppSettings().IsMaintenanceApplication())
|
||||
// {
|
||||
// auto itModule = mapModules.find(pathModule);
|
||||
// if (itModule == mapModules.end()) continue; // Module was not loaded before...
|
||||
@@ -880,6 +827,7 @@ std::filesystem::path CAppConfig::FindInstalledModule(const std::filesystem::pat
|
||||
{
|
||||
case sdv::app::EAppContext::main:
|
||||
case sdv::app::EAppContext::isolated:
|
||||
case sdv::app::EAppContext::external:
|
||||
case sdv::app::EAppContext::maintenance:
|
||||
bServerApp = true;
|
||||
default:
|
||||
@@ -914,6 +862,7 @@ std::string CAppConfig::FindInstalledModuleManifest(const std::filesystem::path&
|
||||
{
|
||||
case sdv::app::EAppContext::main:
|
||||
case sdv::app::EAppContext::isolated:
|
||||
case sdv::app::EAppContext::external:
|
||||
case sdv::app::EAppContext::maintenance:
|
||||
bServerApp = true;
|
||||
default:
|
||||
@@ -948,6 +897,7 @@ std::optional<sdv::SClassInfo> CAppConfig::FindInstalledComponent(const std::str
|
||||
{
|
||||
case sdv::app::EAppContext::main:
|
||||
case sdv::app::EAppContext::isolated:
|
||||
case sdv::app::EAppContext::external:
|
||||
case sdv::app::EAppContext::maintenance:
|
||||
bServerApp = true;
|
||||
default:
|
||||
@@ -980,6 +930,7 @@ bool CAppConfig::RemoveFromConfig(const CInstallManifest& /*rManifest*/)
|
||||
//{
|
||||
//case sdv::app::EAppContext::main:
|
||||
//case sdv::app::EAppContext::isolated:
|
||||
//case sdv::app::EAppContext::external:
|
||||
//case sdv::app::EAppContext::maintenance:
|
||||
// bServerApp = true;
|
||||
//default:
|
||||
@@ -1043,7 +994,7 @@ void CAppConfig::AddCurrentPath()
|
||||
if (!m_lstSearchPaths.empty()) return;
|
||||
|
||||
// Add the core directory
|
||||
std::filesystem::path pathCoreDir = GetCoreDirectory().lexically_normal();
|
||||
std::filesystem::path pathCoreDir = GetAppSettings().GetFrameworkDir().lexically_normal();
|
||||
m_lstSearchPaths.push_back(pathCoreDir / "config/");
|
||||
|
||||
// Add the exe dir
|
||||
|
||||
@@ -39,12 +39,6 @@
|
||||
// The installation might need companion files to be installed in various relative sub-directories.
|
||||
// @endcond
|
||||
|
||||
/**
|
||||
* @brief Get the location of the core_services.sdv.
|
||||
* @return Path to the directory containing the loaded core directory.
|
||||
*/
|
||||
std::filesystem::path GetCoreDirectory();
|
||||
|
||||
/**
|
||||
* @brief Application configuration service
|
||||
* @details In the configuration system objects, devices, basic services, complex services and apps are defined and will be started
|
||||
|
||||
@@ -346,9 +346,9 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
|
||||
// Modules leftover in the vector are added to the list
|
||||
auto vecModuleListCopy = m_vecModuleList;
|
||||
sdv::toml::CNodeCollection nodeModules = nodeConfig.GetDirect("Module");
|
||||
for (size_t nIndex = nodeModules.GetCount() - 1; nIndex < nodeModules.GetCount(); --nIndex)
|
||||
for (int64_t iIndex = static_cast<int64_t>(nodeModules.GetCount() - 1); iIndex >= 0; --iIndex)
|
||||
{
|
||||
sdv::toml::CNodeCollection tableModule = nodeModules.Get(nIndex);
|
||||
sdv::toml::CNodeCollection tableModule = nodeModules.Get(static_cast<size_t>(iIndex));
|
||||
std::filesystem::path pathModule = tableModule.GetDirect("Path").GetValue().get<std::string>();
|
||||
auto itModule = std::find_if(vecModuleListCopy.begin(), vecModuleListCopy.end(),
|
||||
[&](const SModule& rsModule) { return pathModule == rsModule.pathModule; });
|
||||
@@ -374,9 +374,9 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
|
||||
// Classes leftover in the vector are added to the list
|
||||
auto vecClassListCopy = m_vecClassList;
|
||||
sdv::toml::CNodeCollection arrayClasses = nodeConfig.GetDirect("Class");
|
||||
for (size_t nIndex = arrayClasses.GetCount() -1; nIndex < arrayClasses.GetCount(); --nIndex)
|
||||
for (int64_t iIndex = static_cast<int64_t>(arrayClasses.GetCount() - 1); iIndex >= 0; --iIndex)
|
||||
{
|
||||
sdv::toml::CNodeCollection tableClass = arrayClasses.Get(nIndex);
|
||||
sdv::toml::CNodeCollection tableClass = arrayClasses.Get(static_cast<size_t>(iIndex));
|
||||
std::filesystem::path pathModule;
|
||||
if (!bServerApp)
|
||||
pathModule = tableClass.GetDirect("Path").GetValue().get<std::string>();
|
||||
@@ -419,8 +419,7 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
|
||||
if (ssExistingTOML != itClass->ssDefaultConfig)
|
||||
{
|
||||
if (tableParams) tableParams.Delete();
|
||||
if (!itClass->ssDefaultConfig.empty())
|
||||
tableClass.InsertTOML(sdv::toml::npos, itClass->ssDefaultConfig);
|
||||
if (!itClass->ssDefaultConfig.empty()) tableClass.InsertTOML("", itClass->ssDefaultConfig);
|
||||
rbChanged = true;
|
||||
}
|
||||
|
||||
@@ -433,8 +432,7 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
|
||||
tableClass.AddValue("Class", rsClass.ssName);
|
||||
if (!bServerApp)
|
||||
tableClass.AddValue("Path", std::filesystem::u8path(static_cast<std::string>(rsClass.ssModulePath)));
|
||||
if (!rsClass.ssDefaultConfig.empty())
|
||||
tableClass.InsertTOML(sdv::toml::npos, rsClass.ssDefaultConfig);
|
||||
if (!rsClass.ssDefaultConfig.empty()) tableClass.InsertTOML("", rsClass.ssDefaultConfig);
|
||||
rbChanged = true;
|
||||
}
|
||||
|
||||
@@ -444,9 +442,9 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
|
||||
// Components leftover in the vector are added to the list
|
||||
auto vecComponentListCopy = m_vecComponentList;
|
||||
sdv::toml::CNodeCollection nodeComponents = nodeConfig.GetDirect("Component");
|
||||
for (size_t nIndex = nodeComponents.GetCount() - 1; nIndex < nodeComponents.GetCount(); --nIndex)
|
||||
for (int64_t iIndex = static_cast<int64_t>(nodeComponents.GetCount() - 1); iIndex >= 0; --iIndex)
|
||||
{
|
||||
sdv::toml::CNodeCollection tableComponent = nodeComponents.Get(nIndex);
|
||||
sdv::toml::CNodeCollection tableComponent = nodeComponents.Get(static_cast<size_t>(iIndex));
|
||||
std::filesystem::path pathModule;
|
||||
if (!bServerApp)
|
||||
pathModule = tableComponent.GetDirect("Path").GetValue().get<std::string>();
|
||||
@@ -518,8 +516,8 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
|
||||
else if (!tableParams)
|
||||
{
|
||||
// Simply add the parameters
|
||||
tableParams = tableComponent.InsertTable(sdv::toml::npos, "Parameters");
|
||||
tableParams.InsertTOML(sdv::toml::npos, itComponent->ssParameterTOML);
|
||||
tableParams = tableComponent.InsertTable("", "Parameters");
|
||||
tableParams.InsertTOML("", itComponent->ssParameterTOML);
|
||||
rbChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -536,8 +534,8 @@ Version = )toml" + std::to_string(SDVFrameworkInterfaceVersion) + R"toml(
|
||||
tableComponent.AddValue("Name", rsComponent.ssInstanceName);
|
||||
if (!rsComponent.ssParameterTOML.empty())
|
||||
{
|
||||
sdv::toml::CNodeCollection tableParams = tableComponent.InsertTable(sdv::toml::npos, "Parameters");
|
||||
tableParams.InsertTOML(sdv::toml::npos, rsComponent.ssParameterTOML);
|
||||
sdv::toml::CNodeCollection tableParams = tableComponent.InsertTable("", "Parameters");
|
||||
tableParams.InsertTOML("", rsComponent.ssParameterTOML);
|
||||
}
|
||||
rbChanged = true;
|
||||
}
|
||||
@@ -628,12 +626,12 @@ bool CAppConfigFile::InsertComponent(size_t nIndex, const std::filesystem::path&
|
||||
// Need to add a group?
|
||||
if (prKey.first != ssGroup)
|
||||
{
|
||||
group = root.InsertTable(sdv::toml::npos, prKey.first);
|
||||
group = root.InsertTable("", prKey.first);
|
||||
ssGroup = prKey.first;
|
||||
}
|
||||
|
||||
// Add the parameter
|
||||
group.InsertValue(sdv::toml::npos, prKey.second, prParameter.second);
|
||||
group.InsertValue("", prKey.second, prParameter.second);
|
||||
}
|
||||
ssParameterTOML = parser.GenerateTOML();
|
||||
}
|
||||
|
||||
@@ -266,6 +266,9 @@ public:
|
||||
*/
|
||||
void RemoveModule(const std::filesystem::path& rpathModule);
|
||||
|
||||
/**
|
||||
* @brief Merge result enum.
|
||||
*/
|
||||
enum class EMergeResult
|
||||
{
|
||||
successful,
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "module_control.h"
|
||||
#include "repository.h"
|
||||
#include "../../global/base64.h"
|
||||
#include "../../global/tracefifo/trace_fifo.cpp"
|
||||
#include "toml_parser/parser_toml.h"
|
||||
#include "local_shutdown_request.h"
|
||||
#include "app_settings.h"
|
||||
@@ -49,6 +48,9 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
|
||||
{
|
||||
m_pEvent = pEventHandler ? pEventHandler->GetInterface<sdv::app::IAppEvent>() : nullptr;
|
||||
|
||||
// Allow this thread full access
|
||||
m_optpermission = GetPermissionControl().CreatePermissionObject(sdv::core::EAccessPermission::full_access);
|
||||
|
||||
// Intercept the logging...
|
||||
std::stringstream sstreamCOUT, sstreamCLOG, sstreamCERR;
|
||||
std::streambuf* pstreambufCOUT = std::cout.rdbuf(sstreamCOUT.rdbuf());
|
||||
@@ -86,7 +88,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
|
||||
}
|
||||
|
||||
// Open the stream buffer and attach the streams if the application control is initialized as main app.
|
||||
if (GetAppSettings().IsMainApplication())
|
||||
if (!GetAppSettings().RedirectMonitorToConsole() && GetAppSettings().IsMainApplication())
|
||||
{
|
||||
m_fifoTraceStreamBuffer.SetInstanceID(GetAppSettings().GetInstanceID());
|
||||
m_fifoTraceStreamBuffer.Open(1000);
|
||||
@@ -99,7 +101,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
|
||||
std::cerr << sstreamCERR.str();
|
||||
|
||||
// Check for a correctly opened stream buffer
|
||||
if (GetAppSettings().IsMainApplication() && !m_fifoTraceStreamBuffer.IsOpened())
|
||||
if (!GetAppSettings().RedirectMonitorToConsole() && GetAppSettings().IsMainApplication() && !m_fifoTraceStreamBuffer.IsOpened())
|
||||
{
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cerr << "ERROR: Log streaming could not be initialized; cannot continue!" << std::endl;
|
||||
@@ -142,7 +144,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
|
||||
};
|
||||
auto fnCreateObject = [&ssErrorString](const sdv::u8string& rssClass, const sdv::u8string& rssObject, const sdv::u8string& rssConfig) -> bool
|
||||
{
|
||||
bool bLocalRet = GetRepository().CreateObject2(rssClass, rssObject, rssConfig);
|
||||
bool bLocalRet = GetRepository().CreateObject(rssClass, rssObject, rssConfig);
|
||||
if (!bLocalRet)
|
||||
{
|
||||
ssErrorString = std::string("Failed to instantiate a new object from class '") + rssClass + "'";
|
||||
@@ -179,7 +181,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
|
||||
sdv::IInterfaceAccess* pLoggerObj = GetRepository().GetObject(GetAppSettings().GetLoggerClass());
|
||||
if (!pLoggerObj)
|
||||
{
|
||||
GetRepository().DestroyObject2(GetAppSettings().GetLoggerClass());
|
||||
GetRepository().DestroyObject(GetAppSettings().GetLoggerClass());
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cerr << "ERROR: Failed to start the logger. Cannot continue!" << std::endl;
|
||||
Shutdown(true);
|
||||
@@ -247,7 +249,7 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
|
||||
}
|
||||
|
||||
// Load the application settings.
|
||||
if (!GetAppSettings().LoadSettingsFile())
|
||||
if (!GetAppSettings().LoadSettings())
|
||||
{
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cerr << "ERROR: Failed to load application settings file. Cannot continue!" << std::endl;
|
||||
@@ -275,32 +277,88 @@ bool CAppControl::Startup(/*in*/ const sdv::u8string& ssConfig, /*in*/ IInterfac
|
||||
bRet = fnLoadModule("hardware_ident.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("HardwareIdentificationService", "", "");
|
||||
|
||||
// Load shared memory channel
|
||||
if (bRet) bRet = fnLoadModule("ipc_shared_mem.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("DefaultSharedMemoryChannelControl", "", "");
|
||||
// Load default communication provider
|
||||
if (bRet) bRet = fnCreateObject(GetAppSettings().GetDefaultComProvider(), "", "");
|
||||
|
||||
// Load IPC service
|
||||
if (bRet) bRet = fnLoadModule("ipc_com.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("CommunicationControl", "", "");
|
||||
|
||||
// Load IPC service and create listener local connections
|
||||
if (bRet) bRet = fnLoadModule("ipc_listener.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("ConnectionListenerService", "", R"code([Listener]
|
||||
Type = "Local"
|
||||
)code");
|
||||
|
||||
// Load IPC service
|
||||
if (bRet) bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("ConnectionService", "", "");
|
||||
|
||||
// Load proxy/stub for core interfaces
|
||||
if (bRet) bRet = fnLoadModule("core_ps.sdv") ? true : false;
|
||||
|
||||
// // Start the listener
|
||||
// if (bRet) bRet = fnLoadModule("ipc_listener.sdv") ? true : false;
|
||||
// if (bRet) bRet = GetRepository().CreateObject("ConnectionListenerService", "ConnectionListenerService", R"code([Listener]
|
||||
//Type="local"
|
||||
//Instance=)code" + std::to_string(GetInstanceID()));
|
||||
// Load the connection services
|
||||
if (bRet) bRet = fnLoadModule("ipc_listener.sdv") ? true : false;
|
||||
if (bRet) bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
|
||||
|
||||
// For the main application start the configured listeners.
|
||||
if (bRet)
|
||||
{
|
||||
auto seqListeners = GetAppSettings().GetListeners();
|
||||
for (const auto& rssListener : seqListeners)
|
||||
{
|
||||
if (!bRet) break;
|
||||
auto ssListenerConfig = GetAppSettings().GetListenerConfig(rssListener);
|
||||
bRet = fnCreateObject("ListenerConnectService", "Listener_" + rssListener, ssListenerConfig);
|
||||
}
|
||||
}
|
||||
|
||||
// For the main application connect the configured connections (except default connection).
|
||||
if (bRet)
|
||||
{
|
||||
auto seqConnections = GetAppSettings().GetConnections();
|
||||
for (const auto& rssConnection : seqConnections)
|
||||
{
|
||||
if (!bRet) break;
|
||||
if (rssConnection == "Default") continue;
|
||||
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cout << "INFO: Trying to connect to " << rssConnection << "..." << std::endl;
|
||||
|
||||
auto ssConnectionConfig = GetAppSettings().GetConnectionConfig(rssConnection);
|
||||
std::string ssObjectName = "Client_" + rssConnection;
|
||||
bRet = fnCreateObject("ClientConnectService", ssObjectName, ssConnectionConfig);
|
||||
|
||||
// Try connect (for at least nTries) and when successful bind repositories
|
||||
sdv::TInterfaceAccessPtr ptrClient = GetRepository().GetObject(ssObjectName);
|
||||
sdv::com::IClientConnect* pClientConnect = ptrClient.GetInterface<sdv::com::IClientConnect>();
|
||||
if (pClientConnect)
|
||||
{
|
||||
for (uint32_t uiCnt = 0; uiCnt < GetAppSettings().GetConnectRetries(); uiCnt++)
|
||||
{
|
||||
// Try to connect. If not working, wait for 300 ms
|
||||
if (pClientConnect->Connect()) break;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
}
|
||||
|
||||
if (pClientConnect->IsConnected())
|
||||
{
|
||||
// Register the core repo as repo access
|
||||
sdv::core::TLinkID tLinkID = GetRepository().LinkCoreRepository(pClientConnect->GetRemoteRepository());
|
||||
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cout << "INFO: Connection established... " << std::endl;
|
||||
|
||||
// Store the connection object.
|
||||
m_vecConnections.push_back(std::make_pair(ssObjectName, tLinkID));
|
||||
}
|
||||
else
|
||||
{
|
||||
ssErrorString = "Not connected...";
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cout << "ERROR: Failed to connect to " << ssConnectionConfig << std::endl;
|
||||
bRet = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ssErrorString = "No client connect interface...";
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cerr << "ERROR: Cannot create connection object for " << rssConnection << std::endl;
|
||||
bRet = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bRet)
|
||||
{
|
||||
@@ -314,25 +372,69 @@ Type = "Local"
|
||||
}
|
||||
else if (bRet && bLoadRPCClient)
|
||||
{
|
||||
// Interpret the connect string...
|
||||
|
||||
|
||||
// Load hardware identification
|
||||
bRet = fnLoadModule("hardware_ident.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("HardwareIdentificationService", "", "");
|
||||
|
||||
// Load shared memory channel
|
||||
if (bRet) bRet = fnLoadModule("ipc_shared_mem.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("DefaultSharedMemoryChannelControl", "", "");
|
||||
// Load default communication provider
|
||||
if (bRet) bRet = fnCreateObject(GetAppSettings().GetDefaultComProvider(), "", "");
|
||||
|
||||
// Load IPC service
|
||||
if (bRet) bRet = fnLoadModule("ipc_com.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("CommunicationControl", "", "");
|
||||
|
||||
// Load IPC service
|
||||
if (bRet) bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
|
||||
if (bRet) bRet = fnCreateObject("ConnectionService", "", "");
|
||||
// Connect to the core system when running as external aplication. Use the default connection for this.
|
||||
if (bRet && GetAppSettings().GetContextType() == sdv::app::EAppContext::external)
|
||||
{
|
||||
// Load the connection services
|
||||
bRet = fnLoadModule("ipc_connect.sdv") ? true : false;
|
||||
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cout << "INFO: Trying to connect to the core system..." << std::endl;
|
||||
|
||||
// And the one connection
|
||||
auto ssConnectionConfig = GetAppSettings().GetConnectionConfig("Default");
|
||||
if (bRet && !ssConnectionConfig.empty())
|
||||
bRet = fnCreateObject("ClientConnectService", "Client_Default", ssConnectionConfig);
|
||||
|
||||
// Try connect (for at least nTries) and when successful bind repositories
|
||||
sdv::TInterfaceAccessPtr ptrClient = GetRepository().GetObject("Client_Default");
|
||||
sdv::com::IClientConnect* pClientConnect = ptrClient.GetInterface<sdv::com::IClientConnect>();
|
||||
if (pClientConnect)
|
||||
{
|
||||
for (uint32_t uiCnt = 0; uiCnt < GetAppSettings().GetConnectRetries(); uiCnt++)
|
||||
{
|
||||
// Try to connect. If not working, wait for 300 ms
|
||||
if (pClientConnect->Connect()) break;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
}
|
||||
|
||||
if (pClientConnect->IsConnected())
|
||||
{
|
||||
// Register the core repo as repo access
|
||||
sdv::core::TLinkID tLinkID = GetRepository().LinkCoreRepository(pClientConnect->GetRemoteRepository());
|
||||
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cout << "INFO: Connection established... " << std::endl;
|
||||
|
||||
// Store the connection object.
|
||||
m_vecConnections.push_back(std::make_pair("Default", tLinkID));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cout << "ERROR: Failed to connect to the core system" << std::endl;
|
||||
bRet = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!GetAppSettings().IsConsoleSilent())
|
||||
std::cerr << "ERROR: Cannot create connection object for connecting to the core system." << std::endl;
|
||||
bRet = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Load proxy/stub for core interfaces
|
||||
if (bRet) bRet = fnLoadModule("core_ps.sdv") ? true : false;
|
||||
|
||||
@@ -428,6 +530,7 @@ void CAppControl::RunLoop()
|
||||
{
|
||||
case sdv::app::EAppContext::main:
|
||||
case sdv::app::EAppContext::isolated:
|
||||
case sdv::app::EAppContext::external:
|
||||
bLocal = false;
|
||||
break;
|
||||
case sdv::app::EAppContext::maintenance:
|
||||
@@ -490,8 +593,22 @@ void CAppControl::Shutdown(/*in*/ bool bForce)
|
||||
// Disable automatic configuration saving.
|
||||
m_bAutoSaveConfig = false;
|
||||
|
||||
// Update the application settings file
|
||||
GetAppSettings().SaveSettingsFile();
|
||||
// TODO EVE: This is likely not wanted
|
||||
//// Update the application settings file
|
||||
//GetAppSettings().SaveSettings();
|
||||
|
||||
// Disconnect all automatic connections.
|
||||
for (const auto& rprConnectObject : m_vecConnections)
|
||||
{
|
||||
// If there is a registered link ID, unlink the ID.
|
||||
if (rprConnectObject.second)
|
||||
GetRepository().UnlinkCoreRepository(rprConnectObject.second);
|
||||
|
||||
sdv::TInterfaceAccessPtr ptrClient = GetRepository().GetObject(rprConnectObject.first);
|
||||
sdv::com::IClientConnect* pClientConnect = ptrClient.GetInterface<sdv::com::IClientConnect>();
|
||||
if (pClientConnect) pClientConnect->Disconnect();
|
||||
}
|
||||
m_vecConnections.clear();
|
||||
|
||||
// Destroy all objects... this should also remove any registered services, except the custom logger.
|
||||
GetRepository().DestroyAllObjects(std::vector<std::string>({GetAppSettings().GetLoggerClass()}), bForce);
|
||||
@@ -537,7 +654,7 @@ void CAppControl::Shutdown(/*in*/ bool bForce)
|
||||
}
|
||||
|
||||
// End trace streaming
|
||||
if (GetAppSettings().IsMainApplication())
|
||||
if (!GetAppSettings().RedirectMonitorToConsole() && GetAppSettings().IsMainApplication())
|
||||
{
|
||||
std::cout << "**********************************************" << std::endl;
|
||||
|
||||
@@ -551,6 +668,7 @@ void CAppControl::Shutdown(/*in*/ bool bForce)
|
||||
m_bAutoSaveConfig = false;
|
||||
m_bEnableAutoSave = false;
|
||||
GetAppSettings().Reset();
|
||||
m_optpermission.reset();
|
||||
}
|
||||
|
||||
void CAppControl::RequestShutdown()
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <support/component_impl.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include "../../global/tracefifo/trace_fifo.h"
|
||||
#include "permission_control.h"
|
||||
#include <optional>
|
||||
|
||||
/**
|
||||
* @brief Application control class.
|
||||
@@ -140,17 +142,20 @@ private:
|
||||
*/
|
||||
void BroadcastOperationState(sdv::app::EAppOperationState eState);
|
||||
|
||||
sdv::app::EAppOperationState m_eState = sdv::app::EAppOperationState::not_started; ///< The current operation state.
|
||||
sdv::app::IAppEvent* m_pEvent = nullptr; ///< Pointer to the app event interface.
|
||||
sdv::core::TModuleID m_tLoggerModuleID = 0; ///< ID of the logger module.
|
||||
bool m_bEnableAutoSave = false; ///< When set and when enabled in the system settings, allows
|
||||
///< the automatic saving of the configuration.
|
||||
bool m_bRunLoop = false; ///< Used to detect end of running loop function.
|
||||
std::filesystem::path m_pathLockFile; ///< Lock file path name.
|
||||
FILE* m_pLockFile = nullptr; ///< Lock file to test for other instances.
|
||||
CTraceFifoStdBuffer m_fifoTraceStreamBuffer; ///< Trace stream buffer to redirect std::log, std::out and
|
||||
///< std::err when running as service.
|
||||
bool m_bAutoSaveConfig = false; ///< System setting for automatic saving of the user configuration.
|
||||
sdv::app::EAppOperationState m_eState = sdv::app::EAppOperationState::not_started; ///< The current operation state.
|
||||
sdv::app::IAppEvent* m_pEvent = nullptr; ///< Pointer to the app event interface.
|
||||
sdv::core::TModuleID m_tLoggerModuleID = 0; ///< ID of the logger module.
|
||||
bool m_bEnableAutoSave = false; ///< When set and when enabled in the system settings, allows
|
||||
///< the automatic saving of the configuration.
|
||||
bool m_bRunLoop = false; ///< Used to detect end of running loop function.
|
||||
std::filesystem::path m_pathLockFile; ///< Lock file path name.
|
||||
FILE* m_pLockFile = nullptr; ///< Lock file to test for other instances.
|
||||
CTraceFifoStdBuffer m_fifoTraceStreamBuffer; ///< Trace stream buffer to redirect std::log, std::out and
|
||||
///< std::err when running as service.
|
||||
bool m_bAutoSaveConfig = false; ///< System setting for automatic saving of the user configuration.
|
||||
std::vector<std::pair<std::string, sdv::core::TLinkID>> m_vecConnections; ///< Connection objects that were successfully
|
||||
///< connected.
|
||||
std::optional<CAccessPermission> m_optpermission; ///< Main access permission for the core.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,10 @@
|
||||
* #Console output
|
||||
* [Console]
|
||||
* Report = "Silent" # Either "Silent", "Normal" or "Verbose" for no, normal or extensive messages.
|
||||
* RedirectMon = true # When set, redirects messages to the console instead of the monitor application in main mode.
|
||||
*
|
||||
* [Connections]
|
||||
* Retries = 5 # The amount of retries when trying to connect (value between 3 and 30, default is 5).
|
||||
*
|
||||
* # Search directories
|
||||
* @endcode
|
||||
@@ -103,11 +107,40 @@
|
||||
* # Example
|
||||
* # AppConfig = "app_config.toml"
|
||||
* AppConfig = ""
|
||||
*
|
||||
* # A list of zero or more listener definitions that should be instantiated during startup of the
|
||||
* # main application. If no listener definition is available, the default shared-memory listener
|
||||
* # is being instantiated.
|
||||
* #
|
||||
* # [[Settings.Listener]]
|
||||
* # Name = ""
|
||||
* # [Settings.Listerner.Provider]
|
||||
* # Name = ""
|
||||
* # [Settings.Listener.IpcChannel]
|
||||
*
|
||||
* # A list of zero or more client connections that should be instantiated during startup.
|
||||
* #
|
||||
* # [[Settings.Connection]]
|
||||
* # Name = ""
|
||||
* # [Settings.Connection.Provider]
|
||||
* # Name = ""
|
||||
* # [Settings.Listener.IpcChannel]
|
||||
* @endcode
|
||||
*/
|
||||
class CAppSettings : public sdv::IInterfaceAccess, public sdv::app::IAppContext, public sdv::IAttributes
|
||||
class CAppSettings : public sdv::CSdvParamMap, public sdv::IInterfaceAccess, public sdv::app::IAppContext,
|
||||
public sdv::app::IAppSettingsPersist, public sdv::app::IAppConnections
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Console reporting.
|
||||
*/
|
||||
enum class EAppConsoleReporting
|
||||
{
|
||||
silent, ///< No reporting by application control (default)
|
||||
normal, ///< Normal reporting by application control
|
||||
verbose, ///< Extensive reporting by application control
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
@@ -118,11 +151,71 @@ public:
|
||||
*/
|
||||
~CAppSettings();
|
||||
|
||||
#ifndef DOXYGEN_IGNORE
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::app::IAppContext)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
// Application mode labels
|
||||
BEGIN_SDV_LABEL_MAP(sdv::app::EAppContext)
|
||||
SDV_LABEL_ENTRY(sdv::app::EAppContext::no_context, "Undefined")
|
||||
SDV_LABEL_ENTRY(sdv::app::EAppContext::standalone, "Standalone")
|
||||
SDV_LABEL_ENTRY(sdv::app::EAppContext::external, "External")
|
||||
SDV_LABEL_ENTRY(sdv::app::EAppContext::isolated, "Isolated")
|
||||
SDV_LABEL_ENTRY(sdv::app::EAppContext::main, "Main")
|
||||
SDV_LABEL_ENTRY(sdv::app::EAppContext::essential, "Essential")
|
||||
SDV_LABEL_ENTRY(sdv::app::EAppContext::maintenance, "Maintenance")
|
||||
END_SDV_LABEL_MAP()
|
||||
|
||||
// Log severity labels
|
||||
BEGIN_SDV_LABEL_MAP(sdv::core::ELogSeverity)
|
||||
SDV_LABEL_ENTRY(sdv::core::ELogSeverity::trace, "Trace")
|
||||
SDV_LABEL_ENTRY(sdv::core::ELogSeverity::debug, "Debug")
|
||||
SDV_LABEL_ENTRY(sdv::core::ELogSeverity::info, "Info")
|
||||
SDV_LABEL_ENTRY(sdv::core::ELogSeverity::warning, "Warning")
|
||||
SDV_LABEL_ENTRY(sdv::core::ELogSeverity::error, "Error")
|
||||
SDV_LABEL_ENTRY(sdv::core::ELogSeverity::fatal, "Fatal")
|
||||
END_SDV_LABEL_MAP()
|
||||
|
||||
// Console reporting labels
|
||||
BEGIN_SDV_LABEL_MAP(EAppConsoleReporting)
|
||||
SDV_LABEL_ENTRY(EAppConsoleReporting::normal, "Normal")
|
||||
SDV_LABEL_ENTRY(EAppConsoleReporting::silent, "Silent")
|
||||
SDV_LABEL_ENTRY(EAppConsoleReporting::verbose, "Verbose")
|
||||
END_SDV_LABEL_MAP()
|
||||
|
||||
// Parameter map
|
||||
BEGIN_SDV_PARAM_MAP()
|
||||
SDV_PARAM_SET_READONLY()
|
||||
SDV_PARAM_GROUP("LogHandler")
|
||||
SDV_PARAM_ENTRY(m_ssLoggerClass, "Class", "", "", "Component class name of a custom logger")
|
||||
SDV_PARAM_ENTRY(m_pathLoggerModule, "Path", "", "", "Component module path of a custom logger")
|
||||
SDV_PARAM_ENTRY(m_ssProgramTag, "Tag", "", "", "Program tag to use instead of the name SDV_LOG_<pid>")
|
||||
SDV_PARAM_ENUM_ENTRY(m_eSeverityFilter, "Filter", sdv::core::ELogSeverity::info,
|
||||
"Lowest severity filter to use when logging (Trace, Debug, Info, Warning, Error, Fatal)")
|
||||
SDV_PARAM_ENUM_ENTRY(m_eSeverityViewFilter, "ViewFilter", sdv::core::ELogSeverity::error,
|
||||
"Lowest severity filter to use when logging (Trace, Debug, Info, Warning, Error, Fatal)")
|
||||
|
||||
SDV_PARAM_GROUP("Application")
|
||||
SDV_PARAM_ENUM_ENTRY(m_eAppContextType, "Mode", sdv::app::EAppContext::no_context, "Application mode")
|
||||
SDV_PARAM_ENTRY(m_uiInstanceID, "Instance", 0u, "", "System instance ID")
|
||||
SDV_PARAM_ENTRY(m_pathRootDir, "RootDir", "", "", "Location of user component root directory")
|
||||
SDV_PARAM_ENTRY(m_pathInstallDir, "InstallDir", "", "", "Location of user component installations")
|
||||
SDV_PARAM_ENTRY(m_pathPlatformConfig, "PlatformConfig", "", "", "The platform abstraction configuration file")
|
||||
SDV_PARAM_ENTRY(m_pathVehIfcConfig, "VehIfcConfig", "", "", "The vehicle interface configuration file")
|
||||
SDV_PARAM_ENTRY(m_pathVehAbstrConfig, "VehAbstrConfig", "", "", "The vehicle abstraction configuration file")
|
||||
SDV_PARAM_ENTRY(m_pathUserConfig, "AppConfig", "", "", "The application configuration file")
|
||||
|
||||
SDV_PARAM_GROUP("Console")
|
||||
SDV_PARAM_ENUM_ENTRY(m_eConsoleReporting, "Reporting", EAppConsoleReporting::normal, "Console reporting (Normal, Silent, Verbose)")
|
||||
SDV_PARAM_ENTRY(m_bRedirectMon, "RedirectMon", false, "", "Redirect messages from the monitor onto the console.")
|
||||
|
||||
SDV_PARAM_GROUP("Communication")
|
||||
SDV_PARAM_ENTRY(m_ssDefaultComProvider, "DefaultProvider", "", "", "Name of the default communication provider")
|
||||
END_SDV_PARAM_MAP()
|
||||
#endif // !defined DOXYGEN_IGNORE
|
||||
|
||||
/**
|
||||
* @brief Process the application starrtup configuration.
|
||||
* @param[in] rssConfig Reference to the configuration content (TOML format).
|
||||
@@ -131,19 +224,20 @@ public:
|
||||
bool ProcessAppStartupConfig(const sdv::u8string& rssConfig);
|
||||
|
||||
/**
|
||||
* @brief Load the application settings file.
|
||||
* @brief Load the application settings file. Overload of sdv::app::IAppSettingsPersist::LoadSettings.
|
||||
* @attention Only works if the application is running in main, isolation or maintenance mode.
|
||||
* @remarks When there is no settings file, this is not an error. Default settings will be assumed.
|
||||
* @return Returns whether the loading was successful.
|
||||
*/
|
||||
bool LoadSettingsFile();
|
||||
bool LoadSettings() override;
|
||||
|
||||
/**
|
||||
* @brief Save the application settings file (or create when not existing yet).
|
||||
* @attention Only works if the application is running in main, isolation or maintenance mode.
|
||||
* Overload of sdv::app::IAppSettingsPersist::SaveSettings.
|
||||
* @attention Only works if the application is running in maintenance mode.
|
||||
* @return Returns whether the saving was successful.
|
||||
*/
|
||||
bool SaveSettingsFile();
|
||||
bool SaveSettings() override;
|
||||
|
||||
/**
|
||||
* @brief Return whether the current application is the main application.
|
||||
@@ -181,27 +275,33 @@ public:
|
||||
*/
|
||||
bool IsExternalApplication() const;
|
||||
|
||||
/**
|
||||
* @brief Set the application context type.
|
||||
* @param[in] eContextType The application context type to set.
|
||||
*/
|
||||
void SetContextType(sdv::app::EAppContext eContextType);
|
||||
|
||||
/**
|
||||
* @brief Return the application context mode. Overload of sdv::app::IAppContext::GetContextType.
|
||||
* @return The context mode.
|
||||
*/
|
||||
sdv::app::EAppContext GetContextType() const override;
|
||||
|
||||
/**
|
||||
* @brief Set the instance ID.
|
||||
* @param uiID The instance ID to set.
|
||||
*/
|
||||
void SetInstanceID(uint32_t uiID);
|
||||
|
||||
/**
|
||||
* @brief Return the core instance ID. Overload of sdv::app::IAppContext::GetContextType.
|
||||
* @details Get the instance. If not otherwise specified, the current instance depends on whether the application is running
|
||||
* as main or isolated application, in which case the instance is 1000. In all other cases the instance is 0. An instance
|
||||
* ID can be supplied through the app startup configuration.
|
||||
* as main, isolated or maintenance application, in which case the instance is 1000. In all other cases the instance is 0. An
|
||||
* instance ID can be supplied through the app startup configuration.
|
||||
* @return The core instance ID.
|
||||
*/
|
||||
uint32_t GetInstanceID() const override;
|
||||
|
||||
/**
|
||||
* @brief Return the number of retries to establish a connection. Overload of sdv::app::IAppContext::GetRetries.
|
||||
* @return Number of retries.
|
||||
*/
|
||||
uint32_t GetRetries() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the class name of a logger service, if specified in the application startup configuration.
|
||||
* @return The logger class name.
|
||||
@@ -244,6 +344,30 @@ public:
|
||||
*/
|
||||
bool IsConsoleVerbose() const;
|
||||
|
||||
/**
|
||||
* @brief Set the application console reporting status.
|
||||
* @param eReporting The console reporting status to set.
|
||||
*/
|
||||
void SetConsoleReporting(EAppConsoleReporting eReporting);
|
||||
|
||||
/**
|
||||
* @brief Get the current application console reporting status.
|
||||
* @return The console reporting status of the application.
|
||||
*/
|
||||
EAppConsoleReporting GetConsoleReporting() const;
|
||||
|
||||
/**
|
||||
* @brief Redirect the messages monitored for main application onto the console.
|
||||
* @return Returns whether redirection is switched on.
|
||||
*/
|
||||
bool RedirectMonitorToConsole() const;
|
||||
|
||||
/**
|
||||
* @brief Get the framework directory for the application.
|
||||
* @return The location of framework directory.
|
||||
*/
|
||||
std::filesystem::path GetFrameworkDir() const;
|
||||
|
||||
/**
|
||||
* @brief Get the root directory for the application.
|
||||
* @remarks Is only valid when used in main, isolated and maintenance applications.
|
||||
@@ -279,6 +403,7 @@ public:
|
||||
/**
|
||||
* @brief Get the stored or default configuration path name.
|
||||
* @attention Setting a path is only valid when running as main application.
|
||||
* @param[in] eType The configuration type to get the path for.
|
||||
* @return The path name dependent on the configuration type. If no path name was configured, the default path name is returned.
|
||||
*/
|
||||
std::filesystem::path GetConfigPath(EConfigType eType) const;
|
||||
@@ -326,33 +451,80 @@ public:
|
||||
bool RemoveUserConfigPath();
|
||||
|
||||
/**
|
||||
* @brief Get a sequence with the available attribute names. Overload of sdv::IAttributes::GetNames.
|
||||
* @return The sequence of attribute names.
|
||||
* @brief Get the default communication provider (extracted from listener and connection settings).
|
||||
* @return Name of the default communication provider.
|
||||
*/
|
||||
virtual sdv::sequence<sdv::u8string> GetNames() const override;
|
||||
const std::string& GetDefaultComProvider() const;
|
||||
|
||||
/**
|
||||
* @brief Get the attribute value. Overload of sdv::IAttributes::Get.
|
||||
* @param[in] ssAttribute Name of the attribute.
|
||||
* @return The attribute value or an empty any-value if the attribute wasn't found or didn't have a value.
|
||||
* @brief Get a sequence with listener names. Overload of sdv::app::IAppConnections::GetListeners.
|
||||
* @return Sequence with listener name strings.
|
||||
*/
|
||||
virtual sdv::any_t Get(/*in*/ const sdv::u8string& ssAttribute) const override;
|
||||
sdv::sequence<sdv::u8string> GetListeners() const override;
|
||||
|
||||
/**
|
||||
* @brief Set the attribute value. Overload of sdv::IAttributes::Set.
|
||||
* @param[in] ssAttribute Name of the attribute.
|
||||
* @param[in] anyAttribute Attribute value to set.
|
||||
* @return Returns 'true' when setting the attribute was successful or 'false' when the attribute was not found or the
|
||||
* attribute is read-only or another error occurred.
|
||||
* @brief Get the listener configuration. Overload of sdv::app::IAppConnections::GetListenerConfig.
|
||||
* @param[in] ssName Name of the listener.
|
||||
* @return String containing the listener configuration.
|
||||
*/
|
||||
virtual bool Set(/*in*/ const sdv::u8string& ssAttribute, /*in*/ sdv::any_t anyAttribute) override;
|
||||
sdv::u8string GetListenerConfig(/*in*/ const sdv::u8string& ssName) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the attribute flags belonging to a certain attribute. Overload of sdv::IAttributes::GetFlags.
|
||||
* @param[in] ssAttribute Name of the attribute.
|
||||
* @return Returns the attribute flags (zero or more EAttributeFlags flags) or 0 when the attribute could not be found.
|
||||
* @brief Add or update a listener configuration. Overload of sdv::app::IAppConnections::AddListenerConfig.
|
||||
* @remarks Only accessible when the application runs in maintenance mode.
|
||||
* @param[in] ssName Name of the listener configuration.
|
||||
* @param[in] ssConfig The configuration string for the listener.
|
||||
* @return Returns whether the listener could be added (fails when the listener already exists).
|
||||
*/
|
||||
virtual uint32_t GetFlags(/*in*/ const sdv::u8string& ssAttribute) const override;
|
||||
bool AddListenerConfig(/*in*/ const sdv::u8string& ssName, /*in*/ const sdv::u8string& ssConfig) override;
|
||||
|
||||
/**
|
||||
* @brief Remove a listener configuration with the provided name. Overload of sdv::app::IAppConnections::RemoveListenerConfig.
|
||||
* @remarks Only accessible when the application runs in maintenance mode.
|
||||
* @param[in] ssName Name of the listener configuration.
|
||||
* @return Returns whether the removal was successful.
|
||||
*/
|
||||
bool RemoveListenerConfig(/*in*/ const sdv::u8string& ssName) override;
|
||||
|
||||
/**
|
||||
* @brief Get a sequence with connection names. Overload of sdv::app::IAppConnections::GetConnections.
|
||||
* @return Sequence with connection name strings.
|
||||
*/
|
||||
sdv::sequence<sdv::u8string> GetConnections() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the connection configuration. Overload of sdv::app::IAppConnections::GetConnectionConfig.
|
||||
* @param[in] ssName Name of the connection.
|
||||
* @return String containing the connection configuration.
|
||||
*/
|
||||
sdv::u8string GetConnectionConfig(/*in*/ const sdv::u8string& ssName) const override;
|
||||
|
||||
/**
|
||||
* @brief Add or update a connection configuration. Overload of sdv::app::IAppConnections::AddConnectionConfig.
|
||||
* @remarks Only accessible when the application runs in maintenance mode.
|
||||
* @param[in] ssName Name of the connection configuration.
|
||||
* @param[in] ssConfig The configuration string for the connection.
|
||||
* @param[in] ssInsertBefore Reference to the string to connection to insert the the new connection before, or empty when the
|
||||
* the new connection should be placed at the end.
|
||||
* @return Returns whether the connection could be added (fails when the connection already exists).
|
||||
*/
|
||||
bool AddConnectionConfig(/*in*/ const sdv::u8string& ssName, /*in*/ const sdv::u8string& ssConfig,
|
||||
/*in*/ const sdv::u8string& ssInsertBefore = std::string()) override;
|
||||
|
||||
/**
|
||||
* @brief Remove a connection configuration with the provided name. Overload of
|
||||
* sdv::app::IAppConnections::RemoveConnectionConfig.
|
||||
* @remarks Only accessible when the application runs in maintenance mode.
|
||||
* @param[in] ssName Name of the connection configuration.
|
||||
* @return Returns whether the removal was successful.
|
||||
*/
|
||||
bool RemoveConnectionConfig(/*in*/ const sdv::u8string& ssName) override;
|
||||
|
||||
/**
|
||||
* @brief Return the number of retries to establish a connection. Overload of sdv::app::IAppConnections::GetRetries.
|
||||
* @return Number of retries.
|
||||
*/
|
||||
uint32_t GetConnectRetries() const override;
|
||||
|
||||
/**
|
||||
* @brief Reset the settings after a shutdown.
|
||||
@@ -360,26 +532,42 @@ public:
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
sdv::app::EAppContext m_eContextMode = sdv::app::EAppContext::no_context; ///< The application is running as...
|
||||
uint32_t m_uiInstanceID = 0u; ///< Instance number.
|
||||
uint32_t m_uiRetries = 0u; ///< Number of retries to establish a connection.
|
||||
/**
|
||||
* @brief Get the default listener config.
|
||||
* @return String containing the TOML with the listener config.
|
||||
*/
|
||||
std::string DefaultListenerConfig() const;
|
||||
|
||||
/**
|
||||
* @brief Get the default connection config.
|
||||
* @return String containing the TOML with the connection config.
|
||||
*/
|
||||
std::string DefaultConnectionConfig() const;
|
||||
|
||||
sdv::app::EAppContext m_eAppContextType = sdv::app::EAppContext::no_context; ///< The application is running as...
|
||||
uint32_t m_uiInstanceID = 0u; ///< Instance number (default 1000, but only after startup).
|
||||
uint32_t m_uiConnectRetries = 5u; ///< Number of retries to establish a connection.
|
||||
std::string m_ssLoggerClass; ///< Class name of a logger service.
|
||||
std::filesystem::path m_pathLoggerModule; ///< Module name of a custom logger.
|
||||
std::string m_ssProgramTag; ///< Program tag to use when logging.
|
||||
sdv::core::ELogSeverity m_eSeverityFilter = sdv::core::ELogSeverity::info; ///< Severity level filter while logging.
|
||||
sdv::core::ELogSeverity m_eSeverityViewFilter = sdv::core::ELogSeverity::error; ///< Severity level filter while logging.
|
||||
bool m_bSilent = false; ///< When set, no console reporting takes place.
|
||||
bool m_bVerbose = false; ///< When set, extensive console reporting takes place.
|
||||
EAppConsoleReporting m_eConsoleReporting = EAppConsoleReporting::normal; ///< Console reporting
|
||||
bool m_bRedirectMon = false; ///< When set, redirect the message from the monitor onto console.
|
||||
std::filesystem::path m_pathFrameworkDir; ///< Location of framework component directory.
|
||||
std::filesystem::path m_pathRootDir; ///< Location of user component root directory.
|
||||
std::filesystem::path m_pathInstallDir; ///< Location of user component installations (root with instance).
|
||||
std::filesystem::path m_pathPlatformConfig; ///< The platform configuration from the settings file.
|
||||
std::filesystem::path m_pathVehIfcConfig; ///< The vehicle interface configuration from the settings file.
|
||||
std::filesystem::path m_pathVehAbstrConfig; ///< The vehicle abstraction configuration from the settings file.
|
||||
std::filesystem::path m_pathUserConfig; ///< The user configuration from the settings file.
|
||||
bool m_bPlatformConfig = false; ///< Platform config was explicitly enabled/disabled.
|
||||
bool m_bVehIfcConfig = false; ///< Vehicle interface config was explicitly enabled/disabled.
|
||||
bool m_bVehAbstrConfig = false; ///< Vehicle abstraction config was explicitly enabled/disabled.
|
||||
bool m_bUserConfig = false; ///< User config was explicitly enabled/disabled.
|
||||
bool m_bUpdatePlatformConfig = false; ///< Platform config was explicitly marked for update.
|
||||
bool m_bUpdateVehIfcConfig = false; ///< Vehicle interface config was explicitly marked for update.
|
||||
bool m_bUpdateVehAbstrConfig = false; ///< Vehicle abstraction config was explicitly marked for update.
|
||||
bool m_bUpdateUserConfig = false; ///< User config was explicitly marked for update.
|
||||
std::map<std::string, std::string> m_mapListeners; ///< Map with listener configurations.
|
||||
std::vector<std::pair<std::string, std::string>> m_vecConnections; ///< Vector with connection configurations.
|
||||
std::string m_ssDefaultComProvider; ///< Name of the default communication provider.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -398,7 +586,11 @@ public:
|
||||
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY_MEMBER(sdv::IAttributes, GetAppSettings())
|
||||
SDV_INTERFACE_SET_SECTION_CONDITION(GetAppSettings().IsMaintenanceApplication(), 1)
|
||||
SDV_INTERFACE_SECTION(1)
|
||||
SDV_INTERFACE_ENTRY_MEMBER(sdv::app::IAppSettingsPersist, GetAppSettings())
|
||||
SDV_INTERFACE_ENTRY_MEMBER(sdv::app::IAppConnections, GetAppSettings())
|
||||
SDV_INTERFACE_DEFAULT_SECTION()
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
// Object declarations
|
||||
@@ -406,6 +598,11 @@ public:
|
||||
DECLARE_OBJECT_CLASS_NAME("AppSettingsService")
|
||||
DECLARE_OBJECT_SINGLETON()
|
||||
|
||||
// Parameter map
|
||||
BEGIN_SDV_PARAM_MAP()
|
||||
SDV_PARAM_CHAIN_MEMBER(GetAppSettings())
|
||||
END_SDV_PARAM_MAP()
|
||||
|
||||
/**
|
||||
* @brief Get access to the application settings.
|
||||
* @return Returns the one global instance of the application config.
|
||||
|
||||
@@ -38,6 +38,12 @@
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr float kMaxBLOBSize = (24*1024*1024) + 25000000;
|
||||
}
|
||||
|
||||
|
||||
CInstallComposer::~CInstallComposer()
|
||||
{}
|
||||
|
||||
@@ -1019,10 +1025,16 @@ uint32_t CInstallComposer::SerializeModuleBLOB(uint32_t uiChecksumInit, sdv::poi
|
||||
// Calculate the size of the BLOB (including padding and checksum)
|
||||
sdv::installation::SPackageBLOBChecksum sBLOBChecksum{};
|
||||
size_t nSize = 0;
|
||||
sdv::ser_size(sBLOB, nSize);
|
||||
sdv::ser_size(sBLOB, nSize);
|
||||
sdv::ser_size(sBLOBChecksum, nSize);
|
||||
if (nSize % 8) nSize += 8 - nSize % 8;
|
||||
sBLOB.uiBLOBSize = static_cast<uint32_t>(nSize);
|
||||
if(sBLOB.uiBLOBSize > kMaxBLOBSize)
|
||||
{
|
||||
sdv::installation::XPackageSizeExceeded exception;
|
||||
exception.ssFileName = sBLOB.sFileDesc.ssFileName;
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// Serialize the BLOB
|
||||
sdv::serializer<sdv::GetPlatformEndianess(), sdv::crcCRC32C> serializer;
|
||||
@@ -1246,7 +1258,7 @@ sdv::installation::SPackageBLOB CInstallComposer::DeserializeBLOB(std::ifstream&
|
||||
|
||||
// Extend the buffer and read the BLOB data (after the resize, the psPartialBLOB pointer could be invalidated).
|
||||
uint32_t uiBLOBSize = psPartialBLOB->uiBLOBSize;
|
||||
if (uiBLOBSize > 26*1024*1024) // 26 instead of 24 becasue of door example
|
||||
if (uiBLOBSize > kMaxBLOBSize)
|
||||
throw sdv::installation::XIncompatiblePackage(); // Safety
|
||||
ptrBLOB.resize(uiBLOBSize);
|
||||
if (!ptrBLOB)
|
||||
|
||||
@@ -23,11 +23,11 @@ CIsoMonitor::~CIsoMonitor()
|
||||
GetAppControl().RequestShutdown();
|
||||
}
|
||||
|
||||
void CIsoMonitor::Initialize(/*in*/ const sdv::u8string& ssObjectConfig)
|
||||
void CIsoMonitor::Initialize(/*in*/ const sdv::SObjectInfo& sObjectInfo)
|
||||
{
|
||||
if (m_pObjectControl)
|
||||
{
|
||||
m_pObjectControl->Initialize(ssObjectConfig);
|
||||
m_pObjectControl->Initialize(sObjectInfo);
|
||||
m_eObjectState = m_pObjectControl->GetObjectState();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -42,9 +42,9 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Initialize the object. Overload of sdv::IObjectControl::Initialize.
|
||||
* @param[in] ssObjectConfig Optional configuration string.
|
||||
* @param[in] sObjectInfo The registration information of this object.
|
||||
*/
|
||||
virtual void Initialize(/*in*/ const sdv::u8string& ssObjectConfig) override;
|
||||
virtual void Initialize(/*in*/ const sdv::SObjectInfo& sObjectInfo) override;
|
||||
|
||||
/**
|
||||
* @brief Get the current state of the object. Overload of sdv::IObjectControl::GetObjectState.
|
||||
|
||||
@@ -61,6 +61,8 @@ inline bool RequestShutdown(uint32_t uiInstanceID = 1000u)
|
||||
CloseHandle(hEvent);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
std::cerr << "ERROR: Shutdown event handle is not available: " << m_ssSignalName << std::endl;
|
||||
#elif defined __unix__
|
||||
sem_t* pSemaphore = sem_open(m_ssSignalName.c_str(), 0);
|
||||
if (pSemaphore && pSemaphore != SEM_FAILED)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "logger.h"
|
||||
#include <sstream>
|
||||
#include "../../global/exec_dir_helper.h"
|
||||
#include "app_settings.h"
|
||||
|
||||
#ifdef __unix__
|
||||
#include <syslog.h>
|
||||
@@ -38,7 +39,7 @@ CLogger::~CLogger()
|
||||
void CLogger::Log(sdv::core::ELogSeverity eSeverity, /*in*/ const sdv::u8string& ssSrcFile, /*in*/ uint32_t uiSrcLine,
|
||||
/*in*/ sdv::process::TProcessID tProcessID, /*in*/ const sdv:: u8string& ssObjectName, /*in*/ const sdv::u8string& ssMessage)
|
||||
{
|
||||
if (static_cast<uint32_t>(eSeverity) >= static_cast<uint32_t>(m_eViewFilter))
|
||||
if (GetAppSettings().IsConsoleVerbose() && static_cast<uint32_t>(eSeverity) >= static_cast<uint32_t>(m_eViewFilter))
|
||||
{
|
||||
if (tProcessID) std::clog << "[PID#" << static_cast<int64_t>(tProcessID) << "] ";
|
||||
if (!ssObjectName.empty()) std::clog << ssObjectName << " ";
|
||||
|
||||
@@ -297,6 +297,10 @@ bool CModuleInst::Load(const std::filesystem::path& rpathModule) noexcept
|
||||
}
|
||||
|
||||
m_mapClassInfo[sClass.ssName] = sClass;
|
||||
|
||||
// Add aliases?
|
||||
for (const auto& rssAlias : sClass.seqClassAliases)
|
||||
m_mapClassInfo[rssAlias] = sClass;
|
||||
}
|
||||
}
|
||||
catch (const sdv::toml::XTOMLParseException&)
|
||||
|
||||
@@ -250,7 +250,7 @@ std::shared_ptr<CModuleInst> CModuleControl::FindModuleByClass(const std::string
|
||||
}
|
||||
}
|
||||
|
||||
// For main and isolated applications, check whether the module is in one of the installation manifests.
|
||||
// For main, isolated and maintenance applications, check whether the module is in one of the installation manifests.
|
||||
auto optManifest = GetAppConfig().FindInstalledComponent(rssClass);
|
||||
if (!optManifest) return nullptr;
|
||||
std::filesystem::path pathModule = std::filesystem::u8path(static_cast<std::string>(optManifest->ssModulePath));
|
||||
@@ -378,8 +378,6 @@ std::string CModuleControl::SaveConfig(const std::set<std::filesystem::path>& /*
|
||||
|
||||
sdv::core::TModuleID CModuleControl::ContextLoad(const std::filesystem::path& rpathModule, const std::string& rssManifest)
|
||||
{
|
||||
if (GetAppSettings().IsMaintenanceApplication()) return 0; // Not allowed
|
||||
|
||||
// Run through the manifest and check for complex services, applications and utilities.
|
||||
// TODO EVE: Temporary suppression of cppcheck warning.
|
||||
// cppcheck-suppress variableScope
|
||||
@@ -462,7 +460,7 @@ void CModuleControl::AddCurrentPath()
|
||||
if (!m_lstSearchPaths.empty()) return;
|
||||
|
||||
// Add the core directory
|
||||
std::filesystem::path pathCoreDir = GetCoreDirectory().lexically_normal();
|
||||
std::filesystem::path pathCoreDir = GetAppSettings().GetFrameworkDir().lexically_normal();
|
||||
m_lstSearchPaths.push_back(pathCoreDir);
|
||||
|
||||
// Add the exe dir
|
||||
|
||||
167
sdv_services/core/permission_control.cpp
Normal file
167
sdv_services/core/permission_control.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#include "permission_control.h"
|
||||
|
||||
#if defined __GNUC__ && defined _WIN32
|
||||
thread_local std::list<std::pair<sdv::core::EAccessPermission, size_t>>&
|
||||
CPermissionControl::m_lstPermissionTracker = CreatePermissionList();
|
||||
thread_local std::map<sdv::core::TPermissionID, CAccessPermission>&
|
||||
CPermissionControl::m_mapPermissions = CreatePermissionMap();
|
||||
#else
|
||||
thread_local std::list<std::pair<sdv::core::EAccessPermission, size_t>> CPermissionControl::m_lstPermissionTracker;
|
||||
thread_local std::map<sdv::core::TPermissionID, CAccessPermission> CPermissionControl::m_mapPermissions;
|
||||
#endif
|
||||
|
||||
CPermissionControl& GetPermissionControl()
|
||||
{
|
||||
static CPermissionControl control;
|
||||
return control;
|
||||
}
|
||||
|
||||
CAccessPermission::CAccessPermission(CPermissionControl& rPermissionControl, sdv::core::EAccessPermission ePermission) :
|
||||
m_rPermissionControl(rPermissionControl), m_ePermission(ePermission)
|
||||
{
|
||||
if (m_ePermission != sdv::core::EAccessPermission::not_set)
|
||||
rPermissionControl.IncrementPermissionCount(ePermission);
|
||||
}
|
||||
|
||||
CAccessPermission::CAccessPermission(const CAccessPermission& rPermission) :
|
||||
m_rPermissionControl(rPermission.m_rPermissionControl), m_ePermission(rPermission.m_ePermission)
|
||||
{
|
||||
if (m_ePermission != sdv::core::EAccessPermission::not_set)
|
||||
m_rPermissionControl.IncrementPermissionCount(m_ePermission);
|
||||
}
|
||||
|
||||
CAccessPermission::CAccessPermission(CAccessPermission&& rPermission) :
|
||||
m_rPermissionControl(rPermission.m_rPermissionControl), m_ePermission(rPermission.m_ePermission)
|
||||
{
|
||||
rPermission.m_ePermission = sdv::core::EAccessPermission::not_set;
|
||||
}
|
||||
|
||||
CAccessPermission& CAccessPermission::operator=(const CAccessPermission& rPermission)
|
||||
{
|
||||
// Remove current permission and copy the new permission
|
||||
if (m_ePermission != sdv::core::EAccessPermission::not_set)
|
||||
m_rPermissionControl.DecrementPermissionCount(m_ePermission);
|
||||
m_ePermission = rPermission.m_ePermission;
|
||||
if (m_ePermission != sdv::core::EAccessPermission::not_set)
|
||||
m_rPermissionControl.IncrementPermissionCount(m_ePermission);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAccessPermission& CAccessPermission::operator=(CAccessPermission && rPermission)
|
||||
{
|
||||
// Remove current permission and move the new permission
|
||||
if (m_ePermission != sdv::core::EAccessPermission::not_set)
|
||||
m_rPermissionControl.DecrementPermissionCount(m_ePermission);
|
||||
m_ePermission = rPermission.m_ePermission;
|
||||
rPermission.m_ePermission = sdv::core::EAccessPermission::not_set;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAccessPermission ::~CAccessPermission()
|
||||
{
|
||||
if (m_ePermission != sdv::core::EAccessPermission::not_set)
|
||||
m_rPermissionControl.DecrementPermissionCount(m_ePermission);
|
||||
}
|
||||
|
||||
sdv::core::EAccessPermission CAccessPermission::Permission() const
|
||||
{
|
||||
return m_ePermission;
|
||||
}
|
||||
|
||||
sdv::core::TPermissionID CPermissionControl::RestrictAccessPermission(/*in*/ sdv::core::EAccessPermission ePermission)
|
||||
{
|
||||
// Unlike the CreateAccessPermission this function can only be used to restrict an already available restriction. It cannot be
|
||||
// used to set the initial restriction.
|
||||
if (m_lstPermissionTracker.empty()) return false;
|
||||
|
||||
sdv::core::TPermissionID tPermissionID = m_idgen.Generate();
|
||||
if (!tPermissionID) return 0u;
|
||||
m_mapPermissions.emplace(tPermissionID, CreatePermissionObject(ePermission));
|
||||
return tPermissionID;
|
||||
}
|
||||
|
||||
bool CPermissionControl::ReleaseAccessPermission(/*in*/ sdv::core::TPermissionID tPermissionID)
|
||||
{
|
||||
auto itPermission = m_mapPermissions.find(tPermissionID);
|
||||
if (itPermission == m_mapPermissions.end()) return false;
|
||||
m_mapPermissions.erase(itPermission);
|
||||
return true;
|
||||
}
|
||||
|
||||
sdv::core::TPermissionTransferID CPermissionControl::TransferCurrentPermission()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtxPermissionTransfer);
|
||||
sdv::core::TPermissionTransferID tTransferID = m_idgen.Generate();
|
||||
m_mapPermissionTransfer[tTransferID] = GetCurrentPermission();
|
||||
return tTransferID;
|
||||
}
|
||||
|
||||
sdv::core::TPermissionID CPermissionControl::SetAccessPermission(/*in*/ sdv::core::TPermissionTransferID tTransferID)
|
||||
{
|
||||
// Get the access restriction level from the transfer permission map.
|
||||
std::unique_lock<std::mutex> lock(m_mtxPermissionTransfer);
|
||||
auto itTransferPermission = m_mapPermissionTransfer.find(tTransferID);
|
||||
if (itTransferPermission == m_mapPermissionTransfer.end()) return 0u;
|
||||
sdv::core::EAccessPermission ePermission = itTransferPermission->second;
|
||||
m_mapPermissionTransfer.erase(itTransferPermission);
|
||||
|
||||
// Unlike the RestrictAccessPermission function, the SetAccessPermission function can be used to set an initial permission.
|
||||
sdv::core::TPermissionID tPermissionID = m_idgen.Generate();
|
||||
if (!tPermissionID) return 0u;
|
||||
m_mapPermissions.emplace(tPermissionID, CreatePermissionObject(ePermission));
|
||||
return tPermissionID;
|
||||
}
|
||||
|
||||
sdv::core::EAccessPermission CPermissionControl::GetCurrentPermission() const
|
||||
{
|
||||
return m_lstPermissionTracker.empty() ? sdv::core::EAccessPermission::restricted_access : m_lstPermissionTracker.front().first;
|
||||
}
|
||||
|
||||
CAccessPermission CPermissionControl::CreatePermissionObject(sdv::core::EAccessPermission ePermission)
|
||||
{
|
||||
sdv::core::EAccessPermission ePermissionLocal = std::max(ePermission, sdv::core::EAccessPermission::restricted_access);
|
||||
return CAccessPermission(*this, ePermissionLocal);
|
||||
}
|
||||
|
||||
void CPermissionControl::IncrementPermissionCount(sdv::core::EAccessPermission ePermission)
|
||||
{
|
||||
// In the permission tracker list, search for the counter for this permission or, if not existing, the next higher permission.
|
||||
auto itPermissionCounter = m_lstPermissionTracker.begin();
|
||||
for (; itPermissionCounter != m_lstPermissionTracker.end(); ++itPermissionCounter)
|
||||
{
|
||||
if (itPermissionCounter->first >= ePermission)
|
||||
break;
|
||||
}
|
||||
|
||||
// If counter doesn't exist, insert a new counter.
|
||||
if (itPermissionCounter == m_lstPermissionTracker.end() || itPermissionCounter->first > ePermission)
|
||||
itPermissionCounter = m_lstPermissionTracker.insert(itPermissionCounter, std::make_pair(ePermission, 1));
|
||||
else // exists, increase the counter
|
||||
itPermissionCounter->second++;
|
||||
}
|
||||
|
||||
void CPermissionControl::DecrementPermissionCount(sdv::core::EAccessPermission ePermission)
|
||||
{
|
||||
// Find the permission counter
|
||||
auto itPermissionCounter = std::find_if(m_lstPermissionTracker.begin(), m_lstPermissionTracker.end(), [&](const auto& rprPermissionCount)
|
||||
{ return rprPermissionCount.first == ePermission; });
|
||||
if (itPermissionCounter == m_lstPermissionTracker.end()) return;
|
||||
|
||||
// Reduce the counter and if reaching zero, erase the counter
|
||||
itPermissionCounter->second--;
|
||||
if (!itPermissionCounter->second)
|
||||
m_lstPermissionTracker.erase(itPermissionCounter);
|
||||
}
|
||||
263
sdv_services/core/permission_control.h
Normal file
263
sdv_services/core/permission_control.h
Normal file
@@ -0,0 +1,263 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef PERMISSION_CONTROL_H
|
||||
#define PERMISSION_CONTROL_H
|
||||
|
||||
#include <interfaces/permission.h>
|
||||
#include <list>
|
||||
#include <support/component_impl.h>
|
||||
|
||||
#include "../../global/unique_id.h"
|
||||
|
||||
// Forward declaration
|
||||
class CPermissionControl;
|
||||
|
||||
/**
|
||||
* @brief Use a list to create a stack, which allows elements to be deleted.
|
||||
*/
|
||||
using TPermissionStack = std::list<sdv::core::EAccessPermission>;
|
||||
|
||||
/**
|
||||
* @brief Permission class for the requested access. This class manages the lifetime of the permissions.
|
||||
*/
|
||||
class CAccessPermission
|
||||
{
|
||||
private:
|
||||
/// Permission control is allowed to create an access permission object.
|
||||
friend CPermissionControl;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rPermissionControl Reference to permission control.
|
||||
* @param[in] ePermission The requested access permission.
|
||||
*/
|
||||
CAccessPermission(CPermissionControl& rPermissionControl, sdv::core::EAccessPermission ePermission);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CAccessPermission();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param[in] rPermission Reference to the permission object to copy from.
|
||||
*/
|
||||
CAccessPermission(const CAccessPermission& rPermission);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param[in] rPermission Reference to the permission object to move from.
|
||||
*/
|
||||
CAccessPermission(CAccessPermission&& rPermission);
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param[in] rPermission Reference to the permission object to move from.
|
||||
* @return Reference to this access permission object.
|
||||
*/
|
||||
CAccessPermission& operator=(const CAccessPermission& rPermission);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param[in] rPermission Reference to the permission object to move from.
|
||||
* @return Reference to this access permission object.
|
||||
*/
|
||||
CAccessPermission& operator=(CAccessPermission&& rPermission);
|
||||
|
||||
/**
|
||||
* @brief Get the permission level assigned to this object.
|
||||
* @remarks This might not correspond to the current permission level available for this thread.
|
||||
* @return The permission level.
|
||||
*/
|
||||
sdv::core::EAccessPermission Permission() const;
|
||||
|
||||
private:
|
||||
CPermissionControl& m_rPermissionControl; ///< Reference to the permission control.
|
||||
sdv::core::EAccessPermission m_ePermission; ///< Requested permission.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Permission control provides a simple access mechanism to allow the management of access to system functions.
|
||||
*/
|
||||
class CPermissionControl : public sdv::IInterfaceAccess, public sdv::core::IPermissionControl
|
||||
{
|
||||
public:
|
||||
/// Access permission class can access the permission control.
|
||||
friend CAccessPermission;
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CPermissionControl() = default;
|
||||
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::core::IPermissionControl)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Restrict the access permission for the current thread. Overload of
|
||||
* sdv::core.:IPermissionControl::RestrictAccessPermission.
|
||||
* @remarks The access restriction will be assigned to the current thread and combined with previous and future
|
||||
* permissions. The lowest assigned permission will determine the actual access permission for the current thread.
|
||||
* @remarks The access restriction will stay in effect until it is released by the function ReleaseAccessPermission.
|
||||
* @remarks A newly created thread has fully restricted access. This cannot be changed using this function. Use an access
|
||||
* restriction transfer from one thread to this thread to set a higher level of access permission.
|
||||
* @param[in] ePermission The permission to restrict to.
|
||||
* @return The permission ID for this restriction or 0 when the access permission could not be set. Use the
|
||||
* ReleaseAccessPermission to release the restriction again.
|
||||
*/
|
||||
virtual sdv::core::TPermissionID RestrictAccessPermission(/*in*/ sdv::core::EAccessPermission ePermission) override;
|
||||
|
||||
/**
|
||||
* @brief Release a previously set access restriction for the current thread. Overload of
|
||||
* sdv::core::IPermissionControl::ReleaseAccessPermission.
|
||||
* @param[in] tPermissionID The ID of the access restriction previously set for the current thread.
|
||||
* @return Returns whether the restriction could be released successfully.
|
||||
*/
|
||||
virtual bool ReleaseAccessPermission(/*in*/ sdv::core::TPermissionID tPermissionID) override;
|
||||
|
||||
/**
|
||||
* @brief Prepare to transfer the access restriction from the current thread.Overload of
|
||||
* sdv::core.:IPermissionControl::TransferCurrentPermission.
|
||||
* @return The ID of the transfer object containing the current access permissions or 0 when the transfer preparation has
|
||||
* failed.
|
||||
*/
|
||||
virtual sdv::core::TPermissionTransferID TransferCurrentPermission() override;
|
||||
|
||||
/**
|
||||
* @brief Set the access permission using a transfer object from one thread to another. Overload of
|
||||
* sdv::core.:IPermissionControl::SetAccessPermission.
|
||||
* @remarks An new thread has fully restricted access per default. Use this function to set the required access level. If a
|
||||
* thread has already initialized with the proper access level, this function will set identical or lower access permissions
|
||||
* for the current thread.
|
||||
* @param[in] tTransferID The IS of the prepared access permission transfer.
|
||||
* @return The permission ID for this restriction or 0 when the access permission could not be transferred. Use the
|
||||
* ReleaseAccessPermission to release the restriction again.
|
||||
*/
|
||||
virtual sdv::core::TPermissionID SetAccessPermission(/*in*/ sdv::core::TPermissionTransferID tTransferID) override;
|
||||
|
||||
/**
|
||||
* @brief Get the access permission level for the current thread. This will be the lowest restriction set for the current
|
||||
* thread. Overload of sdv::core.:IPermissionControl::GetCurrentPermission.
|
||||
* @return The current access permission level.
|
||||
*/
|
||||
virtual sdv::core::EAccessPermission GetCurrentPermission() const override;
|
||||
|
||||
/**
|
||||
* @brief Create a permission object that assigns the access permissions to the call thread. The permissions stay in place
|
||||
* until a last copy of the object is destroyed.
|
||||
* @param[in] ePermission The new permission to set for the thread. If the permission has a value smaller than
|
||||
* sdv::core::EAccessPermission::restricted_access, the object will be created with restricted access permission.
|
||||
* @return The permission object. The permission will stay in place during the lifetime of the object.
|
||||
*/
|
||||
CAccessPermission CreatePermissionObject(sdv::core::EAccessPermission ePermission);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Increment the counter for a specific permission.
|
||||
* @param[in] ePermission The permission the count should be incremented for.
|
||||
*/
|
||||
void IncrementPermissionCount(sdv::core::EAccessPermission ePermission);
|
||||
|
||||
/**
|
||||
* @brief Increment the counter for a specific permission.
|
||||
* @param[in] ePermission The permission the count should be incremented for.
|
||||
*/
|
||||
void DecrementPermissionCount(sdv::core::EAccessPermission ePermission);
|
||||
|
||||
CUniqueID<uint64_t> m_idgen; ///< Unique ID generator.
|
||||
|
||||
#if defined __GNUC__ && defined _WIN32
|
||||
// https://dev.azure.com/SW4ZF/AZP-431_DivDI_Vehicle_API/_workitems/edit/610009
|
||||
// In MINGW GCC implementation of thread_local, there is an issue with complex classes being used after the destruction. This
|
||||
// is caused by an architectural bug (https://github.com/msys2/MINGW-packages/issues/2519) causing the emutls (GCC Emulated TLS)
|
||||
// managing the memory allocation to be executed before the __cxa_thread_exit, the thread cleanup callback of Windows.
|
||||
// The solution is to use trivial data only (pointer, reference, integers, etc.). A workaround is implemented to use a reference
|
||||
// of the permission list and map instead of an instance to the list and map.
|
||||
|
||||
/**
|
||||
* @brief Create a permission list object.
|
||||
* @return Reference to the created list object.
|
||||
*/
|
||||
static std::list<std::pair<sdv::core::EAccessPermission, size_t>>& CreatePermissionList()
|
||||
{
|
||||
static std::mutex mtxPermissionLists;
|
||||
static std::list<std::list<std::pair<sdv::core::EAccessPermission, size_t>>> lstPermissionLists;
|
||||
std::unique_lock<std::mutex> lock(mtxPermissionLists);
|
||||
lstPermissionLists.resize(lstPermissionLists.size() + 1);
|
||||
return lstPermissionLists.back();
|
||||
}
|
||||
|
||||
/// Thread specific permission tracker list (permission, lowest first and the count for each permission second).
|
||||
static thread_local std::list<std::pair<sdv::core::EAccessPermission, size_t>>& m_lstPermissionTracker;
|
||||
|
||||
/**
|
||||
* @brief Create a permission map object.
|
||||
* @return Reference to the created map object.
|
||||
*/
|
||||
static std::map<sdv::core::TPermissionID, CAccessPermission>& CreatePermissionMap()
|
||||
{
|
||||
static std::mutex mtxPermissionMaps;
|
||||
static std::list<std::map<sdv::core::TPermissionID, CAccessPermission>> lstPermissionMaps;
|
||||
std::unique_lock<std::mutex> lock(mtxPermissionMaps);
|
||||
lstPermissionMaps.resize(lstPermissionMaps.size() + 1);
|
||||
return lstPermissionMaps.back();
|
||||
}
|
||||
|
||||
/// Thread specific permission access map.
|
||||
static thread_local std::map<sdv::core::TPermissionID, CAccessPermission>& m_mapPermissions;
|
||||
#else
|
||||
/// Thread specific permission tracker list (permission, lowest first and the count for each permission second).
|
||||
static thread_local std::list<std::pair<sdv::core::EAccessPermission, size_t>> m_lstPermissionTracker;
|
||||
|
||||
/// Thread specific permission access map.
|
||||
static thread_local std::map<sdv::core::TPermissionID, CAccessPermission> m_mapPermissions;
|
||||
#endif
|
||||
|
||||
/// Permission transfer object map (allow shifting permission from one thread to another).
|
||||
std::map<sdv::core::TPermissionTransferID, sdv::core::EAccessPermission> m_mapPermissionTransfer;
|
||||
|
||||
std::mutex m_mtxPermissionTransfer; ///< Protecting the permission transfer map.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return the permission control.
|
||||
* @return Reference to the permission control.
|
||||
*/
|
||||
CPermissionControl& GetPermissionControl();
|
||||
|
||||
/**
|
||||
* @brief Permission control service
|
||||
*/
|
||||
class CPermissionControlService : public sdv::CSdvObject
|
||||
{
|
||||
public:
|
||||
CPermissionControlService() = default;
|
||||
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_CHAIN_MEMBER(GetPermissionControl())
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
// Object declarations
|
||||
DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::system_object)
|
||||
DECLARE_OBJECT_CLASS_NAME("PermissionControlService")
|
||||
DECLARE_OBJECT_SINGLETON()
|
||||
};
|
||||
|
||||
DEFINE_SDV_OBJECT(CPermissionControlService)
|
||||
|
||||
#endif // !defined PERMISSION_CONTROL_H
|
||||
@@ -16,12 +16,14 @@
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include "object_lifetime_control.h"
|
||||
#include "../../global/base64.h"
|
||||
#include "module_control.h"
|
||||
#include "app_config.h"
|
||||
#include "app_control.h"
|
||||
#include "app_settings.h"
|
||||
#include "permission_control.h"
|
||||
|
||||
// GetRepository might be redirected for unit tests.
|
||||
#ifndef GetRepository
|
||||
@@ -60,39 +62,154 @@ void CRepository::SetRunningMode()
|
||||
|
||||
sdv::IInterfaceAccess* CRepository::GetObject(const sdv::u8string& ssObjectName)
|
||||
{
|
||||
auto eAccessPermission = GetPermissionControl().GetCurrentPermission();
|
||||
if (eAccessPermission < sdv::core::EAccessPermission::remote_access)
|
||||
return nullptr;
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
auto itService = m_mapServiceObjects.find(ssObjectName);
|
||||
if (itService != m_mapServiceObjects.end()) return (*itService->second)->ptrObject;
|
||||
if (itService != m_mapServiceObjects.end())
|
||||
{
|
||||
// Check access permissions
|
||||
switch ((*itService->second)->sClassInfo.eType)
|
||||
{
|
||||
case sdv::EObjectType::complex_service:
|
||||
case sdv::EObjectType::vehicle_function:
|
||||
case sdv::EObjectType::basic_service:
|
||||
case sdv::EObjectType::sensor:
|
||||
case sdv::EObjectType::actuator:
|
||||
// Allowed for remote access or higher
|
||||
//if (eAccessPermission < sdv::core::EAccessPermission::remote_access)
|
||||
// return nullptr;
|
||||
break;
|
||||
case sdv::EObjectType::system_object:
|
||||
// Allowed for local access or higher
|
||||
if (eAccessPermission < sdv::core::EAccessPermission::local_access)
|
||||
return nullptr;
|
||||
break;
|
||||
default:
|
||||
// Allowed for full access only
|
||||
if (eAccessPermission != sdv::core::EAccessPermission::full_access)
|
||||
return nullptr;
|
||||
}
|
||||
return (*itService->second)->ptrObject;
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
// In case the object is not in the service map and this is a main or isolated application, create the object if the object is
|
||||
// known in the installation manifest and is a system object.
|
||||
// known in the installation manifest.
|
||||
auto optManifest = GetAppConfig().FindInstalledComponent(ssObjectName);
|
||||
if (optManifest && optManifest->eType == sdv::EObjectType::system_object)
|
||||
return GetObjectByID(CreateObject(optManifest->ssName, optManifest->ssDefaultObjectName, ""));
|
||||
if (optManifest)
|
||||
{
|
||||
// Check access permissions
|
||||
bool bAutoCreate = false;
|
||||
switch (optManifest->eType)
|
||||
{
|
||||
case sdv::EObjectType::complex_service:
|
||||
case sdv::EObjectType::vehicle_function:
|
||||
case sdv::EObjectType::basic_service:
|
||||
case sdv::EObjectType::sensor:
|
||||
case sdv::EObjectType::actuator:
|
||||
// Automatic component creation only for main application.
|
||||
if (!GetAppSettings().IsMainApplication()) break;
|
||||
bAutoCreate = true;
|
||||
|
||||
// Allowed for remote access or higher
|
||||
if (eAccessPermission < sdv::core::EAccessPermission::remote_access)
|
||||
return nullptr;
|
||||
break;
|
||||
case sdv::EObjectType::system_object:
|
||||
// Automatic component creation allowed for system objects. The objects themselves have to block in case of unwanted
|
||||
// access by external or isolated applications.
|
||||
bAutoCreate = true;
|
||||
|
||||
// Forward the request to core repository if one is linked here (this can only occur with isolated and external applications).
|
||||
if (!m_ptrCoreRepoAccess) return nullptr;
|
||||
sdv::core::IObjectAccess* pObjectAccess = m_ptrCoreRepoAccess.GetInterface<sdv::core::IObjectAccess>();
|
||||
if (!pObjectAccess) return nullptr;
|
||||
return pObjectAccess->GetObject(ssObjectName);
|
||||
// Allowed for local access or higher
|
||||
if (eAccessPermission < sdv::core::EAccessPermission::local_access)
|
||||
return nullptr;
|
||||
break;
|
||||
default:
|
||||
// Automatic component creation only for main application.
|
||||
if (!GetAppSettings().IsMainApplication())
|
||||
break;
|
||||
bAutoCreate = true;
|
||||
|
||||
// Allowed for full access only
|
||||
if (eAccessPermission != sdv::core::EAccessPermission::full_access)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create the object if automatic creation is enabled
|
||||
if (bAutoCreate)
|
||||
return GetObjectByID(CreateObject2(optManifest->ssName, optManifest->ssDefaultObjectName, "", true));
|
||||
}
|
||||
|
||||
// Copy the linked repository and then unlock; could cause a deadlock instead.
|
||||
lock.lock();
|
||||
auto lstCoreRepoAccessCopy = m_lstCoreRepoAccess;
|
||||
lock.unlock();
|
||||
|
||||
// If there is a linked core, use the core to get ther object
|
||||
for (auto& rprLink : lstCoreRepoAccessCopy)
|
||||
{
|
||||
sdv::core::IObjectAccess* pObjectAccess = rprLink.second.GetInterface<sdv::core::IObjectAccess>();
|
||||
if (!pObjectAccess) continue;
|
||||
auto* pObject = pObjectAccess->GetObject(ssObjectName);
|
||||
if (pObject) return pObject;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sdv::IInterfaceAccess* CRepository::GetObjectByID(/*in*/ sdv::core::TObjectID tObjectID)
|
||||
{
|
||||
auto eAccessPermission = GetPermissionControl().GetCurrentPermission();
|
||||
if (eAccessPermission < sdv::core::EAccessPermission::remote_access)
|
||||
return nullptr;
|
||||
|
||||
// Only controlled objects are allowed to be returned using GetObjectByID.
|
||||
std::shared_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
auto itObject = m_mapObjects.find(tObjectID);
|
||||
if (itObject != m_mapObjects.end())
|
||||
return itObject->second->bControlled ? itObject->second->ptrObject : nullptr;
|
||||
{
|
||||
// Check access permissions
|
||||
switch (itObject->second->sClassInfo.eType)
|
||||
{
|
||||
case sdv::EObjectType::complex_service:
|
||||
case sdv::EObjectType::vehicle_function:
|
||||
case sdv::EObjectType::basic_service:
|
||||
case sdv::EObjectType::sensor:
|
||||
case sdv::EObjectType::actuator:
|
||||
//// Allowed for remote access or higher
|
||||
//if (eAccessPermission < sdv::core::EAccessPermission::remote_access)
|
||||
// return nullptr;
|
||||
break;
|
||||
case sdv::EObjectType::system_object:
|
||||
// Allowed for local access or higher
|
||||
if (eAccessPermission < sdv::core::EAccessPermission::local_access)
|
||||
return nullptr;
|
||||
break;
|
||||
default:
|
||||
// Allowed for full access only
|
||||
if (eAccessPermission != sdv::core::EAccessPermission::full_access)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return itObject->second->bControlled ? itObject->second->ptrObject : nullptr;
|
||||
}
|
||||
// TODO: Deal with overlapping IDs in this and in core process...
|
||||
|
||||
// Forward the request to core repository if one is linked here (this can only occur with isolated and external applications).
|
||||
if (!m_ptrCoreRepoAccess) return nullptr;
|
||||
sdv::core::IObjectAccess* pObjectAccess = m_ptrCoreRepoAccess.GetInterface<sdv::core::IObjectAccess>();
|
||||
if (!pObjectAccess) return nullptr;
|
||||
return pObjectAccess->GetObjectByID(tObjectID);
|
||||
// Copy the linked repository and then unlock; could cause a deadlock instead.
|
||||
auto lstCoreRepoAccessCopy = m_lstCoreRepoAccess;
|
||||
lock.unlock();
|
||||
|
||||
// If there is a linked core, use the core to get ther object
|
||||
for (auto& rprLink : lstCoreRepoAccessCopy)
|
||||
{
|
||||
sdv::core::IObjectAccess* pObjectAccess = rprLink.second.GetInterface<sdv::core::IObjectAccess>();
|
||||
if (!pObjectAccess) continue;
|
||||
auto* pObject = pObjectAccess->GetObjectByID(tObjectID);
|
||||
if (pObject) return pObject;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sdv::IInterfaceAccess* CRepository::CreateUtility(/*in*/ const sdv::u8string& ssClassName, /*in*/ const sdv::u8string& ssObjectConfig)
|
||||
@@ -101,6 +218,11 @@ sdv::IInterfaceAccess* CRepository::CreateUtility(/*in*/ const sdv::u8string& ss
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
|
||||
// TODO EVE: Currently only allowed for local access. When utilities are instantiated using isolation, also allowed for remote
|
||||
// access.
|
||||
if (GetPermissionControl().GetCurrentPermission() < sdv::core::EAccessPermission::local_access)
|
||||
return nullptr;
|
||||
|
||||
// Get a fitting module instance
|
||||
std::shared_ptr<CModuleInst> ptrModule = GetModuleControl().FindModuleByClass(ssClassName);
|
||||
if (!ptrModule)
|
||||
@@ -161,7 +283,7 @@ sdv::IInterfaceAccess* CRepository::CreateUtility(/*in*/ const sdv::u8string& ss
|
||||
auto* pObjectControl = ptrObject.GetInterface<sdv::IObjectControl>();
|
||||
if (pObjectControl)
|
||||
{
|
||||
pObjectControl->Initialize(ssObjectConfig);
|
||||
pObjectControl->Initialize(*ptrObjectEntry);
|
||||
if (pObjectControl->GetObjectState() != sdv::EObjectState::initialized)
|
||||
{
|
||||
// Destroy the object
|
||||
@@ -193,22 +315,23 @@ sdv::IInterfaceAccess* CRepository::CreateProxyObject(/*in*/ sdv::interface_id i
|
||||
// Get a fitting module instance
|
||||
std::string ssClassName = "Proxy_" + std::to_string(id);
|
||||
std::shared_ptr<CModuleInst> ptrModule = GetModuleControl().FindModuleByClass(ssClassName);
|
||||
if (!ptrModule && m_ptrCoreRepoAccess)
|
||||
{
|
||||
// Request the server for the name of the module.
|
||||
const sdv::core::IRepositoryInfo* pRepInfo = m_ptrCoreRepoAccess.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
if (pRepInfo)
|
||||
{
|
||||
std::string ssModuleName =
|
||||
std::filesystem::u8path(static_cast<std::string>(pRepInfo->FindClass(ssClassName).ssModulePath)).
|
||||
filename().u8string();
|
||||
if (!ssModuleName.empty())
|
||||
{
|
||||
sdv::core::TModuleID tModule = GetModuleControl().Load(ssModuleName);
|
||||
if (tModule) ptrModule = GetModuleControl().GetModule(tModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO EVE
|
||||
//if (!ptrModule && m_ptrCoreRepoAccess)
|
||||
//{
|
||||
// // Request the server for the name of the module.
|
||||
// const sdv::core::IRepositoryInfo* pRepInfo = m_ptrCoreRepoAccess.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
// if (pRepInfo)
|
||||
// {
|
||||
// std::string ssModuleName =
|
||||
// std::filesystem::u8path(static_cast<std::string>(pRepInfo->FindClass(ssClassName).ssModulePath)).
|
||||
// filename().u8string();
|
||||
// if (!ssModuleName.empty())
|
||||
// {
|
||||
// sdv::core::TModuleID tModule = GetModuleControl().Load(ssModuleName);
|
||||
// if (tModule) ptrModule = GetModuleControl().GetModule(tModule);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
if (!ptrModule)
|
||||
{
|
||||
SDV_LOG_ERROR("Object creation requested but object class was not found \"", ssClassName, "\"!");
|
||||
@@ -270,7 +393,7 @@ sdv::IInterfaceAccess* CRepository::CreateProxyObject(/*in*/ sdv::interface_id i
|
||||
auto* pObjectControl = ptrObject.GetInterface<sdv::IObjectControl>();
|
||||
if (pObjectControl)
|
||||
{
|
||||
pObjectControl->Initialize("");
|
||||
pObjectControl->Initialize(*ptrObjectEntry);
|
||||
if (pObjectControl->GetObjectState() != sdv::EObjectState::initialized)
|
||||
{
|
||||
// Destroy the object
|
||||
@@ -302,22 +425,23 @@ sdv::IInterfaceAccess* CRepository::CreateStubObject(/*in*/ sdv::interface_id id
|
||||
// Get a fitting module instance
|
||||
std::string ssClassName = "Stub_" + std::to_string(id);
|
||||
std::shared_ptr<CModuleInst> ptrModule = GetModuleControl().FindModuleByClass(ssClassName);
|
||||
if (!ptrModule && m_ptrCoreRepoAccess)
|
||||
{
|
||||
// Request the server for the name of the module.
|
||||
const sdv::core::IRepositoryInfo* pRepInfo = m_ptrCoreRepoAccess.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
if (pRepInfo)
|
||||
{
|
||||
std::string ssModuleName =
|
||||
std::filesystem::u8path(static_cast<std::string>(pRepInfo->FindClass(ssClassName).ssModulePath)).
|
||||
filename().u8string();
|
||||
if (!ssModuleName.empty())
|
||||
{
|
||||
sdv::core::TModuleID tModule = GetModuleControl().Load(ssModuleName);
|
||||
if (tModule) ptrModule = GetModuleControl().GetModule(tModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO EVE
|
||||
//if (!ptrModule && m_ptrCoreRepoAccess)
|
||||
//{
|
||||
// // Request the server for the name of the module.
|
||||
// const sdv::core::IRepositoryInfo* pRepInfo = m_ptrCoreRepoAccess.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
// if (pRepInfo)
|
||||
// {
|
||||
// std::string ssModuleName =
|
||||
// std::filesystem::u8path(static_cast<std::string>(pRepInfo->FindClass(ssClassName).ssModulePath)).
|
||||
// filename().u8string();
|
||||
// if (!ssModuleName.empty())
|
||||
// {
|
||||
// sdv::core::TModuleID tModule = GetModuleControl().Load(ssModuleName);
|
||||
// if (tModule) ptrModule = GetModuleControl().GetModule(tModule);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
if (!ptrModule)
|
||||
{
|
||||
SDV_LOG_ERROR("Object creation requested but object class was not found \"", ssClassName, "\"!");
|
||||
@@ -378,7 +502,7 @@ sdv::IInterfaceAccess* CRepository::CreateStubObject(/*in*/ sdv::interface_id id
|
||||
auto* pObjectControl = ptrObject.GetInterface<sdv::IObjectControl>();
|
||||
if (pObjectControl)
|
||||
{
|
||||
pObjectControl->Initialize("");
|
||||
pObjectControl->Initialize(*ptrObjectEntry);
|
||||
if (pObjectControl->GetObjectState() != sdv::EObjectState::initialized)
|
||||
{
|
||||
// Destroy the object
|
||||
@@ -414,11 +538,11 @@ sdv::core::TObjectID CRepository::CreateObject(const sdv::u8string& ssClassName,
|
||||
|
||||
Build dependency list and do these checks on dependent objects as well
|
||||
*/
|
||||
return CreateObject2(ssClassName, ssObjectName, ssObjectConfig);
|
||||
return CreateObject2(ssClassName, ssObjectName, ssObjectConfig, false);
|
||||
}
|
||||
|
||||
sdv::core::TObjectID CRepository::CreateObject2(const sdv::u8string& ssClassName, const sdv::u8string& ssObjectName,
|
||||
const sdv::u8string& ssObjectConfig)
|
||||
const sdv::u8string& ssObjectConfig, bool bIndirect)
|
||||
{
|
||||
// TODO EVE: Link to core repo. Allow only creation of one object if not already created before...
|
||||
// Add support for automatic app control shutdown when utility is closed in case of isolated app.
|
||||
@@ -457,21 +581,29 @@ sdv::core::TObjectID CRepository::CreateObject2(const sdv::u8string& ssClassName
|
||||
switch (optClassInfo->eType)
|
||||
{
|
||||
case sdv::EObjectType::system_object:
|
||||
// Only allowed with full access
|
||||
bError = !bIndirect && (GetPermissionControl().GetCurrentPermission() < sdv::core::EAccessPermission::full_access);
|
||||
break;
|
||||
case sdv::EObjectType::device:
|
||||
case sdv::EObjectType::platform_abstraction:
|
||||
case sdv::EObjectType::vehicle_bus:
|
||||
bError = !bDeviceAndBasicServiceAllowed;
|
||||
// Only allowed with full access
|
||||
bError = !bIndirect && (GetPermissionControl().GetCurrentPermission() < sdv::core::EAccessPermission::full_access);
|
||||
bError |= !bDeviceAndBasicServiceAllowed;
|
||||
break;
|
||||
case sdv::EObjectType::basic_service:
|
||||
case sdv::EObjectType::sensor:
|
||||
case sdv::EObjectType::actuator:
|
||||
bError = !bDeviceAndBasicServiceAllowed;
|
||||
// Only allowed with full access
|
||||
bError = !bIndirect && (GetPermissionControl().GetCurrentPermission() < sdv::core::EAccessPermission::full_access);
|
||||
bError |= !bDeviceAndBasicServiceAllowed;
|
||||
break;
|
||||
case sdv::EObjectType::complex_service:
|
||||
case sdv::EObjectType::vehicle_function:
|
||||
// Only allowed with local access
|
||||
bError = !bIndirect && (GetPermissionControl().GetCurrentPermission() < sdv::core::EAccessPermission::local_access);
|
||||
bIsolate = GetAppSettings().IsMainApplication();
|
||||
bError = !bComplexServiceAllowed;
|
||||
bError |= !bComplexServiceAllowed;
|
||||
m_bIsoObjectLoaded = true;
|
||||
break;
|
||||
default:
|
||||
@@ -498,8 +630,11 @@ sdv::core::TObjectID CRepository::CreateObject2(const sdv::u8string& ssClassName
|
||||
auto itPreviousService = m_mapServiceObjects.find(ssObjectName2);
|
||||
if (itPreviousService != m_mapServiceObjects.end())
|
||||
{
|
||||
// Get the service pointer
|
||||
std::shared_ptr<SObjectEntry> ptrService = *itPreviousService->second;
|
||||
|
||||
// Object entry is valid?
|
||||
if (!*itPreviousService->second)
|
||||
if (!ptrService)
|
||||
{
|
||||
// This should not occur... there is a previous object in the service map, but the object is empty.
|
||||
SDV_LOG_ERROR("Object creation requested for class \"", ssClassName, "\", but object with the same name \"",
|
||||
@@ -508,12 +643,15 @@ sdv::core::TObjectID CRepository::CreateObject2(const sdv::u8string& ssClassName
|
||||
}
|
||||
|
||||
// Trying to create an object with the same name is not an error if the classes are identical.
|
||||
if ((*itPreviousService->second)->sClassInfo.ssName == ssClassName)
|
||||
return (*itPreviousService->second)->tObjectID;
|
||||
const auto& rsClassInfo = ptrService->sClassInfo;
|
||||
if (rsClassInfo.ssName == ssClassName ||
|
||||
std::find(rsClassInfo.seqClassAliases.begin(), rsClassInfo.seqClassAliases.end(), ssClassName) !=
|
||||
rsClassInfo.seqClassAliases.end())
|
||||
return ptrService->tObjectID;
|
||||
|
||||
// Object name was already used by another class. This is an error.
|
||||
SDV_LOG_ERROR("Object creation requested for class \"", ssClassName, "\", but object with the same name \"",
|
||||
ssObjectName2, "\" was already instantiated for class \"", (*itPreviousService->second)->sClassInfo.ssName,
|
||||
ssObjectName2, "\" was already instantiated for class \"", rsClassInfo.ssName,
|
||||
"\"!");
|
||||
return 0;
|
||||
}
|
||||
@@ -549,14 +687,18 @@ sdv::core::TObjectID CRepository::CreateObject2(const sdv::u8string& ssClassName
|
||||
sdv::core::TObjectID CRepository::CreateObjectFromModule(/*in*/ sdv::core::TModuleID tModuleID,
|
||||
/*in*/ const sdv::u8string& ssClassName, /*in*/ const sdv::u8string& ssObjectName, /*in*/ const sdv::u8string& ssObjectConfig)
|
||||
{
|
||||
if(ssClassName.empty()) return false;
|
||||
if(ssClassName.empty()) return 0u;
|
||||
|
||||
// Only allowed with full access
|
||||
if (GetPermissionControl().GetCurrentPermission() != sdv::core::EAccessPermission::full_access)
|
||||
return 0u;
|
||||
|
||||
// Get a fitting module instance
|
||||
std::shared_ptr<CModuleInst> ptrModule = GetModuleControl().GetModule(tModuleID);
|
||||
if (!ptrModule)
|
||||
{
|
||||
SDV_LOG_ERROR("Object creation requested but object class was not found \"", ssClassName, "\"!");
|
||||
return false;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
// Check the class type
|
||||
@@ -564,7 +706,7 @@ sdv::core::TObjectID CRepository::CreateObjectFromModule(/*in*/ sdv::core::TModu
|
||||
if (!optClassInfo)
|
||||
{
|
||||
SDV_LOG_ERROR("Object creation requested but object class was not found \"", ssClassName, "\"!");
|
||||
return false;
|
||||
return 0u;
|
||||
}
|
||||
bool bError = false;
|
||||
bool bDeviceAndBasicServiceAllowed = GetAppSettings().IsMainApplication() || GetAppSettings().IsStandaloneApplication() ||
|
||||
@@ -602,7 +744,7 @@ sdv::core::TObjectID CRepository::CreateObjectFromModule(/*in*/ sdv::core::TModu
|
||||
// Utilities and marshall objects cannot be created using the CreateObject function.
|
||||
SDV_LOG_ERROR("Creation of an object of invalid type \"", sdv::ObjectType2String(optClassInfo->eType),
|
||||
"\" requested for class \"", ssClassName, "\"!");
|
||||
return 0;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
// Check for an object name. If not existing get the default name (being either one specified by the object or the class name).
|
||||
@@ -626,7 +768,7 @@ sdv::core::TObjectID CRepository::CreateObjectFromModule(/*in*/ sdv::core::TModu
|
||||
"\", but object with the same name \"",
|
||||
ssObjectName2,
|
||||
"\" was already instantiated, but cannot be found!");
|
||||
return 0;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
// Trying to create an object with the same name is not an error if the classes are identical.
|
||||
@@ -641,7 +783,7 @@ sdv::core::TObjectID CRepository::CreateObjectFromModule(/*in*/ sdv::core::TModu
|
||||
"\" was already instantiated for class \"",
|
||||
(*itPreviousService->second)->sClassInfo.ssName,
|
||||
"\"!");
|
||||
return 0;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
// Check with singleton objects if the object was already instantiated.
|
||||
@@ -657,7 +799,7 @@ sdv::core::TObjectID CRepository::CreateObjectFromModule(/*in*/ sdv::core::TModu
|
||||
SDV_LOG_ERROR("Object creation requested but object from the same class \"",
|
||||
ssClassName,
|
||||
"\" was already instantiated and only one instance is allowed!");
|
||||
return 0;
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -671,17 +813,41 @@ sdv::core::TObjectID CRepository::CreateObjectFromModule(/*in*/ sdv::core::TModu
|
||||
|
||||
bool CRepository::DestroyObject(/*in*/ const sdv::u8string& ssObjectName)
|
||||
{
|
||||
return DestroyObject2(ssObjectName);
|
||||
TDeferredObjectDestructionList lstDeferredObjectDestruction;
|
||||
bool bRes = DestroyObject2(ssObjectName, false, lstDeferredObjectDestruction);
|
||||
for (auto& rprObject : lstDeferredObjectDestruction)
|
||||
rprObject.first->ptrModule->DestroyObject(rprObject.second);
|
||||
return bRes;
|
||||
}
|
||||
|
||||
bool CRepository::DestroyObject2(/*in*/ const sdv::u8string& ssObjectName)
|
||||
bool CRepository::DestroyObject2(const sdv::u8string& ssObjectName, bool bIndirect,
|
||||
TDeferredObjectDestructionList& rlstDeferredObjectDestruction)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
auto itService = m_mapServiceObjects.find(ssObjectName);
|
||||
if (itService == m_mapServiceObjects.end()) return false;
|
||||
auto ptrObjectEntry = *itService->second;
|
||||
|
||||
// When directly called, check the access permissions
|
||||
if (!bIndirect)
|
||||
{
|
||||
switch (ptrObjectEntry->sClassInfo.eType)
|
||||
{
|
||||
case sdv::EObjectType::complex_service:
|
||||
case sdv::EObjectType::vehicle_function:
|
||||
// Only allowed having local or higher access permission
|
||||
if (GetPermissionControl().GetCurrentPermission() < sdv::core::EAccessPermission::local_access)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
// Only allowed having full access permission
|
||||
if (GetPermissionControl().GetCurrentPermission() != sdv::core::EAccessPermission::full_access)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Print info
|
||||
auto ptrObjectEntry = *itService->second;
|
||||
if (GetAppSettings().IsConsoleVerbose())
|
||||
std::cout << "Destroy a " << sdv::ObjectType2String(ptrObjectEntry->sClassInfo.eType) << " #" << ptrObjectEntry->tObjectID <<
|
||||
" of type " << ptrObjectEntry->sClassInfo.ssName << " with the name " << ssObjectName << std::endl;
|
||||
@@ -717,13 +883,25 @@ bool CRepository::DestroyObject2(/*in*/ const sdv::u8string& ssObjectName)
|
||||
lock.unlock();
|
||||
|
||||
// Only controlled objects can be destroyed this way.
|
||||
if (ptrDependingObject->bControlled) DestroyObject(ptrDependingObject->ssName);
|
||||
if (ptrDependingObject->bControlled) DestroyObject2(ptrDependingObject->ssName, false, rlstDeferredObjectDestruction);
|
||||
}
|
||||
};
|
||||
|
||||
// Static dependance from object class
|
||||
fnDestroyDependingObjects(GetDependingObjectInstancesByClass(ptrObjectEntry->sClassInfo.ssName));
|
||||
if (ptrObjectEntry->sClassInfo.ssName != ptrObjectEntry->sClassInfo.ssDefaultObjectName)
|
||||
fnDestroyDependingObjects(GetDependingObjectInstancesByClass(ptrObjectEntry->sClassInfo.ssDefaultObjectName));
|
||||
|
||||
// Dynamic dependance from object entry
|
||||
std::vector<sdv::core::TObjectID> vecDependingObjects;
|
||||
for (const std::string& rssDependingObject : ptrObjectEntry->setDependentObjects)
|
||||
{
|
||||
auto itObject = m_mapServiceObjects.find(rssDependingObject);
|
||||
if (itObject != m_mapServiceObjects.end())
|
||||
vecDependingObjects.push_back((*itObject->second)->tObjectID);
|
||||
}
|
||||
fnDestroyDependingObjects(vecDependingObjects);
|
||||
|
||||
// Shutdown the object (not all objects expose IObjectControl).
|
||||
auto* pObjectControl = ptrObjectEntry->ptrObject.GetInterface<sdv::IObjectControl>();
|
||||
if (pObjectControl && pObjectControl->GetObjectState() != sdv::EObjectState::destruction_pending)
|
||||
@@ -735,7 +913,8 @@ bool CRepository::DestroyObject2(/*in*/ const sdv::u8string& ssObjectName)
|
||||
sdv::IInterfaceAccess* pObject = ptrObjectEntry->ptrObject;
|
||||
if (ptrObjectEntry->ptrIsoMon)
|
||||
pObject = ptrObjectEntry->ptrIsoMon->GetContainedObject();
|
||||
ptrObjectEntry->ptrModule->DestroyObject(pObject);
|
||||
rlstDeferredObjectDestruction.push_back(std::make_pair(ptrObjectEntry, pObject));
|
||||
//ptrObjectEntry->ptrModule->DestroyObject(pObject);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -805,15 +984,22 @@ sdv::core::TObjectID CRepository::RegisterObject(IInterfaceAccess* pObjectIfc, c
|
||||
return tObjectID;
|
||||
}
|
||||
|
||||
void CRepository::LinkCoreRepository(/*in*/ sdv::IInterfaceAccess* pCoreRepository)
|
||||
sdv::core::TLinkID CRepository::LinkCoreRepository(/*in*/ sdv::IInterfaceAccess* pCoreRepository)
|
||||
{
|
||||
if (!pCoreRepository) return;
|
||||
m_ptrCoreRepoAccess = pCoreRepository;
|
||||
if (!pCoreRepository) return 0;
|
||||
std::unique_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
sdv::core::TLinkID tLinkID = CreateObjectID();
|
||||
m_lstCoreRepoAccess.push_back(std::make_pair(tLinkID, pCoreRepository));
|
||||
return tLinkID;
|
||||
}
|
||||
|
||||
void CRepository::UnlinkCoreRepository()
|
||||
void CRepository::UnlinkCoreRepository(sdv::core::TLinkID tLinkID)
|
||||
{
|
||||
m_ptrCoreRepoAccess = nullptr;
|
||||
std::unique_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
auto itLink = std::find_if(
|
||||
m_lstCoreRepoAccess.begin(), m_lstCoreRepoAccess.end(), [&](const auto rprLink)
|
||||
{ return rprLink.first == tLinkID; });
|
||||
m_lstCoreRepoAccess.erase(itLink);
|
||||
}
|
||||
|
||||
sdv::SClassInfo CRepository::FindClass(/*in*/ const sdv::u8string& ssClassName) const
|
||||
@@ -824,16 +1010,34 @@ sdv::SClassInfo CRepository::FindClass(/*in*/ const sdv::u8string& ssClassName)
|
||||
if (GetAppSettings().IsMainApplication() || GetAppSettings().IsIsolatedApplication())
|
||||
{
|
||||
auto optManifest = GetAppConfig().FindInstalledComponent(ssClassName);
|
||||
if (!optManifest) return {};
|
||||
return *optManifest;
|
||||
if (optManifest)
|
||||
return *optManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the information through the module.
|
||||
auto ptrModule = GetModuleControl().FindModuleByClass(ssClassName);
|
||||
if (ptrModule)
|
||||
{
|
||||
auto optClassInfo = ptrModule->GetClassInfo(ssClassName);
|
||||
if (optClassInfo) return *optClassInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the information through the module.
|
||||
auto ptrModule = GetModuleControl().FindModuleByClass(ssClassName);
|
||||
if (!ptrModule) return {};
|
||||
auto optClassInfo = ptrModule->GetClassInfo(ssClassName);
|
||||
if (!optClassInfo) return {};
|
||||
return *optClassInfo;
|
||||
// Copy the linked repository and then unlock; could cause a deadlock instead.
|
||||
auto lstCoreRepoAccessCopy = m_lstCoreRepoAccess;
|
||||
lock.unlock();
|
||||
|
||||
// If there is a linked core, use the core to get class list
|
||||
for (auto& rprLink : lstCoreRepoAccessCopy)
|
||||
{
|
||||
const sdv::core::IRepositoryInfo* pCoreRepoInfo = rprLink.second.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
sdv::SClassInfo sInfo = pCoreRepoInfo->FindClass(ssClassName);
|
||||
if (!sInfo.ssName.empty()) return sInfo;
|
||||
}
|
||||
|
||||
// Nothing found
|
||||
return {};
|
||||
}
|
||||
|
||||
sdv::sequence<sdv::core::SObjectInfo> CRepository::GetObjectList() const
|
||||
@@ -841,13 +1045,6 @@ sdv::sequence<sdv::core::SObjectInfo> CRepository::GetObjectList() const
|
||||
std::shared_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
sdv::sequence<sdv::core::SObjectInfo> seqObjects;
|
||||
|
||||
// If there is a linked core, use the core to get object list
|
||||
if (m_ptrCoreRepoAccess)
|
||||
{
|
||||
const sdv::core::IRepositoryInfo* pCoreRepoInfo = m_ptrCoreRepoAccess.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
return pCoreRepoInfo ? pCoreRepoInfo->GetObjectList() : seqObjects;
|
||||
}
|
||||
|
||||
// Add object function
|
||||
auto fnAddObject = [&seqObjects](const std::shared_ptr<SObjectEntry>& rptrObjectEntry)
|
||||
{
|
||||
@@ -878,6 +1075,21 @@ sdv::sequence<sdv::core::SObjectInfo> CRepository::GetObjectList() const
|
||||
for (const auto& prLocalObject : m_mapLocalObjects)
|
||||
fnAddObject(prLocalObject.second);
|
||||
|
||||
// Copy the linked repository and then unlock; could cause a deadlock instead.
|
||||
auto lstCoreRepoAccessCopy = m_lstCoreRepoAccess;
|
||||
lock.unlock();
|
||||
|
||||
// If there is a linked core, use the core to get object list
|
||||
for (auto& rprLink : lstCoreRepoAccessCopy)
|
||||
{
|
||||
const sdv::core::IRepositoryInfo* pCoreRepoInfo = rprLink.second.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
if (pCoreRepoInfo)
|
||||
{
|
||||
auto seqListRemote = pCoreRepoInfo->GetObjectList();
|
||||
seqObjects.insert(seqObjects.end(), seqListRemote.begin(), seqListRemote.end());
|
||||
}
|
||||
}
|
||||
|
||||
return seqObjects;
|
||||
}
|
||||
|
||||
@@ -885,54 +1097,78 @@ sdv::core::SObjectInfo CRepository::GetObjectInfo(/*in*/ sdv::core::TObjectID tO
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
|
||||
// If there is a linked core, use the core to get object info
|
||||
if (m_ptrCoreRepoAccess)
|
||||
// Use the internal object map for this.
|
||||
sdv::core::SObjectInfo sInfo{};
|
||||
auto itObject = m_mapObjects.find(tObjectID);
|
||||
if (itObject != m_mapObjects.end())
|
||||
{
|
||||
const sdv::core::IRepositoryInfo* pCoreRepoInfo = m_ptrCoreRepoAccess.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
return pCoreRepoInfo ? pCoreRepoInfo->GetObjectInfo(tObjectID) : sdv::core::SObjectInfo{};
|
||||
if (!itObject->second) return {};
|
||||
|
||||
// Fill in information
|
||||
sInfo.tObjectID = itObject->second->tObjectID;
|
||||
sInfo.tModuleID = itObject->second->ptrModule ? itObject->second->ptrModule->GetModuleID() : 0;
|
||||
sInfo.sClassInfo = itObject->second->sClassInfo;
|
||||
sInfo.ssObjectName = itObject->second->ssName;
|
||||
sInfo.ssObjectConfig = itObject->second->ssConfig;
|
||||
sInfo.uiFlags = 0;
|
||||
if (itObject->second->bControlled)
|
||||
sInfo.uiFlags |= static_cast<uint32_t>(sdv::core::EObjectInfoFlags::object_controlled);
|
||||
if (!itObject->second->ptrModule)
|
||||
sInfo.uiFlags |= static_cast<uint32_t>(sdv::core::EObjectInfoFlags::object_foreign);
|
||||
if (!itObject->second->bIsolated)
|
||||
sInfo.uiFlags |= static_cast<uint32_t>(sdv::core::EObjectInfoFlags::object_isolated);
|
||||
|
||||
return sInfo;
|
||||
}
|
||||
|
||||
// Use the internal object map for this.
|
||||
auto itObject = m_mapObjects.find(tObjectID);
|
||||
if (itObject == m_mapObjects.end()) return {};
|
||||
if (!itObject->second) return {};
|
||||
// Copy the linked repository and then unlock; could cause a deadlock instead.
|
||||
auto lstCoreRepoAccessCopy = m_lstCoreRepoAccess;
|
||||
lock.unlock();
|
||||
|
||||
// Fill in information
|
||||
sdv::core::SObjectInfo sInfo{};
|
||||
sInfo.tObjectID = itObject->second->tObjectID;
|
||||
sInfo.tModuleID = itObject->second->ptrModule ? itObject->second->ptrModule->GetModuleID() : 0;
|
||||
sInfo.sClassInfo = itObject->second->sClassInfo;
|
||||
sInfo.ssObjectName = itObject->second->ssName;
|
||||
sInfo.ssObjectConfig = itObject->second->ssConfig;
|
||||
sInfo.uiFlags = 0;
|
||||
if (itObject->second->bControlled)
|
||||
sInfo.uiFlags |= static_cast<uint32_t>(sdv::core::EObjectInfoFlags::object_controlled);
|
||||
if (!itObject->second->ptrModule)
|
||||
sInfo.uiFlags |= static_cast<uint32_t>(sdv::core::EObjectInfoFlags::object_foreign);
|
||||
if (!itObject->second->bIsolated)
|
||||
sInfo.uiFlags |= static_cast<uint32_t>(sdv::core::EObjectInfoFlags::object_isolated);
|
||||
// If there is a linked core, use the core to get object info
|
||||
for (auto& rprLink : lstCoreRepoAccessCopy)
|
||||
{
|
||||
const sdv::core::IRepositoryInfo* pCoreRepoInfo = rprLink.second.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
if (pCoreRepoInfo)
|
||||
{
|
||||
sInfo = pCoreRepoInfo->GetObjectInfo(tObjectID);
|
||||
if (sInfo.tObjectID == tObjectID) return sInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return sInfo;
|
||||
// Info not found
|
||||
return {};
|
||||
}
|
||||
|
||||
sdv::core::SObjectInfo CRepository::FindObject(/*in*/ const sdv::u8string& ssObjectName) const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
|
||||
// If there is a linked core, use the core to get object info
|
||||
if (m_ptrCoreRepoAccess)
|
||||
{
|
||||
const sdv::core::IRepositoryInfo* pCoreRepoInfo = m_ptrCoreRepoAccess.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
return pCoreRepoInfo ? pCoreRepoInfo->FindObject(ssObjectName) : sdv::core::SObjectInfo{};
|
||||
}
|
||||
|
||||
// Use internal service map for this.
|
||||
auto itService = m_mapServiceObjects.find(ssObjectName);
|
||||
if (itService == m_mapServiceObjects.end()) return {};
|
||||
auto ptrObjectEntry = *itService->second;
|
||||
if (!ptrObjectEntry) return {};
|
||||
if (itService != m_mapServiceObjects.end())
|
||||
{
|
||||
auto ptrObjectEntry = *itService->second;
|
||||
if (!ptrObjectEntry) return {};
|
||||
return GetObjectInfo(ptrObjectEntry->tObjectID);
|
||||
}
|
||||
|
||||
// Copy the linked repository and then unlock; could cause a deadlock instead.
|
||||
auto lstCoreRepoAccessCopy = m_lstCoreRepoAccess;
|
||||
lock.unlock();
|
||||
return GetObjectInfo(ptrObjectEntry->tObjectID);
|
||||
|
||||
// If there is a linked core, use the core to get object info
|
||||
for (auto& rprLink : lstCoreRepoAccessCopy)
|
||||
{
|
||||
const sdv::core::IRepositoryInfo* pCoreRepoInfo = rprLink.second.GetInterface<sdv::core::IRepositoryInfo>();
|
||||
if (pCoreRepoInfo)
|
||||
{
|
||||
sdv::core::SObjectInfo sInfo = pCoreRepoInfo->FindObject(ssObjectName);
|
||||
if (sInfo.tObjectID) return sInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void CRepository::OnDestroyObject(sdv::IInterfaceAccess* pObject)
|
||||
@@ -998,9 +1234,10 @@ void CRepository::DestroyAllObjects(const std::vector<std::string>& rvecIgnoreOb
|
||||
lock.unlock();
|
||||
|
||||
// Destroy the objects in reverse order
|
||||
TDeferredObjectDestructionList lstDeferredObjectDestruction;
|
||||
while (lstCopy.size())
|
||||
{
|
||||
std::string ssObjectName = lstCopy.back() ? lstCopy.back()->ssName : std::string{};
|
||||
sdv::u8string ssObjectName = lstCopy.back() ? lstCopy.back()->ssName : sdv::u8string{};
|
||||
lstCopy.pop_back();
|
||||
if (ssObjectName.empty()) continue;
|
||||
|
||||
@@ -1009,7 +1246,7 @@ void CRepository::DestroyAllObjects(const std::vector<std::string>& rvecIgnoreOb
|
||||
continue;
|
||||
|
||||
// Destroy the object... -> call the repository function to remove it from the list.
|
||||
DestroyObject(ssObjectName);
|
||||
DestroyObject2(ssObjectName, true, lstDeferredObjectDestruction);
|
||||
|
||||
// Needs force!
|
||||
if (bForce)
|
||||
@@ -1038,6 +1275,34 @@ void CRepository::DestroyAllObjects(const std::vector<std::string>& rvecIgnoreOb
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
for (auto& rprObject : lstDeferredObjectDestruction)
|
||||
rprObject.first->ptrModule->DestroyObject(rprObject.second);
|
||||
}
|
||||
|
||||
void CRepository::AddObjectDependency(/*in*/ const sdv::u8string& ssObjectName, /*in*/ const sdv::u8string& ssDependsOnObject)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
auto itService = m_mapServiceObjects.find(ssDependsOnObject);
|
||||
if (itService != m_mapServiceObjects.end())
|
||||
{
|
||||
auto ptrObjectEntry = *itService->second;
|
||||
if (!ptrObjectEntry) return;
|
||||
auto itDependsOn = ptrObjectEntry->setDependentObjects.find(ssObjectName);
|
||||
if (itDependsOn == ptrObjectEntry->setDependentObjects.end())
|
||||
ptrObjectEntry->setDependentObjects.insert(ssObjectName);
|
||||
}
|
||||
}
|
||||
|
||||
void CRepository::RemoveObjectDependency(/*in*/ const sdv::u8string& ssObjectName, /*in*/ const sdv::u8string& ssDependsOnObject)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(m_mtxObjects);
|
||||
auto itService = m_mapServiceObjects.find(ssDependsOnObject);
|
||||
if (itService != m_mapServiceObjects.end())
|
||||
{
|
||||
auto ptrObjectEntry = *itService->second;
|
||||
if (!ptrObjectEntry) return;
|
||||
ptrObjectEntry->setDependentObjects.erase(ssObjectName);
|
||||
}
|
||||
}
|
||||
|
||||
void CRepository::ResetConfigBaseline()
|
||||
@@ -1100,8 +1365,9 @@ sdv::core::EConfigProcessResult CRepository::StartFromConfig(const CAppConfigFil
|
||||
// Destroy the objects when an error occurred during loading.
|
||||
if (!bAllowPartialLoad && nFail)
|
||||
{
|
||||
TDeferredObjectDestructionList lstDeferredObjectDestruction;
|
||||
for (const std::string& rssName : vecLoadedObjects)
|
||||
DestroyObject(rssName);
|
||||
DestroyObject2(rssName, true, lstDeferredObjectDestruction);
|
||||
return sdv::core::EConfigProcessResult::failed;
|
||||
}
|
||||
|
||||
@@ -1185,11 +1451,14 @@ sdv::core::TObjectID CRepository::CreateIsolatedObject(const sdv::SClassInfo& rs
|
||||
sdv::TInterfaceAccessPtr(GetObject("CommunicationControl")).GetInterface<sdv::com::IConnectionControl>();
|
||||
if (!pConnectionControl) return 0;
|
||||
sdv::u8string ssConnectionString;
|
||||
std::optional<CAccessPermission> optPermissionObject =
|
||||
GetPermissionControl().CreatePermissionObject(sdv::core::EAccessPermission::local_access);
|
||||
sdv::com::TConnectionID tConnection =
|
||||
pConnectionControl->CreateServerConnection(sdv::com::EChannelType::local_channel,
|
||||
sdv::core::GetObject("RepositoryService"), 5000, ssConnectionString);
|
||||
if (!tConnection.uiControl) return 0;
|
||||
if (ssConnectionString.empty()) return 0;
|
||||
optPermissionObject.reset();
|
||||
|
||||
// Create the isolation process configuration
|
||||
std::stringstream sstreamConfig;
|
||||
@@ -1298,7 +1567,10 @@ sdv::core::TObjectID CRepository::InternalCreateObject(const std::shared_ptr<CMo
|
||||
if (!ptrObject)
|
||||
{
|
||||
// Destroy the object again
|
||||
DestroyObject(rssObjectName);
|
||||
TDeferredObjectDestructionList lstDeferredObjectDestruction;
|
||||
DestroyObject2(rssObjectName, true, lstDeferredObjectDestruction);
|
||||
for (auto& rprObject : lstDeferredObjectDestruction)
|
||||
rprObject.first->ptrModule->DestroyObject(rprObject.second);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1306,7 +1578,7 @@ sdv::core::TObjectID CRepository::InternalCreateObject(const std::shared_ptr<CMo
|
||||
auto* pObjectControl = ptrObject.GetInterface<sdv::IObjectControl>();
|
||||
if (pObjectControl)
|
||||
{
|
||||
pObjectControl->Initialize(rssObjectConfig);
|
||||
pObjectControl->Initialize(*ptrObjectEntry);
|
||||
if (pObjectControl->GetObjectState() != sdv::EObjectState::initialized)
|
||||
{
|
||||
// Shutdown the object (even if the initialization didn't work properly).
|
||||
@@ -1315,8 +1587,8 @@ sdv::core::TObjectID CRepository::InternalCreateObject(const std::shared_ptr<CMo
|
||||
// Destroy the object
|
||||
rptrModule->DestroyObject(ptrObject);
|
||||
|
||||
// Destroy the object again
|
||||
DestroyObject(rssObjectName);
|
||||
//// Destroy the object again
|
||||
//DestroyObject2(rssObjectName, true);
|
||||
return 0;
|
||||
}
|
||||
switch (GetAppControl().GetOperationState())
|
||||
@@ -1350,14 +1622,7 @@ sdv::core::TObjectID CRepository::InternalCreateObject(const std::shared_ptr<CMo
|
||||
|
||||
sdv::core::TObjectID CRepository::CreateObjectID()
|
||||
{
|
||||
static sdv::core::TObjectID tCurrent = 0;
|
||||
if (!tCurrent)
|
||||
{
|
||||
std::srand(static_cast<unsigned int>(time(0)));
|
||||
tCurrent = 0;
|
||||
while (!tCurrent) tCurrent = std::rand();
|
||||
}
|
||||
return ++tCurrent;
|
||||
return m_idgen.Generate();
|
||||
}
|
||||
|
||||
std::vector<sdv::core::TObjectID> CRepository::GetDependingObjectInstancesByClass(const std::string& rssClass)
|
||||
@@ -1378,6 +1643,7 @@ std::vector<sdv::core::TObjectID> CRepository::GetDependingObjectInstancesByClas
|
||||
bool CRepositoryService::EnableRepositoryObjectControl()
|
||||
{
|
||||
return GetAppSettings().IsMainApplication() ||
|
||||
GetAppSettings().IsMaintenanceApplication() ||
|
||||
GetAppSettings().IsStandaloneApplication() ||
|
||||
GetAppSettings().IsEssentialApplication() ||
|
||||
GetAppSettings().IsIsolatedApplication();
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "object_lifetime_control.h"
|
||||
#include "iso_monitor.h"
|
||||
#include "app_config_file.h"
|
||||
#include "../../global/unique_id.h"
|
||||
|
||||
/**
|
||||
* @brief repository service providing functionality to load modules, create objects and access exiting objects
|
||||
@@ -34,7 +35,8 @@
|
||||
class CRepository :
|
||||
public sdv::IInterfaceAccess, public sdv::core::IObjectAccess, public sdv::core::IRepositoryUtilityCreate,
|
||||
public sdv::core::IRepositoryMarshallCreate, public sdv::core::IRepositoryControl, public sdv::core::IRegisterForeignObject,
|
||||
public sdv::core::IRepositoryInfo, public IObjectDestroyHandler, public sdv::core::ILinkCoreRepository
|
||||
public sdv::core::IRepositoryInfo, public IObjectDestroyHandler, public sdv::core::ILinkCoreRepository,
|
||||
public sdv::core::IObjectDependency
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -45,6 +47,7 @@ public:
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::core::IObjectAccess)
|
||||
SDV_INTERFACE_ENTRY(sdv::core::IObjectDependency)
|
||||
SDV_INTERFACE_ENTRY(sdv::core::IRepositoryMarshallCreate)
|
||||
SDV_INTERFACE_ENTRY(sdv::core::IRepositoryUtilityCreate)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
@@ -102,7 +105,6 @@ public:
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* CreateStubObject(/*in*/ sdv::interface_id id) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Create an object and all its objects it depends on. Overload of Overload of
|
||||
* sdv::core::IRepositoryControl::CreateObject.
|
||||
@@ -127,7 +129,7 @@ protected:
|
||||
*/
|
||||
virtual sdv::core::TObjectID CreateObject(/*in*/ const sdv::u8string& ssClassName, /*in*/ const sdv::u8string& ssObjectName,
|
||||
/*in*/ const sdv::u8string& ssObjectConfig) override;
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Creates an object from a previously loaded module. Provide the module ID to explicitly define what module to
|
||||
* use during object creation. Overload of sdv::core::IRepositoryControl::CreateObjectFromModule.
|
||||
@@ -145,7 +147,6 @@ public:
|
||||
/*in*/ const sdv::u8string& ssClassName, /*in*/ const sdv::u8string& ssObjectName,
|
||||
/*in*/ const sdv::u8string& ssObjectConfig) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destroy a previously created object with the supplied name. Overload of sdv::core::IRepositoryControl::DestroyObject.
|
||||
* @details For standalone and essential applications previously created system, device and service objects can be
|
||||
@@ -156,7 +157,29 @@ protected:
|
||||
*/
|
||||
virtual bool DestroyObject(/*in*/ const sdv::u8string& ssObjectName) override;
|
||||
|
||||
public:
|
||||
private:
|
||||
/**
|
||||
* @brief Object entry
|
||||
* @details The object instance information. Objects that are running remotely are represented by their proxy. Objects can have
|
||||
* multiple references by stubs.
|
||||
*/
|
||||
struct SObjectEntry : sdv::SObjectInfo
|
||||
{
|
||||
sdv::TInterfaceAccessPtr ptrObject; ///< Object interface (could be proxy).
|
||||
std::shared_ptr<CModuleInst> ptrModule; ///< Module instance.
|
||||
bool bControlled = false; ///< When set, the object is controlled.
|
||||
bool bIsolated = false; ///< When set, the object is isolated and running in another process.
|
||||
std::mutex mtxConnect; ///< Mutex used to wait for connection
|
||||
std::condition_variable cvConnect; ///< Condition variable used to wait for connection
|
||||
std::shared_ptr<CIsoMonitor> ptrIsoMon; ///< Object being monitored for shutdown.
|
||||
std::set<std::string> setDependentObjects; ///< List of dependent objects (needed during shutdown).
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief List for collected objects ready for destruction.
|
||||
*/
|
||||
using TDeferredObjectDestructionList = std::list<std::pair<std::shared_ptr<SObjectEntry>, sdv::IInterfaceAccess*>>;
|
||||
|
||||
/**
|
||||
* @brief Create an object and all its objects it depends on. Internal function not accessible through the interface.
|
||||
* @param[in] ssClassName The name of the object class to be created. For the main application, the class string could
|
||||
@@ -166,12 +189,13 @@ public:
|
||||
* the class name. Use the returned object ID to request the name of the object.
|
||||
* @param[in] ssObjectConfig Optional configuration handed over to the object upon creation via IObjectControl. Only
|
||||
* valid for standalone, essential and isolated applications.
|
||||
* @param[in] bIndirect Set when the function was called through a call from GetObject.
|
||||
* @return Returns the object ID when the object creation was successful or 0 when not. On success the object is
|
||||
* available through the IObjectAccess interface. If the object already exists (class and object names are identical),
|
||||
* the object ID of the existing object is returned.
|
||||
*/
|
||||
sdv::core::TObjectID CreateObject2(/*in*/ const sdv::u8string& ssClassName, /*in*/ const sdv::u8string& ssObjectName,
|
||||
/*in*/ const sdv::u8string& ssObjectConfig);
|
||||
sdv::core::TObjectID CreateObject2(const sdv::u8string& ssClassName, const sdv::u8string& ssObjectName,
|
||||
const sdv::u8string& ssObjectConfig, bool bIndirect);
|
||||
|
||||
/**
|
||||
* @brief Destroy a previously created object with the supplied name. Internal function not accessible through the interface.
|
||||
@@ -179,10 +203,14 @@ public:
|
||||
* destroyed. For the main and isolated applications, only the complex service can be destroyed. For isolated
|
||||
* applications a destruction of the object will end the application.
|
||||
* @param[in] ssObjectName The name of the object to destroy.
|
||||
* @param[in] bIndirect Set when the function was not call directly through DestroyObject.
|
||||
* @param[in] rlstDeferredObjectDestruction Reference to the list of objects to be filled with objects to be destroyed.
|
||||
* @return Returns whether the object destruction was successful.
|
||||
*/
|
||||
bool DestroyObject2(/*in*/ const sdv::u8string& ssObjectName);
|
||||
bool DestroyObject2(const sdv::u8string& ssObjectName, bool bIndirect,
|
||||
TDeferredObjectDestructionList& rlstDeferredObjectDestruction);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Register as foreign object and make it public to the system with the given name. Overload of
|
||||
* sdv::core::IRegisterForeignObject::RegisterObject.
|
||||
@@ -196,15 +224,17 @@ public:
|
||||
/*in*/ const sdv::u8string& ssObjectName) override;
|
||||
|
||||
/**
|
||||
* @brief Register the core repository.
|
||||
* @brief Register the core repository. Overload of sdv::core::ILinkCoreRepository::LinkCoreRepository.
|
||||
* @param[in] pCoreRepository Pointer to the proxy interface of the core repository.
|
||||
* @return Returns a link ID to be used in the Unlink function. Or 0 on failure.
|
||||
*/
|
||||
virtual void LinkCoreRepository(/*in*/ sdv::IInterfaceAccess* pCoreRepository) override;
|
||||
virtual sdv::core::TLinkID LinkCoreRepository(/*in*/ sdv::IInterfaceAccess* pCoreRepository) override;
|
||||
|
||||
/**
|
||||
* @brief Unlink a previously linked core repository.
|
||||
* @brief Unlink a previously linked core repository. Overload of sdv::core::ILinkCoreRepository::UnlinkCoreRepository.
|
||||
* @param[in] tLinkID Link ID of the repository link to remove.
|
||||
*/
|
||||
virtual void UnlinkCoreRepository() override;
|
||||
virtual void UnlinkCoreRepository(sdv::core::TLinkID tLinkID) override;
|
||||
|
||||
/**
|
||||
* @brief Find the class information of an object with the supplied name. Overload of
|
||||
@@ -256,6 +286,20 @@ public:
|
||||
*/
|
||||
void DestroyAllObjects(const std::vector<std::string>&rvecIgnoreObjects, bool bForce = false);
|
||||
|
||||
/**
|
||||
* @brief Add a dependency for an object. Overload of sdv::core::IObjectDependency::AddObjectDependency.
|
||||
* @param[in] ssObjectName Name of the object.
|
||||
* @param[in] ssDependsOnObject Name of the object it depends on.
|
||||
*/
|
||||
void AddObjectDependency(/*in*/ const sdv::u8string& ssObjectName, /*in*/ const sdv::u8string& ssDependsOnObject) override;
|
||||
|
||||
/**
|
||||
* @brief Remove an object dependency. Overload of sdv::core::IObjectDependency::RemoveObjectDependency.
|
||||
* @param[in] ssObjectName Name of the object.
|
||||
* @param[in] ssDependsOnObject Name of the object it depends on.
|
||||
*/
|
||||
void RemoveObjectDependency(/*in*/ const sdv::u8string& ssObjectName, /*in*/ const sdv::u8string& ssDependsOnObject) override;
|
||||
|
||||
/**
|
||||
* @brief Reset the current config baseline.
|
||||
*/
|
||||
@@ -306,7 +350,7 @@ private:
|
||||
* @brief Create a new unique object ID.
|
||||
* @return The created object ID.
|
||||
*/
|
||||
static sdv::core::TObjectID CreateObjectID();
|
||||
sdv::core::TObjectID CreateObjectID();
|
||||
|
||||
/**
|
||||
* @brief Get a list of depending object instances of a specific class.
|
||||
@@ -315,26 +359,6 @@ private:
|
||||
*/
|
||||
std::vector<sdv::core::TObjectID> GetDependingObjectInstancesByClass(const std::string& rssClass);
|
||||
|
||||
/**
|
||||
* @brief Object entry
|
||||
* @details The object instance information. Objects that are running remotely are represented by their proxy. Objects can have
|
||||
* multiple references by stubs.
|
||||
*/
|
||||
struct SObjectEntry
|
||||
{
|
||||
sdv::core::TObjectID tObjectID = 0; ///< Object ID (local to this process).
|
||||
sdv::SClassInfo sClassInfo; ///< Object class name.
|
||||
std::string ssName; ///< Object name (can be zero with local objects).
|
||||
std::string ssConfig; ///< Object configuration.
|
||||
sdv::TInterfaceAccessPtr ptrObject; ///< Object interface (could be proxy).
|
||||
std::shared_ptr<CModuleInst> ptrModule; ///< Module instance.
|
||||
bool bControlled = false; ///< When set, the object is controlled.
|
||||
bool bIsolated = false; ///< When set, the object is isolated and running in another process.
|
||||
std::mutex mtxConnect; ///< Mutex used to wait for connection
|
||||
std::condition_variable cvConnect; ///< Condition variable used to wait for connection
|
||||
std::shared_ptr<CIsoMonitor> ptrIsoMon; ///< Object being monitored for shutdown.
|
||||
};
|
||||
|
||||
using TObjectMap = std::map<sdv::core::TObjectID, std::shared_ptr<SObjectEntry>>;
|
||||
using TOrderedObjectList = std::list<std::shared_ptr<SObjectEntry>>;
|
||||
using TObjectIDList = std::list<std::shared_ptr<SObjectEntry>>;
|
||||
@@ -350,11 +374,11 @@ private:
|
||||
TIsolationMap m_mapIsolatedObjects; ///< Map with isolated objects.
|
||||
TObjectMap m_mapObjects; ///< Map with all objects indexed by the object ID.
|
||||
TConfigSet m_setConfigObjects; ///< Set with the objects for storing in the configuration.
|
||||
sdv::TInterfaceAccessPtr m_ptrCoreRepoAccess; ///< Linked core repository access (proxy interface).
|
||||
std::list<std::pair<sdv::core::TLinkID, sdv::TInterfaceAccessPtr>> m_lstCoreRepoAccess; ///< List to Linked core repositories.
|
||||
bool m_bIsoObjectLoaded = false; ///< When set, the isolated object has loaded. Do not allow
|
||||
///< another object of type complex service or utility to be
|
||||
///< created.
|
||||
///
|
||||
CUniqueID<sdv::core::TObjectID> m_idgen; ///< Unique ID generator.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "logger_control.h"
|
||||
#include "logger.h"
|
||||
#include "app_config.h"
|
||||
#include "permission_control.h"
|
||||
|
||||
/**
|
||||
* @brief SDV core instance class containing containing the instances for the core services.
|
||||
@@ -47,6 +48,7 @@ public:
|
||||
SDV_INTERFACE_CHAIN_MEMBER(GetMemoryManager())
|
||||
SDV_INTERFACE_CHAIN_MEMBER(GetRepository())
|
||||
SDV_INTERFACE_CHAIN_MEMBER(GetLoggerControl())
|
||||
SDV_INTERFACE_CHAIN_MEMBER(GetPermissionControl())
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace toml_parser
|
||||
TTokenListIterator it = m_lstTokens.begin();
|
||||
bool bCommaAvailable = false;
|
||||
bool bPrintableCharsAvailable = false;
|
||||
bool bLastTokenIsComment = false;
|
||||
bool bLastTokenIsCommentOrForceNewline = false;
|
||||
bool bNewlineAllowed = rContext.NewlineAllowed() || (eMode == EComposeMode::compose_behind && rContext.FinalNewline());
|
||||
while (it != m_lstTokens.end() && it->Category() != ETokenCategory::token_comment)
|
||||
{
|
||||
// Add comma only when needed.
|
||||
@@ -53,12 +54,12 @@ namespace toml_parser
|
||||
bCommaAvailable = true;
|
||||
break;
|
||||
case ETokenCategory::token_comment:
|
||||
bSkip = !rContext.CommentAndNewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = true;
|
||||
bSkip = !bNewlineAllowed;
|
||||
if (!bSkip) bLastTokenIsCommentOrForceNewline = true;
|
||||
break;
|
||||
case ETokenCategory::token_syntax_new_line:
|
||||
bSkip = !rContext.NewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = false;
|
||||
bSkip = !bNewlineAllowed;
|
||||
if (!bSkip) bLastTokenIsCommentOrForceNewline = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -107,11 +108,11 @@ namespace toml_parser
|
||||
break;
|
||||
case ETokenCategory::token_comment:
|
||||
bSkip = !rContext.CommentAndNewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = true;
|
||||
if (!bSkip) bLastTokenIsCommentOrForceNewline = true;
|
||||
break;
|
||||
case ETokenCategory::token_syntax_new_line:
|
||||
bSkip = !rContext.NewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = false;
|
||||
bSkip = !bNewlineAllowed;
|
||||
if (!bSkip) bLastTokenIsCommentOrForceNewline = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -210,11 +211,11 @@ namespace toml_parser
|
||||
break;
|
||||
case ETokenCategory::token_comment:
|
||||
bSkip = !rContext.CommentAndNewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = true;
|
||||
if (!bSkip) bLastTokenIsCommentOrForceNewline = true;
|
||||
break;
|
||||
case ETokenCategory::token_syntax_new_line:
|
||||
bSkip = !rContext.NewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = false;
|
||||
bSkip = !bNewlineAllowed;
|
||||
if (!bSkip) bLastTokenIsCommentOrForceNewline = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -239,7 +240,7 @@ namespace toml_parser
|
||||
}
|
||||
|
||||
// Default newline needed
|
||||
if (rContext.FinalNewline() && ((m_lstTokens.empty() && m_ssComment.empty()) || bLastTokenIsComment))
|
||||
if (rContext.FinalNewline() && ((m_lstTokens.empty() && m_ssComment.empty()) || bLastTokenIsCommentOrForceNewline))
|
||||
sstream << std::endl;
|
||||
break;
|
||||
case EComposeMode::compose_before:
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "exception.h"
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <support/toml.h>
|
||||
#include "parser_toml.h"
|
||||
|
||||
namespace toml_parser
|
||||
{
|
||||
@@ -560,4 +562,21 @@ namespace toml_parser
|
||||
return sstreamQuotedText.str();
|
||||
}
|
||||
}
|
||||
|
||||
bool CompareEqual(const std::string& rssToml1, const std::string& rssToml2)
|
||||
{
|
||||
try
|
||||
{
|
||||
CParser parser1(rssToml1);
|
||||
CParser parser2(rssToml2);
|
||||
sdv::toml::CNodeCollection collection1(&parser1.Root());
|
||||
sdv::toml::CNodeCollection collection2(&parser2.Root());
|
||||
return sdv::toml::internal::CompareNodes(collection1, collection2) == sdv::toml::ECompareResult::compare_identical;
|
||||
}
|
||||
catch (const toml_parser::XTOMLParseException&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace toml_parser
|
||||
@@ -108,6 +108,16 @@ namespace toml_parser
|
||||
* @return The quoted key (if applicable); otherwise the key without quotes.
|
||||
*/
|
||||
std::string QuoteText(const std::string& rssText, EQuoteRequest eQuoteRequest = EQuoteRequest::smart_text);
|
||||
|
||||
/**
|
||||
* @brief Compare the content of TOML string with the content of another TOML string. Use internal TOML parser for the
|
||||
* comparison.
|
||||
* @param[in] rssToml1 Reference to the first TOML string to compare with the second TOML string.
|
||||
* @param[in] rssToml2 Reference to the second TOML string to compare with the first TOML string.
|
||||
* @return The comparison result.
|
||||
*/
|
||||
bool CompareEqual(const std::string& rssToml1, const std::string& rssToml2);
|
||||
|
||||
} // namespace toml_parser
|
||||
|
||||
#endif // !defined MISCELLANEOUS_H
|
||||
145
sdv_services/core/toml_parser/parser_node_indexer.cpp
Normal file
145
sdv_services/core/toml_parser/parser_node_indexer.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#include "parser_node_indexer.h"
|
||||
#include <interfaces/toml.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace toml_parser
|
||||
{
|
||||
CNodeIndex::CNodeIndex(CIndexList& rIndexList, CIndexListIterator itPos) : m_ptrPos(std::make_shared<CIteratorWrapper>(rIndexList, itPos))
|
||||
{}
|
||||
|
||||
CNodeIndex::~CNodeIndex()
|
||||
{
|
||||
m_ptrPos.reset();
|
||||
}
|
||||
|
||||
CNodeIndex::CNodeIndex(const CNodeIndex& rIndex) : m_ptrPos(rIndex.m_ptrPos)
|
||||
{}
|
||||
|
||||
CNodeIndex::CNodeIndex(CNodeIndex&& rIndex) : m_ptrPos(std::move(rIndex.m_ptrPos))
|
||||
{}
|
||||
|
||||
CNodeIndex& CNodeIndex::operator=(const CNodeIndex& rIndex)
|
||||
{
|
||||
m_ptrPos = rIndex.m_ptrPos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CNodeIndex& CNodeIndex::operator=(CNodeIndex&& rIndex)
|
||||
{
|
||||
m_ptrPos = std::move(rIndex.m_ptrPos);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CNodeIndex::operator==(const CNodeIndex& rIndex) const
|
||||
{
|
||||
return rIndex.m_ptrPos == m_ptrPos;
|
||||
}
|
||||
|
||||
bool CNodeIndex::operator!=(const CNodeIndex& rIndex) const
|
||||
{
|
||||
return !operator==(rIndex);
|
||||
}
|
||||
|
||||
bool CNodeIndex::operator<(const CNodeIndex& rIndex) const
|
||||
{
|
||||
if (!m_ptrPos) return false;
|
||||
if (!rIndex.m_ptrPos) return true;
|
||||
return m_ptrPos->Index() < rIndex.m_ptrPos->Index();
|
||||
}
|
||||
|
||||
bool CNodeIndex::operator<=(const CNodeIndex& rIndex) const
|
||||
{
|
||||
if (!m_ptrPos) return false;
|
||||
if (!rIndex.m_ptrPos) return true;
|
||||
return rIndex.m_ptrPos == m_ptrPos || m_ptrPos->Index() < rIndex.m_ptrPos->Index();
|
||||
}
|
||||
|
||||
bool CNodeIndex::operator>(const CNodeIndex& rIndex) const
|
||||
{
|
||||
if (!m_ptrPos) return true;
|
||||
if (!rIndex.m_ptrPos) return false;
|
||||
return m_ptrPos->Index() > rIndex.m_ptrPos->Index();
|
||||
}
|
||||
|
||||
bool CNodeIndex::operator>=(const CNodeIndex& rIndex) const
|
||||
{
|
||||
if (!m_ptrPos) return true;
|
||||
if (!rIndex.m_ptrPos) return false;
|
||||
return rIndex.m_ptrPos == m_ptrPos || m_ptrPos->Index() > rIndex.m_ptrPos->Index();
|
||||
}
|
||||
|
||||
CNodeIndex::operator bool() const
|
||||
{
|
||||
return m_ptrPos ? true : false;
|
||||
}
|
||||
|
||||
void CNodeIndex::MoveBefore(const CNodeIndex& rIndex)
|
||||
{
|
||||
if (m_ptrPos && rIndex.m_ptrPos)
|
||||
m_ptrPos->MoveBeforeIndex(*rIndex.m_ptrPos);
|
||||
}
|
||||
|
||||
uint32_t CNodeIndex::Index() const
|
||||
{
|
||||
if (!m_ptrPos) return sdv::toml::npos;
|
||||
return m_ptrPos->Index();
|
||||
}
|
||||
|
||||
CNodeIndex::CIteratorWrapper::CIteratorWrapper(CIndexList& rIndexList, CIndexListIterator itPos) :
|
||||
m_rIndexList(rIndexList), m_itPos(itPos)
|
||||
{}
|
||||
|
||||
CNodeIndex::CIteratorWrapper ::~CIteratorWrapper()
|
||||
{
|
||||
m_rIndexList.erase(m_itPos);
|
||||
}
|
||||
|
||||
uint32_t CNodeIndex::CIteratorWrapper::Index() const
|
||||
{
|
||||
return static_cast<uint32_t>(std::distance(m_rIndexList.cbegin(), m_itPos));
|
||||
}
|
||||
|
||||
void CNodeIndex::CIteratorWrapper::MoveBeforeIndex(const CIteratorWrapper& ritTarget)
|
||||
{
|
||||
m_rIndexList.splice(ritTarget.m_itPos, m_rIndexList, m_itPos);
|
||||
}
|
||||
|
||||
// Global index list
|
||||
CIndexList CNodeIndexer::m_lstIndexList;
|
||||
|
||||
CNodeIndexer::CNodeIndexer()
|
||||
{}
|
||||
|
||||
CNodeIndex CNodeIndexer::CreateIndex()
|
||||
{
|
||||
auto itPos = m_lstIndexList.insert(m_lstIndexList.end(), SNodeIndexElement());
|
||||
CNodeIndex index(m_lstIndexList, itPos);
|
||||
return index;
|
||||
}
|
||||
|
||||
CNodeIndex CNodeIndexer::CreateIndex(const CNodeIndex& rInsertBefore)
|
||||
{
|
||||
CNodeIndex node_index = CreateIndex();
|
||||
node_index.MoveBefore(rInsertBefore);
|
||||
return node_index;
|
||||
}
|
||||
|
||||
size_t CNodeIndexer::Count()
|
||||
{
|
||||
return m_lstIndexList.size();
|
||||
}
|
||||
|
||||
} // namespace toml_parser
|
||||
227
sdv_services/core/toml_parser/parser_node_indexer.h
Normal file
227
sdv_services/core/toml_parser/parser_node_indexer.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef PARSER_NODE_INDEXER_H
|
||||
#define PARSER_NODE_INDEXER_H
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
namespace toml_parser
|
||||
{
|
||||
class CNodeIndex;
|
||||
class CNodeIndexer;
|
||||
/// Placeholder index element
|
||||
struct SNodeIndexElement {};
|
||||
/// Index list
|
||||
using CIndexList = std::list<SNodeIndexElement>;
|
||||
/// Const iterator to an element in the index list
|
||||
using CIndexListIterator = CIndexList::const_iterator;
|
||||
|
||||
/**
|
||||
* @brief Node index object used to manage the node order.
|
||||
*/
|
||||
class CNodeIndex
|
||||
{
|
||||
friend CNodeIndexer; ///< CNodeIndex uses friend access to create the node index and assign the iterator holding the
|
||||
///< the position within the index list.
|
||||
private:
|
||||
/**
|
||||
* @brief Constructor of the node index object. Use the CNodeIndexer::CreateIndex function to create the object.
|
||||
* @param[in] rIndexList Reference to the index list.
|
||||
* @param[in] itPos Iterator to the position in the index list.
|
||||
*/
|
||||
CNodeIndex(CIndexList& rIndexList, CIndexListIterator itPos);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CNodeIndex();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor of the node index object.
|
||||
* @param[in] rIndex Reference to the index object to copy from.
|
||||
*/
|
||||
CNodeIndex(const CNodeIndex& rIndex);
|
||||
|
||||
/**
|
||||
* @brief Move constructor of the node index object.
|
||||
* @param[in] rIndex Reference to the index object to move from.
|
||||
*/
|
||||
CNodeIndex(CNodeIndex&& rIndex);
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator of the node index object.
|
||||
* @param[in] rIndex Reference to the index object to copy from.
|
||||
* @return Returns a reference to this object.
|
||||
*/
|
||||
CNodeIndex& operator=(const CNodeIndex& rIndex);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator of the node index object.
|
||||
* @param[in] rIndex Reference to the index object to move from.
|
||||
* @return Returns a reference to this object.
|
||||
*/
|
||||
CNodeIndex& operator=(CNodeIndex&& rIndex);
|
||||
|
||||
/**
|
||||
* @brief Compare this node index object to the supplied index object and return whether the position of this object is
|
||||
* identical to the position of the supplied object.
|
||||
* @param[in] rIndex Reference to the node index object to compare with.
|
||||
* @return Returns whether the provided index is identical to this index.
|
||||
*/
|
||||
bool operator==(const CNodeIndex& rIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Compare this node index object to the supplied index object and return whether the position of this object is
|
||||
* not identical to the position of the supplied object.
|
||||
* @param[in] rIndex Reference to the node index object to compare with.
|
||||
* @return Returns whether the provided index is different than this index.
|
||||
*/
|
||||
bool operator!=(const CNodeIndex& rIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Compare this node index object to the supplied index object and return whether the position of this object is
|
||||
* smaller than the position of the supplied object.
|
||||
* @param[in] rIndex Reference to the node index object to compare with.
|
||||
* @return Returns whether the provided index is smaller than this index.
|
||||
*/
|
||||
bool operator<(const CNodeIndex& rIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Compare this node index object to the supplied index object and return whether the position of this object is
|
||||
* smaller than or equal to the position of the supplied object.
|
||||
* @param[in] rIndex Reference to the node index object to compare with.
|
||||
* @return Returns whether the provided index is smaller than or equal to this index.
|
||||
*/
|
||||
bool operator<=(const CNodeIndex& rIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Compare this node index object to the supplied index object and return whether the position of this object is
|
||||
* larger than the position of the supplied object.
|
||||
* @param[in] rIndex Reference to the node index object to compare with.
|
||||
* @return Returns whether the provided index is larger than this index.
|
||||
*/
|
||||
bool operator>(const CNodeIndex& rIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Compare this node index object to the supplied index object and return whether the position of this object is
|
||||
* larger than or equal to the position of the supplied object.
|
||||
* @param[in] rIndex Reference to the node index object to compare with.
|
||||
* @return Returns whether the provided index is larger than or equal to this index.
|
||||
*/
|
||||
bool operator>=(const CNodeIndex& rIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Check for validity.
|
||||
* @return Returns whether the index object contains a valid index.
|
||||
*/
|
||||
operator bool() const;
|
||||
|
||||
/**
|
||||
* @brief Move the node index object before the index object provided as an argument.
|
||||
* @param[in] rIndex Reference to the node index object to move the object before.
|
||||
*/
|
||||
void MoveBefore(const CNodeIndex& rIndex);
|
||||
|
||||
/**
|
||||
* @brief Get the index in the list. Returns sdv::toml::npos if the index is not in the list any more.
|
||||
* @remarks This index os calculated dynamically and can change if indices are added, removed or swapped.
|
||||
* @return The current index in the list.
|
||||
*/
|
||||
uint32_t Index() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Iterator wrapper object with lifetime management.
|
||||
* @remarks The wrapper keeps track of the shared index list as well. It is possible that the parser is deleted before the
|
||||
* nodes are deleted, causing an issue when accessing the index list.
|
||||
*/
|
||||
struct CIteratorWrapper
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rIndexList Reference to the index list.
|
||||
* @param[in] itPos Position of this index in the index list.
|
||||
*/
|
||||
CIteratorWrapper(CIndexList& rIndexList, CIndexListIterator itPos);
|
||||
|
||||
/**
|
||||
* @brief Destructor removing the index object from the index list.
|
||||
*/
|
||||
~CIteratorWrapper();
|
||||
|
||||
/**
|
||||
* @brief Get the index in the list.
|
||||
* @remarks This index os calculated dynamically and can change if indices are added, removed or swapped.
|
||||
* @return The current index in the list.
|
||||
*/
|
||||
uint32_t Index() const;
|
||||
|
||||
/**
|
||||
* @brief Move the index object before the supplied index object.
|
||||
* @param[in] ritTarget Reference to the index object to move the object before.
|
||||
*/
|
||||
void MoveBeforeIndex(const CIteratorWrapper& ritTarget);
|
||||
|
||||
private:
|
||||
CIndexList& m_rIndexList; ///< Reference to the index list.
|
||||
CIndexListIterator m_itPos; ///< Iterator in the list
|
||||
};
|
||||
|
||||
std::shared_ptr<CIteratorWrapper> m_ptrPos; ///< Position in the index list
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Node indexer object managing the node index objects allowing determining and changing the order of nodes.
|
||||
*/
|
||||
class CNodeIndexer
|
||||
{
|
||||
friend CNodeIndex; ///< CNodeIndex has friend relationship allowing access to specific indexing functions using the
|
||||
///< index iterator from the index list.
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
CNodeIndexer();
|
||||
|
||||
/**
|
||||
* @brief Create a node index object.
|
||||
* @return The new node index object.
|
||||
*/
|
||||
CNodeIndex CreateIndex();
|
||||
|
||||
/**
|
||||
* @brief Create a new node index object and insert this object before the supplied object.
|
||||
* @attention There is no protection for supplying an invalid iterator or an iterator from a different indexer.
|
||||
* @param[in] rInsertBefore Insert the index object before the supplied iterator position.
|
||||
* @return The new node index object.
|
||||
*/
|
||||
CNodeIndex CreateIndex(const CNodeIndex& rInsertBefore);
|
||||
|
||||
/**
|
||||
* @brief Return the amount of indices allocated.
|
||||
* @return The amount of indices allocated in the index list.
|
||||
*/
|
||||
static size_t Count();
|
||||
|
||||
private:
|
||||
static CIndexList m_lstIndexList; ///< List of all node indices. This list is global to allow nodes from one
|
||||
///< parser to be inserted into the list of another parser.
|
||||
};
|
||||
} // namespace toml_parser
|
||||
|
||||
#endif // !defined PARSER_NODE_INDEXER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
||||
#include <support/interface_ptr.h>
|
||||
#include "miscellaneous.h"
|
||||
#include "code_snippet.h"
|
||||
#include "parser_node_indexer.h"
|
||||
|
||||
/// The TOML parser namespace
|
||||
namespace toml_parser
|
||||
@@ -72,11 +73,12 @@ namespace toml_parser
|
||||
void InitTopMostNode(const std::shared_ptr<const CNode>& rptrNode);
|
||||
|
||||
/**
|
||||
* @brief Check whether the provided node is a parent of the top most node.
|
||||
* @param[in] rptrNode Reference to the node to use for the checking.
|
||||
* @return Returns true if the node is a parent of the top most node, false otherwise.
|
||||
* @brief A node is part of the view if either it is an inline node, or it is a standard node and the current parent is the
|
||||
* root view.
|
||||
* @param[in] rptrNode Reference to the smart pointer to the node to check for.
|
||||
* @return Returns whether the node is part of the view.
|
||||
*/
|
||||
bool PartOfExcludedParents(const std::shared_ptr<const CNode>& rptrNode) const;
|
||||
bool IsPartOfView(const std::shared_ptr<const CNode>& rptrNode) const;
|
||||
|
||||
/**
|
||||
* @brief Create a copy of the context class with a new key context.
|
||||
@@ -289,10 +291,42 @@ namespace toml_parser
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Get a reference to the TOML parser that generated this node.
|
||||
* @return Reference to the TOML parse.
|
||||
*/
|
||||
CParser& Parser();
|
||||
const CParser& Parser() const;
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Return the index object of the node.
|
||||
* @return Reference to the node index object.
|
||||
*/
|
||||
const CNodeIndex& NodeIndex() const;
|
||||
CNodeIndex& NodeIndex();
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Compare the index position of this node with the position of another node and return whether this node occurs
|
||||
* before the other node.
|
||||
* @param[in] rNode Reference to the node to compare the position with.
|
||||
* @return Returns whether this node occurs before the other node.
|
||||
*/
|
||||
bool operator<(const CNode& rNode) const;
|
||||
|
||||
/**
|
||||
* @brief Compare the index position of this node with the position of another node and return whether this node occurs
|
||||
* before the other node.
|
||||
* @param[in] rptrNode Reference to the node to compare the position with.
|
||||
* @return Returns whether this node occurs before the other node.
|
||||
*/
|
||||
bool operator<(const std::shared_ptr<CNode>& rptrNode) const;
|
||||
|
||||
/**
|
||||
* @brief Get the node name (no conversion to a literal or quoted key is made). Overload of sdv::toml::INodeInfo::GetName.
|
||||
@@ -328,9 +362,8 @@ namespace toml_parser
|
||||
virtual sdv::any_t GetValue() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the index of this node within the view collection (either the assigned view or the parent). Overload of
|
||||
* sdv::toml::INodeInfo::GetIndex.
|
||||
* @return The index of the node within the view collection node or npos when no parent is available.
|
||||
* @brief Get the index of this node within the parent collection. Overload of sdv::toml::INodeInfo::GetIndex.
|
||||
* @return The index of the node within the parent collection node or npos when no parent is available.
|
||||
*/
|
||||
virtual uint32_t GetIndex() const override;
|
||||
|
||||
@@ -370,10 +403,10 @@ namespace toml_parser
|
||||
virtual sdv::u8string GetComment(sdv::toml::INodeInfo::ECommentType eType) override;
|
||||
|
||||
/**
|
||||
* @brief Format the node automatically. This will remove the whitespace between the elements within the node. Comments
|
||||
* will not be changed. Overload of sdv::toml::INodeInfo::AutomaticFormat.
|
||||
* @brief Format the node automatically, remove redundant whitespace. Overload of sdv::toml::INodeInfo::AutomaticFormat.
|
||||
* @param[in] bRemoveComments When set, the comments are removed from the node.
|
||||
*/
|
||||
virtual void AutomaticFormat() override;
|
||||
virtual void AutomaticFormat(/*in*/ bool bRemoveComments) override;
|
||||
|
||||
/**
|
||||
* @brief Is the node inline? Overload of sdv::toml::INodeInfo::IsInline.
|
||||
@@ -457,10 +490,11 @@ namespace toml_parser
|
||||
std::shared_ptr<const TNodeType> Cast() const;
|
||||
|
||||
/**
|
||||
* @brief Set the parent node.
|
||||
* @brief Reassign the parent node and if necessary the parser reference.
|
||||
* @details This function allows shifting nodes from one parser to another.
|
||||
* @param[in] rptrParent Reference to the node to assign to this node as a parent.
|
||||
*/
|
||||
void SetParentPtr(const std::shared_ptr<CNodeCollection>& rptrParent);
|
||||
virtual void SetParentPtr(const std::shared_ptr<CNodeCollection>& rptrParent);
|
||||
|
||||
/**
|
||||
* @brief Gets the parent node pointer.
|
||||
@@ -475,29 +509,6 @@ namespace toml_parser
|
||||
*/
|
||||
std::string GetParentPath() const;
|
||||
|
||||
/**
|
||||
* @brief Set the view definition node. The view definition node is a parent or grand parent that presents the node when
|
||||
* generating TOML code. When not set, the parent node is taking over this role.
|
||||
* @param[in] rptrView Reference to the node to assign to this node as a parent or grand parent.
|
||||
*/
|
||||
void SetViewPtr(const std::shared_ptr<CNodeCollection>& rptrView);
|
||||
|
||||
/**
|
||||
* @brief Gets the view definition node pointer.
|
||||
* @return Returns the store view definition node pointer or an empty pointer when no view was assigned.
|
||||
*/
|
||||
std::shared_ptr<CNodeCollection> GetViewPtr() const;
|
||||
|
||||
/**
|
||||
* @brief Checks whether the node is part of the view.
|
||||
* @details The node is part of the view if the supplied pointer is identical to the view definition pointer, when the view
|
||||
* definition pointer is not part of a parent of the topmost node. In all other cases, the node is part of the view.
|
||||
* @param[in] rContext Reference to the context class to use during TOML code generation.
|
||||
* @param[in] rptrNode Reference to the node to check whether it registered for a view.
|
||||
* @return Returns whether this node is part of the view with the supplied pointer.
|
||||
*/
|
||||
bool IsPartOfView(const CGenContext& rContext, const std::shared_ptr<const CNodeCollection>& rptrNode) const;
|
||||
|
||||
/**
|
||||
* @brief Accesses a node by its key in the parse tree.
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
|
||||
@@ -507,7 +518,7 @@ namespace toml_parser
|
||||
* @attention Array indexing starts with 0!
|
||||
* @attention For an array, when no indexing is supplied, the latest entry will be returned.
|
||||
* @param[in] rssPath The path of the node to searched for.
|
||||
* @return Returns a shared pointer to the wanted Node if it was found or a node with invalid content if it was not found.
|
||||
* @return Returns a shared pointer to the wanted node if it was found or a node with invalid content if it was not found.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Direct(const std::string& rssPath) const = 0;
|
||||
|
||||
@@ -577,13 +588,20 @@ namespace toml_parser
|
||||
*/
|
||||
std::string GetCustomPath(const std::string& rssPrefixKey, const std::string& rssContext) const;
|
||||
|
||||
/**
|
||||
* @brief When the parent changes (e.g. when moving items from one parser to the other), the items and all its sub-items
|
||||
* need to reasign the parser.
|
||||
* @param[in] rParser Reference to the parser to assign.
|
||||
*/
|
||||
virtual void ReassignParser(CParser& rParser);
|
||||
|
||||
private:
|
||||
std::weak_ptr<CNodeCollection> m_ptrParent; ///< Weak pointer to the parent node (if existing).
|
||||
std::weak_ptr<CNodeCollection> m_ptrView; ///< Weak pointer to the view node (if existing and explicitly set).
|
||||
std::string m_ssName; ///< Name of the node.
|
||||
std::string m_ssRawName; ///< Raw name of the node.
|
||||
bool m_bDeleted = false; ///< Enabled when the node was marked for deletion.
|
||||
CParser& m_rParser; ///< Reference to the TOML parser.
|
||||
CNodeIndex m_index; ///< Node index object holding the overall node position.
|
||||
std::weak_ptr<CNodeCollection> m_ptrParent; ///< Weak pointer to the parent node (if existing).
|
||||
std::string m_ssName; ///< Name of the node.
|
||||
std::string m_ssRawName; ///< Raw name of the node.
|
||||
bool m_bDeleted = false; ///< Enabled when the node was marked for deletion.
|
||||
std::reference_wrapper<CParser> m_refParser; ///< Reference to the TOML parser.
|
||||
std::vector<std::map<std::string, CCodeSnippet>> m_vecCodeSnippets; ///< Vector with comments/code snippets.
|
||||
|
||||
public:
|
||||
@@ -596,11 +614,16 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief With some node collections it is possible to switch between inline and normal.
|
||||
* @remarks Additional node composition information will be removed and the order within the parent node might be changed.
|
||||
* @remarks When made inline, all child nodes must be made inline as well. When made standard, only this node is made
|
||||
* standard.
|
||||
* @remarks Making this node a standard node, this is only possible when the parent is not an inline mode.
|
||||
* @param[in] bInline When set, try to switch to inline. Otherwise try to switch to normal.
|
||||
* @param[in] bIncludeChildren When set and bInline is not set, applicable child nodes are converted as well (only tables
|
||||
* and table-arrays can be defined as standard). Making a node inline is always including the children.
|
||||
* @return Returns whether the switch was successful. A switch to the same type (normal to normal or inline to inline is
|
||||
* always successful). When returning false, the switching might not be supported for this type.
|
||||
*/
|
||||
virtual bool Inline(bool bInline) = 0;
|
||||
virtual bool Inline(bool bInline, bool bIncludeChildren = true) = 0;
|
||||
|
||||
/**
|
||||
* @brief Checks whether the table was explicitly defined.
|
||||
@@ -654,10 +677,12 @@ namespace toml_parser
|
||||
* @brief With some node collections it is possible to switch between inline and normal. Overload of CNode::Inline.
|
||||
* @remarks Additional node composition information will be removed and the order within the parent node might be changed.
|
||||
* @param[in] bInline When set, try to switch to inline. Otherwise try to switch to normal.
|
||||
* @param[in] bIncludeChildren When set and bInline is not set, applicable child nodes are converted as well (only tables
|
||||
* and table-arrays can be defined as standard). Making a node inline is always including the children.
|
||||
* @return Returns whether the switch was successful. A switch to the same type (normal to normal or inline to inline is
|
||||
* always successful). When returning false, the switching might not be supported for this type.
|
||||
*/
|
||||
virtual bool Inline(bool bInline) override;
|
||||
virtual bool Inline(bool bInline, bool bIncludeChildren = true) override;
|
||||
|
||||
/**
|
||||
* @brief Accesses a node by its key in the parse tree. Overload of CNode::Direct.
|
||||
@@ -668,7 +693,7 @@ namespace toml_parser
|
||||
* @attention Array indexing starts with 0!
|
||||
* @attention For an array, when no indexing is supplied, the latest entry will be returned.
|
||||
* @param[in] rssPath The path of the node to searched for.
|
||||
* @return Returns a shared pointer to the wanted Node if it was found or a node with invalid content if it was not found.
|
||||
* @return Returns a shared pointer to the wanted node if it was found or a node with invalid content if it was not found.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Direct(const std::string& rssPath) const override;
|
||||
|
||||
@@ -943,10 +968,10 @@ namespace toml_parser
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Format the node automatically. This will remove the whitespace between the elements within the node. Comments
|
||||
* will not be changed. Overload of sdv::toml::INodeInfo::AutomaticFormat.
|
||||
* @brief Format the node automatically, remove redundant whitespace. Overload of sdv::toml::INodeInfo::AutomaticFormat.
|
||||
* @param[in] bRemoveComments When set, the comments are removed from the node.
|
||||
*/
|
||||
virtual void AutomaticFormat() override;
|
||||
virtual void AutomaticFormat(/*in*/ bool bRemoveComments) override;
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of nodes. Overload of sdv::toml::INodeCollection::GetCount.
|
||||
@@ -966,7 +991,28 @@ namespace toml_parser
|
||||
* @param[in] uiIndex Index of the node to get.
|
||||
* @return Smart pointer to the node object.
|
||||
*/
|
||||
std::shared_ptr<CNode> Get(uint32_t uiIndex) const;
|
||||
virtual std::shared_ptr<CNode> Get(uint32_t uiIndex) const;
|
||||
|
||||
/**
|
||||
* @brief After every insert, deletion and shift, the node order of this and all sub- tables need to be rebuild.
|
||||
* @param[in] bForce Force rebuild, even if locked.
|
||||
*/
|
||||
virtual void RebuildNodeOrder(bool bForce);
|
||||
|
||||
/**
|
||||
* @brief After every insert, deletion and shift, the node order needs to be rebuild.
|
||||
* @details Adding is done iteratively through the node list. In case the top level flag is set, all nodes are added that
|
||||
* are marked explicit or if a node is implicit, the explicit sub-nodes are added. In case this is root view, all sub-nodes
|
||||
* which are standard tables or standard table arrays are added. This flattens the hierarchy. When the root view is not set,
|
||||
* only the tables and table arrays are added that are a direct child of the node collection. At the end of building the
|
||||
* root view, the nodes are sorted using their index. Furthermore, inline nodes are moved to the beginning of the vector and
|
||||
* standard nodes to the end.
|
||||
* @param[in, out] rvecNodes Reference to the vector being filled with the nodes for the view.
|
||||
* @param[in] bRootView Set when the count is top level.
|
||||
* @param[in] bTopLevel Set when this is the top level node for adding sub nodes.
|
||||
*/
|
||||
virtual void FillNodeOrderVector(std::vector<std::shared_ptr<CNode>>& rvecNodes, bool bRootView = true,
|
||||
bool bTopLevel = true);
|
||||
|
||||
/**
|
||||
* @brief Accesses a node by its key in the parse tree. Overload of CNode::Direct.
|
||||
@@ -977,7 +1023,7 @@ namespace toml_parser
|
||||
* @attention Array indexing starts with 0!
|
||||
* @attention For an array, when no indexing is supplied, the latest entry will be returned.
|
||||
* @param[in] rssPath The path of the node to searched for.
|
||||
* @return Returns a shared pointer to the wanted Node if it was found or a node with invalid content if it was not found.
|
||||
* @return Returns a shared pointer to the wanted node if it was found or a node with invalid content if it was not found.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Direct(const std::string& rssPath) const override;
|
||||
|
||||
@@ -993,85 +1039,124 @@ namespace toml_parser
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* GetNodeDirect(/*in*/ const sdv::u8string& ssPath) const override;
|
||||
|
||||
/**
|
||||
* @brief Get or create the parent nodes automotatically from the path.
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
|
||||
* E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be accessed and
|
||||
* traversed by using the index number in brackets. E.g. 'array[3]' would access the fourth element of the array 'array'.
|
||||
* These access conventions can also be chained like 'table.array[2][1].subtable.integerElement'.
|
||||
* @attention Array indexing starts with 0!
|
||||
* @attention For an array, when no indexing or a too large index number is supplied, a new entry will be created and
|
||||
* returned.
|
||||
* @param[in] rssPath The path of the node to searched for.
|
||||
* @param[in] bInsertTableArray Since a table array consists of an array and a table, this is different than the other
|
||||
* insertions that only insert one element. Some special treatment is needed at certain points.
|
||||
* @return Returns a pair with the shared pointer to the parent node and the leftover name. If the creation could not be
|
||||
* done, a NULL pointer is returned.
|
||||
*/
|
||||
virtual std::pair<std::shared_ptr<CNodeCollection>, std::string> SmartParentCreate(const std::string& rssPath,
|
||||
bool bInsertTableArray = false);
|
||||
|
||||
/**
|
||||
* @brief Insert a value into the collection at the location before the supplied index. Overload of
|
||||
* sdv::toml::INodeCollectionInsert::InsertValue.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Value nodes cannot be inserted behind external
|
||||
* tables and table arrays. If the index is referencing a position behind an external table or a table array, the index
|
||||
* is automatically corrected.
|
||||
* @param[in] ssName Name of the node to insert. Will be ignored for an array collection. The name must adhere to the
|
||||
* key names defined by the TOML specification. Defining the key multiple times is not allowed. Quotation of key names
|
||||
* is done automatically; the parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] anyValue The value of the node, being either an integer, floating point number, virtual bool value or a string.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since values are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] anyValue The value of the node, being either an integer, floating point number, virtual bool value or a
|
||||
* string.
|
||||
* Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* InsertValue(uint32_t uiIndex, const sdv::u8string& ssName, sdv::any_t anyValue) override;
|
||||
virtual sdv::IInterfaceAccess* InsertValue(/*in*/ const sdv::u8string& ssInsertBefore, /*in*/ const sdv::u8string& ssName,
|
||||
/*in*/ sdv::any_t anyValue) override;
|
||||
|
||||
/**
|
||||
* @brief Insert an array into the collection at the location before the supplied index. Overload of
|
||||
* sdv::toml::INodeCollectionInsert::InsertArray.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Array nodes cannot be inserted behind external
|
||||
* tables and table arrays. If the index is referencing a position behind an external table or a table array, the index
|
||||
* is automatically corrected.
|
||||
* @param[in] ssName Name of the array node to insert. Will be ignored if the current node is also an array collection.
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since arrays are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* InsertArray(uint32_t uiIndex, const sdv::u8string& ssName) override;
|
||||
virtual sdv::IInterfaceAccess* InsertArray(/*in*/ const sdv::u8string& ssInsertBefore,
|
||||
/*in*/ const sdv::u8string& ssName) override;
|
||||
|
||||
/**
|
||||
* @brief Insert a table into the collection at the location before the supplied index. Overload of
|
||||
* sdv::toml::INodeCollectionInsert::InsertTable.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table nodes cannot be inserted before value nodes
|
||||
* or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @param[in] ssName Name of the table node to insert. Will be ignored if the current node is an array collection.
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Tables can be inserted as inline node, in which
|
||||
* case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] ePreference The preferred form of the node to be inserted.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* InsertTable(uint32_t uiIndex, const sdv::u8string& ssName,
|
||||
sdv::toml::INodeCollectionInsert::EInsertPreference ePreference) override;
|
||||
virtual sdv::IInterfaceAccess* InsertTable(/*in*/ const sdv::u8string& ssInsertBefore, /*in*/ const sdv::u8string& ssName,
|
||||
/*in*/ sdv::toml::EInsertPreference ePreference) override;
|
||||
|
||||
/**
|
||||
* @brief Insert a table array into the collection at the location before the supplied index. Overload of
|
||||
* sdv::toml::INodeCollectionInsert::InsertTableArray.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
|
||||
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @param[in] ssName Name of the array node to insert. Will be ignored if the current node is also an array collection.
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Table arrays can be inserted as inline node, in
|
||||
* which case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] ePreference The preferred form of the node to be inserted.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* InsertTableArray(uint32_t uiIndex, const sdv::u8string& ssName,
|
||||
sdv::toml::INodeCollectionInsert::EInsertPreference ePreference) override;
|
||||
virtual sdv::IInterfaceAccess* InsertTableArray(/*in*/ const sdv::u8string& ssInsertBefore, /*in*/ const sdv::u8string& ssName,
|
||||
/*in*/ sdv::toml::EInsertPreference ePreference) override;
|
||||
|
||||
/**
|
||||
* @brief Insert a TOML string as a child of the current collection node. If the collection is a table, the TOML string
|
||||
* should contain values and inline/external/array-table nodes with names. If the collection is an array, the TOML
|
||||
* string should contain and inline table nodes without names. Overload of sdv::toml::INodeCollectionInsert::InsertTOML.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
|
||||
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Dependable on the nodes defined in the TOML they
|
||||
* might be transferred to inline or they might be inserted at a different location.
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssTOML The TOML string to insert.
|
||||
* @param[in] bRollbackOnPartly If only part of the nodes could be inserted, no node will be inserted.
|
||||
* @return The result of the insertion.
|
||||
*/
|
||||
virtual sdv::toml::INodeCollectionInsert::EInsertResult InsertTOML(uint32_t uiIndex, const sdv::u8string& ssTOML,
|
||||
bool bRollbackOnPartly) override;
|
||||
virtual sdv::toml::INodeCollectionInsert::EInsertResult InsertTOML(/*in*/ const sdv::u8string& ssInsertBefore,
|
||||
/*in*/ const sdv::u8string& ssTOML, /*in*/ bool bRollbackOnPartly) override;
|
||||
|
||||
/**
|
||||
* @brief Insert a TOML string as a child of the current collection node. If the collection is a table, the TOML string
|
||||
* should contain values and inline/external/array-table nodes with names. If the collection is an array, the TOML
|
||||
* string should contain and inline table nodes without names.
|
||||
* @param[in] rptrInsertBefore The node to insert the TOML nodes before (if possible). Can be NULL, causing the TOML nodes
|
||||
* to be inserted at the end.
|
||||
* @param[in] ssTOML The TOML string to insert.
|
||||
* @param[in] bRollbackOnPartly If only part of the nodes could be inserted, no node will be inserted.
|
||||
* @return A pair structure with the result of the insertion and a vector of all the inserted nodes.
|
||||
*/
|
||||
std::pair<sdv::toml::INodeCollectionInsert::EInsertResult, std::vector<std::shared_ptr<CNode>>> InsertTOML(
|
||||
const std::shared_ptr<CNode>& rptrInsertBefore, const sdv::u8string& ssTOML, bool bRollbackOnPartly);
|
||||
|
||||
/**
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeUpdate::DeleteNode.
|
||||
@@ -1080,6 +1165,23 @@ namespace toml_parser
|
||||
*/
|
||||
virtual bool DeleteNode() override;
|
||||
|
||||
/**
|
||||
* @brief The derived class from the node collection can be inline or not. Overload of CNode::Inline.
|
||||
* @return Returns whether the node is an inline node.
|
||||
*/
|
||||
virtual bool Inline() const override;
|
||||
|
||||
/**
|
||||
* @brief With some node collections it is possible to switch between inline and normal. Overload of CNode::Inline.
|
||||
* @remarks Additional node composition information will be removed and the order within the parent node might be changed.
|
||||
* @param[in] bInline When set, try to switch to inline. Otherwise try to switch to normal.
|
||||
* @param[in] bIncludeChildren When set and bInline is not set, applicable child nodes are converted as well (only tables
|
||||
* and table-arrays can be defined as standard). Making a node inline is always including the children.
|
||||
* @return Returns whether the switch was successful. A switch to the same type (normal to normal or inline to inline is
|
||||
* always successful). When returning false, the switching might not be supported for this type.
|
||||
*/
|
||||
virtual bool Inline(bool bInline, bool bIncludeChildren = true) override;
|
||||
|
||||
/**
|
||||
* @brief Can the node convert to an inline definition? Overload of sdv::toml::INodeCollectionConvert::CanMakeInline.
|
||||
* @return Returns whether the conversion to inline is possible. Returns 'true' when the node is already inline.
|
||||
@@ -1101,10 +1203,12 @@ namespace toml_parser
|
||||
|
||||
/**
|
||||
* @brief Convert the node to a standard node. Overload of sdv::toml::INodeCollectionConvert::MakeStandard.
|
||||
* @param[in] bIncludeChildren When set, applicable child nodes are made are converted to standard nodes as well (only
|
||||
* tables and table-arrays can be defined as standard).
|
||||
* @return Returns whether the conversion was successful. Returns 'true' when the node was already defined as standard
|
||||
* node.
|
||||
*/
|
||||
virtual bool MakeStandard() override;
|
||||
virtual bool MakeStandard(/*in*/ bool bIncludeChildren) override;
|
||||
|
||||
/**
|
||||
* @brief Delete a node from the collection.
|
||||
@@ -1114,28 +1218,6 @@ namespace toml_parser
|
||||
*/
|
||||
bool DeleteNode(const std::shared_ptr<CNode>& rptrNode);
|
||||
|
||||
/**
|
||||
* @brief Insert the node into the view.
|
||||
* @remarks The node must be a descendant (direct child or an indirect child) of the node.
|
||||
* @details Insert the node into the vector (and remove it from any previous vector if still assigned). Inline nodes can be
|
||||
* assigned to stadard and inline nodes. Standard nodes can only be assigned to standard nodes. In the vector, first the
|
||||
* inline nodes and then the standard nodes are located. This means that an inline node will be placed before standard nodes
|
||||
* and standard nodes behind inline nodes, regardless of the index provided.
|
||||
* @param[in] uiIndex Location within the vector to insert the node. Could be sdv::toml::npos to insert as last node.
|
||||
* @param[in] rptrNode Reference to the smart pointer to the node to set the view for. If the node is not a direct child
|
||||
* node, the view pointer of the node will be set.
|
||||
* @return Returns true when the insertion was successful, false when node (likely because the node to insert is a standard
|
||||
* node, whereas this node is an inline node.
|
||||
*/
|
||||
bool InsertIntoView(uint32_t uiIndex, const std::shared_ptr<CNode>& rptrNode);
|
||||
|
||||
/**
|
||||
* @brief Remove a node from a view.
|
||||
* @param[in] rptrNode Reference to the smart pointer pointing to the node to remove.
|
||||
* @return Returns whether the removal was successful.
|
||||
*/
|
||||
bool RemoveFromView(const std::shared_ptr<CNode>& rptrNode);
|
||||
|
||||
/**
|
||||
* @brief Find the index belonging to the provided node.
|
||||
* @param[in] rptrNode Reference to the smart pointer holding the node to return the index for.
|
||||
@@ -1151,7 +1233,7 @@ namespace toml_parser
|
||||
bool IsDescendant(const std::shared_ptr<CNode>& rptrNode) const;
|
||||
|
||||
/**
|
||||
* @brief Generic inserting function for nodes.
|
||||
* @brief Generic add function for nodes.
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
|
||||
* E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be accessed and
|
||||
* traversed by using the index number in brackets. E.g. 'array[3]' would access the fourth element of the array 'array'.
|
||||
@@ -1160,10 +1242,6 @@ namespace toml_parser
|
||||
* @attention For an array, when no indexing is supplied, the latest entry will be returned.
|
||||
* @remarks If the node to insert exists already, but is marked implicit, the node will be returned and made explicit. In
|
||||
* all other cases the an error will occur that the node already exists.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
|
||||
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @param[in] rrangeKeyPath Reference to the token range containing the path to the node to insert.
|
||||
* @param[in] rtArgs Zero or more references to arguments passed to the constructor of the node classes being created by
|
||||
* this function.
|
||||
@@ -1171,7 +1249,7 @@ namespace toml_parser
|
||||
* there the returned node is a table within the table array.
|
||||
*/
|
||||
template <typename TNodeType, typename... TArgs>
|
||||
std::shared_ptr<CNode> Insert(uint32_t uiIndex, const CTokenRange& rrangeKeyPath, const TArgs&... rtArgs);
|
||||
std::shared_ptr<CNode> AddNodeFromRange(const CTokenRange& rrangeKeyPath, const TArgs&... rtArgs);
|
||||
|
||||
/**
|
||||
* @brief Combine the collection with the provided content (mathematical union).
|
||||
@@ -1191,6 +1269,13 @@ namespace toml_parser
|
||||
*/
|
||||
virtual bool Reduce(const std::shared_ptr<CNodeCollection>& rptrCollection) = 0;
|
||||
|
||||
/**
|
||||
* @brief When the parent changes (e.g. when moving items from one parser to the other), the items and all its sub-items
|
||||
* need to reasign the parser. Overload of CNode::ReassignParser.
|
||||
* @param[in] rParser Reference to the parser to assign.
|
||||
*/
|
||||
virtual void ReassignParser(CParser& rParser) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief When set, the child nodes need grouping (values following each other, tables and table arrays at the end).
|
||||
@@ -1228,8 +1313,6 @@ namespace toml_parser
|
||||
// The child node uses the parent node pointer to indicate which node holds node.
|
||||
// The child node uses the view node pointer to indicate which node displays the node content.
|
||||
|
||||
std::vector<std::shared_ptr<CNode>> m_vecNodeOrder; ///< Vector holding the child nodes (could contain grand children as
|
||||
///< well).
|
||||
std::list<std::shared_ptr<CNode>> m_lstNodes; ///< List holding the direct child nodes.
|
||||
std::list<std::shared_ptr<CNode>> m_lstRecycleBin; ///< List holding the child elements that were deleted. This will
|
||||
///< prevent destruction of the node class, which would otherwise
|
||||
@@ -1283,6 +1366,26 @@ namespace toml_parser
|
||||
*/
|
||||
virtual sdv::toml::ENodeType GetType() const override;
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of nodes. Overload of sdv::toml::INodeCollection::GetCount.
|
||||
* @return The amount of nodes.
|
||||
*/
|
||||
virtual uint32_t GetCount() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the node. Overload of CNodeCollection::Get.
|
||||
* @param[in] uiIndex Index of the node to get.
|
||||
* @return Smart pointer to the node object.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Get(uint32_t uiIndex) const override;
|
||||
|
||||
/**
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeUpdate::DeleteNode.
|
||||
* @attention A successful deletion will cause all interfaces to the current node to become inoperable.
|
||||
* @return Returns whether the deletion was successful.
|
||||
*/
|
||||
virtual bool DeleteNode() override;
|
||||
|
||||
/**
|
||||
* @brief Create the TOML text based on the content using an optional prefix node. Overload of CNode::GenerateTOML.
|
||||
* @param[in] rContext Reference to the context class to use during TOML code generation.
|
||||
@@ -1308,10 +1411,12 @@ namespace toml_parser
|
||||
* table doesn't have a name.
|
||||
* @remarks Additional node composition information will be removed and the order within the parent node might be changed.
|
||||
* @param[in] bInline When set, try to switch to inline. Otherwise try to switch to normal.
|
||||
* @param[in] bIncludeChildren When set and bInline is not set, applicable child nodes are converted as well (only tables
|
||||
* and table-arrays can be defined as standard). Making a node inline is always including the children.
|
||||
* @return Returns whether the switch was successful. A switch to the same type (normal to normal or inline to inline is
|
||||
* always successful). When returning false, the switching might not be supported for this type.
|
||||
*/
|
||||
virtual bool Inline(bool bInline) override;
|
||||
virtual bool Inline(bool bInline, bool bIncludeChildren = true) override;
|
||||
|
||||
/**
|
||||
* @brief Checks whether the table was explicitly defined. Overload of CNodeCollection::ExplicitlyDefined.
|
||||
@@ -1342,9 +1447,17 @@ namespace toml_parser
|
||||
*/
|
||||
virtual bool Reduce(const std::shared_ptr<CNodeCollection>& rptrCollection) override;
|
||||
|
||||
/**
|
||||
* @brief After every insert, deletion and shift, the node order of this and all sub- tables need to be rebuild.
|
||||
* @param[in] bForce Force rebuild, even if locked.
|
||||
*/
|
||||
virtual void RebuildNodeOrder(bool bForce) override;
|
||||
|
||||
private:
|
||||
bool m_bDefinedExplicitly = true; ///< When set, the table is defined explicitly.
|
||||
bool m_bInline = false; ///< Flag determining whether the table is inline or not.
|
||||
bool m_bDefinedExplicitly = true; ///< When set, the table is defined explicitly.
|
||||
bool m_bInline = false; ///< Flag determining whether the table is inline or not.
|
||||
std::vector<std::shared_ptr<CNode>> m_vecNodeOrder; ///< Vector holding the child nodes (could contain grand children as
|
||||
///< well).
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1426,10 +1539,28 @@ namespace toml_parser
|
||||
* @attention Array element access indices starts with 0!
|
||||
* @attention For an array element inserting, when no indexing is supplied, the latest entry will be returned.
|
||||
* @param[in] rssPath Reference to the path of the node to searched for.
|
||||
* @return Returns a shared pointer to the wanted Node if it was found or a node with invalid content if it was not found.
|
||||
* @return Returns a shared pointer to the wanted node if it was found or a node with invalid content if it was not found.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Direct(const std::string& rssPath) const override;
|
||||
|
||||
/**
|
||||
* @brief Get or create the parent nodes automotatically from the path. Overload of CNodeCollection::SmartParentCreate.
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
|
||||
* E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be accessed and
|
||||
* traversed by using the index number in brackets. E.g. 'array[3]' would access the fourth element of the array 'array'.
|
||||
* These access conventions can also be chained like 'table.array[2][1].subtable.integerElement'.
|
||||
* @attention Array indexing starts with 0!
|
||||
* @attention For an array, when no indexing or a too large index number is supplied, a new entry will be created and
|
||||
* returned.
|
||||
* @param[in] rssPath The path of the node to searched for.
|
||||
* @param[in] bInsertTableArray Since a table array consists of an array and a table, this is different than the other
|
||||
* insertions that only insert one element. Some special treatment is needed at certain points.
|
||||
* @return Returns a pair with the shared pointer to the parent node and the leftover name. If the creation could not be
|
||||
* done, a NULL pointer is returned.
|
||||
*/
|
||||
virtual std::pair<std::shared_ptr<CNodeCollection>, std::string> SmartParentCreate(const std::string& rssPath,
|
||||
bool bInsertTableArray = false) override;
|
||||
|
||||
/**
|
||||
* @brief Create the TOML text based on the content using an optional prefix node. Overload of CNode::GenerateTOML.
|
||||
* @param[in] rContext Reference to the context class to use during TOML code generation.
|
||||
@@ -1450,13 +1581,6 @@ namespace toml_parser
|
||||
*/
|
||||
bool TableArray() const;
|
||||
|
||||
/**
|
||||
* @brief Can the node convert to a standard definition? Overload of sdv::toml::INodeCollectionConvert::CanMakeStandard.
|
||||
* @return Returns whether the conversion to standard is possible. Returns 'true' when the node is already defined as
|
||||
* standard node.
|
||||
*/
|
||||
virtual bool CanMakeStandard() const override;
|
||||
|
||||
/**
|
||||
* @brief The derived class from the node collection can be inline or not. Overload of CNode::Inline.
|
||||
* @return Returns whether the node is an inline node.
|
||||
@@ -1472,10 +1596,19 @@ namespace toml_parser
|
||||
* doesn't have a name that can be used to define the explicit table array.
|
||||
* @remarks Additional node composition information will be removed and the order within the parent node might be changed.
|
||||
* @param[in] bInline When set, try to switch to inline. Otherwise try to switch to normal.
|
||||
* @param[in] bIncludeChildren When set and bInline is not set, applicable child nodes are converted as well (only tables
|
||||
* and table-arrays can be defined as standard). Making a node inline is always including the children.
|
||||
* @return Returns whether the switch was successful. A switch to the same type (normal to normal or inline to inline is
|
||||
* always successful). When returning false, the switching might not be supported for this type.
|
||||
*/
|
||||
virtual bool Inline(bool bInline) override;
|
||||
virtual bool Inline(bool bInline, bool bIncludeChildren = true) override;
|
||||
|
||||
/**
|
||||
* @brief Can the node convert to a standard definition? Overload of sdv::toml::INodeCollectionConvert::CanMakeStandard.
|
||||
* @return Returns whether the conversion to standard is possible. Returns 'true' when the node is already defined as
|
||||
* standard node.
|
||||
*/
|
||||
virtual bool CanMakeStandard() const override;
|
||||
|
||||
/**
|
||||
* @brief Does the last child node need a comma following the node?
|
||||
@@ -1534,7 +1667,7 @@ namespace toml_parser
|
||||
* @brief Constructor
|
||||
* @param[in] rparser Reference to the TOML parser.
|
||||
*/
|
||||
CRootTable(CParser& rparser) : CTable(rparser, "root", "", false)
|
||||
CRootTable(CParser& rparser) : CTable(rparser, "root", "", false, true)
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -1550,20 +1683,25 @@ namespace toml_parser
|
||||
*/
|
||||
virtual bool Inline() const override
|
||||
{
|
||||
// The root node can never be inline.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief With some node collections it is possible to switch between inline and normal. Overload of
|
||||
* CNodeCollection::Inline.
|
||||
* @brief Switch between inline and explicit table definition. Overload of CNodeCollection::Inline.
|
||||
* @attention It is not possible to switch to an explicit table definition if the table is part of an array, since the
|
||||
* table doesn't have a name.
|
||||
* @remarks Additional node composition information will be removed and the order within the parent node might be changed.
|
||||
* @param[in] bInline When set, try to switch to inline. Otherwise try to switch to normal.
|
||||
* @param[in] bIncludeChildren When set and bInline is not set, applicable child nodes are converted as well (only tables
|
||||
* and table-arrays can be defined as standard). Making a node inline is always including the children.
|
||||
* @return Returns whether the switch was successful. A switch to the same type (normal to normal or inline to inline is
|
||||
* always successful). When returning false, the switching might not be supported for this type.
|
||||
*/
|
||||
virtual bool Inline(bool bInline) override
|
||||
virtual bool Inline(bool bInline, bool bIncludeChildren = true) override
|
||||
{
|
||||
return bInline == false;
|
||||
// Pass call to table implementation.
|
||||
return CTable::Inline(bInline, bIncludeChildren);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1580,7 +1718,7 @@ namespace toml_parser
|
||||
}
|
||||
|
||||
template <typename TNodeType, typename... TArgs>
|
||||
inline std::shared_ptr<CNode> CNodeCollection::Insert(uint32_t uiIndex, const CTokenRange& rrangeKeyPath, const TArgs&... rtArgs)
|
||||
inline std::shared_ptr<CNode> CNodeCollection::AddNodeFromRange(const CTokenRange& rrangeKeyPath, const TArgs&... rtArgs)
|
||||
{
|
||||
// Get the first part of the node
|
||||
auto prKey = SplitNodeKey(rrangeKeyPath);
|
||||
@@ -1613,9 +1751,8 @@ namespace toml_parser
|
||||
"' exists already, but is not a table array.");
|
||||
|
||||
// Create the table.
|
||||
ptrNode = ptrTableArray->Insert<CTable>(sdv::toml::npos, CTokenRange(prKey.first, prKey.first.get().Next()),
|
||||
ptrNode = ptrTableArray->AddNodeFromRange<CTable>(CTokenRange(prKey.first, prKey.first.get().Next()),
|
||||
false, true);
|
||||
ptrNode->SetViewPtr(Cast<CNodeCollection>());
|
||||
} else if (!Cast<CArray>() && itNode != m_lstNodes.end())
|
||||
{
|
||||
// If existing... this might be a duplicate if not explicitly defined before.
|
||||
@@ -1644,7 +1781,7 @@ namespace toml_parser
|
||||
// If the current node is implicit, take over the inline flag (this determines whether a sub-table definition is
|
||||
// allowed or not).
|
||||
if (!ExplicitlyDefined())
|
||||
Inline(ptrNode->Inline());
|
||||
Inline(ptrNode->Inline(), false);
|
||||
}
|
||||
}
|
||||
else // Intermediate node
|
||||
@@ -1663,6 +1800,9 @@ namespace toml_parser
|
||||
auto prNextKey = SplitNodeKey(prKey.second);
|
||||
if (prNextKey.first.get().Category() != ETokenCategory::token_integer)
|
||||
{
|
||||
// The table array should have an ordered vector. This is not the case yet. Rebuild the table array.
|
||||
ptrNode->Cast<CTableArray>()->RebuildNodeOrder(true);
|
||||
|
||||
// Get the last table
|
||||
if (!ptrNode->Cast<CTableArray>()->GetCount())
|
||||
throw XTOMLParseException("The parent table array node '" + prKey.first.get().StringValue() +
|
||||
@@ -1700,23 +1840,14 @@ namespace toml_parser
|
||||
std::shared_ptr<CNodeCollection> ptrNodeCollection = ptrNode->Cast<CNodeCollection>();
|
||||
if (!ptrNodeCollection)
|
||||
throw XTOMLParseException("Parent node is not an array or table '" + ptrNode->GetPath(true) + "'.");
|
||||
ptrNode = ptrNodeCollection->Insert<TNodeType>(sdv::toml::npos, prKey.second, rtArgs...);
|
||||
ptrNode = ptrNodeCollection->AddNodeFromRange<TNodeType>(prKey.second, rtArgs...);
|
||||
if (!ptrNode)
|
||||
throw XTOMLParseException("Could not create the node '" + prKey.first.get().StringValue() + "'.");
|
||||
}
|
||||
|
||||
// Insert the node at the requested location if this node is inline or this is the view of the node.
|
||||
auto itPos = (static_cast<size_t>(uiIndex) >= m_vecNodeOrder.size()) ? m_vecNodeOrder.end() :
|
||||
m_vecNodeOrder.begin() + static_cast<size_t>(uiIndex);
|
||||
m_vecNodeOrder.insert(itPos, ptrNode);
|
||||
if (ptrNode->GetParentPtr() != Cast<CNodeCollection>())
|
||||
ptrNode->SetViewPtr(Cast<CNodeCollection>());
|
||||
|
||||
// Return the result
|
||||
return ptrNode;
|
||||
}
|
||||
|
||||
|
||||
} // namespace toml_parser
|
||||
|
||||
#endif // !defined PARSER_NODE_TOML_H
|
||||
@@ -54,6 +54,9 @@ namespace toml_parser
|
||||
|
||||
try
|
||||
{
|
||||
// Lock the rebuild of the node order
|
||||
auto lock = CreateRebuildLockObject();
|
||||
|
||||
// Run through all tokens of the lexer and process the tokens.
|
||||
bool bEOF = false; // Explicit test, since the peek could return EOF, but the cursor might not be at the end yet.
|
||||
while (!bEOF && !m_lexer.IsEnd())
|
||||
@@ -95,7 +98,7 @@ namespace toml_parser
|
||||
}
|
||||
catch (const sdv::toml::XTOMLParseException& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
std::cerr << e.what() << std::endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -115,6 +118,11 @@ namespace toml_parser
|
||||
return m_lexer;
|
||||
}
|
||||
|
||||
CNodeIndexer& CParser::Indexer()
|
||||
{
|
||||
return m_indexer;
|
||||
}
|
||||
|
||||
const CNodeCollection& CParser::Root() const
|
||||
{
|
||||
auto ptrCollection = m_ptrRoot->Cast<CTable>();
|
||||
@@ -139,6 +147,49 @@ namespace toml_parser
|
||||
return m_ptrRoot->GenerateTOML(rssPrefixKey);
|
||||
}
|
||||
|
||||
CParser::CLockRebuild::CLockRebuild(CParser& rParser) : m_rParser(rParser)
|
||||
{
|
||||
rParser.IncrRebuildLockCnt();
|
||||
}
|
||||
|
||||
CParser::CLockRebuild::CLockRebuild(const CLockRebuild& rLockRebuild) : m_rParser(rLockRebuild.m_rParser)
|
||||
{
|
||||
m_rParser.IncrRebuildLockCnt();
|
||||
}
|
||||
|
||||
CParser::CLockRebuild::CLockRebuild(CLockRebuild&& rLockRebuild) : m_rParser(rLockRebuild.m_rParser)
|
||||
{
|
||||
m_rParser.IncrRebuildLockCnt();
|
||||
}
|
||||
|
||||
CParser::CLockRebuild::~CLockRebuild()
|
||||
{
|
||||
m_rParser.DecrRebuildLockCnt();
|
||||
}
|
||||
|
||||
CParser::CLockRebuild CParser::CreateRebuildLockObject()
|
||||
{
|
||||
return CLockRebuild(*this);
|
||||
}
|
||||
|
||||
bool CParser::RebuildLocked() const
|
||||
{
|
||||
return m_nRebuildLockCnt ? true : false;
|
||||
}
|
||||
|
||||
void CParser::IncrRebuildLockCnt()
|
||||
{
|
||||
++m_nRebuildLockCnt;
|
||||
}
|
||||
|
||||
void CParser::DecrRebuildLockCnt()
|
||||
{
|
||||
if (!m_nRebuildLockCnt)
|
||||
return; // Should not occur
|
||||
--m_nRebuildLockCnt;
|
||||
if (!m_nRebuildLockCnt) Root().RebuildNodeOrder(false);
|
||||
}
|
||||
|
||||
void CParser::ProcessTable(CNodeTokenRange& rNodeRange)
|
||||
{
|
||||
// Get the table path (table name preceded by parent tables separated with dots).
|
||||
@@ -154,7 +205,7 @@ namespace toml_parser
|
||||
m_lexer.SmartExtendNodeRange(rNodeRange);
|
||||
|
||||
// Add the table to the root
|
||||
auto ptrTable = m_ptrRoot->Insert<CTable>(sdv::toml::npos, rangeKeyPath, false);
|
||||
auto ptrTable = m_ptrRoot->AddNodeFromRange<CTable>(rangeKeyPath, false);
|
||||
if (ptrTable)
|
||||
{
|
||||
m_ptrCurrentCollection = ptrTable->Cast<CTable>();
|
||||
@@ -176,7 +227,7 @@ namespace toml_parser
|
||||
m_lexer.SmartExtendNodeRange(rNodeRange);
|
||||
|
||||
// Add the table array to the root
|
||||
auto ptrTableArray = m_ptrRoot->Insert<CTableArray>(sdv::toml::npos, rangeKeyPath);
|
||||
auto ptrTableArray = m_ptrRoot->AddNodeFromRange<CTableArray>(rangeKeyPath);
|
||||
if (ptrTableArray)
|
||||
{
|
||||
m_ptrCurrentCollection = ptrTableArray->Cast<CNodeCollection>();
|
||||
@@ -226,46 +277,43 @@ namespace toml_parser
|
||||
switch (rAssignmentValue.Category())
|
||||
{
|
||||
case ETokenCategory::token_boolean:
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CBooleanNode>(sdv::toml::npos, rrangeKeyPath, rAssignmentValue.BooleanValue(),
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CBooleanNode>(rrangeKeyPath, rAssignmentValue.BooleanValue(),
|
||||
rAssignmentValue.RawString());
|
||||
break;
|
||||
case ETokenCategory::token_integer:
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CIntegerNode>(sdv::toml::npos, rrangeKeyPath, rAssignmentValue.IntegerValue(),
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CIntegerNode>(rrangeKeyPath, rAssignmentValue.IntegerValue(),
|
||||
rAssignmentValue.RawString());
|
||||
break;
|
||||
case ETokenCategory::token_float:
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CFloatingPointNode>(sdv::toml::npos, rrangeKeyPath, rAssignmentValue.FloatValue(),
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CFloatingPointNode>(rrangeKeyPath, rAssignmentValue.FloatValue(),
|
||||
rAssignmentValue.RawString());
|
||||
break;
|
||||
case ETokenCategory::token_string:
|
||||
switch (rAssignmentValue.StringType())
|
||||
{
|
||||
case ETokenStringType::literal_string:
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CStringNode>(sdv::toml::npos, rrangeKeyPath, rAssignmentValue.StringValue(),
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CStringNode>(rrangeKeyPath, rAssignmentValue.StringValue(),
|
||||
CStringNode::EQuotationType::literal_string, rAssignmentValue.RawString());
|
||||
break;
|
||||
case ETokenStringType::multi_line_literal:
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CStringNode>(
|
||||
sdv::toml::npos, rrangeKeyPath, rAssignmentValue.StringValue(), CStringNode::EQuotationType::multi_line_literal,
|
||||
rAssignmentValue.RawString());
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CStringNode>(rrangeKeyPath, rAssignmentValue.StringValue(),
|
||||
CStringNode::EQuotationType::multi_line_literal, rAssignmentValue.RawString());
|
||||
break;
|
||||
case ETokenStringType::multi_line_quoted:
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CStringNode>(
|
||||
sdv::toml::npos, rrangeKeyPath, rAssignmentValue.StringValue(), CStringNode::EQuotationType::multi_line_quoted,
|
||||
rAssignmentValue.RawString());
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CStringNode>(rrangeKeyPath, rAssignmentValue.StringValue(),
|
||||
CStringNode::EQuotationType::multi_line_quoted, rAssignmentValue.RawString());
|
||||
break;
|
||||
case ETokenStringType::quoted_string:
|
||||
default:
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CStringNode>(
|
||||
sdv::toml::npos, rrangeKeyPath, rAssignmentValue.StringValue(), CStringNode::EQuotationType::quoted_string,
|
||||
rAssignmentValue.RawString());
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CStringNode>(rrangeKeyPath, rAssignmentValue.StringValue(),
|
||||
CStringNode::EQuotationType::quoted_string, rAssignmentValue.RawString());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ETokenCategory::token_syntax_array_open:
|
||||
{
|
||||
auto ptrCurrentCollectionStored = m_ptrCurrentCollection;
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CArray>(sdv::toml::npos, rrangeKeyPath);
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CArray>(rrangeKeyPath);
|
||||
m_ptrCurrentCollection = ptrNode->Cast<CNodeCollection>();
|
||||
m_stackEnvironment.push(EEnvironment::array);
|
||||
ProcessArray(rNodeRange);
|
||||
@@ -276,7 +324,7 @@ namespace toml_parser
|
||||
case ETokenCategory::token_syntax_inline_table_open:
|
||||
{
|
||||
auto ptrCurrentCollectionStored = m_ptrCurrentCollection;
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CTable>(sdv::toml::npos, rrangeKeyPath, true);
|
||||
ptrNode = m_ptrCurrentCollection->AddNodeFromRange<CTable>(rrangeKeyPath, true);
|
||||
m_ptrCurrentCollection = ptrNode->Cast<CNodeCollection>();
|
||||
m_stackEnvironment.push(EEnvironment::inline_table);
|
||||
ProcessInlineTable(rNodeRange);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "lexer_toml.h"
|
||||
#include "parser_node_toml.h"
|
||||
#include "miscellaneous.h"
|
||||
#include "parser_node_indexer.h"
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -25,7 +26,9 @@
|
||||
/// The TOML parser namespace
|
||||
namespace toml_parser
|
||||
{
|
||||
// Forward declarations
|
||||
class CNode;
|
||||
class CNodeCollection;
|
||||
|
||||
/**
|
||||
* @brief Creates a tree structure from input of UTF-8 encoded TOML source data
|
||||
@@ -33,6 +36,10 @@ namespace toml_parser
|
||||
class CParser : public sdv::IInterfaceAccess, public sdv::toml::ITOMLParser
|
||||
{
|
||||
public:
|
||||
// Forward declaration
|
||||
class CLockRebuild;
|
||||
friend CLockRebuild; ///< Friend class can trigger manage rebuild lock counter.
|
||||
|
||||
/**
|
||||
* @brief Construct a new Parser object
|
||||
* @param[in] rssString UTF-8 encoded data of a TOML source
|
||||
@@ -66,6 +73,12 @@ namespace toml_parser
|
||||
*/
|
||||
CLexer& Lexer();
|
||||
|
||||
/**
|
||||
* @brief Get the indexer object managing the overall order of the nodes.
|
||||
* @return Reference to the index object.
|
||||
*/
|
||||
CNodeIndexer& Indexer();
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Return the root node.
|
||||
@@ -85,7 +98,65 @@ namespace toml_parser
|
||||
*/
|
||||
std::string GenerateTOML(const std::string& rssPrefixKey = std::string()) const;
|
||||
|
||||
/**
|
||||
* @brief Lock rebuild object preventing rebuilding the node order of all the tables.
|
||||
*/
|
||||
class CLockRebuild
|
||||
{
|
||||
friend CParser; ///< Parser can access the constructor
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rParser Reference to the parser object
|
||||
*/
|
||||
CLockRebuild(CParser& rParser);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param[in] rLockRebuild Reference to another rebuild lock object.
|
||||
*/
|
||||
CLockRebuild(const CLockRebuild& rLockRebuild);
|
||||
|
||||
/**
|
||||
* @brief Move constructor
|
||||
* @param[in] rLockRebuild Reference to another rebuild lock object.
|
||||
*/
|
||||
CLockRebuild(CLockRebuild&& rLockRebuild);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CLockRebuild();
|
||||
|
||||
private:
|
||||
CParser& m_rParser; ///< Reference to the parser object
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a rebuild lock object. During the lifetime of the object rebuilding the node order is locked using the lock
|
||||
* counter method.
|
||||
* @return An instance of the rebuild lock object.
|
||||
*/
|
||||
CLockRebuild CreateRebuildLockObject();
|
||||
|
||||
/**
|
||||
* @brief Returns whether rebuild is locked at the moment.
|
||||
* @return Set when rebuild is locked.
|
||||
*/
|
||||
bool RebuildLocked() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Increase the rebuild lock counter. A lock count larger than 0 will prevent a rebuild.
|
||||
*/
|
||||
void IncrRebuildLockCnt();
|
||||
|
||||
/**
|
||||
* @brief Decrease the rebuild lock counter. A lock count of 0 will trigger the rebuild.
|
||||
*/
|
||||
void DecrRebuildLockCnt();
|
||||
|
||||
/**
|
||||
* @brief Process a table declaration.
|
||||
* @param[in, out] rNodeRange Reference to the extended token range of the node.
|
||||
@@ -139,10 +210,13 @@ namespace toml_parser
|
||||
inline_table ///< Environment for a table
|
||||
};
|
||||
|
||||
enum_stack<EEnvironment, EEnvironment::none> m_stackEnvironment; ///< Tracking of environments in nested structures.
|
||||
std::shared_ptr<CRootTable> m_ptrRoot; ///< The one root node.
|
||||
std::shared_ptr<CNodeCollection> m_ptrCurrentCollection; ///< The current collection node.
|
||||
CLexer m_lexer; ///< Lexer.
|
||||
enum_stack<EEnvironment, EEnvironment::none> m_stackEnvironment; ///< Tracking of environments in nested structures.
|
||||
std::shared_ptr<CRootTable> m_ptrRoot; ///< The one root node.
|
||||
std::shared_ptr<CNodeCollection> m_ptrCurrentCollection; ///< The current collection node.
|
||||
CLexer m_lexer; ///< Lexer object user for lexing the TOML code.
|
||||
CNodeIndexer m_indexer; ///< Indexer managing the oberall order of the nodes.
|
||||
size_t m_nRebuildLockCnt = 0; ///< A lock counter > 0 will prevent the node order
|
||||
///< rebuild.
|
||||
};
|
||||
} // namespace toml_parser
|
||||
|
||||
|
||||
Reference in New Issue
Block a user