Commit eef09ec9 authored by Bryan Berthou's avatar Bryan Berthou
Browse files

Move registry/factory/module mechanisms from PARTONS to ElementaryUtils

to be able to refactor integration as module in NumA++.
parent 19899287
#ifndef BASE_OBJECT_H
#define BASE_OBJECT_H
/**
* @file BaseObject.h
* @author Bryan BERTHOU (SPhN / CEA Saclay)
* @date September 09, 2014
* @version 1.0
*/
#include <string>
namespace ElemUtils {
class Packet;
} /* namespace ElemUtils */
namespace ElemUtils {
/** @class BaseObject
*
* @brief BaseObject is the ”zeroth-level-object” of the architecture.
* Each module in PARTONS is referred to with a unique class name and a unique int used as ID.
*
* Any C++ object in PARTONS can inherit of it. It fulfills several needs:
* 1. It contains a clone function to be used to the factory to provide the user an object identified by a simple key (a string).
* 2. It carries information on the identity of a specific object among others to transmit an explicit message to the logger (i.e. understandable by a human being, not an address in memory).
* 3. It handles Packets to allow systematic computations over lists of inputs e.g. with threads.
* 4. It allows the registry to store pointers to all modules in a generic way.
*/
class BaseObject {
public:
/**
* Constructor.
* Takes a string parameter that represents the class's name of the child instance class.
*
* @param className class's name of child class.
*/
BaseObject(const std::string &className);
/**
* Default destructor.
*/
virtual ~BaseObject();
/**
* Virtual clone function to allow the factory to clone all derived members object stored in the BaseObjectRegistry.
* @return
*/
virtual BaseObject* clone() const;
/**
* Because of the initialization step order of the program, objects are registered in a total random order and some objects depend on others.
* To avoid the problem of pointer resolution order, this method is called by the BaseObjectRegistery after all objects are well registered in it.
* See BaseObjectRegistry class documentation for more details.
*/
virtual void resolveObjectDependencies();
/**
* Return a pre-formatted characters string for output visualization of class member's values.
*
* @return a pre-formatted characters string.
*/
virtual std::string toString() const;
/**
* Used to split a complex C++ object into a concatenation of simple types.
*
* @param packet
*/
void serialize(ElemUtils::Packet &packet) const;
/**
* Used to rebuild a complex C++ object from a concatenation of simple type.
*
* @param packet
*/
void unserialize(ElemUtils::Packet &packet);
/**
* Overload of < operator to sort BaseObject object by its indexId value.
*
* @param other
* @return
*/
bool operator <(const BaseObject& other) const;
// ##### GETTERS & SETTERS #####
/**
*
* @return Name of last child class.
*/
const std::string& getClassName() const;
/**
*
* @return Unique id identifying each object.
*/
unsigned int getObjectId() const;
/**
*
* @return Integer used when object is created from database. It is related to the id column value in the right database table.
*/
int getIndexId() const;
/**
*
* @param indexId Integer used when object is created from database. It is related to the id column value in the right database table.
*/
void setIndexId(int indexId);
protected:
/**
* Copy constructor.
*
* @param other
*/
BaseObject(const BaseObject& other);
/**
* Print info message into logger.
*
* @param functionName Name of the function throwing an information. Use \_\_func\_\_ to set it automatically.
* @param message Message to the logger.
*/
void info(const std::string &functionName,
const std::string &message) const;
/**
* Print debug message into logger.
*
* @param functionName ame of the function throwing an information. Use \_\_func\_\_ to set it automatically.
* @param message Message to the logger.
*/
void debug(const std::string &functionName,
const std::string &message) const;
/**
* Print warning message into logger.
*
* @param functionName ame of the function throwing an information. Use \_\_func\_\_ to set it automatically.
* @param message Message to the logger.
*/
void warn(const std::string &functionName,
const std::string &message) const;
/**
* Use in automation process to throw exception when a parameter is missing from the XML scenario file.
*
* @param parameterName
*/
void errorMissingParameter(const std::string &parameterName) const;
private:
unsigned int m_objectId; ///< Unique id identifying each object.
std::string m_className; ///< String that represents class's name used by the LoggerManager's class to know the source of the output trace.
int m_indexId; ///< Integer used when object is created from database. It is related to the id column value in the right database table.
static unsigned int m_uniqueObjectIdCounter;
/**
* On call, returns an incremented by one uniqueID member value.
*
* @return incremented unsigned int ID.
*/
unsigned int getUniqueObjectId();
};
Packet& operator <<(Packet& packet, BaseObject& object);
Packet& operator >>(Packet& packet, BaseObject& object);
} /* namespace ElemUtils */
#endif /* BASE_OBJECT_H */
#ifndef BASE_OBJECT_DATA_H
#define BASE_OBJECT_DATA_H
/**
* @file BaseObjectData.h
* @author Bryan BERTHOU (SPhN / CEA Saclay)
* @date October 28, 2016
* @version 1.0
*/
#include <map>
#include <string>
#include "../parameters/Parameters.h"
#include "BaseObject.h"
namespace ElemUtils {
class Parameter;
/**
* @class BaseObjectData
*
* @brief Container to store data to be used by base objects.
*
* This class is a container to store data used by base objects in the automation process.
* An object of this class is intended to be created by a XML parser during running PARTONS runtime from a specific XML file, which can be local or can be retrieved from a database.
* Therefore, this class may be seen as a representation of a set of parameters encoded in a XML file, like:
\code{.py}
<kinematics type="GPDKinematic">
<param name="x" value="0.1" />
<param name="xi" value="0.05" />
<param name="t" value="-0.3" />
<param name="MuF2" value="8." />
<param name="MuR2" value="8." />
</kinematics>
\endcode
*/
class BaseObjectData: public BaseObject {
public:
/**
* Default constructor.
*/
BaseObjectData();
/**
* Assignment constructor.
* @param moduleType Type of module intended to use parameters stored in this class.
* @param moduleClassName Name of module intended to use parameters stored in this class.
*/
BaseObjectData(const std::string &moduleType,
const std::string &moduleClassName);
/**
* Destructor.
*/
virtual ~BaseObjectData();
/**
* Add submodule, i.e. indicate that this BaseObjectData object has a tree-like structure.
* @param moduleType Type of module intended to use parameters stored in this class.
* @param moduleClassName Name of module intended to use parameters stored in this class.
* @return Reference to added BaseObjectData object.
*/
BaseObjectData& addSubModule(const std::string &moduleType,
const std::string &moduleClassName);
/**
* Add a single parameter.
* @param parameter Parameter to be added.
*/
void addParameter(const Parameter &parameter);
/**
* Add a set of parameters.
* @param parameters Parameters to be added.
*/
void addParameters(const Parameters &parameters);
/**
* Check if parameters of submodule of a given type are available.
* @param moduleClassType Requested type of submodule.
* @return True if parameters are available, otherwise false.
*/
bool isAvailableSubModule(const std::string &moduleClassType) const;
/**
* Get BaseObjectData object indicated by the last call of BaseObjectData::isAvailableSubModule() function.
* @return Reference to object marked by the last call of BaseObjectData::isAvailableSubModule() function.
*/
const BaseObjectData& getLastAvailable() const; // Care ! Use it after isAvailable() to ensure that the iterator is in the map range.
virtual std::string toString() const;
//********************************************************
//*** SETTERS AND GETTERS ********************************
//********************************************************
/**
* Get type of module intended to use parameters stored in this class.
*/
const std::string& getModuleType() const;
/**
* Set type of module intended to use parameters stored in this class.
*/
void setModuleType(const std::string& moduleType);
/**
* Get name of module intended to use parameters stored in this class.
*/
const std::string& getModuleClassName() const;
/**
* Set name of module intended to use parameters stored in this class.
*/
void setModuleClassName(const std::string& moduleClassName);
/**
* Get parameters stored in this class.
*/
const Parameters& getParameters() const;
/**
* Set parameters stored in this class.
*/
void setParameters(const Parameters& parameters);
/**
* Get map to build a tree-like structure of BaseObjectData objects to be used if submodules are used. The keys in the map indicate type of modules intended to use parameters stored in corresponding BaseObjectData objects.
*/
const std::map<std::string, BaseObjectData>& getSubModules() const;
private:
/**
* Type of module intended to use parameters stored in this class.
*/
std::string m_moduleType;
/**
* Name of module intended to use parameters stored in this class.
*/
std::string m_moduleClassName;
/**
* Parameters stored in this class.
*/
Parameters m_parameters;
/**
* Map to build a tree-like structure of BaseObjectData objects to be used if submodules are used. The keys in the map indicate type of modules intended to use parameters stored in corresponding BaseObjectData objects.
*/
std::map<std::string, BaseObjectData> m_subModules;
//Mutable keyword is use too indicate that member can be modify in const function. In this case useful with iterator m_it & isAvailable() function.
/**
* Iterator of BaseObjectData::m_subModules map.
*/
mutable std::map<std::string, BaseObjectData>::const_iterator m_it;
};
} /* namespace ElemUtils */
#endif /* BASE_OBJECT_DATA_H */
#ifndef BASE_OBJECT_FACTORY_H_
#define BASE_OBJECT_FACTORY_H
/**
* @file BaseObjectFactory.h
* @author Bryan BERTHOU (SPhN / CEA Saclay)
* @date June 26, 2015
* @version 1.0
*/
#include <SFML/System/Mutex.hpp>
#include <map>
#include <string>
#include "BaseObject.h"
namespace ElemUtils {
class BaseObjectRegistry;
/**
* @class BaseObjectFactory
*
* @brief Provides a clone (returned as a BaseObject pointer) of an object identified by its class name and previously stored in the BaseObjectRegistry.
* Furthermore, a pointer to each clone is registered in order to destroy it later on if it becomes orphan.\n
* This class is only instantiable by the class Partons to avoid any error at the initialization of the program.
*/
class BaseObjectFactory {
public:
/**
* Default destructor.
*/
virtual ~BaseObjectFactory();
/**
* Provides a clone of the desired object class stored in the registry identified by its integer identifier.
*
* @param classId
* @return
*/
BaseObject* newBaseObject(unsigned int classId);
/**
* Provides a clone of the desired object class stored in the registry identified by its string class name.
*
* @param classId
* @return
*/
BaseObject* newBaseObject(const std::string &className);
/**
* Remove an object from the factory.
*
* @param baseObjectUniqueId Unique id identifying each object.
*/
void removeFromStore(unsigned int baseObjectUniqueId);
private:
// To allow only ObjectFactoryManager class to create a unique of this class.
// Used to avoid multiple singleton class and to avoid multithreading problem especially when getInstance() is called.
// There is a bad behaviour with first instance initialization and mutex.
friend class ObjectFactoryManager;
sf::Mutex m_mutex; ///< Mutex to secure concurrent access to the map of instanciated obejcts.
BaseObjectRegistry* m_pBaseObjectRegistry; ///< Pointer to ask BaseObjectRegistry pointer associated to a specific object class.
std::map<unsigned int, BaseObject*> m_pInstantiatedObject; ///< Store BaseObject pointer created by the factory; used at the end of the program to delete orphan pointer.
/**
* Private default constructor to ensure the creation of a single instance of the class, managed by Parton's class.
*
* @param pBaseObjectRegistry
*/
BaseObjectFactory(BaseObjectRegistry* pBaseObjectRegistry);
/**
* Store cloned object pointer to its instantiated object map.
*
* @param pBaseObject
*/
void store(BaseObject* pBaseObject);
};
} /* namespace ElemUtils */
#endif /* BASE_OBJECT_FACTORY_H */
#ifndef BASE_OBJECT_REGISTRY_H
#define BASE_OBJECT_REGISTRY_H
/**
* @file BaseObjectRegistry.h
* @author Bryan BERTHOU (SPhN / CEA Saclay)
* @date June 25, 2015
* @version 1.0
*/
#include <stddef.h>
#include <SFML/System/Mutex.hpp>
#include <map>
#include <string>
#include "BaseObject.h"
namespace ElemUtils {
/** @class BaseObjectRegistry
*
* @brief The Registry is the analog of a phonebook, which lists all available objects (modules or services most of the time) identified by a unique integer identifier or by a unique string (class name) for translation. And only one species of each.
*
* From the point of view of software engineering, the registry corresponds to the singleton design pattern which ensures that it is unique.
* When a new module or services are created, the first thing to do is to call this unique instance, and to register the new module or services with a name provided by the developer of the class.
* In turn the Registry gives a unique identifier encoded in a integer variable for performance purposes.
* Registry stores pointers to all objects in a generic way, i.e. whatever their nature are: pointers to GPDModule, to RunningAlphaStrongModule, to AutomationService, etc.
* This is achieved by requiring all objects to derive from a single parent class named BaseObject.
*/
class BaseObjectRegistry {
public:
/**
* Static function to be able to retrieve a unique instance pointer of this class anywhere in the code.
*
* @return a unique instance of this class
*/
static BaseObjectRegistry* getInstance();
/**
* Default destructor
*/
virtual ~BaseObjectRegistry();
/**
* Store a unique instance of a module identified by a unique string character key.
* @param pBaseObject: an instance of the module built by its default constructor.
* @return A unique identifier by class
*/
unsigned int registerBaseObject(BaseObject * pBaseObject);
/**
* Some objects like modules depend on each other.
* But it is impossible to guarantee the order in which they are added to the registry will be made upon the resolution of statics variables (mechanism of self-registration)
* So we need to perform this task just before the use of PARTONS software to resolve dependencies between all kind of registered objects.
*/
void resolveBaseObjectDependencies();
/**
* Try to find stored object identified by its unique class identifier.
*
* @param classId
* @return reference to object in memory or throw an exception
*/
BaseObject* get(unsigned int classId) const;
/**
* Try to find stored object identified by its class name.
*
* @param className
* @return reference to object in memory or throw an exception
*/
BaseObject* get(const std::string &className) const;
/**
* Print information about current state of the registry (size of the registry, which objects are stored, ...).
*
* @return string
*/
virtual std::string toString() const;
/**
* Return the size of the registry.
* How many objects are stored.
*
* @return Registry size.
*/
size_t size() const;
unsigned int getObjectClassIdByClassName(const std::string &className);
private:
/**
* Private pointer of this class for a unique instance.
*/
static BaseObjectRegistry* m_pInstance;
/**
* Private default constructor for a unique instance.
*/
BaseObjectRegistry();
/**
* Because of PARTONS is a program using threads we must ensure that only one object manipulates the registry at the same time to avoid memory access violation.
* It's performed by a mechanism called mutex or semaphore.
*/
mutable sf::Mutex m_mutex;
std::map<unsigned int, BaseObject*> m_baseObjectList; ///< List of registered objects identified by their unique integer identifier.
std::map<std::string, BaseObject*> m_translateList; ///< List of registered objects identified by their class name.
std::map<std::string, unsigned int> m_classIdByClassName; ///< Translation map between class id and class name.
static unsigned int m_uniqueClassIdCounter; ///< Increment unique class identifier.
/**
* For performance purposes, it's faster to compare two integers than two strings when we search for an object in the registry.
* This method return a unique integer identifier when a new class object is added to the registry.
* It's just an integer incremented one by one.
*
* @return Unique identifier by class.
*/
unsigned int getUniqueClassId();
/**
* Try to find an object into the registry by its class name.
*
* @param className
* @return Pointer to object if class name found into registry, NULL else.
*/
BaseObject* isAvailable(const std::string &className) const;
/**
* Try to find an object into the registry by its class identifier.
*
* @param classId
* @return Pointer to object if class name found into registry, NULL else.
*/
BaseObject* isAvailable(const unsigned int classId) const;
/**
* Return last referenced object by the iterator on m_translateList.
*
* @return Reference to the object in memory.
*/
BaseObject* getLastAvailableObjectIdentifiedByClassName() const;
/**
* Return last referenced object by the iterator on m_baseObjectList.
*
* @return Reference to the object in memory.
*/
BaseObject* getLastAvailableObjectIdentifiedByClassId() const;
// Stop the compiler generating methods of copy the object
BaseObjectRegistry(BaseObjectRegistry const& other); // Not Implemented
BaseObjectRegistry& operator=(BaseObjectRegistry const& other); // Not Implemented
};
} /* namespace ElemUtils */
#endif /* BASE_OBJECT_REGISTRY_H */
#ifndef MODULE_OBJECT_H
#define MODULE_OBJECT_H
/**
* @file ModuleObject.h
* @author Bryan BERTHOU (SPhN / CEA Saclay)
* @date Aout 06, 2014
* @version 1.0
*/
#include <map>
#include <string>
#include "../parameters/Parameters.h"
#include "../thread/Thread.h"
#include "BaseObjectData.h"
namespace ElemUtils {
class Parameters;
class ModuleObjectFactory;
/**
* @class ModuleObject
*
* @brief Super class of all module types - A module