From e1e7e73bce7c6ccc70b79afc79aadd308ac4c0e3 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 22 Jun 2026 17:08:34 +0200 Subject: [PATCH] Start refactoring of ObjectFactory --- .../src/sofa/component/statecontainer/init.h | 5 - Sofa/framework/Core/CMakeLists.txt | 5 +- .../Core/src/sofa/core/CategoryLibrary.cpp | 468 +++++----- .../Core/src/sofa/core/CategoryLibrary.h | 166 ++-- .../Core/src/sofa/core/ComponentCreator.h | 58 ++ .../Core/src/sofa/core/ComponentFactory.cpp | 269 ++++++ .../Core/src/sofa/core/ComponentFactory.h | 187 ++++ .../Core/src/sofa/core/ComponentLibrary.cpp | 220 ++--- .../Core/src/sofa/core/ComponentLibrary.h | 126 +-- .../src/sofa/core/ComponentRegistrationData.h | 167 ++++ .../Core/src/sofa/core/ObjectFactory.cpp | 855 ------------------ .../Core/src/sofa/core/ObjectFactory.h | 401 +------- .../Core/src/sofa/core/ObjectFactoryJson.cpp | 314 +++---- .../Core/src/sofa/core/ObjectFactoryJson.h | 10 +- .../Core/src/sofa/core/SofaLibrary.cpp | 306 +++---- .../Core/src/sofa/core/SofaLibrary.h | 140 +-- .../sofa/simulation/DefaultAnimationLoop.cpp | 2 +- .../SceneCheckMissingRequiredPlugin.cpp | 52 +- .../SceneChecking/SceneCheckUsingAlias.cpp | 14 +- 19 files changed, 1597 insertions(+), 2168 deletions(-) create mode 100644 Sofa/framework/Core/src/sofa/core/ComponentCreator.h create mode 100644 Sofa/framework/Core/src/sofa/core/ComponentFactory.cpp create mode 100644 Sofa/framework/Core/src/sofa/core/ComponentFactory.h create mode 100644 Sofa/framework/Core/src/sofa/core/ComponentRegistrationData.h delete mode 100644 Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp diff --git a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/init.h b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/init.h index 8beb96cc0d7..10aed6d49f2 100644 --- a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/init.h +++ b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/init.h @@ -23,11 +23,6 @@ #include -namespace sofa::core -{ - class ObjectFactory; -} - namespace sofa::component::statecontainer { SOFA_COMPONENT_STATECONTAINER_API void init(); diff --git a/Sofa/framework/Core/CMakeLists.txt b/Sofa/framework/Core/CMakeLists.txt index 5d049ec19bf..33881334318 100644 --- a/Sofa/framework/Core/CMakeLists.txt +++ b/Sofa/framework/Core/CMakeLists.txt @@ -31,8 +31,11 @@ set(HEADER_FILES ${SRC_ROOT}/CategoryLibrary.h ${SRC_ROOT}/CollisionElement.h ${SRC_ROOT}/CollisionModel.h + ${SRC_ROOT}/ComponentCreator.h + ${SRC_ROOT}/ComponentFactory.h ${SRC_ROOT}/ComponentLibrary.h ${SRC_ROOT}/ComponentNameHelper.h + ${SRC_ROOT}/ComponentRegistrationData.h ${SRC_ROOT}/ConstraintOrder.h ${SRC_ROOT}/ConstraintParams.h ${SRC_ROOT}/DataEngine.h @@ -232,6 +235,7 @@ set(SOURCE_FILES ${SRC_ROOT}/BehaviorModel.cpp ${SRC_ROOT}/CategoryLibrary.cpp ${SRC_ROOT}/CollisionModel.cpp + ${SRC_ROOT}/ComponentFactory.cpp ${SRC_ROOT}/ComponentLibrary.cpp ${SRC_ROOT}/ComponentNameHelper.cpp ${SRC_ROOT}/ConstraintParams.cpp @@ -248,7 +252,6 @@ set(SOURCE_FILES ${SRC_ROOT}/MechanicalParams.cpp ${SRC_ROOT}/Multi2Mapping.cpp ${SRC_ROOT}/MultiMapping.cpp - ${SRC_ROOT}/ObjectFactory.cpp ${SRC_ROOT}/ObjectFactoryJson.cpp ${SRC_ROOT}/PathResolver.cpp ${SRC_ROOT}/SofaLibrary.cpp diff --git a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp index 63ca8745277..f84a638cc97 100644 --- a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp +++ b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp @@ -1,234 +1,234 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace sofa::core -{ - - -//------------------------------------------------------------------------------------------------------- -CategoryLibrary::CategoryLibrary( const std::string &categoryName): name(categoryName) -{ -} - - -ComponentLibrary *CategoryLibrary::addComponent(const std::string &componentName, ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles) -{ - //Special case of Mapping and MechanicalMapping - const bool isMechanicalMapping = (name == "MechanicalMapping"); - const bool isMapping = (name == "Mapping"); - - ComponentLibrary* component = createComponent(componentName, entry, exampleFiles); - - //Add the corresponding templates - std::map::iterator itTemplate; - - //It exists Mappings only Mechanical or only Visual. So, we must add the component if only a creator is available for the current category - bool componentCreationPossible=false; - //read all the template possible, and remove unused (for Mapping processing) - std::list templates; - for (itTemplate=entry->creatorMap.begin(); itTemplate!= entry->creatorMap.end(); ++itTemplate) - { - const std::string &templateName = itTemplate->first; - //If the component corresponds to a MechanicalMapping, we must remove the template related to the visual mapping - if (isMechanicalMapping) - { - const std::string nonMechanical = templateName.substr(0,7); - if (nonMechanical == "Mapping") continue; - } - //If the component corresponds to a Mapping, we must remove the template related to the Mechanical Mapping - else if (isMapping) - { - const std::string mechanical = templateName.substr(0,17); - if (mechanical == "MechanicalMapping") continue; - } - componentCreationPossible=true; - //component->addTemplate(itTemplate->first); - if (templateName == (entry->defaultTemplate.empty() ? std::string("Vec3d") : entry->defaultTemplate)) - templates.push_front(templateName); // make sure the default template is first - else - templates.push_back(templateName); - } - for (std::list::const_iterator it = templates.begin(); it != templates.end(); ++it) - component->addTemplate(*it); - component->endConstruction(); - - //If no constructor is available, we delete the component - if (!componentCreationPossible) - { - delete component; - component=nullptr; - } - else - components.push_back(component); - - return component; -} - -void CategoryLibrary::endConstruction() -{ -} - - -const ComponentLibrary *CategoryLibrary::getComponent( const std::string &categoryName) const -{ - for (VecComponentIterator it=components.begin(); it != components.end(); ++it) - { - if ((*it)->getName().find(categoryName) != std::string::npos) - return *it; - } - return nullptr; -} - - -std::vector CategoryLibrary::getCategories() -{ - return std::vector{ - "AnimationLoop", - "BehaviorModel", - "CollisionAlgorithm", - "CollisionModel", - "ConfigurationSetting", - "ConstraintSet", - "ConstraintSolver", - "ConstraintSolver", - "ContextObject", - "Controller", - "Engine", - "Exporter", - "ForceField", - "InteractionForceField", - "LinearSolver", - "LinearSystem", - "Loader", - "Mapping", - "Mass", - "MechanicalState", - "OdeSolver", - "OrderingMethod", - "ProjectiveConstraintSet", - "TopologicalMapping", - "Topology", - "TopologyObject", - "VisualModel", - "_Miscellaneous" - }; -} - -void CategoryLibrary::getCategories(const objectmodel::BaseClass* mclass, - std::vector& v) -{ - if (mclass->hasParent(objectmodel::ContextObject::GetClass())) - v.push_back("ContextObject"); - if (mclass->hasParent(visual::VisualModel::GetClass())) - v.push_back("VisualModel"); - if (mclass->hasParent(BehaviorModel::GetClass())) - v.push_back("BehaviorModel"); - if (mclass->hasParent(CollisionModel::GetClass())) - v.push_back("CollisionModel"); - if (mclass->hasParent(behavior::BaseMechanicalState::GetClass())) - v.push_back("MechanicalState"); - // A Mass is a technically a ForceField, but we don't want it to appear in the ForceField category - if (mclass->hasParent(behavior::BaseForceField::GetClass()) && !mclass->hasParent(behavior::BaseMass::GetClass())) - v.push_back("ForceField"); - if (mclass->hasParent(behavior::BaseInteractionForceField::GetClass())) - v.push_back("InteractionForceField"); - if (mclass->hasParent(behavior::BaseProjectiveConstraintSet::GetClass())) - v.push_back("ProjectiveConstraintSet"); - if (mclass->hasParent(behavior::BaseConstraintSet::GetClass())) - v.push_back("ConstraintSet"); - if (mclass->hasParent(BaseMapping::GetClass())) - v.push_back("Mapping"); - if (mclass->hasParent(DataEngine::GetClass())) - v.push_back("Engine"); - if (mclass->hasParent("BaseSimulationExporter")) - v.push_back("Exporter"); - if (mclass->hasParent(topology::TopologicalMapping::GetClass())) - v.push_back("TopologicalMapping"); - if (mclass->hasParent(behavior::BaseMass::GetClass())) - v.push_back("Mass"); - if (mclass->hasParent(behavior::OdeSolver::GetClass())) - v.push_back("OdeSolver"); - if (mclass->hasParent(behavior::ConstraintSolver::GetClass())) - v.push_back("ConstraintSolver"); - if (mclass->hasParent(behavior::BaseConstraintCorrection::GetClass())) - v.push_back("ConstraintSolver"); - if (mclass->hasParent(behavior::BaseMatrixLinearSystem::GetClass())) - v.push_back("LinearSystem"); - if (mclass->hasParent(behavior::BaseOrderingMethod::GetClass())) - v.push_back("OrderingMethod"); - if (mclass->hasParent(behavior::LinearSolver::GetClass())) - v.push_back("LinearSolver"); - if (mclass->hasParent(behavior::BaseAnimationLoop::GetClass())) - v.push_back("AnimationLoop"); - // Just like Mass and ForceField, we don't want TopologyObject to appear in the Topology category - if (mclass->hasParent(topology::Topology::GetClass()) && !mclass->hasParent(topology::BaseTopologyObject::GetClass())) - v.push_back("Topology"); - if (mclass->hasParent(topology::BaseTopologyObject::GetClass())) - v.push_back("TopologyObject"); - if (mclass->hasParent(behavior::BaseController::GetClass())) - v.push_back("Controller"); - if (mclass->hasParent(loader::BaseLoader::GetClass())) - v.push_back("Loader"); - if (mclass->hasParent(collision::CollisionAlgorithm::GetClass())) - v.push_back("CollisionAlgorithm"); - if (mclass->hasParent(collision::Pipeline::GetClass())) - v.push_back("CollisionAlgorithm"); - if (mclass->hasParent(collision::Intersection::GetClass())) - v.push_back("CollisionAlgorithm"); - if (mclass->hasParent(objectmodel::ConfigurationSetting::GetClass())) - v.push_back("ConfigurationSetting"); - if (v.empty()) - v.push_back("_Miscellaneous"); -} - - -} // namespace sofa::core +// /****************************************************************************** +// * SOFA, Simulation Open-Framework Architecture * +// * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +// * * +// * This program is free software; you can redistribute it and/or modify it * +// * under the terms of the GNU Lesser General Public License as published by * +// * the Free Software Foundation; either version 2.1 of the License, or (at * +// * your option) any later version. * +// * * +// * This program is distributed in the hope that it will be useful, but WITHOUT * +// * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +// * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +// * for more details. * +// * * +// * You should have received a copy of the GNU Lesser General Public License * +// * along with this program. If not, see . * +// ******************************************************************************* +// * Authors: The SOFA Team and external contributors (see Authors.txt) * +// * * +// * Contact information: contact@sofa-framework.org * +// ******************************************************************************/ +// +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// +// namespace sofa::core +// { +// +// +// //------------------------------------------------------------------------------------------------------- +// CategoryLibrary::CategoryLibrary( const std::string &categoryName): name(categoryName) +// { +// } +// +// +// ComponentLibrary *CategoryLibrary::addComponent(const std::string &componentName, ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles) +// { +// //Special case of Mapping and MechanicalMapping +// const bool isMechanicalMapping = (name == "MechanicalMapping"); +// const bool isMapping = (name == "Mapping"); +// +// ComponentLibrary* component = createComponent(componentName, entry, exampleFiles); +// +// //Add the corresponding templates +// std::map::iterator itTemplate; +// +// //It exists Mappings only Mechanical or only Visual. So, we must add the component if only a creator is available for the current category +// bool componentCreationPossible=false; +// //read all the template possible, and remove unused (for Mapping processing) +// std::list templates; +// for (itTemplate=entry->creatorMap.begin(); itTemplate!= entry->creatorMap.end(); ++itTemplate) +// { +// const std::string &templateName = itTemplate->first; +// //If the component corresponds to a MechanicalMapping, we must remove the template related to the visual mapping +// if (isMechanicalMapping) +// { +// const std::string nonMechanical = templateName.substr(0,7); +// if (nonMechanical == "Mapping") continue; +// } +// //If the component corresponds to a Mapping, we must remove the template related to the Mechanical Mapping +// else if (isMapping) +// { +// const std::string mechanical = templateName.substr(0,17); +// if (mechanical == "MechanicalMapping") continue; +// } +// componentCreationPossible=true; +// //component->addTemplate(itTemplate->first); +// if (templateName == (entry->defaultTemplate.empty() ? std::string("Vec3d") : entry->defaultTemplate)) +// templates.push_front(templateName); // make sure the default template is first +// else +// templates.push_back(templateName); +// } +// for (std::list::const_iterator it = templates.begin(); it != templates.end(); ++it) +// component->addTemplate(*it); +// component->endConstruction(); +// +// //If no constructor is available, we delete the component +// if (!componentCreationPossible) +// { +// delete component; +// component=nullptr; +// } +// else +// components.push_back(component); +// +// return component; +// } +// +// void CategoryLibrary::endConstruction() +// { +// } +// +// +// const ComponentLibrary *CategoryLibrary::getComponent( const std::string &categoryName) const +// { +// for (VecComponentIterator it=components.begin(); it != components.end(); ++it) +// { +// if ((*it)->getName().find(categoryName) != std::string::npos) +// return *it; +// } +// return nullptr; +// } +// +// +// std::vector CategoryLibrary::getCategories() +// { +// return std::vector{ +// "AnimationLoop", +// "BehaviorModel", +// "CollisionAlgorithm", +// "CollisionModel", +// "ConfigurationSetting", +// "ConstraintSet", +// "ConstraintSolver", +// "ConstraintSolver", +// "ContextObject", +// "Controller", +// "Engine", +// "Exporter", +// "ForceField", +// "InteractionForceField", +// "LinearSolver", +// "LinearSystem", +// "Loader", +// "Mapping", +// "Mass", +// "MechanicalState", +// "OdeSolver", +// "OrderingMethod", +// "ProjectiveConstraintSet", +// "TopologicalMapping", +// "Topology", +// "TopologyObject", +// "VisualModel", +// "_Miscellaneous" +// }; +// } +// +// void CategoryLibrary::getCategories(const objectmodel::BaseClass* mclass, +// std::vector& v) +// { +// if (mclass->hasParent(objectmodel::ContextObject::GetClass())) +// v.push_back("ContextObject"); +// if (mclass->hasParent(visual::VisualModel::GetClass())) +// v.push_back("VisualModel"); +// if (mclass->hasParent(BehaviorModel::GetClass())) +// v.push_back("BehaviorModel"); +// if (mclass->hasParent(CollisionModel::GetClass())) +// v.push_back("CollisionModel"); +// if (mclass->hasParent(behavior::BaseMechanicalState::GetClass())) +// v.push_back("MechanicalState"); +// // A Mass is a technically a ForceField, but we don't want it to appear in the ForceField category +// if (mclass->hasParent(behavior::BaseForceField::GetClass()) && !mclass->hasParent(behavior::BaseMass::GetClass())) +// v.push_back("ForceField"); +// if (mclass->hasParent(behavior::BaseInteractionForceField::GetClass())) +// v.push_back("InteractionForceField"); +// if (mclass->hasParent(behavior::BaseProjectiveConstraintSet::GetClass())) +// v.push_back("ProjectiveConstraintSet"); +// if (mclass->hasParent(behavior::BaseConstraintSet::GetClass())) +// v.push_back("ConstraintSet"); +// if (mclass->hasParent(BaseMapping::GetClass())) +// v.push_back("Mapping"); +// if (mclass->hasParent(DataEngine::GetClass())) +// v.push_back("Engine"); +// if (mclass->hasParent("BaseSimulationExporter")) +// v.push_back("Exporter"); +// if (mclass->hasParent(topology::TopologicalMapping::GetClass())) +// v.push_back("TopologicalMapping"); +// if (mclass->hasParent(behavior::BaseMass::GetClass())) +// v.push_back("Mass"); +// if (mclass->hasParent(behavior::OdeSolver::GetClass())) +// v.push_back("OdeSolver"); +// if (mclass->hasParent(behavior::ConstraintSolver::GetClass())) +// v.push_back("ConstraintSolver"); +// if (mclass->hasParent(behavior::BaseConstraintCorrection::GetClass())) +// v.push_back("ConstraintSolver"); +// if (mclass->hasParent(behavior::BaseMatrixLinearSystem::GetClass())) +// v.push_back("LinearSystem"); +// if (mclass->hasParent(behavior::BaseOrderingMethod::GetClass())) +// v.push_back("OrderingMethod"); +// if (mclass->hasParent(behavior::LinearSolver::GetClass())) +// v.push_back("LinearSolver"); +// if (mclass->hasParent(behavior::BaseAnimationLoop::GetClass())) +// v.push_back("AnimationLoop"); +// // Just like Mass and ForceField, we don't want TopologyObject to appear in the Topology category +// if (mclass->hasParent(topology::Topology::GetClass()) && !mclass->hasParent(topology::BaseTopologyObject::GetClass())) +// v.push_back("Topology"); +// if (mclass->hasParent(topology::BaseTopologyObject::GetClass())) +// v.push_back("TopologyObject"); +// if (mclass->hasParent(behavior::BaseController::GetClass())) +// v.push_back("Controller"); +// if (mclass->hasParent(loader::BaseLoader::GetClass())) +// v.push_back("Loader"); +// if (mclass->hasParent(collision::CollisionAlgorithm::GetClass())) +// v.push_back("CollisionAlgorithm"); +// if (mclass->hasParent(collision::Pipeline::GetClass())) +// v.push_back("CollisionAlgorithm"); +// if (mclass->hasParent(collision::Intersection::GetClass())) +// v.push_back("CollisionAlgorithm"); +// if (mclass->hasParent(objectmodel::ConfigurationSetting::GetClass())) +// v.push_back("ConfigurationSetting"); +// if (v.empty()) +// v.push_back("_Miscellaneous"); +// } +// +// +// } // namespace sofa::core diff --git a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h index a7a71ebfccd..cce84c415cf 100644 --- a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h +++ b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h @@ -1,83 +1,83 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -namespace sofa::core -{ - - -using Creator = sofa::core::ObjectFactory::BaseObjectCreator; - -/** - * \brief An Generic Category of the Sofa Library - * - * It contains all the components available for Sofa corresponding to a given category (force field, mass, mapping...) - * This Interface is used for the Modeler mainly. - * - */ -class SOFA_CORE_API CategoryLibrary -{ -public: - typedef std::vector< ComponentLibrary* > VecComponent; - typedef VecComponent::const_iterator VecComponentIterator; - - CategoryLibrary( const std::string &categoryName); - virtual ~CategoryLibrary() {} - - virtual ComponentLibrary *addComponent(const std::string &componentName, ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles); - virtual void endConstruction(); - - const std::string &getName() const { return name;} - const VecComponent &getComponents() const {return components;} - - const ComponentLibrary *getComponent( const std::string &componentName) const; - - size_t getNumComponents() const {return components.size();} - - /** \brief Get the list of categories a class belongs to, based on its parent classes. - * - * @param mclass the class the categorize - * @param outputVector the vector where to push the categories - * - * The categories are: AnimationLoop, BehaviorModel, - * CollisionAlgorithm, CollisionAlgorithm, CollisionAlgorithm, - * CollisionModel, ConfigurationSetting, ConstraintSet, - * ConstraintSolver, ConstraintSolver, ContextObject, Controller, - * Engine, Exporter, ForceField, InteractionForceField, LinearSolver, LinearSystem, - * Loader, Mapping, Mass, MechanicalState, OdeSolver, OrderingMethod, - * ProjectiveConstraintSet, TopologicalMapping, Topology, - * TopologyObject, and VisualModel - */ - static void getCategories(const sofa::core::objectmodel::BaseClass* mclass, - std::vector& outputVector); - static std::vector getCategories(); - -protected: - virtual ComponentLibrary *createComponent(const std::string &componentName, ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles) {return new ComponentLibrary(componentName, name, entry, exampleFiles);} - - std::string name; - VecComponent components; -}; - -} // namespace sofa::core +// /****************************************************************************** +// * SOFA, Simulation Open-Framework Architecture * +// * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +// * * +// * This program is free software; you can redistribute it and/or modify it * +// * under the terms of the GNU Lesser General Public License as published by * +// * the Free Software Foundation; either version 2.1 of the License, or (at * +// * your option) any later version. * +// * * +// * This program is distributed in the hope that it will be useful, but WITHOUT * +// * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +// * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +// * for more details. * +// * * +// * You should have received a copy of the GNU Lesser General Public License * +// * along with this program. If not, see . * +// ******************************************************************************* +// * Authors: The SOFA Team and external contributors (see Authors.txt) * +// * * +// * Contact information: contact@sofa-framework.org * +// ******************************************************************************/ +// #pragma once +// +// #include +// +// namespace sofa::core +// { +// +// +// using Creator = sofa::core::ObjectFactory::BaseObjectCreator; +// +// /** +// * \brief An Generic Category of the Sofa Library +// * +// * It contains all the components available for Sofa corresponding to a given category (force field, mass, mapping...) +// * This Interface is used for the Modeler mainly. +// * +// */ +// class SOFA_CORE_API CategoryLibrary +// { +// public: +// typedef std::vector< ComponentLibrary* > VecComponent; +// typedef VecComponent::const_iterator VecComponentIterator; +// +// CategoryLibrary( const std::string &categoryName); +// virtual ~CategoryLibrary() {} +// +// virtual ComponentLibrary *addComponent(const std::string &componentName, ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles); +// virtual void endConstruction(); +// +// const std::string &getName() const { return name;} +// const VecComponent &getComponents() const {return components;} +// +// const ComponentLibrary *getComponent( const std::string &componentName) const; +// +// size_t getNumComponents() const {return components.size();} +// +// /** \brief Get the list of categories a class belongs to, based on its parent classes. +// * +// * @param mclass the class the categorize +// * @param outputVector the vector where to push the categories +// * +// * The categories are: AnimationLoop, BehaviorModel, +// * CollisionAlgorithm, CollisionAlgorithm, CollisionAlgorithm, +// * CollisionModel, ConfigurationSetting, ConstraintSet, +// * ConstraintSolver, ConstraintSolver, ContextObject, Controller, +// * Engine, Exporter, ForceField, InteractionForceField, LinearSolver, LinearSystem, +// * Loader, Mapping, Mass, MechanicalState, OdeSolver, OrderingMethod, +// * ProjectiveConstraintSet, TopologicalMapping, Topology, +// * TopologyObject, and VisualModel +// */ +// static void getCategories(const sofa::core::objectmodel::BaseClass* mclass, +// std::vector& outputVector); +// static std::vector getCategories(); +// +// protected: +// virtual ComponentLibrary *createComponent(const std::string &componentName, ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles) {return new ComponentLibrary(componentName, name, entry, exampleFiles);} +// +// std::string name; +// VecComponent components; +// }; +// +// } // namespace sofa::core diff --git a/Sofa/framework/Core/src/sofa/core/ComponentCreator.h b/Sofa/framework/Core/src/sofa/core/ComponentCreator.h new file mode 100644 index 00000000000..f842c1196e3 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentCreator.h @@ -0,0 +1,58 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include + +#include + +namespace sofa::core +{ + +struct SOFA_CORE_API BaseComponentCreator +{ + virtual ~BaseComponentCreator() = default; + virtual objectmodel::BaseComponent::SPtr create() const = 0; + virtual const objectmodel::BaseClass* getClass() = 0; + virtual std::unique_ptr clone() const = 0; +}; + +template +struct ComponentCreator : public BaseComponentCreator +{ + objectmodel::BaseComponent::SPtr create() const override + { + return sofa::core::objectmodel::New(); + } + + const objectmodel::BaseClass* getClass() override + { + return RealComponent::GetClass(); + } + + std::unique_ptr clone() const override + { + return std::make_unique(); + } +}; + +} diff --git a/Sofa/framework/Core/src/sofa/core/ComponentFactory.cpp b/Sofa/framework/Core/src/sofa/core/ComponentFactory.cpp new file mode 100644 index 00000000000..b3cb77bbfbf --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentFactory.cpp @@ -0,0 +1,269 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include +#include +#include + +namespace sofa::core +{ + +std::vector ComponentFactory::getComponentsFromName(const std::string& componentName) const +{ + std::vector result; + + std::string componentToSearch = componentName; + + using sofa::helper::lifecycle::renamedComponents; + auto renamedComponent = renamedComponents.find(componentName); + if( renamedComponent != renamedComponents.end() ) + { + componentToSearch = renamedComponent->second.getNewName(); + } + + for (const auto& component : m_registry) + { + const auto fullName = component->componentNamespace + "." + component->componentName; + + if (component->componentName == componentToSearch || fullName == componentToSearch) + { + result.push_back(component); + } + else + { + for (const auto& alias : component->aliases) + { + const auto fullNameAlias = component->componentNamespace + "." + alias; + + if (alias == componentToSearch || fullNameAlias == componentToSearch) + { + result.push_back(component); + } + } + } + } + + return result; +} + +typedef struct ObjectRegistrationEntry +{ + inline static const char* symbol = "registerObjects"; + typedef void (*FuncPtr) (sofa::core::ComponentFactory*); + FuncPtr func; + void operator()(sofa::core::ComponentFactory* data) const + { + if (func) return func(data); + } + ObjectRegistrationEntry() :func(nullptr) {} +} ObjectRegistrationEntry; + +bool ComponentFactory::registerObjectsFromPlugin(const std::string& pluginName) +{ + sofa::helper::system::PluginManager& pluginManager = sofa::helper::system::PluginManager::getInstance(); + auto* plugin = pluginManager.getPlugin(pluginName); + if (plugin == nullptr) + { + msg_error("ObjectFactory") << pluginName << " has not been loaded yet."; + return false; + } + + // do not register if it was already done before + if(m_registeredPluginSet.contains(pluginName)) + { + // This warning should be generalized (i.e not only in dev mode) when runSofa will not auto-load modules/plugins by default anymore + // Commented warning since it is triggered even for SOFA meta-modules (e.g. Sofa.Components) + // dmsg_warning("ObjectFactory") << pluginName << " has already registered its components."; + return false; + } + + ObjectRegistrationEntry registerObjects; + if (pluginManager.getEntryFromPlugin(plugin, registerObjects)) + { + registerObjects(this); + m_registeredPluginSet.insert(pluginName); + return true; + } + else + { + return false; + } +} + +bool ComponentFactory::registerObjects(ComponentRegistrationData& ro) +{ + auto& creators = ro.creators; + + if (creators.empty()) + { + msg_error() << "No creator provided"; + return false; + } + + for (auto& creator : ro.creators) + { + ComponentDescription::SPtr component = std::make_shared(); + + component->componentName = ro.componentName; + component->aliases = ro.aliases; + component->componentNamespace = ro.componentNamespace; + component->componentModule = ro.componentModule; + + component->description = ro.description; + component->authors = sofa::helper::join(ro.authors, ","); + component->license = ro.license; + component->documentationURL = ro.documentationURL; + + { + //special cases for official documentation + const auto modulePaths = sofa::helper::split(component->componentModule, '.'); + if (modulePaths.size() > 2 && modulePaths[0] == "Sofa" && modulePaths[1] == "Component") + { + std::string officialDocURL = std::string(sofa::SOFA_DOCUMENTATION_URL) + std::string("components/"); + officialDocURL += sofa::helper::join(modulePaths.begin() + 2, modulePaths.end(), + [](const std::string& m){ return sofa::helper::downcaseString(m);}, "/"); + officialDocURL += std::string("/") + sofa::helper::downcaseString(component->componentName); + + component->documentationURL.insert(officialDocURL); + } + } + + component->creator = std::move(creator); + + this->m_registry.push_back(component); + } + + return true; + +} + +objectmodel::BaseComponent::SPtr ComponentFactory::createComponent( + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) +{ + if (!arg) + return nullptr; + + const char* typeAttribute = arg->getAttribute( "type", nullptr); + + if (typeAttribute == nullptr) + return nullptr; + + std::string classname {typeAttribute}; + + auto candidates = this->getComponentsFromName(classname); + + if (candidates.empty()) + { + //try to load a potential plugin based on the component name + auto lastDot = classname.find_last_of('.'); + if (lastDot != std::string::npos) + { + auto pluginName = classname.substr(0, lastDot); + auto status = helper::system::PluginManager::getInstance().loadPluginByName(pluginName); + if (status == helper::system::PluginManager::PluginLoadStatus::SUCCESS) + { + this->registerObjectsFromPlugin(pluginName); + candidates = this->getComponentsFromName(classname); + } + } + } + + if (candidates.empty()) + { + return nullptr; + } + + std::sort(candidates.begin(), candidates.end(), + [](const auto& a, const auto& b) { return a->instantiationPriority > b->instantiationPriority; }); + + std::erase_if(candidates, [](const ComponentDescription::SPtr& candidate) + { + return helper::system::PluginManager::getInstance().isPluginUnloaded(candidate->componentModule); + }); + + for (const auto& component : candidates) + { + + } + + const auto firstCandidate = candidates.front(); + + firstCandidate->componentModule; + + auto component = candidates.front()->creator->create(); + + if (component) + { + if (context) + { + context->addObject(component); + } + + component->parse(arg); + } + + return component; +} + +bool ComponentFactory::hasCreator(const std::string& classname) const +{ + return std::any_of(m_registry.begin(), m_registry.end(), + [&](const auto& component){ return component->componentName == classname; }); +} + +void ComponentFactory::getEntriesFromTarget(std::vector& result, + const std::string& target) const +{ + for (const auto& component : m_registry) + { + if (component->componentModule == target) + { + result.push_back(component); + } + } +} + +std::string ComponentFactory::listClassesFromTarget(std::string target, std::string separator) +{ + std::vector entries; + this->getEntriesFromTarget(entries, target); + return sofa::helper::join(entries, separator); +} + +ComponentFactory* ComponentFactory::getInstance() { return MainComponentFactory::getInstance(); } +objectmodel::BaseComponent::SPtr ComponentFactory::CreateObject( + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) +{ + return MainComponentFactory::CreateComponent(context, arg); +} + +bool ComponentFactory::HasCreator(const std::string& classname) +{ + return MainComponentFactory::HasCreator(classname); +} + +bool MainComponentFactory::HasCreator(const std::string& classname) +{ + return getInstance()->hasCreator(classname); +} + +} // namespace sofa::core diff --git a/Sofa/framework/Core/src/sofa/core/ComponentFactory.h b/Sofa/framework/Core/src/sofa/core/ComponentFactory.h new file mode 100644 index 00000000000..9aa05debcc9 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentFactory.h @@ -0,0 +1,187 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include +#include +#include + +namespace sofa::core +{ + +struct SOFA_CORE_API ComponentDescription +{ + using SPtr = std::shared_ptr; + + std::string componentName; + std::set aliases; + + std::set templateAttributes; + std::string componentNamespace; + std::string componentModule; + + unsigned int instantiationPriority {}; + + std::string description; + std::string authors; + std::string license; + std::set documentationURL; + + std::unique_ptr creator; +}; + +class SOFA_CORE_API ComponentFactory +{ +public: + + // to deprecate + using ClassEntry = ComponentDescription; + + std::vector getComponentsFromName(const std::string& componentName) const; + + bool registerObjectsFromPlugin(const std::string& pluginName); + bool registerObjects(ComponentRegistrationData& ro); + + + + /// Create a component given a context and a description. + objectmodel::BaseComponent::SPtr createComponent(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + + + + /// Test if a creator exists for a given classname + bool hasCreator(const std::string& classname) const; + + /// Fill the given vector with the registered classes from a given target + void getEntriesFromTarget(std::vector& result, const std::string& target) const; + + /// Return the list of classes from a given target + std::string listClassesFromTarget(std::string target, std::string separator = ", "); + + /// Fill the given vector with all the registered classes derived from BaseClass + template + std::vector getEntriesDerivedFrom() const; + + /// Return the list of classes derived from BaseClass as a string + template + std::string listClassesDerivedFrom(const std::string& separator = ", ") const; + + + static SOFA_ATTRIBUTE_DEPRECATED("v26.12", "v27.12", "Use MainComponentFactory::getInstance instead") ComponentFactory* getInstance(); + static SOFA_ATTRIBUTE_DEPRECATED("v26.12", "v27.12", "Use MainComponentFactory::CreateComponent instead") objectmodel::BaseComponent::SPtr CreateObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + static bool SOFA_ATTRIBUTE_DEPRECATED("v26.12", "v27.12", "Use MainComponentFactory::HasCreator instead") HasCreator(const std::string& classname); + + + void getEntry(std::string) = delete; + +protected: + + /// Keep track of plugins who already registered + using RegisteredPluginSet = std::set; + RegisteredPluginSet m_registeredPluginSet; + + std::vector m_registry; +}; + + +template +std::vector ComponentFactory::getEntriesDerivedFrom() const +{ + std::vector result; + + auto* componentClass = Class::GetClass(); + if (!componentClass) + { + return result; + } + + for (const auto& component : m_registry) + { + if (auto* componentClassInRegistry = component->creator->getClass()) + { + if (componentClassInRegistry->hasParent(componentClass)) + { + result.push_back(component); + } + } + } + + return result; +} + +template +std::string ComponentFactory::listClassesDerivedFrom(const std::string& separator) const +{ + auto entries = getEntriesDerivedFrom(); + + return sofa::helper::join(entries.begin(), entries.end(), + [](const ComponentDescription::SPtr& entry){ return entry->componentName;}, separator); +} + + + + +struct SOFA_CORE_API MainComponentFactory +{ + static ComponentFactory* getInstance() + { + static ComponentFactory instance; + return &instance; + } + + static objectmodel::BaseComponent::SPtr CreateComponent(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) + { + return getInstance()->createComponent(context, arg); + } + + //to deprecate + static objectmodel::BaseComponent::SPtr CreateObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) + { + return CreateComponent(context, arg); + } + + /// Test if a creator exists for a given classname + static bool HasCreator(const std::string& classname); +}; + + +} + + + + + + + +namespace sofa::helper::logging +{ + +inline bool notMuted(const core::ComponentFactory*) +{ + return true; +} + +inline ComponentInfo::SPtr getComponentInfo(const core::ComponentFactory*) +{ + return std::make_shared("ComponentFactory"); +} +} diff --git a/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp b/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp index 491e001d3c9..265889f3919 100644 --- a/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp +++ b/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp @@ -1,110 +1,110 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include -#include - -namespace sofa::core -{ - -std::string caseInsensitive(const std::string &text) -{ - std::string result; result.resize(text.size()); - for (unsigned int i=0; i(toupper(text[i])); - return result; -} - -//------------------------------------------------------------------------------------------------------- -ComponentLibrary::ComponentLibrary( const std::string &componentN, const std::string &categoryN, ClassEntry::SPtr e, const std::vector< std::string > &exampleFiles): name(componentN), categoryName(categoryN),entry(e) -{ - - description = std::string("

