#ifndef VAPI_REPOSITORY_H #define VAPI_REPOSITORY_H #include #include #include #include #include #include #include #include #include #include "module.h" #include "object_lifetime_control.h" #include "iso_monitor.h" /** * @brief repository service providing functionality to load modules, create objects and access exiting objects */ 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: /** * @brief Default constructor */ CRepository() = default; // Interface map BEGIN_SDV_INTERFACE_MAP() SDV_INTERFACE_ENTRY(sdv::core::IObjectAccess) SDV_INTERFACE_ENTRY(sdv::core::IRepositoryMarshallCreate) SDV_INTERFACE_ENTRY(sdv::core::IRepositoryUtilityCreate) END_SDV_INTERFACE_MAP() /** * @brief Switch all components in config mode. */ void SetConfigMode(); /** * @brief Switch all components in running mode. */ void SetRunningMode(); /** * @brief Get the object instance previously created through the repository service. Overload of IObjectAccess::GetObject. * @param[in] ssObjectName The name of the requested object. * @return Returns the IInterfaceAccess interface of the object instance if found and nullptr otherwise. */ virtual sdv::IInterfaceAccess* GetObject(/*in*/ const sdv::u8string& ssObjectName) override; /** * @brief Get the object instance previously created through the repository service. * @attention Utilities cannot be returned by this function. * @param[in] tObjectID The ID of the requested object. * @return Returns the IInterfaceAccess interface of the object instance if found and nullptr otherwise. */ virtual sdv::IInterfaceAccess* GetObjectByID(/*in*/ sdv::core::TObjectID tObjectID) override; /** * @brief Creates an utility object from a previously loaded module. Overload of IRepositoryUtilityCreate::CreateUtility. * @attention Utilities are standalone objects. Use IObjectDestroy to destroy the utility. * @param[in] ssClassName The name of the object class to be created. * @param[in] ssObjectConfig Optional configuration handed over to the object upon creation via IObjectControl. * @return Returns the IInterfaceAccess interface of newly created utility. */ virtual sdv::IInterfaceAccess* CreateUtility(/*in*/ const sdv::u8string& ssClassName, /*in*/ const sdv::u8string& ssObjectConfig) override; /** * @brief Create a proxy object for the interface with the supplied ID. If successful, this object is initialized, but * not linked to any other object within the system. Overload of sdv::core::IRepositoryMarshallCreate::CreateProxyObject. * @details Create a proxy object with the name "proxy_". "ifc_id" is the decimal value of an interface ID. * @param[in] id The interface ID to create the object for. * @return Returns the interface to the proxy object. Destruction of the object can be achieved through IObjectDestroy. */ virtual sdv::IInterfaceAccess* CreateProxyObject(/*in*/ sdv::interface_id id) override; /** * @brief Create a stub object for the interface with the supplied ID. If successful, this object is initialized, but * not linked to any other object within the system. Overload of sdv::core::IRepositoryMarshallCreate::CreateStubObject. * @details Create a stub object with the name "stub_". "ifc_id" is the decimal value of an interface ID. * @param[in] id The interface ID to create the object for. * @return Returns the interface to the stub object. Destruction of the object can be achieved through IObjectDestroy. */ 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. * @details For standalone and essential applications, this function allows the creation of system, device and service * objects if the module was loaded previously. For the main and isolated application, this function allows the * creation of complex services only and only those that are in the installation. For the isolated application only one * complex service can be created. External apps, utilities, and proxy and stub objects cannot be created at all using * this function. * Objects that the to be create object is depending on will be created as well. For the main application this is * limited to complex services. Isolated applications cannot load other services; this is taken over by the main * application. * @param[in] ssClassName The name of the object class to be created. For the main application, the class string could * be empty for the main application if the object was defined in the installation. * @param[in] ssObjectName Name of the object, required to be unique. For standalone and essential applications, the * name string can be empty, in which case the object might either provide a name proposal or the name is the same as * 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. * @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. */ 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. * @param[in] tModuleID Module ID that contains the object class to create the object with. * @param[in] ssClassName The name of the object class to be created. * @param[in] ssObjectName Optional name of the object - required to be unique. If not supplied, the object might * either provide a name proposal or the name is the same as 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. * @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. */ virtual sdv::core::TObjectID CreateObjectFromModule(/*in*/ sdv::core::TModuleID tModuleID, /*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 * 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. * @return Returns whether the object destruction was successful. */ virtual bool DestroyObject(/*in*/ const sdv::u8string& ssObjectName) override; public: /** * @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 * be empty for the main application if the object was defined in the installation. * @param[in] ssObjectName Name of the object, required to be unique. For standalone and essential applications, the * name string can be empty, in which case the object might either provide a name proposal or the name is the same as * 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. * @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); /** * @brief Destroy a previously created object with the supplied name. Internal function not accessible through the interface. * @details For standalone and essential applications previously created system, device and service objects can be * 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. * @return Returns whether the object destruction was successful. */ bool DestroyObject2(/*in*/ const sdv::u8string& ssObjectName); /** * @brief Register as foreign object and make it public to the system with the given name. Overload of * sdv::core::IRegisterForeignObject::RegisterObject. * @param[in] pObjectIfc Interface of the object to be registered. * @param[in] ssObjectName The name under which the object - required to be unique. * @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. */ virtual sdv::core::TObjectID RegisterObject(/*in*/ sdv::IInterfaceAccess* pObjectIfc, /*in*/ const sdv::u8string& ssObjectName) override; /** * @brief Register the core repository. * @param[in] pCoreRepository Pointer to the proxy interface of the core repository. */ virtual void LinkCoreRepository(/*in*/ sdv::IInterfaceAccess* pCoreRepository) override; /** * @brief Unlink a previously linked core repository. */ virtual void UnlinkCoreRepository() override; /** * @brief Find the class information of an object with the supplied name. Overload of * sdv::core::IRepositoryControl::IRepositoryInfo::FindClass. * @param[in] ssClassName Object class name. * @return The object class information. */ virtual sdv::SClassInfo FindClass(/*in*/ const sdv::u8string& ssClassName) const override; /** * @brief Get a list of all the instantiated objects. Overload of sdv::core::IRepositoryControl::IRepositoryInfo::GetObjectList. * @return Sequence containing the object information structures. */ virtual sdv::sequence GetObjectList() const override; /** * @brief Get the object info for the requested object. Overload of sdv::core::IRepositoryInfo::GetObjectInfo. * @param[in] tObjectID The object ID to return the object information for. * @return The object information structure if the object is available or an empty structure if not. */ virtual sdv::core::SObjectInfo GetObjectInfo(/*in*/ sdv::core::TObjectID tObjectID) const override; /** * @brief Find an object with the supplied name. Only object instances that are in the service list can be found with this * function (devices, basic and complex services, and system objects). Overload of sdv::core::IRepositoryInfo::FindObject. * @param[in] ssObjectName Object name to search for. * @return The object information structure if the object is available or an empty structure if not. */ virtual sdv::core::SObjectInfo FindObject(/*in*/ const sdv::u8string& ssObjectName) const override; /** * @brief Remove an object instance from the local object map. Overload of IObjectDestroyHandler::OnDestroyObject. * @param[in] pObject Interface pointer to the object instance. */ virtual void OnDestroyObject(sdv::IInterfaceAccess* pObject) override; /** * @brief Destroy all objects from the service map created for a specific module. * @param[in] tModuleID Module ID that contains the object class to destroy. */ void DestroyModuleObjects(sdv::core::TModuleID tModuleID); /** * @brief Destroy all objects from the service map. * @remarks In Emergency, the objects should be removed without unloading to prevent any more calls to take place. The reason * is, that the system could do an emergency shutdown and part of the system might have been cleaned up already and part not. * @param[in] rvecIgnoreObjects Reference to the vector of objects to not destroy. * @param[in] bForce Force destruction (remove without calling any more function). */ void DestroyAllObjects(const std::vector&rvecIgnoreObjects, bool bForce = false); /** * @brief Reset the current config baseline. */ void ResetConfigBaseline(); /** * @brief Save the configuration of all components. * @return The string containing all the components. */ std::string SaveConfig(); private: /** * @brief Create an isolated object (object running in a separate process). Only allowed to be called by the main application. * @param[in] rsClassInfo Reference to the class information structure of the object. * @param[in] rssObjectName Reference to the name of the object - required to be unique. * @param[in] rssObjectConfig Reference to an optional configuration handed over to the object upon creation via IObjectControl. * @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 CreateIsolatedObject(const sdv::SClassInfo& rsClassInfo, const sdv::u8string& rssObjectName, const sdv::u8string& rssObjectConfig); /** * @brief Creates an object from the supplied module instance. * @param[in] rptrModule Reference to the module that contains the object class to create the object with. * @param[in] rsClassInfo Reference to the class information structure of the object. * @param[in] rssObjectName Reference to the name of the object - required to be unique. * @param[in] rssObjectConfig Reference to an optional configuration handed over to the object upon creation via IObjectControl. * @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 InternalCreateObject(const std::shared_ptr& rptrModule, const sdv::SClassInfo& rsClassInfo, const sdv::u8string& rssObjectName, const sdv::u8string& rssObjectConfig); /** * @brief Create a new unique object ID. * @return The created object ID. */ static sdv::core::TObjectID CreateObjectID(); /** * @brief Get a list of depending object instances of a specific class. * @param[in] rssClass Reference to the class name. * @return Returns a list of object instances. */ std::vector 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 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 ptrIsoMon; ///< Object being monitored for shutdown. }; using TObjectMap = std::map>; using TOrderedObjectList = std::list>; using TObjectIDList = std::list>; using TServiceMap = std::map; using TIsolationMap = std::map>; using TLocalObjectMap = std::map>; using TConfigSet = std::set; mutable std::shared_mutex m_mtxObjects; ///< Protects against concurrent access. TOrderedObjectList m_lstOrderedServiceObjects; ///< List of service object IDs in order of creation. TServiceMap m_mapServiceObjects; ///< Map of service objects indexed by object name an pointing ///< to the entry in the list. TLocalObjectMap m_mapLocalObjects; ///< Map with local objects indexed by object pointer. 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). 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. }; #ifndef DO_NOT_INCLUDE_IN_UNIT_TEST /** * @brief Repository service */ class CRepositoryService : public sdv::CSdvObject { public: CRepositoryService() = default; // Interface map BEGIN_SDV_INTERFACE_MAP() SDV_INTERFACE_CHAIN_MEMBER(GetRepository()) SDV_INTERFACE_ENTRY_MEMBER(sdv::core::IRepositoryInfo, GetRepository()) SDV_INTERFACE_SET_SECTION_CONDITION(EnableRepositoryObjectControl(), 1) SDV_INTERFACE_SECTION(1) SDV_INTERFACE_ENTRY_MEMBER(sdv::core::IRepositoryControl, GetRepository()) SDV_INTERFACE_DEFAULT_SECTION() SDV_INTERFACE_SET_SECTION_CONDITION(EnableRepositoryRegisterForeignApp(), 2) SDV_INTERFACE_SECTION(2) SDV_INTERFACE_ENTRY_MEMBER(sdv::core::IRegisterForeignObject, GetRepository()) SDV_INTERFACE_DEFAULT_SECTION() SDV_INTERFACE_SET_SECTION_CONDITION(EnableRepositoryLink(), 3) SDV_INTERFACE_SECTION(3) SDV_INTERFACE_ENTRY_MEMBER(sdv::core::ILinkCoreRepository, GetRepository()) END_SDV_INTERFACE_MAP() // Object declarations DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::SystemObject) DECLARE_OBJECT_CLASS_NAME("RepositoryService") DECLARE_OBJECT_SINGLETON() /** * @brief Get access to the repository. * @return Returns a reference to the one repository of this module. */ static CRepository& GetRepository(); /** * @brief When set, the repository object control access will be enabled. * @return Returns whether object control interface access is granted. */ static bool EnableRepositoryObjectControl(); /** * @brief When set, the foreign app registration into the repository will be enabled. * @return Returns whether foreign app rgeistration interface access is granted. */ static bool EnableRepositoryRegisterForeignApp(); /** * @brief When set, the core repository link access will be enabled. * @return Returns whether core repository link interface access is granted. */ static bool EnableRepositoryLink(); }; DEFINE_SDV_OBJECT_NO_EXPORT(CRepositoryService) #endif #endif // !define VAPI_REPOSITORY_H