") + entry->className + std::string(": "); - - std::vector< std::string > possiblePaths; - - std::vector categories; - const objectmodel::BaseClass* entryClass = entry->creatorMap.begin()->second->getClass(); - CategoryLibrary::getCategories(entryClass, categories); - for (std::vector< std::string >::iterator it=categories.begin(); it!=categories.end() ; ++it) - { - if (it != categories.begin()) description += std::string(", "); - description += (*it); - } - - //Find a scene - std::string nameComponentCaseInsensitive = caseInsensitive(entry->className); - - for (unsigned int i=0; iclassName.c_str()) >= 0 ) - if (exampleCaseInsensitive.find(nameComponentCaseInsensitive) != std::string::npos) - possiblePaths.push_back(exampleFiles[i]); - } - - std::string nameSpace = sofa::helper::NameDecoder::decodeNamespaceName(entry->creatorMap.begin()->second->type()); - - description += std::string("

"); - - description += std::string("
    "); - - description += std::string("
  • Description: ") + entry->description + std::string("
  • "); - - - if (!nameSpace.empty()) - description += std::string("
  • NameSpace: ")+nameSpace +std::string("
  • "); - if (!entry->authors.empty()) - description += std::string("
  • Authors: ")+entry->authors +std::string("
  • "); - if (!entry->license.empty()) - description += std::string("
  • License: ") + entry->license + std::string("
  • "); - if (!entry->documentationURL.empty()) - description += std::string("
  • Documentation: ") + entry->documentationURL + std::string("
  • "); - - if (possiblePaths.size() != 0) - { - description += std::string("
  • Example: "); - } - - description += std::string("
"); -} - - - - - -void ComponentLibrary::addTemplate( const std::string &nameT) -{ - if (nameT.empty()) return; - templateName.push_back(nameT); -} - - -void ComponentLibrary::endConstruction() -{ -} - -} +// /****************************************************************************** +// * SOFA, Simulation Open-Framework Architecture * +// * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +// * * +// * This program is free software; you can redistribute it and/or modify it * +// * under the terms of the GNU Lesser General Public License as published by * +// * the Free Software Foundation; either version 2.1 of the License, or (at * +// * your option) any later version. * +// * * +// * This program is distributed in the hope that it will be useful, but WITHOUT * +// * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +// * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +// * for more details. * +// * * +// * You should have received a copy of the GNU Lesser General Public License * +// * along with this program. If not, see . * +// ******************************************************************************* +// * Authors: The SOFA Team and external contributors (see Authors.txt) * +// * * +// * Contact information: contact@sofa-framework.org * +// ******************************************************************************/ +// +// #include +// #include +// +// namespace sofa::core +// { +// +// std::string caseInsensitive(const std::string &text) +// { +// std::string result; result.resize(text.size()); +// for (unsigned int i=0; i(toupper(text[i])); +// return result; +// } +// +// //------------------------------------------------------------------------------------------------------- +// ComponentLibrary::ComponentLibrary( const std::string &componentN, const std::string &categoryN, ClassEntry::SPtr e, const std::vector< std::string > &exampleFiles): name(componentN), categoryName(categoryN),entry(e) +// { +// +// description = std::string("

") + entry->className + std::string(": "); +// +// std::vector< std::string > possiblePaths; +// +// std::vector categories; +// const objectmodel::BaseClass* entryClass = entry->creatorMap.begin()->second->getClass(); +// CategoryLibrary::getCategories(entryClass, categories); +// for (std::vector< std::string >::iterator it=categories.begin(); it!=categories.end() ; ++it) +// { +// if (it != categories.begin()) description += std::string(", "); +// description += (*it); +// } +// +// //Find a scene +// std::string nameComponentCaseInsensitive = caseInsensitive(entry->className); +// +// for (unsigned int i=0; iclassName.c_str()) >= 0 ) +// if (exampleCaseInsensitive.find(nameComponentCaseInsensitive) != std::string::npos) +// possiblePaths.push_back(exampleFiles[i]); +// } +// +// std::string nameSpace = sofa::helper::NameDecoder::decodeNamespaceName(entry->creatorMap.begin()->second->type()); +// +// description += std::string("

"); +// +// description += std::string("
    "); +// +// description += std::string("
  • Description: ") + entry->description + std::string("
  • "); +// +// +// if (!nameSpace.empty()) +// description += std::string("
  • NameSpace: ")+nameSpace +std::string("
  • "); +// if (!entry->authors.empty()) +// description += std::string("
  • Authors: ")+entry->authors +std::string("
  • "); +// if (!entry->license.empty()) +// description += std::string("
  • License: ") + entry->license + std::string("
  • "); +// if (!entry->documentationURL.empty()) +// description += std::string("
  • Documentation: ") + entry->documentationURL + std::string("
  • "); +// +// if (possiblePaths.size() != 0) +// { +// description += std::string("
  • Example: "); +// } +// +// description += std::string("
"); +// } +// +// +// +// +// +// void ComponentLibrary::addTemplate( const std::string &nameT) +// { +// if (nameT.empty()) return; +// templateName.push_back(nameT); +// } +// +// +// void ComponentLibrary::endConstruction() +// { +// } +// +// } diff --git a/Sofa/framework/Core/src/sofa/core/ComponentLibrary.h b/Sofa/framework/Core/src/sofa/core/ComponentLibrary.h index c886bcc2b01..b37751d5426 100644 --- a/Sofa/framework/Core/src/sofa/core/ComponentLibrary.h +++ b/Sofa/framework/Core/src/sofa/core/ComponentLibrary.h @@ -1,63 +1,63 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -namespace sofa::core -{ - -typedef sofa::core::ObjectFactory::ClassEntry ClassEntry; - -/** - * \brief An Generic Component of the Sofa Library - * - * It contains all the information related to a Sofa component: its name, the templates available, a description of it, its creator, ... - * This Interface is used for the Modeler mainly. - * - */ -class SOFA_CORE_API ComponentLibrary -{ -public: - ComponentLibrary(const std::string& componentName, const std::string& categoryName, ClassEntry::SPtr entry, const std::vector< std::string >& exampleFiles); - virtual ~ComponentLibrary() {} - - virtual void addTemplate( const std::string& templateName); - virtual void endConstruction(); - virtual void setDisplayed(bool ) {} - - const std::string& getName() const { return name;} - const std::string& getDescription() const { return description;} - const std::string& getCategory() const { return categoryName;} - const std::vector< std::string >& getTemplates() const { return templateName;} - const ClassEntry::SPtr getEntry() const { return entry;} - -protected: - //-------------------------------------------- - //Sofa information - std::string name; - std::vector< std::string > templateName; - std::string description; - std::string categoryName; - ClassEntry::SPtr entry; -}; -} +// /****************************************************************************** +// * SOFA, Simulation Open-Framework Architecture * +// * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +// * * +// * This program is free software; you can redistribute it and/or modify it * +// * under the terms of the GNU Lesser General Public License as published by * +// * the Free Software Foundation; either version 2.1 of the License, or (at * +// * your option) any later version. * +// * * +// * This program is distributed in the hope that it will be useful, but WITHOUT * +// * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +// * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +// * for more details. * +// * * +// * You should have received a copy of the GNU Lesser General Public License * +// * along with this program. If not, see . * +// ******************************************************************************* +// * Authors: The SOFA Team and external contributors (see Authors.txt) * +// * * +// * Contact information: contact@sofa-framework.org * +// ******************************************************************************/ +// #pragma once +// +// #include +// +// namespace sofa::core +// { +// +// typedef sofa::core::ObjectFactory::ClassEntry ClassEntry; +// +// /** +// * \brief An Generic Component of the Sofa Library +// * +// * It contains all the information related to a Sofa component: its name, the templates available, a description of it, its creator, ... +// * This Interface is used for the Modeler mainly. +// * +// */ +// class SOFA_CORE_API ComponentLibrary +// { +// public: +// ComponentLibrary(const std::string& componentName, const std::string& categoryName, ClassEntry::SPtr entry, const std::vector< std::string >& exampleFiles); +// virtual ~ComponentLibrary() {} +// +// virtual void addTemplate( const std::string& templateName); +// virtual void endConstruction(); +// virtual void setDisplayed(bool ) {} +// +// const std::string& getName() const { return name;} +// const std::string& getDescription() const { return description;} +// const std::string& getCategory() const { return categoryName;} +// const std::vector< std::string >& getTemplates() const { return templateName;} +// const ClassEntry::SPtr getEntry() const { return entry;} +// +// protected: +// //-------------------------------------------- +// //Sofa information +// std::string name; +// std::vector< std::string > templateName; +// std::string description; +// std::string categoryName; +// ClassEntry::SPtr entry; +// }; +// } diff --git a/Sofa/framework/Core/src/sofa/core/ComponentRegistrationData.h b/Sofa/framework/Core/src/sofa/core/ComponentRegistrationData.h new file mode 100644 index 00000000000..7bb36a8c5fd --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentRegistrationData.h @@ -0,0 +1,167 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace sofa::core +{ + +class SOFA_CORE_API ComponentRegistrationData +{ +public: + + std::string componentName; + std::set aliases; + std::string description; + + std::set authors; + std::string license; + std::set documentationURL; + std::string componentNamespace; + std::string componentModule; + + std::optional defaultTemplateId; + + std::vector> creators; + + /// Start the registration by giving the description of this class. + explicit ComponentRegistrationData(const std::string& description) + { + if (!description.empty()) + { + addDescription(description); + } + } + + ComponentRegistrationData(const ComponentRegistrationData&) = delete; + void operator=(const ComponentRegistrationData&) = delete; + + /// Add an alias name for this class + ComponentRegistrationData& addAlias(std::string val) + { + aliases.insert(val); + return *this; + } + + /// Add more descriptive text about this class + ComponentRegistrationData& addDescription(const std::string& val) + { + if (description.empty()) + { + description = val; + } + else + { + dmsg_error("ComponentRegistrationData") << "Trying to add multiple descriptions for a single component whereas only one is supported"; + } + return *this; + } + + /// Specify a list of authors (separated with spaces) + ComponentRegistrationData& addAuthor(std::string val) + { + authors.insert(val); + return *this; + } + + /// Specify a license (LGPL, GPL, ...) + ComponentRegistrationData& addLicense(std::string val) + { + if (license.empty()) + { + license = val; + } + else + { + dmsg_error("ComponentRegistrationData") << "Trying to add multiple licenses for a single component whereas only one is supported"; + } + return *this; + } + + /// Specify a documentation URL + ComponentRegistrationData& addDocumentationURL(std::string url) + { + documentationURL.insert(url); + return *this; + } + + /// Add a template instantiation of this class. + /// + /// \param defaultTemplate set to true if this should be the default instance when no template name is given. + template + ComponentRegistrationData& add(bool defaultTemplate = false) + { +#ifdef SOFA_TARGET + const std::string target = sofa_tostring(SOFA_TARGET); + + if (!target.empty()) + { + componentNamespace = target; + componentModule = target; + } +#else + dmsg_warning("ComponentFactory") << "Module name cannot be found when registering " + << RealObject::GetClass()->className << "<" << RealObject::GetClass()->templateName << "> into the component factory"; +#endif + + const std::string classname = sofa::core::objectmodel::BaseClassNameHelper::getClassName(); + if (componentName.empty()) + { + componentName = classname; + } + else + { + if (componentName != classname) + { + msg_error("ComponentFactory") << "Trying to define a class (" << classname << ") unrelated to " << componentName; + return *this; + } + } + + creators.push_back(std::unique_ptr(new ComponentCreator)); + + if (defaultTemplate) + { + if (defaultTemplateId.has_value()) + { + msg_error("ComponentFactory") << "Trying to define a default template for " + << RealObject::GetClass()->className << " whereas one was already defined before"; + } + else + { + defaultTemplateId = creators.size() - 1; + } + } + + return *this; + } + +}; + +} diff --git a/Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp b/Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp deleted file mode 100644 index 24947674ec5..00000000000 --- a/Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp +++ /dev/null @@ -1,855 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include -#include -#include -#include -#include -#include - -namespace sofa::core -{ - -ObjectFactory::~ObjectFactory() -{ -} - -ObjectFactory::ClassEntry& ObjectFactory::getEntry(std::string classname) -{ - if (!registry.contains(classname)) - { - registry[classname] = std::make_shared(); - registry[classname]->className = classname; - } - - return *registry[classname]; -} - -/// Test if a creator exists for a given classname -bool ObjectFactory::hasCreator(std::string classname) -{ - const ClassEntryMap::iterator it = registry.find(classname); - if (it == registry.end()) - return false; - const ClassEntry::SPtr entry = it->second; - return (!entry->creatorMap.empty()); -} - -std::string ObjectFactory::shortName(std::string classname) -{ - const ClassEntryMap::iterator it = registry.find(classname); - if (it != registry.end()) - { - const ClassEntry::SPtr entry = it->second; - if(!entry->creatorMap.empty()) - { - const auto firstElement = entry->creatorMap.begin(); - const BaseObjectCreator::SPtr c = firstElement->second; - return c->getClass()->shortName; - } - } - return {}; -} - -bool ObjectFactory::addAlias(std::string name, std::string target, bool force, - ClassEntry::SPtr* previous) -{ - // Check that the pointed class does exist - const ClassEntryMap::iterator it = registry.find(target); - if (it == registry.end()) - { - msg_error("ObjectFactory::addAlias()") << "Target class for alias '" << target << "' not found: " << name; - return false; - } - - const ClassEntry::SPtr& pointedEntry = it->second; - ClassEntry::SPtr& aliasEntry = registry[name]; - - // Check that the alias does not already exist, unless 'force' is true - if (aliasEntry.get()!=nullptr && !force) - { - msg_error("ObjectFactory::addAlias()") << "Name already exists: " << name; - return false; - } - - if (previous) - { - const ClassEntry::SPtr& entry = aliasEntry; - *previous = entry; - } - - registry[name] = pointedEntry; - pointedEntry->aliases.insert(name); - return true; -} - -void ObjectFactory::resetAlias(std::string name, ClassEntry::SPtr previous) -{ - registry[name] = previous; -} - - -void findTemplatedCreator( - objectmodel::BaseContext* context, - const ObjectFactory::BaseObjectCreator::SPtr& creator, const std::string& templateName, - std::map>& creatorsErrors, - std::vector< std::pair >& creators, - objectmodel::BaseObjectDescription* arg) -{ - if (helper::system::PluginManager::getInstance().isPluginUnloaded(creator->getTarget())) - { - creatorsErrors[templateName].emplace_back( - "The object was previously registered, but the module that " - "registered the object has been unloaded, preventing the object creation."); - arg->clearErrors(); - } - else - { - if (creator->canCreate(context, arg)) - { - creators.emplace_back(templateName, creator); - } - else - { - creatorsErrors[templateName] = arg->getErrors(); - arg->clearErrors(); - } - } -} - -objectmodel::BaseComponent::SPtr ObjectFactory::createObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) -{ - objectmodel::BaseComponent::SPtr object = nullptr; - std::vector< std::pair > creators; - std::string classname = arg->getAttribute( "type", ""); - std::string usertemplatename = arg->getAttribute( "template", ""); - ClassEntry::SPtr entry ; - - //////////////////////////////////////////////////////////////////////////////////////////////// - /// Process the template aliases. - /// (1) split in a vector the user provided templates by ',' - /// (2) for each entry search if there is an alias - /// (3) if there is none then keep value as is - /// otherwise replace the value with the alias. - /// if there is one and it is "undefined" generate a warning. - /// and "undefined" behavior means that the template is converting a specifically given - /// type precision into a different one. - /// (4) rebuild the template string by joining them all with ','. - std::vector usertemplatenames = sofa::helper::split(usertemplatename, ','); - std::vector deprecatedTemplates; - for(auto& name : usertemplatenames) - { - const sofa::defaulttype::TemplateAlias* alias; - if( (alias=sofa::defaulttype::TemplateAliases::getTemplateAlias(name)) != nullptr ) - { - assert(alias != nullptr); - /// This alias results in "undefined" behavior. - if( alias->second ) - { - deprecatedTemplates.push_back("The deprecated template '"+name+"' has been replaced by "+alias->first+"."); - } - - name = alias->first; - } - } - std::string templatename = sofa::helper::join(usertemplatenames, ","); - std::string userresolved = templatename; // Copy in case we change for the default one - //////////////////////////////////////////////////////////////////////////////////////////////// - - - //Check if object has been renamed - - using sofa::helper::lifecycle::renamedComponents; - auto renamedComponent = renamedComponents.find(classname); - if( renamedComponent != renamedComponents.end() ) - { - classname = renamedComponent->second.getNewName(); - } - - - // In order to get the errors from the creators only, we save the current errors at this point - // and we clear them. Once we extracted the errors from the creators, we put push them back. - std::map> creators_errors; // (template_name, errors) - const auto previous_errors = arg->getErrors(); - arg->clearErrors(); - - // For every classes in the registry - ClassEntryMap::iterator it = registry.find(classname); - if (it != registry.end()) // Found the classname - { - entry = it->second; - // If no template has been given or if the template does not exist, first try with the default one - if(templatename.empty() || !entry->creatorMap.contains(templatename)) - templatename = entry->defaultTemplate; - - - if (auto it2 = entry->creatorMap.find(templatename); - it2 != entry->creatorMap.end()) - { - findTemplatedCreator(context, it2->second, it2->first, creators_errors, creators, arg); - } - - // If object cannot be created with the given template (or the default one), try all possible ones - if (creators.empty()) - { - for (const auto& [creatorTemplateName, creator] : entry->creatorMap) - { - if (creatorTemplateName != templatename) - { - findTemplatedCreator(context, creator, creatorTemplateName, creators_errors, creators, arg); - } - } - } - } - - // Restore previous errors without the errors from the creator - arg->logErrors(previous_errors); - - if (creators.empty()) - { - //// The object cannot be created - arg->logError("Object type " + classname + std::string("<") + templatename + std::string("> was not created")); - - using sofa::helper::lifecycle::ComponentChange; - using sofa::helper::lifecycle::uncreatableComponents; - using sofa::helper::lifecycle::movedComponents; - using sofa::helper::lifecycle::dealiasedComponents; - if(it == registry.end()) - { - arg->logError("The component '" + classname + "' cannot be found in the factory."); - auto uncreatableComponent = uncreatableComponents.find(classname); - auto movedComponent = movedComponents.find(classname); - auto dealiasedComponent = dealiasedComponents.find(classname); - - const bool isUncreatable = uncreatableComponent != uncreatableComponents.end(); - const bool isMoved = movedComponent != movedComponents.end(); - const bool isDealiased = dealiasedComponent != dealiasedComponents.end(); - - const bool multipleReasons = static_cast(isUncreatable) + static_cast(isMoved) + static_cast(isDealiased) > 1; - std::size_t reasonNumber = 1; - const auto number = [&reasonNumber, multipleReasons]() -> std::string - { - return multipleReasons ? std::to_string(reasonNumber++) + ") " : ""; - }; - - if (multipleReasons) - { - arg->logError("Several reasons are possible:"); - } - - if(isUncreatable) - { - arg->logError(number() + uncreatableComponent->second.getMessage() ); - } - if (isMoved) - { - arg->logError(number() + movedComponent->second.getMessage() ); - } - if (isDealiased) - { - arg->logError(number() + dealiasedComponent->second.getMessage()); - } - else - { - std::vector possibleNames; - possibleNames.reserve(registry.size()); - for(auto& k : registry) - { - possibleNames.emplace_back(k.first); - } - - const auto closestMatches = sofa::helper::getClosestMatch(classname, possibleNames, 5, 0.6); - if (!closestMatches.empty()) - { - arg->logError("But the following object(s) exist:"); - for(auto& [name, score] : closestMatches) - { - arg->logError( " : " + name + " ("+ std::to_string((int)(100*score))+"% match)"); - } - } - } - } - else - { - std::stringstream tmp; - tmp << "The object is in the factory but cannot be created." << msgendl; - tmp << "Requested template : " << (usertemplatename.empty() ? "None" : usertemplatename) << msgendl; - if (templatename.empty()) { - tmp << "Used template : None" << msgendl; - } else { - tmp << "Used template : " << templatename; - if (templatename == entry->defaultTemplate) { - tmp << " (default)"; - } - tmp << msgendl; - } - - // Collect the errors from the creator with the specified (or default) template name - auto main_creator_errors_iterator = creators_errors.find(templatename); - if (main_creator_errors_iterator != creators_errors.end()) { - tmp << "Reason(s) : "; - if (main_creator_errors_iterator->second.empty()) { - tmp << "No reasons given" << msgendl; - } else if (main_creator_errors_iterator->second.size() == 1) { - tmp << main_creator_errors_iterator->second[0] << msgendl; - } else { - tmp << msgendl; - for (std::size_t i = 0; i < main_creator_errors_iterator->second.size(); ++i) { - tmp << " " << (i+1) << ". " << main_creator_errors_iterator->second[i] << msgendl; - } - } - creators_errors.erase(main_creator_errors_iterator); - } - - // Collect the errors from the creator with all remaining template names - if (! creators_errors.empty()) { - for (const auto & creator_errors_it : creators_errors) { - const std::string & creator_template_name = creator_errors_it.first; - const std::vector & creator_errors = creator_errors_it.second; - tmp << "Also tried to create the object with the template '"<logError(tmp.str()); - } - return nullptr; - } - - object = creators[0].second->createInstance(context, arg); - assert(object!=nullptr); - - /// The object has been created, but not with the template given by the user - if (!usertemplatename.empty() && object->getTemplateName() != userresolved) - { - std::vector templateList; - if (entry) - for (const auto& cr : entry->creatorMap) - templateList.push_back(cr.first); - std::stringstream ss; - bool isUserTemplateNameInTemplateList = false; - for(unsigned int i = 0; i < templateList.size(); ++i) - { - ss << templateList[i]; - isUserTemplateNameInTemplateList |= (templateList[i] == usertemplatename || templateList[i] == userresolved); - if (i != templateList.size() - 1) - ss << ", "; - } - if (isUserTemplateNameInTemplateList) - { - msg_error(object.get()) << "Requested template '" << usertemplatename << "' " - << "is not compatible with the current context. " - << "Falling back to the first compatible template: '" - << object->getTemplateName() << "'."; - } - else - { - msg_error(object.get()) << "Requested template '" << usertemplatename << "' " - << "cannot be found in the list of available templates [" << ss.str() << "]. " - << "Falling back to the first compatible template: '" - << object->getTemplateName() << "'."; - } - } - else if (creators.size() > 1) - { // There were multiple possibilities, we used the first one (not necessarily the default, as it can be incompatible) - std::string w = "Template '" + templatename + std::string("' incorrect, used ") + object->getTemplateName() + std::string(" in the list:"); - for(unsigned int i = 0; i < creators.size(); ++i) - w += std::string("\n\t* ") + creators[i].first; - msg_warning(object.get()) << w; - } - - ////////////////////////// This code is emitting a warning messages if the scene is loaded - if( m_callbackOnCreate ) - m_callbackOnCreate(object.get(), arg); - - ///////////////////////// All this code is just there to implement the MakeDataAlias component. - std::vector todelete; - for(auto& kv : entry->m_dataAlias) - { - if(object->findData(kv.first)==nullptr) - { - msg_warning(object.get()) << "The object '"<< (object->getClassName()) <<"' does not have an alias named '"<< kv.first <<"'. " - << "To remove this error message you need to use a valid data name for the 'dataname field'. "; - - todelete.push_back(kv.first); - } - } - - for(auto& todeletename : todelete) - { - entry->m_dataAlias.erase( entry->m_dataAlias.find(todeletename) ) ; - } - - for(auto& kv : entry->m_dataAlias) - { - objectmodel::BaseObjectDescription newdesc; - for(std::string& alias : kv.second){ - object->addAlias(object->findData(kv.first), alias.c_str()) ; - - /// The Alias is used in the argument - const std::string val(arg->getAttribute(alias)); - if( !val.empty() ){ - newdesc.setAttribute( alias, val ); - } - } - object->parse(&newdesc); - } - - /// We managed to create an object but there is error message in the log. Thus we emit them - /// as warning to this object. - if(!deprecatedTemplates.empty()) - { - msg_deprecated(object.get()) << sofa::helper::join(deprecatedTemplates, msgendl) ; - } - - return object; -} - -ObjectFactory* ObjectFactory::getInstance() -{ - static ObjectFactory instance; - return &instance; -} - -void ObjectFactory::getAllEntries(std::vector& result, const bool filterUnloadedPlugins) -{ - result.clear(); - for (const auto& [className, entry] : registry) - { - // Push the entry only if it is not an alias - if (entry->className == className) - { - result.push_back(entry); - } - } - - if (filterUnloadedPlugins) - { - for (auto itEntry = result.begin(); itEntry != result.end();) - { - auto& creatorMap = (*itEntry)->creatorMap; - for (auto itCreator = creatorMap.begin(); itCreator != creatorMap.end();) - { - if (helper::system::PluginManager::getInstance().isPluginUnloaded(itCreator->second->getTarget())) - { - itCreator = creatorMap.erase(itCreator); - } - else - { - ++itCreator; - } - } - - if (creatorMap.empty()) - { - itEntry = result.erase(itEntry); - } - else - { - ++itEntry; - } - } - } -} - -void ObjectFactory::getEntriesFromTarget(std::vector& result, std::string target) -{ - result.clear(); - for(ClassEntryMap::iterator it = registry.begin(), itEnd = registry.end(); - it != itEnd; ++it) - { - ClassEntry::SPtr entry = it->second; - if(entry->className == it->first) - { - - bool inTarget = false; - for (ObjectTemplateCreatorMap::iterator itc = entry->creatorMap.begin(), itcend = entry->creatorMap.end(); itc != itcend; ++itc) - { - const BaseObjectCreator::SPtr c = itc->second; - if (target == c->getTarget()) - { - inTarget = true; - break; - } - } - if (inTarget) - result.push_back(entry); - } - } -} - -std::string ObjectFactory::listClassesFromTarget(std::string target, std::string separator) -{ - std::vector entries; - getEntriesFromTarget(entries, target); - std::ostringstream oss; - for (unsigned int i=0; iclassName; - } - std::string result = oss.str(); - return result; -} - -void ObjectFactory::dump(std::ostream& out) -{ - for (ClassEntryMap::iterator it = registry.begin(), itend = registry.end(); it != itend; ++it) - { - const ClassEntry::SPtr entry = it->second; - if (entry->className != it->first) continue; - out << "class " << entry->className <<" :\n"; - if (!entry->aliases.empty()) - { - out << " aliases :"; - for (std::set::iterator myit = entry->aliases.begin(), aliasesEnd = entry->aliases.end(); myit != aliasesEnd; ++myit) - out << " " << *myit; - out << "\n"; - } - if (!entry->description.empty()) - out << entry->description; - if (!entry->authors.empty()) - out << " authors : " << entry->authors << "\n"; - if (!entry->license.empty()) - out << " license : " << entry->license << "\n"; - if (!entry->documentationURL.empty()) - out << " documentation : " << entry->documentationURL << "\n"; - for (ObjectTemplateCreatorMap::iterator itc = entry->creatorMap.begin(), itcend = entry->creatorMap.end(); itc != itcend; ++itc) - { - out << " template instance : " << itc->first << "\n"; - } - } -} - -static std::string xmlencode(const std::string& str) -{ - std::string res; - for (unsigned int i=0; i': res += ">"; break; - case '&': res += "&"; break; - case '"': res += """; break; - case '\'': res += "'"; break; - default: res += str[i]; - } - } - return res; -} - -void ObjectFactory::dumpXML(std::ostream& out) -{ - for (ClassEntryMap::iterator it = registry.begin(), itend = registry.end(); it != itend; ++it) - { - const ClassEntry::SPtr entry = it->second; - if (entry->className != it->first) continue; - out << "className) <<"\">\n"; - for (std::set::iterator myit = entry->aliases.begin(), aliasesEnd = entry->aliases.end(); myit != aliasesEnd; ++myit) - out << "" << xmlencode(*myit) << "\n"; - if (!entry->description.empty()) - out << ""<description<<"\n"; - if (!entry->authors.empty()) - out << ""<authors<<"\n"; - if (!entry->license.empty()) - out << ""<license<<"\n"; - if (!entry->documentationURL.empty()) - out << ""<documentationURL<<"\n"; - for (ObjectTemplateCreatorMap::iterator itc = entry->creatorMap.begin(), itcend = entry->creatorMap.end(); itc != itcend; ++itc) - { - out << "first.empty()) out << " template=\"" << xmlencode(itc->first) << "\""; - out << "/>\n"; - } - out << "\n"; - } -} - -void ObjectFactory::dumpHTML(std::ostream& out) -{ - out << "
    \n"; - for (ClassEntryMap::iterator it = registry.begin(), itend = registry.end(); it != itend; ++it) - { - const ClassEntry::SPtr entry = it->second; - if (entry->className != it->first) continue; - out << "
  • " << xmlencode(entry->className) <<"\n"; - if (!entry->description.empty()) - out << "
    "<description<<"\n"; - out << "
      \n"; - if (!entry->aliases.empty()) - { - out << "
    • Aliases:"; - for (std::set::iterator myit = entry->aliases.begin(), aliasesEnd = entry->aliases.end(); myit != aliasesEnd; ++myit) - out << " " << xmlencode(*myit); - out << "
    • \n"; - } - if (!entry->authors.empty()) - out << "
    • Authors: "<authors<<"
    • \n"; - if (!entry->license.empty()) - out << "
    • License: "<license<<"
    • \n"; - if (!entry->documentationURL.empty()) - out << "
    • Documentation: "<documentationURL<<"
    • \n"; - if (entry->creatorMap.size()>2 || (entry->creatorMap.size()==1 && !entry->creatorMap.begin()->first.empty())) - { - out << "
    • Template instances:"; - for (ObjectTemplateCreatorMap::iterator itc = entry->creatorMap.begin(), itcend = entry->creatorMap.end(); itc != itcend; ++itc) - { - if (itc->first == entry->defaultTemplate) - out << " " << xmlencode(itc->first) << ""; - else - out << " " << xmlencode(itc->first); - } - out << "
    • \n"; - } - out << "
    \n"; - out << "
  • \n"; - } - out << "
\n"; -} - -bool ObjectFactory::registerObjects(ObjectRegistrationData& ro) -{ - return ro.commitTo(this); -} - -ObjectRegistrationData::ObjectRegistrationData(const std::string& description) -{ - if (!description.empty()) - { - addDescription(description); - } -} - -ObjectRegistrationData& ObjectRegistrationData::addAlias(std::string val) -{ - entry.aliases.insert(val); - return *this; -} - -ObjectRegistrationData& ObjectRegistrationData::addDescription(std::string val) -{ - val += '\n'; - entry.description += val; - return *this; -} - -ObjectRegistrationData& ObjectRegistrationData::addAuthor(std::string val) -{ - val += ' '; - entry.authors += val; - return *this; -} - -ObjectRegistrationData& ObjectRegistrationData::addLicense(std::string val) -{ - entry.license += val; - return *this; -} - -ObjectRegistrationData& ObjectRegistrationData::addDocumentationURL(std::string url) -{ - entry.documentationURL += url; - return *this; -} - -ObjectRegistrationData& ObjectRegistrationData::addCreator(std::string classname, - std::string templatename, - ObjectFactory::BaseObjectCreator::SPtr creator) -{ - - if (!entry.className.empty() && entry.className != classname) - { - msg_error("ObjectFactory") << "Template already instantiated with a different classname: " << entry.className << " != " << classname; - } - else if (entry.creatorMap.contains(templatename)) - { - msg_error("ObjectFactory") << "Component already registered: " << classname << "<" << templatename << ">"; - } - else - { - entry.className = classname; - entry.creatorMap[templatename] = creator; - } - return *this; -} - -bool ObjectRegistrationData::commitTo(sofa::core::ObjectFactory* objectFactory) const -{ - if (entry.className.empty() || objectFactory == nullptr) - { - return false; - } - else - { - ObjectFactory::ClassEntry& reg = objectFactory->getEntry(entry.className); - reg.description += entry.description; - reg.authors += entry.authors; - reg.license += entry.license; - reg.documentationURL += entry.documentationURL; - if (!entry.defaultTemplate.empty()) - { - if (!reg.defaultTemplate.empty()) - { - msg_warning("ObjectFactory") << "Default template for class " << entry.className << " already registered (" << reg.defaultTemplate << "), do not register " << entry.defaultTemplate << " as the default"; - } - else - { - reg.defaultTemplate = entry.defaultTemplate; - } - } - for (const auto& creator_entry : entry.creatorMap) - { - const std::string & template_name = creator_entry.first; - const auto [it, success] = reg.creatorMap.insert(creator_entry); - if (!success) - { - std::string classType = entry.className; - if (!template_name.empty()) - { - classType += "<" + template_name + ">"; - } - - msg_warning("ObjectFactory") << "Class already registered in the ObjectFactory: " << classType; - } - } - - for (const auto & alias : entry.aliases) - { - if (!reg.aliases.contains(alias)) - { - objectFactory->addAlias(alias,entry.className); - } - } - return true; - } - -} - -typedef struct ObjectRegistrationEntry -{ - inline static const char* symbol = "registerObjects"; - typedef void (*FuncPtr) (sofa::core::ObjectFactory*); - FuncPtr func; - void operator()(sofa::core::ObjectFactory* data) - { - if (func) return func(data); - } - ObjectRegistrationEntry() :func(nullptr) {} -} ObjectRegistrationEntry; - -bool ObjectFactory::registerObjectsFromPlugin(const std::string& pluginName) -{ - sofa::helper::system::PluginManager& pluginManager = sofa::helper::system::PluginManager::getInstance(); - auto* plugin = pluginManager.getPlugin(pluginName); - if (plugin == nullptr) - { - msg_error("ObjectFactory") << pluginName << " has not been loaded yet."; - return false; - } - - // do not register if it was already done before - if(m_registeredPluginSet.contains(pluginName)) - { - // This warning should be generalized (i.e not only in dev mode) when runSofa will not auto-load modules/plugins by default anymore - // Commented warning since it is triggered even for SOFA meta-modules (e.g. Sofa.Components) - // dmsg_warning("ObjectFactory") << pluginName << " has already registered its components."; - return false; - } - - ObjectRegistrationEntry registerObjects; - if (pluginManager.getEntryFromPlugin(plugin, registerObjects)) - { - registerObjects(this); - m_registeredPluginSet.insert(pluginName); - return true; - } - else - { - return false; - } -} - -RegisterObject::RegisterObject(const std::string& description) - : m_objectRegistrationdata(description) -{ - -} - -RegisterObject& RegisterObject::addAlias(std::string val) -{ - m_objectRegistrationdata.addAlias(val); - return *this; -} - -RegisterObject& RegisterObject::addDescription(std::string val) -{ - m_objectRegistrationdata.addDescription(val); - return *this; -} - -RegisterObject& RegisterObject::addAuthor(std::string val) -{ - m_objectRegistrationdata.addAuthor(val); - return *this; -} - -RegisterObject& RegisterObject::addLicense(std::string val) -{ - m_objectRegistrationdata.addLicense(val); - return *this; -} - -RegisterObject& RegisterObject::addDocumentationURL(std::string url) -{ - m_objectRegistrationdata.addDocumentationURL(url); - return *this; -} - -RegisterObject& RegisterObject::addCreator(std::string classname, std::string templatename, - ObjectFactory::BaseObjectCreator::SPtr creator) -{ - m_objectRegistrationdata.addCreator(classname, templatename, creator); - return *this; -} - -RegisterObject::operator int() const -{ - dmsg_warning("RegisterObject") << m_objectRegistrationdata.entry.className - << ": Implicit object registration is deprecated since v24.12. Check #4429 for more information."; - return commitTo(ObjectFactory::getInstance()); -} - -int RegisterObject::commitTo(ObjectFactory* factory) const -{ - return (m_objectRegistrationdata.commitTo(factory) ? 1 : 0); -} - -} // namespace sofa::core diff --git a/Sofa/framework/Core/src/sofa/core/ObjectFactory.h b/Sofa/framework/Core/src/sofa/core/ObjectFactory.h index d297f11a72f..16b34881a49 100644 --- a/Sofa/framework/Core/src/sofa/core/ObjectFactory.h +++ b/Sofa/framework/Core/src/sofa/core/ObjectFactory.h @@ -21,408 +21,13 @@ ******************************************************************************/ #pragma once -#include - -#include -#include -#include -#include -#include - - -namespace sofa::helper::system -{ - class Plugin; -} +#include namespace sofa::core { -class ObjectRegistrationData; - -typedef std::function OnCreateCallback ; - -/** - * \brief Main class used to register and dynamically create objects - * - * It uses the Factory design pattern, where each class is registered in a map - * and dynamically retrieved given the type name. - * - * It also stores metainformation on each class, such as description, - * authors, license, and available template types. - */ -class SOFA_CORE_API ObjectFactory -{ -public: - - /** - * Abstract interface used to create instances (object) of a given type - * See the derived class @ref ObjectCreator. - */ - class SOFA_CORE_API BaseObjectCreator - { - public: - using SPtr = std::shared_ptr; - - virtual ~BaseObjectCreator() = default; - - /// Pre-construction check. - /// - /// \return true if the object can be created successfully. - virtual bool canCreate(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) = 0; - - /// Construction method called by the factory. - /// - /// \pre canCreate(context, arg) == true. - virtual objectmodel::BaseComponent::SPtr createInstance(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) = 0; - - /// type_info structure associated with the type of instantiated objects. - virtual const std::type_info& type() = 0; - - /// BaseClass structure associated with the type of instantiated objects. - virtual const objectmodel::BaseClass* getClass() = 0; - - /// The name of the library or executable containing the binary code for this component - virtual const char* getTarget() = 0; - - virtual const char* getHeaderFileLocation() = 0; - }; - using Creator SOFA_CORE_DEPRECATED_RENAME_CREATOR_BASEOBJECTCREATOR() = BaseObjectCreator; - - using TemplateName = std::string; - - /// For a given templated class, the map stores all creators and the key is the template name. - using ObjectTemplateCreatorMap = std::map; - - using CreatorMap SOFA_CORE_DEPRECATED_RENAME_CREATORMAP_OBJECTTEMPLATECREATORMAP() = ObjectTemplateCreatorMap; - - /// Record storing information about a class - class ClassEntry - { - public: - using SPtr = std::shared_ptr; - - std::string className; - std::set aliases; - std::string description; - std::string authors; - std::string license; - std::string documentationURL; - std::string defaultTemplate; - ObjectTemplateCreatorMap creatorMap; // to create instances of the class for different templates - std::map> m_dataAlias ; - }; - - using ClassName = std::string; - - /// Map to store all class entries, key is the class name. - using ClassEntryMap = std::map; - -protected: - - /// Main registry of all classes - ClassEntryMap registry; - - OnCreateCallback m_callbackOnCreate ; - - /// Keep track of plugins who already registered - using RegisteredPluginSet = std::set; - RegisteredPluginSet m_registeredPluginSet; - -public: - - ~ObjectFactory(); - - /// Get an entry given a class name (or alias) - ClassEntry& getEntry(std::string classname); - - /// Test if a creator exists for a given classname - bool hasCreator(std::string classname); - - /// Return the shortname for this classname. Empty string if - /// no creator exists for this classname. - std::string shortName(std::string classname); - - /// Fill the given vector with all the registered classes - void getAllEntries(std::vector& result, bool filterUnloadedPlugins = true); - - /// Fill the given vector with the registered classes from a given target - void getEntriesFromTarget(std::vector& result, std::string target); - - /// Return the list of classes from a given target - std::string listClassesFromTarget(std::string target, std::string separator = ", "); - - /// Fill the given vector with all the registered classes derived from BaseClass - template - void getEntriesDerivedFrom(std::vector& result) const; - - /// Return the list of classes derived from BaseClass as a string - template - std::string listClassesDerivedFrom(const std::string& separator = ", ") const; - - /// Add an alias name for an already registered class - /// - /// \param name name of the new alias - /// \param target class pointed to by the new alias - /// \param force set to true if this method should override any entry already registered for this name - /// \param previous (output) previous ClassEntry registered for this name - bool addAlias(std::string name, std::string target, bool force=false, - ClassEntry::SPtr* previous = nullptr); - - /// Reset an alias to a previous state - /// - /// \param name name of the new alias - /// \param previous previous ClassEntry that need to be registered back for this name - void resetAlias(std::string name, ClassEntry::SPtr previous); - - /// Create an object given a context and a description. - objectmodel::BaseComponent::SPtr createObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); - - /// Get the ObjectFactory singleton instance - static ObjectFactory* getInstance(); - - /// \copydoc createObject - static objectmodel::BaseComponent::SPtr CreateObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) - { - return getInstance()->createObject(context, arg); - } - - /// \copydoc addAlias - static bool AddAlias(std::string name, std::string result, bool force=false, - ClassEntry::SPtr* previous = nullptr) - { - return getInstance()->addAlias(name, result, force, previous); - } - - /// \copydoc resetAlias - static void ResetAlias(std::string name, ClassEntry::SPtr previous) - { - getInstance()->resetAlias(name, previous); - } - - /// \copydoc hasCreator - static bool HasCreator(std::string classname) - { - return getInstance()->hasCreator(classname); - } - - static std::string ShortName(std::string classname) - { - return getInstance()->shortName(classname); - } - - /// Dump the content of the factory to a text stream. - void dump(std::ostream& out = std::cout); - - /// Dump the content of the factory to a XML stream. - void dumpXML(std::ostream& out = std::cout); - - /// Dump the content of the factory to a HTML stream. - void dumpHTML(std::ostream& out = std::cout); - - void setCallback(OnCreateCallback cb) { m_callbackOnCreate = cb ; } - - bool registerObjectsFromPlugin(const std::string& pluginName); - bool registerObjects(ObjectRegistrationData& ro); - -}; - -template -void ObjectFactory::getEntriesDerivedFrom(std::vector& result) const -{ - result.clear(); - for (const auto& [mapKeyClassName, entryInRegistry] : registry) - { - // Discard the entry if its class name is not consistent with its key in the map. - // Differences happen for class aliases. - if (entryInRegistry->className == mapKeyClassName) - { - const auto& templateCreators = entryInRegistry->creatorMap; - const auto isAnyInstantiationDerived = std::any_of(templateCreators.begin(), templateCreators.end(), - [](const auto& it) - { - const auto& templateInstantiation = it.second; - const auto* instantiationClass = templateInstantiation->getClass(); - return instantiationClass - && instantiationClass->hasParent(BaseClass::GetClass()); - }); - if (isAnyInstantiationDerived) //at least one template instantiation of the class is derived from BaseClass - { - result.push_back(entryInRegistry); - } - } - } -} - -template -std::string ObjectFactory::listClassesDerivedFrom(const std::string& separator) const -{ - std::vector entries; - getEntriesDerivedFrom(entries); - - return sofa::helper::join(entries.begin(), entries.end(), - [](const ClassEntry::SPtr& entry){ return entry->className;}, separator); -} - -/** - * \brief Typed Creator class used to create instances of object type RealObject - */ -template -class ObjectCreator : public ObjectFactory::BaseObjectCreator -{ -public: - bool canCreate(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) override - { - RealObject* instance = nullptr; - return RealObject::canCreate(instance, context, arg); - } - objectmodel::BaseComponent::SPtr createInstance(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) override - { - RealObject* instance = nullptr; - return RealObject::create(instance, context, arg); - } - const std::type_info& type() override - { - return typeid(RealObject); - } - const objectmodel::BaseClass* getClass() override - { - return RealObject::GetClass(); - } - /// The name of the library or executable containing the binary code for this component - const char* getTarget() override - { -#ifdef SOFA_TARGET - return sofa_tostring(SOFA_TARGET); -#else - return ""; -#endif - } - - const char* getHeaderFileLocation() override - { - return RealObject::HeaderFileLocation(); - } -}; - -/** - * \brief Helper class used to register a class in the ObjectFactory. - * - * This class accumulate information about a given class, as well as creators - * for each supported template instantiation, to register a new entry in - * the ObjectFactory. - * - * It should be used as a temporary object, finalized when used to initialize - * an int static variable. For example : - * \code - * int Fluid3DClass = core::RegisterObject("Eulerian 3D fluid") - * .add\< Fluid3D \>() - * .addLicense("LGPL") - * ; - * \endcode - * - */ -class SOFA_CORE_API ObjectRegistrationData -{ -protected: - /// Class entry being constructed - ObjectFactory::ClassEntry entry; - -public: - - /// Start the registration by giving the description of this class. - explicit ObjectRegistrationData(const std::string& description); - - /// Add an alias name for this class - ObjectRegistrationData& addAlias(std::string val); - - /// Add more descriptive text about this class - ObjectRegistrationData& addDescription(std::string val); - - /// Specify a list of authors (separated with spaces) - ObjectRegistrationData& addAuthor(std::string val); - - /// Specify a license (LGPL, GPL, ...) - ObjectRegistrationData& addLicense(std::string val); - - /// Specify a documentation URL - ObjectRegistrationData& addDocumentationURL(std::string url); - - /// Add a creator able to instance this class with the given templatename. - /// - /// See the add() method for an easy way to add a Creator. - ObjectRegistrationData& addCreator(std::string classname, std::string templatename, - ObjectFactory::BaseObjectCreator::SPtr creator); - - /// Add a template instantiation of this class. - /// - /// \param defaultTemplate set to true if this should be the default instance when no template name is given. - template - ObjectRegistrationData& add(bool defaultTemplate=false) - { - const std::string classname = sofa::core::objectmodel::BaseClassNameHelper::getClassName(); - const std::string templatename = sofa::core::objectmodel::BaseClassNameHelper::getTemplateName(); - - if (defaultTemplate) - entry.defaultTemplate = templatename; - - if (entry.documentationURL.empty()) - { - const std::string target = sofa_tostring(SOFA_TARGET); - const auto modulePaths = sofa::helper::split(target, '.'); - if (modulePaths.size() > 2 && modulePaths[0] == "Sofa" && modulePaths[1] == "Component") - { - entry.documentationURL = std::string(sofa::SOFA_DOCUMENTATION_URL) + std::string("components/"); - entry.documentationURL += sofa::helper::join(modulePaths.begin() + 2, modulePaths.end(), - [](const std::string& m){ return sofa::helper::downcaseString(m);}, "/"); - entry.documentationURL += std::string("/") + sofa::helper::downcaseString(classname); - } - } - - auto objectCreator = std::make_shared >(); - if (strcmp(objectCreator->getTarget(), "") == 0) - { - dmsg_warning("ObjectFactory") << "Module name cannot be found when registering " - << RealObject::GetClass()->className << "<" << RealObject::GetClass()->templateName << "> into the object factory"; - } - return addCreator(classname, templatename, objectCreator); - } - - /// This is the final operation that will actually commit the additions to the ObjectFactory. - bool commitTo(sofa::core::ObjectFactory* objectFactory) const; - - friend class RegisterObject; -}; - - -// Legacy structure, to keep compatibility with olden code -// using the singleton to get the instance of ObjectFactory -class SOFA_ATTRIBUTE_DEPRECATED__REGISTEROBJECT() SOFA_CORE_API RegisterObject -{ -private: - ObjectRegistrationData m_objectRegistrationdata; - -public: - explicit RegisterObject(const std::string& description); - - RegisterObject& addAlias(std::string val); - RegisterObject& addDescription(std::string val); - RegisterObject& addAuthor(std::string val); - RegisterObject& addLicense(std::string val); - RegisterObject& addDocumentationURL(std::string url); - RegisterObject& addCreator(std::string classname, std::string templatename, - ObjectFactory::BaseObjectCreator::SPtr creator); - - template - RegisterObject& add(bool defaultTemplate = false) - { - m_objectRegistrationdata.add(defaultTemplate); - return *this; - } - - operator int() const; +using ObjectFactory = ComponentFactory; +using ObjectRegistrationData = ComponentRegistrationData; - int commitTo(ObjectFactory* factory) const; -}; } // namespace sofa::core diff --git a/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.cpp b/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.cpp index 348a006831f..cb623e830f3 100644 --- a/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.cpp +++ b/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.cpp @@ -1,157 +1,157 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -#include -#include - - -namespace sofa::core -{ - -namespace objectmodel -{ - -inline void to_json(nlohmann::json& json, - const objectmodel::BaseClass& baseClass) -{ - json["namespaceName"] = baseClass.namespaceName; - json["typeName"] = baseClass.typeName; - json["className"] = baseClass.className; - json["templateName"] = baseClass.templateName; - json["shortName"] = baseClass.shortName; - - sofa::type::vector parents; - parents.reserve(baseClass.parents.size()); - for (const auto* parent : baseClass.parents) - { - if (parent) - { - parents.push_back(parent->typeName); - } - } - json["parents"] = parents; - - std::vector categories; - sofa::core::CategoryLibrary::getCategories(&baseClass, categories); - json["categories"] = categories; -} - -inline void to_json(nlohmann::json& json, - const objectmodel::BaseData* data) -{ - if (data) - { - json["name"] = data->m_name; - json["group"] = data->group; - json["help"] = data->help; - json["type"] = data->getValueTypeString(); - json["defaultValue"] = data->getDefaultValueString(); - } -} - -inline void to_json(nlohmann::json& json, - const objectmodel::BaseLink* link) -{ - if (link) - { - json["name"] = link->getName(); - json["help"] = link->getHelp(); - json["destinationTypeName"] = link->getValueTypeString(); - } -} - -inline void to_json(nlohmann::json& json, - const objectmodel::BaseComponent::SPtr& object) -{ - if (object) - { - json["data"] = object->getDataFields(); - json["link"] = object->getLinks(); - } -} - -} - -inline void to_json(nlohmann::json& json, - const sofa::core::ObjectFactory::BaseObjectCreator::SPtr& creator) -{ - if (creator) - { - if (const char* target = creator->getTarget()) - { - json["target"] = target; - } - else - { - json["target"] = "targetCannotBeFound"; - } - json["class"] = *creator->getClass(); - - sofa::core::objectmodel::BaseObjectDescription desc; - if (const auto object = creator->createInstance(nullptr, &desc)) - { - json["object"] = object; - } - } -} - -inline void to_json(nlohmann::json& json, - const sofa::core::ObjectFactory::ClassEntry::SPtr& entry) -{ - if (entry) - { - json["className"] = entry->className; - json["description"] = entry->description; - - json["creator"] = entry->creatorMap; - } -} - -std::string ObjectFactoryJson::dump(ObjectFactory* factory) -{ - if (!factory) - { - msg_error("ObjectFactoryJson") << "Invalid factory: cannot dump to json"; - return {}; - } - - std::vector entries; - factory->getAllEntries(entries, true); - - const nlohmann::json json = entries; - - std::string dump{}; - - try - { - dump = json.dump(); - } - catch (const nlohmann::json::type_error& e) - { - msg_error("ObjectFactoryJson") << "Error while dumping json from the object factory: " << e.what(); - dump = json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace); - } - - return dump; -} -} +// /****************************************************************************** +// * SOFA, Simulation Open-Framework Architecture * +// * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +// * * +// * This program is free software; you can redistribute it and/or modify it * +// * under the terms of the GNU Lesser General Public License as published by * +// * the Free Software Foundation; either version 2.1 of the License, or (at * +// * your option) any later version. * +// * * +// * This program is distributed in the hope that it will be useful, but WITHOUT * +// * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +// * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +// * for more details. * +// * * +// * You should have received a copy of the GNU Lesser General Public License * +// * along with this program. If not, see . * +// ******************************************************************************* +// * Authors: The SOFA Team and external contributors (see Authors.txt) * +// * * +// * Contact information: contact@sofa-framework.org * +// ******************************************************************************/ +// #include +// #include +// #include +// #include +// +// +// namespace sofa::core +// { +// +// namespace objectmodel +// { +// +// inline void to_json(nlohmann::json& json, +// const objectmodel::BaseClass& baseClass) +// { +// json["namespaceName"] = baseClass.namespaceName; +// json["typeName"] = baseClass.typeName; +// json["className"] = baseClass.className; +// json["templateName"] = baseClass.templateName; +// json["shortName"] = baseClass.shortName; +// +// sofa::type::vector parents; +// parents.reserve(baseClass.parents.size()); +// for (const auto* parent : baseClass.parents) +// { +// if (parent) +// { +// parents.push_back(parent->typeName); +// } +// } +// json["parents"] = parents; +// +// std::vector categories; +// sofa::core::CategoryLibrary::getCategories(&baseClass, categories); +// json["categories"] = categories; +// } +// +// inline void to_json(nlohmann::json& json, +// const objectmodel::BaseData* data) +// { +// if (data) +// { +// json["name"] = data->m_name; +// json["group"] = data->group; +// json["help"] = data->help; +// json["type"] = data->getValueTypeString(); +// json["defaultValue"] = data->getDefaultValueString(); +// } +// } +// +// inline void to_json(nlohmann::json& json, +// const objectmodel::BaseLink* link) +// { +// if (link) +// { +// json["name"] = link->getName(); +// json["help"] = link->getHelp(); +// json["destinationTypeName"] = link->getValueTypeString(); +// } +// } +// +// inline void to_json(nlohmann::json& json, +// const objectmodel::BaseComponent::SPtr& object) +// { +// if (object) +// { +// json["data"] = object->getDataFields(); +// json["link"] = object->getLinks(); +// } +// } +// +// } +// +// inline void to_json(nlohmann::json& json, +// const sofa::core::ObjectFactory::BaseObjectCreator::SPtr& creator) +// { +// if (creator) +// { +// if (const char* target = creator->getTarget()) +// { +// json["target"] = target; +// } +// else +// { +// json["target"] = "targetCannotBeFound"; +// } +// json["class"] = *creator->getClass(); +// +// sofa::core::objectmodel::BaseObjectDescription desc; +// if (const auto object = creator->createInstance(nullptr, &desc)) +// { +// json["object"] = object; +// } +// } +// } +// +// inline void to_json(nlohmann::json& json, +// const sofa::core::ObjectFactory::ClassEntry::SPtr& entry) +// { +// if (entry) +// { +// json["className"] = entry->className; +// json["description"] = entry->description; +// +// json["creator"] = entry->creatorMap; +// } +// } +// +// std::string ObjectFactoryJson::dump(ObjectFactory* factory) +// { +// if (!factory) +// { +// msg_error("ObjectFactoryJson") << "Invalid factory: cannot dump to json"; +// return {}; +// } +// +// std::vector entries; +// factory->getAllEntries(entries, true); +// +// const nlohmann::json json = entries; +// +// std::string dump{}; +// +// try +// { +// dump = json.dump(); +// } +// catch (const nlohmann::json::type_error& e) +// { +// msg_error("ObjectFactoryJson") << "Error while dumping json from the object factory: " << e.what(); +// dump = json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace); +// } +// +// return dump; +// } +// } diff --git a/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.h b/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.h index 393f75ab778..9fd4cba4e97 100644 --- a/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.h +++ b/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.h @@ -26,10 +26,10 @@ namespace sofa::core { -class ObjectFactory; -struct SOFA_CORE_API ObjectFactoryJson -{ - static std::string dump(ObjectFactory* factory); -}; +// class ObjectFactory; +// struct SOFA_CORE_API ObjectFactoryJson +// { +// static std::string dump(ObjectFactory* factory); +// }; } diff --git a/Sofa/framework/Core/src/sofa/core/SofaLibrary.cpp b/Sofa/framework/Core/src/sofa/core/SofaLibrary.cpp index 0b29730050e..79f69853b3f 100644 --- a/Sofa/framework/Core/src/sofa/core/SofaLibrary.cpp +++ b/Sofa/framework/Core/src/sofa/core/SofaLibrary.cpp @@ -1,153 +1,153 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include -#include - - -namespace sofa::core -{ - -//Automatically create and destroy all the components available: easy way to verify the default constructor and destructor -void SofaLibrary::build( const std::vector< std::string >& examples) -{ - exampleFiles=examples; - //----------------------------------------------------------------------- - //Read the content of the Object Factory - //----------------------------------------------------------------------- - std::vector entries; - sofa::core::ObjectFactory::getInstance()->getAllEntries(entries); - //Set of categories found in the Object Factory - std::set< std::string > mainCategories; - //Data containing all the entries for a given category - std::multimap< std::string, ClassEntry::SPtr> inventory; - - for (std::size_t i=0; icreatorMap.begin(); - if (creatorEntry != entries[i]->creatorMap.end()) - { - const objectmodel::BaseClass* baseClass = creatorEntry->second->getClass(); - std::vector categoriesVec; - CategoryLibrary::getCategories(baseClass, categoriesVec); - for (std::vector::iterator it = categoriesVec.begin(); it != categoriesVec.end(); ++it) - { - mainCategories.insert((*it)); - inventory.insert(std::make_pair((*it), entries[i])); - } - } - } - - //----------------------------------------------------------------------- - //Using the inventory, Add each component to the Sofa Library - //----------------------------------------------------------------------- - std::set< std::string >::iterator itCategory; - typedef std::multimap< std::string, ClassEntry::SPtr >::iterator IteratorInventory; - - - //We add the components category by category - for (itCategory = mainCategories.begin(); itCategory != mainCategories.end(); ++itCategory) - { - const std::string& categoryName = *itCategory; - IteratorInventory itComponent; - - std::pair< IteratorInventory,IteratorInventory > rangeCategory; - rangeCategory = inventory.equal_range(categoryName); - - - - const unsigned int numComponentInCategory = (unsigned int)inventory.count(categoryName); - CategoryLibrary *category = createCategory(categoryName,numComponentInCategory); - - //Process all the component of the current category, and add them to the group - for (itComponent=rangeCategory.first; itComponent != rangeCategory.second; ++itComponent) - { - const ClassEntry::SPtr entry = itComponent->second; - const std::string &componentName=entry->className; - - //Add the component to the category - category->addComponent(componentName, entry, exampleFiles); - } - category->endConstruction(); - addCategory(category); - } - computeNumComponents(); -} - -void SofaLibrary::computeNumComponents() -{ - numComponents=0; - for (std::size_t cat=0; catgetNumComponents(); - } - -} - -void SofaLibrary::addCategory(CategoryLibrary *category) -{ - categories.push_back(category); -} - - -std::string SofaLibrary::getComponentDescription( const std::string &componentName ) const -{ - const ComponentLibrary *component = getComponent(componentName); - if (component) return component->getDescription(); - else return ""; -} - -const CategoryLibrary *SofaLibrary::getCategory( const std::string &categoryName) const -{ - for (VecCategoryIterator it=categories.begin(); it != categories.end(); ++it) - { - if ((*it)->getName().find(categoryName) != std::string::npos) - return *it; - } - return nullptr; -} - -const ComponentLibrary *SofaLibrary::getComponent( const std::string &componentName ) const -{ - //Look into all the categories - for (std::size_t cat=0; cat &components = categories[cat]->getComponents(); - for (std::size_t comp=0; compgetName()) return components[comp]; - } - } - return nullptr; -} - -void SofaLibrary::clear() -{ - for (std::size_t i=0; i. * +// ******************************************************************************* +// * Authors: The SOFA Team and external contributors (see Authors.txt) * +// * * +// * Contact information: contact@sofa-framework.org * +// ******************************************************************************/ +// +// #include +// #include +// +// +// namespace sofa::core +// { +// +// //Automatically create and destroy all the components available: easy way to verify the default constructor and destructor +// void SofaLibrary::build( const std::vector< std::string >& examples) +// { +// exampleFiles=examples; +// //----------------------------------------------------------------------- +// //Read the content of the Object Factory +// //----------------------------------------------------------------------- +// std::vector entries; +// sofa::core::ObjectFactory::getInstance()->getAllEntries(entries); +// //Set of categories found in the Object Factory +// std::set< std::string > mainCategories; +// //Data containing all the entries for a given category +// std::multimap< std::string, ClassEntry::SPtr> inventory; +// +// for (std::size_t i=0; icreatorMap.begin(); +// if (creatorEntry != entries[i]->creatorMap.end()) +// { +// const objectmodel::BaseClass* baseClass = creatorEntry->second->getClass(); +// std::vector categoriesVec; +// CategoryLibrary::getCategories(baseClass, categoriesVec); +// for (std::vector::iterator it = categoriesVec.begin(); it != categoriesVec.end(); ++it) +// { +// mainCategories.insert((*it)); +// inventory.insert(std::make_pair((*it), entries[i])); +// } +// } +// } +// +// //----------------------------------------------------------------------- +// //Using the inventory, Add each component to the Sofa Library +// //----------------------------------------------------------------------- +// std::set< std::string >::iterator itCategory; +// typedef std::multimap< std::string, ClassEntry::SPtr >::iterator IteratorInventory; +// +// +// //We add the components category by category +// for (itCategory = mainCategories.begin(); itCategory != mainCategories.end(); ++itCategory) +// { +// const std::string& categoryName = *itCategory; +// IteratorInventory itComponent; +// +// std::pair< IteratorInventory,IteratorInventory > rangeCategory; +// rangeCategory = inventory.equal_range(categoryName); +// +// +// +// const unsigned int numComponentInCategory = (unsigned int)inventory.count(categoryName); +// CategoryLibrary *category = createCategory(categoryName,numComponentInCategory); +// +// //Process all the component of the current category, and add them to the group +// for (itComponent=rangeCategory.first; itComponent != rangeCategory.second; ++itComponent) +// { +// const ClassEntry::SPtr entry = itComponent->second; +// const std::string &componentName=entry->className; +// +// //Add the component to the category +// category->addComponent(componentName, entry, exampleFiles); +// } +// category->endConstruction(); +// addCategory(category); +// } +// computeNumComponents(); +// } +// +// void SofaLibrary::computeNumComponents() +// { +// numComponents=0; +// for (std::size_t cat=0; catgetNumComponents(); +// } +// +// } +// +// void SofaLibrary::addCategory(CategoryLibrary *category) +// { +// categories.push_back(category); +// } +// +// +// std::string SofaLibrary::getComponentDescription( const std::string &componentName ) const +// { +// const ComponentLibrary *component = getComponent(componentName); +// if (component) return component->getDescription(); +// else return ""; +// } +// +// const CategoryLibrary *SofaLibrary::getCategory( const std::string &categoryName) const +// { +// for (VecCategoryIterator it=categories.begin(); it != categories.end(); ++it) +// { +// if ((*it)->getName().find(categoryName) != std::string::npos) +// return *it; +// } +// return nullptr; +// } +// +// const ComponentLibrary *SofaLibrary::getComponent( const std::string &componentName ) const +// { +// //Look into all the categories +// for (std::size_t cat=0; cat &components = categories[cat]->getComponents(); +// for (std::size_t comp=0; compgetName()) return components[comp]; +// } +// } +// return nullptr; +// } +// +// void SofaLibrary::clear() +// { +// for (std::size_t i=0; i. * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -namespace sofa::core -{ - - -/** - * \brief An Generic Library - * - * It reads the content of the Object Factory and builds a library of components sorted inside categories. - * This Interface is used for the Modeler mainly. - * - */ -class SOFA_CORE_API SofaLibrary -{ -public: - typedef std::vector< CategoryLibrary* > VecCategory; - typedef VecCategory::const_iterator VecCategoryIterator; - - virtual ~SofaLibrary() {} - - virtual void build(const std::vector< std::string >& examples=std::vector< std::string >()); - virtual void clear(); - - std::string getComponentDescription( const std::string &componentName) const; - - const VecCategory& getCategories() const {return categories;}; - - const CategoryLibrary *getCategory( const std::string &categoryName ) const; - const ComponentLibrary *getComponent( const std::string &componentName) const; - unsigned int getNumComponents() const {return numComponents;} - -protected: - virtual CategoryLibrary *createCategory(const std::string &category, - unsigned int /* numCategory */) { - return new CategoryLibrary(category); - } - virtual void addCategory(CategoryLibrary *); - void computeNumComponents(); - - VecCategory categories; - std::vector< std::string > exampleFiles; - unsigned int numComponents; - -}; - -} +// /****************************************************************************** +// * SOFA, Simulation Open-Framework Architecture * +// * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +// * * +// * This program is free software; you can redistribute it and/or modify it * +// * under the terms of the GNU Lesser General Public License as published by * +// * the Free Software Foundation; either version 2.1 of the License, or (at * +// * your option) any later version. * +// * * +// * This program is distributed in the hope that it will be useful, but WITHOUT * +// * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +// * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +// * for more details. * +// * * +// * You should have received a copy of the GNU Lesser General Public License * +// * along with this program. If not, see . * +// ******************************************************************************* +// * Authors: The SOFA Team and external contributors (see Authors.txt) * +// * * +// * Contact information: contact@sofa-framework.org * +// ******************************************************************************/ +// #pragma once +// +// #include +// +// namespace sofa::core +// { +// +// +// /** +// * \brief An Generic Library +// * +// * It reads the content of the Object Factory and builds a library of components sorted inside categories. +// * This Interface is used for the Modeler mainly. +// * +// */ +// class SOFA_CORE_API SofaLibrary +// { +// public: +// typedef std::vector< CategoryLibrary* > VecCategory; +// typedef VecCategory::const_iterator VecCategoryIterator; +// +// virtual ~SofaLibrary() {} +// +// virtual void build(const std::vector< std::string >& examples=std::vector< std::string >()); +// virtual void clear(); +// +// std::string getComponentDescription( const std::string &componentName) const; +// +// const VecCategory& getCategories() const {return categories;}; +// +// const CategoryLibrary *getCategory( const std::string &categoryName ) const; +// const ComponentLibrary *getComponent( const std::string &componentName) const; +// unsigned int getNumComponents() const {return numComponents;} +// +// protected: +// virtual CategoryLibrary *createCategory(const std::string &category, +// unsigned int /* numCategory */) { +// return new CategoryLibrary(category); +// } +// virtual void addCategory(CategoryLibrary *); +// void computeNumComponents(); +// +// VecCategory categories; +// std::vector< std::string > exampleFiles; +// unsigned int numComponents; +// +// }; +// +// } diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultAnimationLoop.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultAnimationLoop.cpp index 605062dedf9..fb920a31b36 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultAnimationLoop.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultAnimationLoop.cpp @@ -51,7 +51,7 @@ #include #include #include - +#include namespace sofa::simulation { diff --git a/applications/projects/SceneChecking/src/SceneChecking/SceneCheckMissingRequiredPlugin.cpp b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckMissingRequiredPlugin.cpp index ffa39e73864..27d905fbda2 100644 --- a/applications/projects/SceneChecking/src/SceneChecking/SceneCheckMissingRequiredPlugin.cpp +++ b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckMissingRequiredPlugin.cpp @@ -51,32 +51,32 @@ const std::string SceneCheckMissingRequiredPlugin::getDesc() void SceneCheckMissingRequiredPlugin::doCheckOn(sofa::simulation::Node* node) { - for (const auto& object : node->object) - { - const ObjectFactory::ClassEntry entry = ObjectFactory::getInstance()->getEntry(object->getClassName()); - if(!entry.creatorMap.empty()) - { - ObjectFactory::ObjectTemplateCreatorMap::const_iterator it = entry.creatorMap.find(object->getTemplateName()); - if(entry.creatorMap.end() != it && *it->second->getTarget()) - { - const std::string pluginName = it->second->getTarget(); - const std::string path = PluginManager::getInstance().findPlugin(pluginName); - if( PluginManager::getInstance().pluginIsLoaded(path) - && !m_loadedPlugins.contains(pluginName)) - { - m_requiredPlugins[pluginName].push_back(object->getClassName()); - } - } - } - } - - //sort and remove duplicates - for (auto& plugins : m_requiredPlugins) - { - auto& v = plugins.second; - std::sort(v.begin(), v.end()); - v.erase(std::unique(v.begin(), v.end()), v.end()); - } + // for (const auto& object : node->object) + // { + // const ObjectFactory::ClassEntry entry = ObjectFactory::getInstance()->getEntry(object->getClassName()); + // if(!entry.creatorMap.empty()) + // { + // ObjectFactory::ObjectTemplateCreatorMap::const_iterator it = entry.creatorMap.find(object->getTemplateName()); + // if(entry.creatorMap.end() != it && *it->second->getTarget()) + // { + // const std::string pluginName = it->second->getTarget(); + // const std::string path = PluginManager::getInstance().findPlugin(pluginName); + // if( PluginManager::getInstance().pluginIsLoaded(path) + // && !m_loadedPlugins.contains(pluginName)) + // { + // m_requiredPlugins[pluginName].push_back(object->getClassName()); + // } + // } + // } + // } + // + // //sort and remove duplicates + // for (auto& plugins : m_requiredPlugins) + // { + // auto& v = plugins.second; + // std::sort(v.begin(), v.end()); + // v.erase(std::unique(v.begin(), v.end()), v.end()); + // } } void SceneCheckMissingRequiredPlugin::printSummary(simulation::SceneLoader* sceneLoader) diff --git a/applications/projects/SceneChecking/src/SceneChecking/SceneCheckUsingAlias.cpp b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckUsingAlias.cpp index a94e895a5cc..40d02d4d5f2 100644 --- a/applications/projects/SceneChecking/src/SceneChecking/SceneCheckUsingAlias.cpp +++ b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckUsingAlias.cpp @@ -40,13 +40,13 @@ using sofa::core::ObjectFactory; SceneCheckUsingAlias::SceneCheckUsingAlias() { /// Add a callback to be n - ObjectFactory::getInstance()->setCallback([this](Base* o, BaseObjectDescription *arg) { - const std::string typeNameInScene = arg->getAttribute("type", ""); - if ( typeNameInScene != o->getClassName() ) - { - this->m_componentsCreatedUsingAlias[o->getClassName()].push_back(typeNameInScene); - } - }); + // ObjectFactory::getInstance()->setCallback([this](Base* o, BaseObjectDescription *arg) { + // const std::string typeNameInScene = arg->getAttribute("type", ""); + // if ( typeNameInScene != o->getClassName() ) + // { + // this->m_componentsCreatedUsingAlias[o->getClassName()].push_back(typeNameInScene); + // } + // }); } SceneCheckUsingAlias::~SceneCheckUsingAlias()