diff --git a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h index 6dd41130825..40a1971067d 100644 --- a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h +++ b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h @@ -70,7 +70,9 @@ class Distances : public core::DataEngine DistancesInternalData data; friend class DistancesInternalData; - Distances ( sofa::component::topology::container::dynamic::DynamicSparseGridTopologyContainer* hexaTopoContainer, core::behavior::MechanicalState* targetPointSet ); + explicit Distances( + topology::container::dynamic::DynamicSparseGridTopologyContainer* hexaTopoContainer = nullptr, + core::behavior::MechanicalState* targetPointSet = nullptr ); ~Distances() override {} diff --git a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SparseLDLSolver.cpp b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SparseLDLSolver.cpp index 5b336137077..c757d91a13c 100644 --- a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SparseLDLSolver.cpp +++ b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SparseLDLSolver.cpp @@ -29,11 +29,23 @@ namespace sofa::component::linearsolver::direct using namespace sofa::linearalgebra; +constexpr std::string_view description { "Direct linear solver using a Sparse LDL^T factorization." }; + +template +void registerComponent(sofa::core::ComponentFactory* factory) +{ + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription(std::string(description)) + .template addTemplateAttribute("matrixType") + ); +}; + void registerSparseLDLSolver(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Direct linear solver using a Sparse LDL^T factorization.") - .add< SparseLDLSolver< CompressedRowSparseMatrix, FullVector > >(true) - .add< SparseLDLSolver< CompressedRowSparseMatrix >, FullVector > >()); + registerComponent, FullVector>(factory); + registerComponent>, FullVector>(factory); } template class SOFA_COMPONENT_LINEARSOLVER_DIRECT_API SparseLDLSolver< CompressedRowSparseMatrix,FullVector >; diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMapping.cpp b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMapping.cpp index 8617f33bc88..a3d429fb178 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMapping.cpp +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMapping.cpp @@ -32,8 +32,14 @@ using namespace sofa::defaulttype; void registerBarycentricMapping(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Mapping using barycentric coordinates of the child with respect to cells of its parent.") - .add< BarycentricMapping< Vec3Types, Vec3Types > >(true)); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Mapping using barycentric coordinates of the child with respect to cells of its parent.") + .template addTemplateAttribute("inDofType") + .template addTemplateAttribute("outDofType") + .template withDeductionRule>>() + ); } template class SOFA_COMPONENT_MAPPING_LINEAR_API BarycentricMapping< Vec3Types, Vec3Types >; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.cpp index cad84bcd07f..613200e9f78 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.cpp @@ -32,8 +32,11 @@ using namespace sofa::defaulttype; void registerBeamFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Beam finite elements.") - .add< BeamFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Beam finite elements.") + ); } namespace _beamfemforcefield_ @@ -43,4 +46,4 @@ namespace _beamfemforcefield_ } // namespace _beamfemforcefield_ -} // namespace sofa::component::solidmechanics::fem::elastic \ No newline at end of file +} // namespace sofa::component::solidmechanics::fem::elastic diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/CorotationalFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/CorotationalFEMForceField.cpp index efd7c5d6bca..1b3ba139284 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/CorotationalFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/CorotationalFEMForceField.cpp @@ -29,22 +29,34 @@ namespace sofa::component::solidmechanics::fem::elastic { -void registerCorotationalFEMForceField(sofa::core::ObjectFactory* factory) +static constexpr std::string_view description { "Hooke's law using the corotational approach" }; + +template +void registerComponent(sofa::core::ObjectFactory* factory) { - factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law using the corotational approach") - // .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() - .add< CorotationalFEMForceField >() + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription(std::string(description)) + .template addTemplateAttribute("dofType") + .addTemplateAttribute("elementType", sofa::geometry::elementTypeToString(ElementType::Element_type)) ); } +void registerCorotationalFEMForceField(sofa::core::ObjectFactory* factory) +{ + // registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); +} + // template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API CorotationalFEMForceField; template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API CorotationalFEMForceField; template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API CorotationalFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.cpp index b53d9746a7e..d5fb127ebc7 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.cpp @@ -33,8 +33,12 @@ using namespace sofa::defaulttype; void registerFastTetrahedralCorotationalForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Fast Corotational Tetrahedral Mesh.") - .add< FastTetrahedralCorotationalForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Fast Corotational Tetrahedral Mesh.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API FastTetrahedralCorotationalForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.cpp index 8f1861c8d33..27f37b22f25 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.cpp @@ -32,8 +32,12 @@ using namespace sofa::defaulttype; void registerHexahedralFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Hexahedral finite elements.") - .add< HexahedralFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Hexahedral finite elements.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API HexahedralFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.cpp index bb5d20549a4..0e9dad8b04f 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.cpp @@ -32,8 +32,12 @@ using namespace sofa::defaulttype; void registerHexahedralFEMForceFieldAndMass(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Hexahedral finite elements with mass") - .add< HexahedralFEMForceFieldAndMass >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Hexahedral finite elements with mass") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API HexahedralFEMForceFieldAndMass; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.cpp index d0a796b234d..25711fe4896 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.cpp @@ -32,8 +32,12 @@ using namespace sofa::defaulttype; void registerHexahedronFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Hexahedral finite elements.") - .add< HexahedronFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Hexahedral finite elements.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API HexahedronFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceFieldAndMass.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceFieldAndMass.cpp index 79e828ac592..8df4e713051 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceFieldAndMass.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceFieldAndMass.cpp @@ -31,12 +31,16 @@ using namespace sofa::defaulttype; void registerHexahedronFEMForceFieldAndMass(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Hexahedral finite elements with mass.") - .add< HexahedronFEMForceFieldAndMass >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Hexahedral finite elements with mass.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API HexahedronFEMForceFieldAndMass; -} // namespace sofa::component::solidmechanics::fem::elastic \ No newline at end of file +} // namespace sofa::component::solidmechanics::fem::elastic diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/LinearSmallStrainFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/LinearSmallStrainFEMForceField.cpp index 52a1eb9a6e2..5feccd9e48c 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/LinearSmallStrainFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/LinearSmallStrainFEMForceField.cpp @@ -29,22 +29,34 @@ namespace sofa::component::solidmechanics::fem::elastic { -void registerLinearSmallStrainFEMForceField(sofa::core::ObjectFactory* factory) +static constexpr std::string_view description { "Hooke's law assuming small strain" }; + +template +void registerComponent(sofa::core::ObjectFactory* factory) { - factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law assuming small strain") - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() - .add< LinearSmallStrainFEMForceField >() + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription(std::string(description)) + .template addTemplateAttribute("dofType") + .addTemplateAttribute("elementType", sofa::geometry::elementTypeToString(ElementType::Element_type)) ); } +void registerLinearSmallStrainFEMForceField(sofa::core::ObjectFactory* factory) +{ + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); +} + template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API LinearSmallStrainFEMForceField; template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API LinearSmallStrainFEMForceField; template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API LinearSmallStrainFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.cpp index e28740b453a..1b43e6572ac 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.cpp @@ -36,8 +36,12 @@ using namespace sofa::defaulttype; void registerQuadBendingFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Bending Quad finite elements") - .add< QuadBendingFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Bending Quad finite elements") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API QuadBendingFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.cpp index 3d88496861e..4a014b40729 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.cpp @@ -33,8 +33,12 @@ using namespace sofa::defaulttype; void registerTetrahedralCorotationalFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Corotational FEM Tetrahedral finite elements") - .add< TetrahedralCorotationalFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Corotational FEM Tetrahedral finite elements") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API TetrahedralCorotationalFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.cpp index 853c16850f8..613be7440b3 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.cpp @@ -33,8 +33,12 @@ using namespace sofa::defaulttype; void registerTetrahedronFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Tetrahedral finite elements.") - .add< TetrahedronFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Tetrahedral finite elements.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API TetrahedronFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.cpp index 6bb56243188..dcbfbc5103d 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.cpp @@ -33,8 +33,12 @@ using namespace sofa::defaulttype; void registerTriangleFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Triangular finite elements for static topology.") - .add< TriangleFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Triangular finite elements for static topology.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API TriangleFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.cpp index a0df8632e60..29c2f854a56 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.cpp @@ -31,8 +31,12 @@ using namespace sofa::defaulttype; void registerTriangularAnisotropicFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Triangular finite element model using anisotropic material.") - .add< TriangularAnisotropicFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Triangular finite element model using anisotropic material.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API TriangularAnisotropicFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.cpp index 6224c5da527..e5896fca806 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.cpp @@ -34,8 +34,12 @@ using namespace sofa::defaulttype; void registerTriangularFEMForceField(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Corotational Triangular finite elements for dynamic topology.") - .add< TriangularFEMForceField >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Corotational Triangular finite elements for dynamic topology.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API TriangularFEMForceField; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceFieldOptim.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceFieldOptim.cpp index 5b31f4ce4d5..28a5750ba1e 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceFieldOptim.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceFieldOptim.cpp @@ -32,8 +32,12 @@ using namespace sofa::defaulttype; void registerTriangularFEMForceFieldOptim(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Corotational Triangular finite elements.") - .add< TriangularFEMForceFieldOptim >()); + factory->registerComponent( + core::CreateComponent>() + .withModule(MODULE_NAME) + .withDescription("Corotational Triangular finite elements.") + .template addTemplateAttribute("dofType") + ); } template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API TriangularFEMForceFieldOptim; diff --git a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.cpp b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.cpp index 9763be97bde..dbff2488cb9 100644 --- a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.cpp +++ b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.cpp @@ -41,15 +41,28 @@ template class SOFA_COMPONENT_STATECONTAINER_API MechanicalObject; template class SOFA_COMPONENT_STATECONTAINER_API MechanicalObject; template class SOFA_COMPONENT_STATECONTAINER_API MechanicalObject; +static constexpr std::string_view description {"Mechanical state vectors"}; + +template +void registerComponent(sofa::core::ComponentFactory* factory) +{ + factory->registerComponent( + core::CreateComponent>("MechanicalObject") + .withModule(MODULE_NAME) + .withDescription(std::string(description)) + .template addTemplateAttribute("dofType") + ); +}; + void registerMechanicalObject(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("mechanical state vectors") - .add< MechanicalObject >(true) // default template - .add< MechanicalObject >() - .add< MechanicalObject >() - .add< MechanicalObject >() - .add< MechanicalObject >() - .add< MechanicalObject >()); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + registerComponent(factory); + } template<> 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/Component/src/sofa/component/init.cpp b/Sofa/Component/src/sofa/component/init.cpp index 6e1494deb84..3bb59ff5a99 100644 --- a/Sofa/Component/src/sofa/component/init.cpp +++ b/Sofa/Component/src/sofa/component/init.cpp @@ -44,7 +44,7 @@ #include #include -#include +#include #include namespace sofa::component @@ -54,7 +54,7 @@ extern "C" { SOFA_EXPORT_DYNAMIC_LIBRARY void initExternalModule(); SOFA_EXPORT_DYNAMIC_LIBRARY const char* getModuleName(); SOFA_EXPORT_DYNAMIC_LIBRARY const char* getModuleVersion(); - SOFA_EXPORT_DYNAMIC_LIBRARY void registerObjects(sofa::core::ObjectFactory * factory); + SOFA_EXPORT_DYNAMIC_LIBRARY void registerObjects(sofa::core::ComponentFactory * factory); } void initExternalModule() @@ -72,7 +72,7 @@ const char* getModuleVersion() return MODULE_VERSION; } -void registerObjects(sofa::core::ObjectFactory* factory) +void registerObjects(sofa::core::ComponentFactory* factory) { factory->registerObjectsFromPlugin(Sofa.Component.AnimationLoop); factory->registerObjectsFromPlugin(Sofa.Component.Collision); diff --git a/Sofa/framework/Core/CMakeLists.txt b/Sofa/framework/Core/CMakeLists.txt index 5d049ec19bf..30036392f69 100644 --- a/Sofa/framework/Core/CMakeLists.txt +++ b/Sofa/framework/Core/CMakeLists.txt @@ -31,8 +31,12 @@ 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}/ComponentFactoryFilters.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 @@ -64,6 +68,7 @@ set(HEADER_FILES ${SRC_ROOT}/sptr.h ${SRC_ROOT}/State.h ${SRC_ROOT}/State.inl + ${SRC_ROOT}/TemplateDeductionRules.h ${SRC_ROOT}/VecId.h ${SRC_ROOT}/behavior/BaseAnimationLoop.h ${SRC_ROOT}/behavior/BaseConstraint.h @@ -232,6 +237,8 @@ set(SOURCE_FILES ${SRC_ROOT}/BehaviorModel.cpp ${SRC_ROOT}/CategoryLibrary.cpp ${SRC_ROOT}/CollisionModel.cpp + ${SRC_ROOT}/ComponentFactory.cpp + ${SRC_ROOT}/ComponentFactoryFilters.cpp ${SRC_ROOT}/ComponentLibrary.cpp ${SRC_ROOT}/ComponentNameHelper.cpp ${SRC_ROOT}/ConstraintParams.cpp @@ -248,7 +255,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 @@ -257,6 +263,7 @@ set(SOURCE_FILES ${SRC_ROOT}/behavior/BaseAnimationLoop.cpp ${SRC_ROOT}/behavior/BaseConstraintCorrection.cpp ${SRC_ROOT}/behavior/BaseConstraintSet.cpp + ${SRC_ROOT}/behavior/BaseController.cpp ${SRC_ROOT}/behavior/BaseForceField.cpp ${SRC_ROOT}/behavior/BaseInteractionForceField.cpp ${SRC_ROOT}/behavior/BaseLagrangianConstraint.cpp diff --git a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp index 63ca8745277..36f8bb708c0 100644 --- a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp +++ b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.cpp @@ -53,82 +53,6 @@ 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{ diff --git a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h index a7a71ebfccd..16ed898d803 100644 --- a/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h +++ b/Sofa/framework/Core/src/sofa/core/CategoryLibrary.h @@ -22,38 +22,26 @@ #pragma once #include +#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); + CategoryLibrary( const std::string &categoryName) = delete; virtual ~CategoryLibrary() {} - virtual ComponentLibrary *addComponent(const std::string &componentName, ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles); - virtual void endConstruction(); + virtual ComponentLibrary *addComponent(const std::string &componentName, ComponentFactory::ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles) = delete; + virtual void endConstruction() = delete; - const std::string &getName() const { return name;} - const VecComponent &getComponents() const {return components;} + const std::string &getName() const = delete; + const std::vector< ComponentLibrary* > &getComponents() const = delete; - const ComponentLibrary *getComponent( const std::string &componentName) const; + const ComponentLibrary *getComponent( const std::string &componentName) const = delete; - size_t getNumComponents() const {return components.size();} + size_t getNumComponents() const = delete; /** \brief Get the list of categories a class belongs to, based on its parent classes. * @@ -74,10 +62,10 @@ class SOFA_CORE_API CategoryLibrary 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);} + virtual ComponentLibrary *createComponent(const std::string &componentName, ComponentFactory::ClassEntry::SPtr entry, const std::vector< std::string > &exampleFiles) = delete; - std::string name; - VecComponent components; + DeprecatedAndRemoved name; + DeprecatedAndRemoved 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..058d8d1144f --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentCreator.h @@ -0,0 +1,82 @@ +/****************************************************************************** +* 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 + +namespace sofa::core::objectmodel { class BaseComponent; } + +namespace sofa::core +{ + +/** + * @brief Base class for component instantiation. + * + * This abstract interface is used by ComponentFactory to interact with component creators + * without knowing the specific concrete type of the component being created. + */ +struct SOFA_CORE_API BaseComponentCreator +{ + virtual ~BaseComponentCreator() = default; + + /** + * @brief Instantiates a new component. + * Used by ComponentFactory to generate object instances before attribute parsing. + * @return A shared pointer to the newly created BaseComponent. + */ + virtual sofa::core::sptr create() const = 0; + + /** + * @brief Creates a copy of the creator. + * Ensures the factory registry owns unique instances of creators during registration. + */ + virtual std::unique_ptr clone() const = 0; +}; + +/** + * @brief Templated implementation of BaseComponentCreator. + * + * Binds a specific component class to the factory mechanism, ensuring components + * are created using SOFA's memory management (sofa::core::objectmodel::New). + * + * @tparam RealComponent The concrete component class to instantiate. + */ +template +struct ComponentCreator : public BaseComponentCreator +{ + sofa::core::sptr create() const override + { + // WARNING: + // It obliges the class to have a default constructor + return objectmodel::New(); + } + + 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..fa47b8ab7d6 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentFactory.cpp @@ -0,0 +1,578 @@ +/****************************************************************************** +* 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::helper::logging +{ + +inline bool notMuted(const core::ComponentFactory*) +{ + return true; +} + +inline ComponentInfo::SPtr getComponentInfo(const core::ComponentFactory*) +{ + return std::make_shared("ComponentFactory"); +} + +} + +namespace sofa::core +{ + +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(LegacyComponentRegistrationData& ro) +{ + auto& creators = ro.m_componentCreators; + + if (creators.empty()) + { + msg_error() << "No creator provided"; + return false; + } + + for (std::size_t i = 0; i < creators.size(); ++i) + { + auto creator = creators[i]; + + auto component = std::make_shared(); + + if (i < ro.m_componentNames.size()) + { + component->componentName = ro.m_componentNames[i]; + } + component->description = ro.m_description; + if (i < ro.m_moduleNames.size()) + { + component->componentModule = ro.m_moduleNames[i]; + } + if (i < ro.m_instantiationPriority.size()) + { + component->instantiationPriority = ro.m_instantiationPriority[i]; + } + if (i < ro.m_componentTemplates.size()) + { + component->templateAttributes.emplace_back("template", ro.m_componentTemplates[i]); + } + + component->creator = creator->clone(); + + component->aliases = ro.m_aliases; + component->authors.insert(ro.m_authors); + component->license = ro.m_license; + component->documentationURL.insert(ro.m_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->templateDeductionRule = ro.m_templateDeductionRules[i]; + + this->m_registry.push_back(component); + } + + return true; + +} +void ComponentFactory::registerComponent( + const ComponentRegistrationData::SPtr& componentRegistrationData) +{ + //check no duplicate + for (const auto& component : m_registry) + { + if (component->componentName == componentRegistrationData->componentName) + { + auto allTemplateAttributes = true; + for (const auto& templateAttribute : componentRegistrationData->templateAttributes) + { + if (std::find(component->templateAttributes.begin(), component->templateAttributes.end(), + templateAttribute) == component->templateAttributes.end()) + { + allTemplateAttributes = false; + } + } + if (!componentRegistrationData->templateAttributes.empty() && allTemplateAttributes) + { + msg_error() << "Attempt to register a new component in the factory with identical attributes than " << *component; + } + } + } + + m_registry.push_back(componentRegistrationData); +} + +namespace +{ + + +std::vector getComponentsFromName( + const ComponentFactory& self, + const std::string& componentName, + const std::string& pluginName) +{ + 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 : self.getRegistry()) + { + if (!pluginName.empty() && component->componentModule != pluginName) + { + continue; + } + + const auto fullName = component->componentModule + "." + component->componentName; + + if (component->componentName == componentToSearch || fullName == componentToSearch) + { + result.push_back(component); + } + else + { + for (const auto& alias : component->aliases) + { + const auto fullNameAlias = component->componentModule + "." + alias; + + if (alias == componentToSearch || fullNameAlias == componentToSearch) + { + result.push_back(component); + } + } + } + } + + return result; +} + +void extractModuleName(const std::string& inputClassName, std::string& className, std::string& moduleName) +{ + // The last dot separates the module name from the component name + // Example: Module.Name.ComponentName (it is common to have dots in the module names) + // It is assumed that the component name does not contain any dot + auto lastDot = inputClassName.find_last_of('.'); + if (lastDot != std::string::npos) + { + moduleName = inputClassName.substr(0, lastDot); + className = inputClassName.substr(lastDot + 1); + } + else + { + moduleName = {}; + className = inputClassName; + } +} + +void autoLoadPlugin(ComponentFactory& self, const std::string& pluginName) +{ + if (!pluginName.empty()) + { + const auto [path, loaded] = helper::system::PluginManager::getInstance().isPluginLoaded(pluginName); + if (!loaded) + { + auto status = helper::system::PluginManager::getInstance().loadPluginByName(pluginName); + if (status == helper::system::PluginManager::PluginLoadStatus::SUCCESS) + { + self.registerObjectsFromPlugin(pluginName); + } + } + } +} + +std::vector similarComponentNames(const ComponentFactory& self, const std::string& className) +{ + std::set allClassNames; + std::transform(self.getRegistry().begin(), self.getRegistry().end(), std::inserter(allClassNames, allClassNames.begin()), + [](const ComponentRegistrationData::SPtr& component){ return component->componentName; }); + const auto result = sofa::helper::getClosestMatch(className, std::vector(allClassNames.begin(), allClassNames.end()), 5, 0.6); + std::vector similarComponentNames; + std::transform(result.begin(), result.end(), std::back_inserter(similarComponentNames), + [](const auto& match) { return std::get<0>(match); } ); + return similarComponentNames; +} + +bool knownIssues(const ComponentFactory& self, const std::string& clasName) +{ + auto uncreatableComponent = helper::lifecycle::uncreatableComponents.find(clasName); + auto dealiasedComponent = helper::lifecycle::dealiasedComponents.find(clasName); + + const bool isUncreatable = uncreatableComponent != helper::lifecycle::uncreatableComponents.end(); + const bool isDealiased = dealiasedComponent != helper::lifecycle::dealiasedComponents.end(); + + if (isUncreatable) + { + msg_error(&self) << uncreatableComponent->second.getMessage(); + return true; + } + if (isDealiased) + { + msg_error(&self) << dealiasedComponent->second.getMessage(); + return true; + } + + return false; +} + +std::vector selectCandidatesDeductionRules( + const std::vector& candidates, + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) +{ + std::vector matchingCandidates; + + for (const auto& candidate : candidates) + { + // Check if the component has a rule AND if that rule applies. + if (const auto rule = candidate->templateDeductionRule; + rule && rule->doesComponentComplyWith(context, arg)) + { + matchingCandidates.push_back(candidate); + } + } + + return matchingCandidates; +} + +/** + * Apply a filter on a list of potential candidates. If the filtered list has a unique element, a + * component will be created based on this element. Otherwise, the filtered list is further filtered + * based on deduction rules. + */ +ComponentRegistrationData::SPtr applyFilter( + const ComponentFactory& self, + const std::string& componentName, + const std::vector& candidates, + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg, + const ComponentFilter& filter) +{ + const auto filteredCandidates = filter.filter(candidates, context, arg); + + if (!filteredCandidates.empty()) + { + if (filteredCandidates.size() == 1) + { + // No ambiguity: The unique candidate is returned + return filteredCandidates.front(); + } + else + { + // Multiple candidates: Use deduction rules to resolve ambiguity. + auto deducedCandidates = selectCandidatesDeductionRules(filteredCandidates, context, arg); + if (!deducedCandidates.empty()) + { + msg_warning_when(deducedCandidates.size() > 1, &self) + << "Attempt to create component '" << componentName + << "', however multiple potential candidates match the provided attributes (" + << sofa::helper::join( + deducedCandidates.begin(), deducedCandidates.end(), ", ") + << "). The first one is selected."; + return deducedCandidates.front(); + } + else + { + msg_warning_when(filteredCandidates.size() > 1, &self) + << "Attempt to create component '" << componentName + << "', however multiple potential candidates match the provided attributes (" + << sofa::helper::join( + filteredCandidates.begin(), filteredCandidates.end(), + [](const ComponentRegistrationData::SPtr& desc){ std::stringstream ss; ss << *desc; return ss.str(); }, ", ") + << "). The first one is selected."; + // None of the deduction rules matches: returning the first filtered candidate + return filteredCandidates.front(); + } + } + } + return nullptr; +} + +void reportMissingComponents(ComponentFactory& self, const std::string& componentName) +{ + std::stringstream ss; + ss << "Cannot create component '" << componentName << "': '" << componentName << "' not found in the factory registry."; + + const auto similarNames = similarComponentNames(self, componentName); + if (!similarNames.empty()) + { + ss << " Suggestion: Components were found with similar names: " << sofa::helper::join(similarNames, ", "); + } + + msg_error(&self) << ss.str(); +} + +bool filterUnloadedPluginsCandidates(const ComponentFactory& self, + const std::string& componentName, + const std::vector& candidates) +{ + auto candidatesWithoutUnloadedPlugins = candidates; + std::erase_if(candidatesWithoutUnloadedPlugins, [](const ComponentRegistrationData::SPtr& candidate) + { + return helper::system::PluginManager::getInstance().isPluginUnloaded(candidate->componentModule); + }); + + if (candidatesWithoutUnloadedPlugins.empty()) + { + std::set unloadedPlugins; + std::transform(candidates.begin(), candidates.end(), std::inserter(unloadedPlugins, unloadedPlugins.begin()), + [](const ComponentRegistrationData::SPtr& component) { return component->componentModule; }); + const auto unloadedPluginsString = sofa::helper::join(unloadedPlugins.begin(), unloadedPlugins.end(), ", "); + msg_error(&self) << "Attempted to create component '" << componentName + << "' but all potential candidates rely on component from currently unloaded plugins:" << unloadedPluginsString << "]"; + return false; + } + return true; +} + +} + + +ComponentRegistrationData::SPtr ComponentFactory::findComponent(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) +{ + if (!arg) return nullptr; + + std::string componentName, moduleName; + { + const char* typeAttribute = arg->getAttribute( "type", nullptr); + if (typeAttribute == nullptr) return nullptr; + extractModuleName(std::string{typeAttribute}, componentName, moduleName); + } + + if (knownIssues(*this, componentName)) return nullptr; + + // 1. Ensure plugins are loaded + if (auto it = helper::lifecycle::movedComponents.find(componentName); + it != helper::lifecycle::movedComponents.end()) + { + // autoLoadPlugin(*this, ); + } + + if (!moduleName.empty()) + { + autoLoadPlugin(*this, moduleName); + } + + // 2. Get initial candidates + std::vector candidates = getComponentsFromName(*this, componentName, moduleName); + if (candidates.empty()) + { + reportMissingComponents(*this, componentName); + return nullptr; + } + + // 3. Filter out candidates from unloaded plugins + if (!filterUnloadedPluginsCandidates(*this, componentName, candidates)) + { + return nullptr; + } + + // 4. Sort by priority + // In case of ambiguity (multiple candidates), sorting candidates will allow returning the + // component with the highest priority. + std::sort(candidates.begin(), candidates.end(), + [](const auto& a, const auto& b) { return a->instantiationPriority > b->instantiationPriority; }); + + // 5. Apply template matching filters + static std::array, 4> filters { + std::make_unique(), //Exact Template Match (Highest Priority). + std::make_unique(), //Selection by Legacy 'template' Keyword (Medium-High Priority) + std::make_unique(), //Partial Template Matching (Medium Priority) + std::make_unique() //General Template Deduction (Lowest Priority) + }; + + for (const auto& filter : filters) + { + if (auto component = applyFilter(*this, componentName, candidates, context, arg, *filter)) + { + return component; + } + } + + // Final fallback + if (!candidates.empty()) + { + return candidates.front(); + } + + // Final failure + msg_error() << "Could not find or select a unique component for '" << componentName << "'"; + + return nullptr; +} + +objectmodel::BaseComponent::SPtr ComponentFactory::createComponent( + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) +{ + if (auto componentData = findComponent(context, arg)) + { + auto component = componentData->creator->create(); + + if (component) + { + if (context) + { + context->addObject(component); + } + + msg_warning_when(componentData->componentModule.empty(), component.get()) << "Module name is empty"; + + component->parse(arg); + component->m_factoryRegistrationData = componentData; + } + + return component; + } + return nullptr; +} + +objectmodel::BaseComponent::SPtr ComponentFactory::createObject( + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) +{ + return this->createComponent(context, arg); +} + +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) const +{ + std::vector entries; + this->getEntriesFromTarget(entries, target); + return sofa::helper::join(entries.begin(), entries.end(), + [](const auto& entry) { std::stringstream ss; ss << *entry; return ss.str();}, 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); +} + +ComponentFactory* MainComponentFactory::getInstance() +{ + static ComponentFactory instance; + return &instance; +} + +objectmodel::BaseComponent::SPtr MainComponentFactory::CreateComponent( + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) +{ + return getInstance()->createComponent(context, arg); +} + +objectmodel::BaseComponent::SPtr MainComponentFactory::CreateObject( + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) +{ + return CreateComponent(context, arg); +} + +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..4547efb6f97 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentFactory.h @@ -0,0 +1,199 @@ +/****************************************************************************** +* 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 + +namespace sofa::core +{ + +/** + * @brief Factory class for SOFA components. + * + * This class manages the registration and instantiation of SOFA components. + * It maintains a registry of ComponentRegistrationData which contains the creators + * and metadata for each component. + */ +class SOFA_CORE_API ComponentFactory +{ +public: + + using SOFA_CORE_DEPRECATED_OBJECTFACTORY_CLASSENTRY() ClassEntry = ComponentRegistrationData; + + using Registry = std::vector; + /** @brief Get the list of all registered components. */ + const Registry& getRegistry() const { return m_registry; } + + /** + * @brief Register components defined in a plugin. + * @param pluginName The name of the plugin to register. + * @return true if the registration was successful or already done, false if the plugin is not loaded. + */ + bool registerObjectsFromPlugin(const std::string& pluginName); + + /** + * @brief Register a component in the factory. + * @param componentRegistrationData The data containing component info and its creator. + */ + void registerComponent(const ComponentRegistrationData::SPtr& componentRegistrationData); + + /** + * @brief Find the most suitable component registration data for a given description. + * + * This method handles plugin auto-loading, alias resolution, and candidate selection + * based on template attributes and deduction rules. + * + * @param context The context in which the search is performed. + * @param arg The description of the object to find (must contain a "type" attribute). + * @return The matching ComponentRegistrationData, or nullptr if none found. + */ + ComponentRegistrationData::SPtr findComponent(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + + /** + * @brief Create a component given a context and a description. + * + * This method first finds the appropriate component using @ref findComponent, + * then instantiates it, adds it to the context, and parses its attributes. + * + * @param context The context where the component will be added. + * @param arg The description of the component to create. + * @return A smart pointer to the created component, or nullptr on failure. + */ + objectmodel::BaseComponent::SPtr createComponent(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + + /** @brief Test if a creator exists for a given classname. */ + bool hasCreator(const std::string& classname) const; + + /** @brief Fill the given vector with the registered classes from a given target module/plugin. */ + void getEntriesFromTarget(std::vector& result, const std::string& target) const; + + /** @brief Return a string list of classes from a given target module/plugin. */ + std::string listClassesFromTarget(std::string target, std::string separator = ", ") const; + + /** @brief Fill the given vector with all the registered classes derived from BaseClass. */ + template + std::vector getEntriesDerivedFrom() const; + + /** @brief Return the list of classes derived from BaseClass as a string. */ + template + std::string listClassesDerivedFrom(const std::string& separator = ", ") const; + + objectmodel::BaseComponent::SPtr SOFA_CORE_DEPRECATED_OBJECTFACTORY_CREATEOBJECT() createObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + + /** + * @brief Legacy method to register multiple objects. + * @deprecated Use registerComponent instead. + */ + SOFA_CORE_DEPRECATED_OBJECTFACTORY_REGISTEROBJECTS() + bool registerObjects(LegacyComponentRegistrationData& ro); + + SOFA_ATTRIBUTE_DEPRECATED("v26.12", "v27.12", "Use MainComponentFactory::getInstance instead") + static ComponentFactory* getInstance(); + + SOFA_ATTRIBUTE_DEPRECATED("v26.12", "v27.12", "Use MainComponentFactory::CreateComponent instead") + static objectmodel::BaseComponent::SPtr CreateObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + + SOFA_ATTRIBUTE_DEPRECATED("v26.12", "v27.12", "Use MainComponentFactory::HasCreator instead") + static bool HasCreator(const std::string& classname); + + void getEntry(std::string) = delete; + void getAllEntries(std::vector& result, bool filterUnloadedPlugins = true) = delete; + + std::string shortName(std::string classname) = delete; + + void dumpXML(std::ostream& out = std::cout) = delete; + void dumpHTML(std::ostream& out = std::cout) = delete; + + static std::string ShortName(std::string classname) = delete; + static void ResetAlias(std::string name, ClassEntry::SPtr previous) = delete; + static bool AddAlias(std::string name, std::string result, bool force=false, + ClassEntry::SPtr* previous = nullptr) = delete; + +protected: + + /// Keep track of plugins who already registered + using RegisteredPluginSet = std::set; + RegisteredPluginSet m_registeredPluginSet; + + Registry 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->classData) + { + 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 ComponentRegistrationData::SPtr& entry){ return entry->componentName;}, separator); +} + + +struct SOFA_CORE_API MainComponentFactory +{ + static ComponentFactory* getInstance(); + + static objectmodel::BaseComponent::SPtr CreateComponent(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + + // to deprecate + static objectmodel::BaseComponent::SPtr CreateObject(objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg); + + /// Test if a creator exists for a given classname + static bool HasCreator(const std::string& classname); +}; + + +template +using ObjectCreator = DeprecatedAndRemoved; + +using RegisterObject = DeprecatedAndRemoved; + +} diff --git a/Sofa/framework/Core/src/sofa/core/ComponentFactoryFilters.cpp b/Sofa/framework/Core/src/sofa/core/ComponentFactoryFilters.cpp new file mode 100644 index 00000000000..b8140f865d8 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentFactoryFilters.cpp @@ -0,0 +1,132 @@ +/****************************************************************************** +* 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::vector ExactTemplateMatchFilter::filter( + const std::vector& candidates, + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) const +{ + SOFA_UNUSED(context); + + std::vector exactlyMatchingCandidates; + + for (const auto& candidate : candidates) + { + bool matchAllTemplateParameters = true; + for (const auto& [attribute, value] : candidate->templateAttributes) + { + const auto resolvedValue = defaulttype::TemplateAliases::resolveAlias(value); + const char* attr = arg->getAttribute(attribute, nullptr); + if (attr == nullptr) + { + matchAllTemplateParameters = false; + } + else + { + const std::string attrStr{attr}; + const auto resolvedAlias = defaulttype::TemplateAliases::resolveAlias(attrStr); + if (resolvedAlias != resolvedValue) + { + matchAllTemplateParameters = false; + } + } + } + + if (matchAllTemplateParameters) + { + exactlyMatchingCandidates.push_back(candidate); + } + } + + return exactlyMatchingCandidates; +} + +std::vector LegacyTemplateKeywordFilter::filter( + const std::vector& candidates, + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) const +{ + SOFA_UNUSED(context); + + const char* templateAttr = arg->getAttribute("template", nullptr); + if (!templateAttr) return {}; + + std::string templateAttrStr{templateAttr}; + templateAttrStr = defaulttype::TemplateAliases::resolveAlias(templateAttrStr); + + std::vector matchingCandidates; + + for (const auto& candidate : candidates) + { + const auto templateList = sofa::helper::join( + candidate->templateAttributes.begin(), candidate->templateAttributes.end(), + [](const auto& attr) + { return defaulttype::TemplateAliases::resolveAlias(attr.second); }, ','); + if (templateAttrStr == templateList) + { + matchingCandidates.push_back(candidate); + } + } + + return matchingCandidates; +} + +std::vector PartialTemplateMatchFilter::filter( + const std::vector& candidates, + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) const +{ + SOFA_UNUSED(context); + + std::vector partiallyMatchingCandidates; + + for (const auto& candidate : candidates) + { + for (const auto& [attribute, value] : candidate->templateAttributes) + { + const char* attr = arg->getAttribute(attribute, nullptr); + if (attr != nullptr) + { + const std::string attrStr{attr}; + if (defaulttype::TemplateAliases::resolveAlias(attrStr) == value) + { + partiallyMatchingCandidates.push_back(candidate); + break; + } + } + } + } + + return partiallyMatchingCandidates; +} + +std::vector NoFilter::filter( + const std::vector& candidates, + objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) const +{ + SOFA_UNUSED(context); + SOFA_UNUSED(arg); + return candidates; +} +} // namespace sofa::core diff --git a/Sofa/framework/Core/src/sofa/core/ComponentFactoryFilters.h b/Sofa/framework/Core/src/sofa/core/ComponentFactoryFilters.h new file mode 100644 index 00000000000..7f2e6d8a936 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentFactoryFilters.h @@ -0,0 +1,77 @@ +/****************************************************************************** +* 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 +{ + + +class ComponentFilter +{ +public: + virtual ~ComponentFilter() = default; + virtual std::vector filter( + const std::vector& candidates, + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) const = 0; +}; + +class ExactTemplateMatchFilter final : public ComponentFilter +{ +public: + std::vector filter( + const std::vector& candidates, + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) const override; +}; + +class LegacyTemplateKeywordFilter final : public ComponentFilter +{ +public: + std::vector filter( + const std::vector& candidates, + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) const override; +}; + +class PartialTemplateMatchFilter final : public ComponentFilter +{ +public: + std::vector filter( + const std::vector& candidates, + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) const override; +}; + +class NoFilter final : public ComponentFilter +{ +public: + std::vector filter( + const std::vector& candidates, + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) const override; +}; + + +} diff --git a/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp b/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp index 491e001d3c9..694385b181c 100644 --- a/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp +++ b/Sofa/framework/Core/src/sofa/core/ComponentLibrary.cpp @@ -21,90 +21,8 @@ ******************************************************************************/ #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..7d440547b61 100644 --- a/Sofa/framework/Core/src/sofa/core/ComponentLibrary.h +++ b/Sofa/framework/Core/src/sofa/core/ComponentLibrary.h @@ -21,43 +21,11 @@ ******************************************************************************/ #pragma once -#include +#include namespace sofa::core { -typedef sofa::core::ObjectFactory::ClassEntry ClassEntry; +using ComponentLibrary = DeprecatedAndRemoved; -/** - * \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..f144f112918 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/ComponentRegistrationData.h @@ -0,0 +1,289 @@ +/****************************************************************************** +* 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 +#include + +namespace sofa::core +{ + +struct SOFA_CORE_API ComponentRegistrationData +{ + friend class ComponentFactory; + using SPtr = std::shared_ptr; + + std::string componentName; + std::set aliases; + + std::vector> templateAttributes; + + std::string componentModule; + + unsigned int instantiationPriority {}; + + std::string description; + std::set authors; + std::string license; + std::set documentationURL; + + std::shared_ptr templateDeductionRule; + + std::unique_ptr creator; + const BaseClass* classData { nullptr }; + +private: + // ComponentRegistrationData() = default; +}; + +struct SOFA_CORE_API ComponentRegistrationDataBuilder +{ + ComponentRegistrationData::SPtr data; + + ComponentRegistrationDataBuilder& withName(const std::string& name) + { + data->componentName = name; + return *this; + } + + ComponentRegistrationDataBuilder& withModule(const std::string& componentModule) + { + data->componentModule = componentModule; + return *this; + } + + ComponentRegistrationDataBuilder& withDescription(const std::string& description) + { + data->description = description; + return *this; + } + + ComponentRegistrationDataBuilder& addAlias(const std::string& alias) + { + data->aliases.insert(alias); + return *this; + } + + ComponentRegistrationDataBuilder& addTemplateAttribute( + const std::string& templateAttribute, const std::string& value) + { + data->templateAttributes.emplace_back(templateAttribute, value); + return *this; + } + + template + ComponentRegistrationDataBuilder& addTemplateAttribute(const std::string& templateAttribute) + { + return addTemplateAttribute(templateAttribute, T::Name()); + } + + ComponentRegistrationDataBuilder& addAuthor(const std::string& _author) + { + data->authors.insert(_author); + return *this; + } + + ComponentRegistrationDataBuilder& withLicense(const std::string& _license) + { + data->license = _license; + return *this; + } + + ComponentRegistrationDataBuilder& withDocumentationURL(const std::string& _documentationURL) + { + data->documentationURL.insert(_documentationURL); + return *this; + } + + ComponentRegistrationDataBuilder& withDeductionRule(const std::shared_ptr& rule) + { + data->templateDeductionRule = rule; + return *this; + } + + ComponentRegistrationDataBuilder& withInstantiationPriority(unsigned int instantiationPriority) + { + data->instantiationPriority = instantiationPriority; + return *this; + } + + ComponentRegistrationDataBuilder& withClass(const BaseClass* classData) + { + data->classData = classData; + return *this; + } + + ComponentRegistrationDataBuilder& withCreator(std::unique_ptr creator) + { + data->creator = std::move(creator); + return *this; + } + + operator ComponentRegistrationData::SPtr() const + { + return data; + } +}; + +inline std::ostream& operator<<(std::ostream& os, const ComponentRegistrationData& data) +{ + os << data.componentName; + if (!data.templateAttributes.empty()) + { + os << "["; + os << sofa::helper::join(data.templateAttributes.begin(), data.templateAttributes.end(), + [](const std::pair& pair) + { + return pair.first + "=" + pair.second; + }, ','); + os << "]"; + } + return os; +} + +template +concept HasTemplateDeductionRule = requires { + typename T::TemplateDeductionRule; +}; + +template +ComponentRegistrationDataBuilder CreateComponent(const std::string& componentName) +{ + std::shared_ptr templateDeductionRule { nullptr }; + if constexpr (HasTemplateDeductionRule) + { + templateDeductionRule = std::make_shared(); + } + else + { + templateDeductionRule = std::make_shared>(); + } + + auto builder = ComponentRegistrationDataBuilder() + .withName(componentName) + .withClass(Component::GetClass()) + .withDeductionRule(templateDeductionRule) + .withCreator(std::make_unique>()); + + if constexpr (requires {typename Component::DataTypes;}) + { + return builder.addTemplateAttribute("dofType", typename Component::DataTypes::Name()); + } + else + { + return builder; + } +} + +template +ComponentRegistrationDataBuilder CreateComponent() +{ + BaseClass* classData = Component::GetClass(); + return CreateComponent(classData->className); +} + + +/**************************************************************************************************/ + + +//to deprecate +struct SOFA_CORE_DEPRECATED_OBJECTFACTORY_LEGACYREGISTRATIONDATA() SOFA_CORE_API LegacyComponentRegistrationData +{ + + std::string m_description; + explicit LegacyComponentRegistrationData(const std::string& description) + : m_description(description) + {} + + std::vector m_componentCreators; + ~LegacyComponentRegistrationData() + { + for (auto* componentCreator : m_componentCreators) + { + delete componentCreator; + } + } + + std::vector m_componentNames; + std::vector m_componentTemplates; + std::vector m_moduleNames; + std::vector m_instantiationPriority; + std::vector > m_templateDeductionRules; + template LegacyComponentRegistrationData& add(bool defaultTemplate = false) + { + m_componentCreators.push_back(new ComponentCreator); + m_componentNames.push_back(sofa::core::objectmodel::BaseClassNameHelper::getClassName()); + m_componentTemplates.push_back(sofa::core::objectmodel::BaseClassNameHelper::getTemplateName()); +#ifdef SOFA_TARGET + m_moduleNames.push_back(sofa_tostring(SOFA_TARGET)); +#else + m_moduleNames.emplace_back(); +#endif + m_templateDeductionRules.push_back(std::make_shared>()); + m_instantiationPriority.push_back(std::numeric_limits::max() * defaultTemplate); + return *this; + } + + std::string m_documentationURL; + LegacyComponentRegistrationData& addDocumentationURL(const std::string& documentationURL) + { + m_documentationURL = documentationURL; + return *this; + } + + LegacyComponentRegistrationData& addDescription(const std::string& description) + { + m_description = description; + return *this; + } + + std::set m_aliases; + LegacyComponentRegistrationData& addAlias(const std::string& alias) + { + m_aliases.insert(alias); + return *this; + } + + std::string m_authors; + LegacyComponentRegistrationData& addAuthor(const std::string& author) + { + m_authors = author; + return *this; + } + + std::string m_license; + LegacyComponentRegistrationData& addLicense(const std::string& license) + { + m_license = license; + 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..f5fa1460c8a 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 = LegacyComponentRegistrationData; - 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..e525ae3d752 100644 --- a/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.cpp +++ b/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.cpp @@ -20,7 +20,7 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #include -#include +#include #include #include @@ -31,31 +31,6 @@ 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) { @@ -93,41 +68,26 @@ inline void to_json(nlohmann::json& json, } 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) + const sofa::core::ComponentRegistrationData::SPtr& entry) { if (entry) { - json["className"] = entry->className; + json["name"] = entry->componentName; + json["attributes"] = entry->templateAttributes; + json["module"] = entry->componentModule; json["description"] = entry->description; + json["documentationURL"] = entry->documentationURL; + // json["templateDeductionRule"] = entry->templateDeductionRule; - json["creator"] = entry->creatorMap; + if (entry->creator) + { + auto component = entry->creator->create(); + json["component"] = component; + } } } -std::string ObjectFactoryJson::dump(ObjectFactory* factory) +std::string ObjectFactoryJson::dump(ComponentFactory* factory) { if (!factory) { @@ -135,10 +95,9 @@ std::string ObjectFactoryJson::dump(ObjectFactory* factory) return {}; } - std::vector entries; - factory->getAllEntries(entries, true); + const auto& registry = factory->getRegistry(); - const nlohmann::json json = entries; + const nlohmann::json json = registry; std::string dump{}; diff --git a/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.h b/Sofa/framework/Core/src/sofa/core/ObjectFactoryJson.h index 393f75ab778..84fc7c211f6 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; +class ComponentFactory; struct SOFA_CORE_API ObjectFactoryJson { - static std::string dump(ObjectFactory* factory); + static std::string dump(ComponentFactory* 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/Core/src/sofa/core/TemplateDeductionRules.h b/Sofa/framework/Core/src/sofa/core/TemplateDeductionRules.h new file mode 100644 index 00000000000..1641c322273 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/TemplateDeductionRules.h @@ -0,0 +1,78 @@ +/****************************************************************************** +* 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 BaseTemplateDeductionRule +{ + bool doesComponentComplyWith( + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) + { + if (!context) return false; + return doDoesComponentComplyWith(context, arg); + }; + +protected: + + virtual bool doDoesComponentComplyWith( + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) = 0; +}; + +template +struct OtherComponentsInContextDeductionRule : public BaseTemplateDeductionRule +{ +protected: + bool doDoesComponentComplyWith( + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) override + { + SOFA_UNUSED(arg); + return ((context->get() != nullptr) && ...); + } +}; + +template +using MechanicalStateDeductionRule = OtherComponentsInContextDeductionRule>; + +template +struct CanCreateDeductionRule : public BaseTemplateDeductionRule +{ +protected: + bool doDoesComponentComplyWith( + objectmodel::BaseContext* context, + objectmodel::BaseObjectDescription* arg) override + { + T* instance = nullptr; + return T::canCreate(instance, context, arg); + } +}; + + +} diff --git a/Sofa/framework/Core/src/sofa/core/behavior/BaseController.cpp b/Sofa/framework/Core/src/sofa/core/behavior/BaseController.cpp new file mode 100644 index 00000000000..97d6fa96a45 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/behavior/BaseController.cpp @@ -0,0 +1,22 @@ +/****************************************************************************** +* 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 diff --git a/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h b/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h index 91e87c4abeb..ce8230d50dd 100644 --- a/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h +++ b/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h @@ -55,6 +55,9 @@ class ForceField : public BaseForceField, public virtual SingleStateAccessor DataVecCoord; typedef core::objectmodel::Data DataVecDeriv; + + using TemplateDeductionRule = core::MechanicalStateDeductionRule; + protected: explicit ForceField(MechanicalState *mm = nullptr); diff --git a/Sofa/framework/Core/src/sofa/core/config.h.in b/Sofa/framework/Core/src/sofa/core/config.h.in index 2215e894724..ccee0106f27 100644 --- a/Sofa/framework/Core/src/sofa/core/config.h.in +++ b/Sofa/framework/Core/src/sofa/core/config.h.in @@ -127,3 +127,31 @@ SOFA_ATTRIBUTE_DEPRECATED("v26.06", "v29.06", "Use toBaseComponent instead.") #define SOFA_CORE_DEPRECATED_RENAME_CREATORMAP_OBJECTTEMPLATECREATORMAP() \ SOFA_ATTRIBUTE_DISABLED("v25.12", "v26.06", "Type CreatorMap has been renamed to ObjectTemplateCreatorMap.") #endif + +#ifdef SOFA_BUILD_SOFA_CORE + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_CLASSENTRY() +#else + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_CLASSENTRY() \ + SOFA_ATTRIBUTE_DISABLED("v26.12", "v27.06", "Type ClassEntry has been replaced by ComponentRegistrationData.") +#endif + +#ifdef SOFA_BUILD_SOFA_CORE + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_REGISTEROBJECTS() +#else + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_REGISTEROBJECTS() \ + SOFA_ATTRIBUTE_DISABLED("v26.12", "v27.06", "Use registerComponent instead.") +#endif + +#ifdef SOFA_BUILD_SOFA_CORE + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_CREATEOBJECT() +#else + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_CREATEOBJECT() \ + SOFA_ATTRIBUTE_DISABLED("v26.12", "v27.06", "Use createComponent instead.") +#endif + +#ifdef SOFA_BUILD_SOFA_CORE + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_LEGACYREGISTRATIONDATA() +#else + #define SOFA_CORE_DEPRECATED_OBJECTFACTORY_LEGACYREGISTRATIONDATA() \ + SOFA_ATTRIBUTE_DISABLED("v26.12", "v27.06", "Use CreateComponent instead.") +#endif diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseComponent.h b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseComponent.h index 667f91a6e39..eaef54a53b1 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseComponent.h +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseComponent.h @@ -21,9 +21,10 @@ ******************************************************************************/ #pragma once -#include +#include #include #include +#include namespace sofa::core::objectmodel { @@ -43,6 +44,8 @@ class SOFA_CORE_API BaseComponent : public virtual Base SOFA_CLASS(BaseComponent, Base); SOFA_BASE_CAST_IMPLEMENTATION(BaseComponent) + friend class ComponentFactory; + protected: BaseComponent(); @@ -184,7 +187,6 @@ class SOFA_CORE_API BaseComponent : public virtual Base Base* findLinkDestClass(const BaseClass* destType, const std::string& path, const BaseLink* link) override; - /// Return the full path name of this object virtual std::string getPathName() const override; @@ -222,9 +224,13 @@ class SOFA_CORE_API BaseComponent : public virtual Base /// BaseNode can set the context of its own objects friend class BaseNode; +private: + ComponentRegistrationData::SPtr m_factoryRegistrationData; public: + ComponentRegistrationData::SPtr getFactoryRegistrationData() const { return m_factoryRegistrationData; } + /// the component can insert itself directly in the right sequence in the Node /// so the Node does not have to test its type against all known types /// \returns true if the component was inserted diff --git a/Sofa/framework/Core/test/CMakeLists.txt b/Sofa/framework/Core/test/CMakeLists.txt index 951a6e0701a..e0a0c6f9119 100644 --- a/Sofa/framework/Core/test/CMakeLists.txt +++ b/Sofa/framework/Core/test/CMakeLists.txt @@ -24,6 +24,7 @@ set(SOURCE_FILES objectmodel/VectorData_test.cpp topology/BaseMeshTopology_test.cpp topology/TopologySubsetIndices_test.cpp + ComponentFactory_test.cpp DataEngine_test.cpp Engine_test.cpp MatrixAccumulator_test.cpp diff --git a/Sofa/framework/Core/test/ComponentFactory_test.cpp b/Sofa/framework/Core/test/ComponentFactory_test.cpp new file mode 100644 index 00000000000..ca38aa6d7cd --- /dev/null +++ b/Sofa/framework/Core/test/ComponentFactory_test.cpp @@ -0,0 +1,480 @@ +/****************************************************************************** +* 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 + +namespace sofa +{ + +// factory.registerComponent(core::CreateComponent("DummyComponent") +// .withModule("test") +// .withDescription("dummy") +// ); +struct DummyComponent : public core::objectmodel::BaseComponent +{ + SOFA_CLASS(DummyComponent, core::objectmodel::BaseComponent); +}; + +// factory.registerComponent(core::CreateComponent("DummyComponentWith1Template") +// .withModule("test") +// .withDescription("dummy") +// .addTemplateAttribute("t") +// ); +template +struct DummyComponentWith1Template : public core::objectmodel::BaseComponent +{ + SOFA_CLASS(DummyComponentWith1Template, core::objectmodel::BaseComponent); +}; + +// factory.registerComponent(core::CreateComponent("DummyComponentWith1Template") +// .withModule("test") +// .withDescription("dummy") +// .addTemplateAttribute("t1") +// .addTemplateAttribute("t2") +// ); +template +struct DummyComponentWith2Template : public core::objectmodel::BaseComponent +{ + SOFA_CLASS(SOFA_TEMPLATE2(DummyComponentWith2Template, T1, T2), core::objectmodel::BaseComponent); +}; + + +struct ComponentFactory_test : public ::testing::Test +{ + void SetUp() override + { + sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance()); + node = sofa::simulation::getSimulation()->createNewNode("root"); + } + + core::ComponentFactory factory; + simulation::Node::SPtr node; +}; + +TEST_F(ComponentFactory_test, CreateComponent) +{ + factory.registerComponent(core::CreateComponent("DummyComponent") + .withModule("test") + .withDescription("dummy") + ); + + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "DummyComponent"); + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_EQ(createdComponent->getName(), "nameInTheScene"); + EXPECT_EQ(createdComponent->getClassName(), "DummyComponent"); + EXPECT_EQ(createdComponent->getFactoryRegistrationData()->componentName, "DummyComponent"); +} + +TEST_F(ComponentFactory_test, CreateComponentDifferentName) +{ + factory.registerComponent(core::CreateComponent("NotDummyComponent") + .withModule("test") + .withDescription("dummy") + ); + + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "NotDummyComponent"); + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_EQ(createdComponent->getName(), "nameInTheScene"); + EXPECT_EQ(createdComponent->getClassName(), "DummyComponent"); + EXPECT_EQ(createdComponent->getFactoryRegistrationData()->componentName, "NotDummyComponent"); +} + +TEST_F(ComponentFactory_test, HasCreator) +{ + factory.registerComponent(core::CreateComponent("DummyComponent") + .withModule("test") + .withDescription("dummy") + ); + + EXPECT_TRUE(factory.hasCreator("DummyComponent")); + EXPECT_FALSE(factory.hasCreator("NonExistentComponent")); +} + +TEST_F(ComponentFactory_test, Aliases) +{ + factory.registerComponent(core::CreateComponent("DummyComponent") + .withModule("test") + .withDescription("dummy") + .addAlias("DummyAlias") + ); + + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "DummyAlias"); + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_EQ(createdComponent->getClassName(), "DummyComponent"); +} + +TEST_F(ComponentFactory_test, TargetEntries) +{ + factory.registerComponent(core::CreateComponent("Compo1") + .withModule("ModuleA") + .withDescription("d1") + ); + factory.registerComponent(core::CreateComponent("Compo2") + .withModule("ModuleA") + .withDescription("d2") + ); + factory.registerComponent(core::CreateComponent("Compo3") + .withModule("ModuleB") + .withDescription("d3") + ); + + std::vector entries; + factory.getEntriesFromTarget(entries, "ModuleA"); + EXPECT_EQ(entries.size(), 2); + + std::string list = factory.listClassesFromTarget("ModuleA"); + EXPECT_TRUE(list.find("Compo1") != std::string::npos); + EXPECT_TRUE(list.find("Compo2") != std::string::npos); + EXPECT_FALSE(list.find("Compo3") != std::string::npos); +} + +TEST_F(ComponentFactory_test, OneTemplate_attributes) +{ + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "int") + ); + + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "float") + ); + + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "TemplatedCompo"); + desc.setAttribute("t", "int"); + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_NE(dynamic_cast*>(createdComponent.get()), nullptr); +} + +TEST_F(ComponentFactory_test, OneTemplate_identicalRegistration) +{ + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "int") + ); + + { + EXPECT_MSG_EMIT(Error); + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "int") + ); + } + + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "TemplatedCompo"); + desc.setAttribute("t", "int"); + EXPECT_MSG_EMIT(Warning); //ambiguity because of identical registration + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_NE(dynamic_cast*>(createdComponent.get()), nullptr); +} + +TEST_F(ComponentFactory_test, OneTemplate_identicalRegistrationNoTemplateAttribute) +{ + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "int") + ); + + { + EXPECT_MSG_EMIT(Error); + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "int") + ); + } + + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "TemplatedCompo"); + EXPECT_MSG_EMIT(Warning); //ambiguity because of identical registration + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_NE(dynamic_cast*>(createdComponent.get()), nullptr); +} + +TEST_F(ComponentFactory_test, OneTemplate_templateKeyword) +{ + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "int") + ); + + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t", "int") + ); + + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "TemplatedCompo"); + desc.setAttribute("template", "int"); + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_NE(dynamic_cast*>(createdComponent.get()), nullptr); +} + +TEST_F(ComponentFactory_test, TwoTemplate_attributes) +{ + EXPECT_MSG_NOEMIT(Warning); + EXPECT_MSG_NOEMIT(Error); + + // Register component using two templates (e.g., int and float attributes) + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t1", "int") + .addTemplateAttribute("t2", "float") + ); + + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t1", "int") + .addTemplateAttribute("t2", "string") + ); + + // Create component specifying both template attributes + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "TemplatedCompo"); + desc.setAttribute("t1", "int"); + desc.setAttribute("t2", "float"); + auto createdComponent = factory.createComponent(node.get(), &desc); + + ASSERT_NE(createdComponent, nullptr); + // Check if the component is correctly cast to the expected template type + auto* cast = dynamic_cast*>(createdComponent.get()); + EXPECT_NE(cast, nullptr); +} + +TEST_F(ComponentFactory_test, TwoTemplate_templateKeyword) +{ + EXPECT_MSG_NOEMIT(Warning); + EXPECT_MSG_NOEMIT(Error); + + // Register two different components using two templates + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t1", "int") + .addTemplateAttribute("t2", "float") + ); + + factory.registerComponent(core::CreateComponent>("TemplatedCompo") + .withModule("test") + .withDescription("dummy") + .addTemplateAttribute("t1", "double") + .addTemplateAttribute("t2", "bool") + ); + + // Use the 'template' keyword to specify all template arguments: t1=int, t2=float + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "TemplatedCompo"); + desc.setAttribute("template", "int,float"); // Assuming comma-separated list of attributes + auto createdComponent = factory.createComponent(node.get(), &desc); + + ASSERT_NE(createdComponent, nullptr); + // Check if the component is correctly cast to the expected template type + auto* cast = dynamic_cast*>(createdComponent.get()); + EXPECT_NE(cast, nullptr); +} + +TEST_F(ComponentFactory_test, CreateUnknownComponent) +{ + EXPECT_MSG_EMIT(Error); + core::objectmodel::BaseObjectDescription desc("nameInTheScene", "UnknownComponent"); + auto createdComponent = factory.createComponent(node.get(), &desc); + EXPECT_EQ(createdComponent, nullptr); +} + +TEST_F(ComponentFactory_test, InstantiationPriority) +{ + auto lowPriority = core::CreateComponent("PriorityCompo") + .withModule("test") + .withDescription("low") + .withInstantiationPriority(1); + factory.registerComponent(lowPriority); + + auto highPriority = core::CreateComponent("PriorityCompo") + .withModule("test") + .withDescription("high") + .withInstantiationPriority(10); + factory.registerComponent(highPriority); + + core::objectmodel::BaseObjectDescription desc("name", "PriorityCompo"); + auto createdComponent = factory.createComponent(node.get(), &desc); + + ASSERT_NE(createdComponent, nullptr); + // The one with description "high" (priority 10) should be selected. + // Since both are DummyComponent, we check the factory data if available or just ensure it doesn't crash. + // In ComponentFactory.cpp, it sorts by priority descending. + EXPECT_EQ(createdComponent->getClassName(), "DummyComponent"); +} + +TEST_F(ComponentFactory_test, FullNameCreation) +{ + factory.registerComponent(core::CreateComponent("MyComponent") + .withModule("MyModule") + .withDescription("desc") + ); + + // Create using "Module.Component" syntax + core::objectmodel::BaseObjectDescription desc("name", "MyModule.MyComponent"); + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); + EXPECT_EQ(createdComponent->getClassName(), "DummyComponent"); + EXPECT_EQ(createdComponent->getFactoryRegistrationData()->componentName, "MyComponent"); +} + +TEST_F(ComponentFactory_test, SuggestionOnMisspell) +{ + factory.registerComponent(core::CreateComponent("SpecificComponent") + .withModule("test").withDescription("description") + ); + + EXPECT_MSG_EMIT(Error); // Should contain suggestion + core::objectmodel::BaseObjectDescription desc("name", "SpecificComponnt"); // Typos + auto createdComponent = factory.createComponent(node.get(), &desc); + EXPECT_EQ(createdComponent, nullptr); +} + +TEST_F(ComponentFactory_test, TemplateAliasResolution) +{ + // Sofa often uses aliases like 'Vec3d' for 'std::vector' etc. + // Here we simulate a registration with a specific type and creation with an alias. + factory.registerComponent(core::CreateComponent>("AliasedCompo") + .withModule("test") + .withDescription("description") + .addTemplateAttribute("t", "d") + ); + + core::objectmodel::BaseObjectDescription desc("name", "AliasedCompo"); + desc.setAttribute("t", "double"); + auto createdComponent = factory.createComponent(node.get(), &desc); + ASSERT_NE(createdComponent, nullptr); +} + + + + + + + + + + + + +TEST_F(ComponentFactory_test, LegacyRegistration) +{ + core::LegacyComponentRegistrationData legacyData("legacy description"); + legacyData.add(); + legacyData.addAlias("LegacyAlias"); + legacyData.addAuthor("Legacy Author"); + legacyData.addLicense("LGPL"); + + bool registered = factory.registerObjects(legacyData); + EXPECT_TRUE(registered); + + // Test creation by class name + { + core::objectmodel::BaseObjectDescription desc("name1", "DummyComponent"); + auto created = factory.createComponent(node.get(), &desc); + ASSERT_NE(created, nullptr); + EXPECT_EQ(created->getClassName(), "DummyComponent"); + } + + // Test creation by alias + { + core::objectmodel::BaseObjectDescription desc("name2", "LegacyAlias"); + auto created = factory.createComponent(node.get(), &desc); + ASSERT_NE(created, nullptr); + EXPECT_EQ(created->getClassName(), "DummyComponent"); + } + + // Verify metadata in registry + const auto& registry = factory.getRegistry(); + auto it = std::find_if(registry.begin(), registry.end(), [](const auto& reg) + { + return reg->componentName == "DummyComponent"; + }); + ASSERT_NE(it, registry.end()); + EXPECT_EQ((*it)->description, "legacy description"); + EXPECT_TRUE((*it)->authors.contains("Legacy Author")); + EXPECT_EQ((*it)->license, "LGPL"); +} + +TEST_F(ComponentFactory_test, LegacyRegistrationTemplated) +{ + core::LegacyComponentRegistrationData legacyData("templated legacy"); + legacyData.add>(); + + factory.registerObjects(legacyData); + + core::objectmodel::BaseObjectDescription desc("name", "DummyComponentWith1Template"); + desc.setAttribute("template", "int"); + auto created = factory.createComponent(node.get(), &desc); + ASSERT_NE(created, nullptr); + EXPECT_NE(dynamic_cast*>(created.get()), nullptr); +} + +TEST_F(ComponentFactory_test, LegacyRegistrationTwoTemplates) +{ + core::LegacyComponentRegistrationData legacyData("two templates legacy"); + legacyData.add>(); + + factory.registerObjects(legacyData); + + { + core::objectmodel::BaseObjectDescription desc("name", "DummyComponentWith2Template"); + desc.setAttribute("template", "int,float"); + auto created = factory.createComponent(node.get(), &desc); + + ASSERT_NE(created, nullptr); + auto* cast = dynamic_cast*>(created.get()); + EXPECT_NE(cast, nullptr); + } + + { + core::objectmodel::BaseObjectDescription desc("name", "DummyComponentWith2Template"); + desc.setAttribute("template", "i,f"); + auto created = factory.createComponent(node.get(), &desc); + + ASSERT_NE(created, nullptr); + auto* cast = dynamic_cast*>(created.get()); + EXPECT_NE(cast, nullptr); + } +} + + + +} diff --git a/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp b/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp index a59bd34718e..90e105c0c64 100644 --- a/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp +++ b/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp @@ -1,78 +1,78 @@ -/****************************************************************************** -* 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 -{ -TEST(ObjectFactoryJson, noObject) -{ - core::ObjectFactory o; - const auto dump = core::ObjectFactoryJson::dump(&o); - EXPECT_EQ(dump, "[]"); -} - -TEST(ObjectFactoryJson, oneObject) -{ - core::ObjectFactory o; - - EXPECT_EQ(core::RegisterObject("foo") - .add< simulation::DefaultAnimationLoop >().commitTo(&o), 1); - - const auto dump = core::ObjectFactoryJson::dump(&o); - const std::string expectedDump = R"x([{"className":"DefaultAnimationLoop","creator":{"":{"class":{"categories":["AnimationLoop"],"className":"DefaultAnimationLoop","namespaceName":"sofa::simulation","parents":["BaseAnimationLoop"],"shortName":"defaultAnimationLoop","templateName":"","typeName":"DefaultAnimationLoop"},"object":{"data":[{"defaultValue":"unnamed","group":"","help":"object name","name":"name","type":"string"},{"defaultValue":"0","group":"","help":"if true, emits extra messages at runtime.","name":"printLog","type":"bool"},{"defaultValue":"","group":"","help":"list of the subsets the object belongs to","name":"tags","type":"TagSet"},{"defaultValue":"","group":"","help":"this object bounding box","name":"bbox","type":"BoundingBox"},{"defaultValue":"Undefined","group":"","help":"The state of the component among (Dirty, Valid, Undefined, Loading, Invalid).","name":"componentState","type":"ComponentState"},{"defaultValue":"0","group":"","help":"if true, handle the events, otherwise ignore the events","name":"listening","type":"bool"},{"defaultValue":"1","group":"","help":"If true, compute the global bounding box of the scene at each time step. Used mostly for rendering.","name":"computeBoundingBox","type":"bool"},{"defaultValue":"0","group":"","help":"If true, solves all the ODEs in parallel","name":"parallelODESolving","type":"bool"}],"link":[{"destinationTypeName":"BaseContext","help":"Graph Node containing this object (or BaseContext::getDefault() if no graph is used)","name":"context"},{"destinationTypeName":"BaseComponent","help":"Sub-objects used internally by this object","name":"slaves"},{"destinationTypeName":"BaseComponent","help":"nullptr for regular objects, or master object for which this object is one sub-objects","name":"master"},{"destinationTypeName":"BaseNode","help":"Link to the scene's node that will be processed by the loop","name":"targetNode"}]},"target":""}},"description":"foo\n"}])x"; - EXPECT_EQ(dump, expectedDump); -} - -template -class DummyComponent : public core::objectmodel::BaseComponent -{ -public: - SOFA_CLASS(DummyComponent, BaseObject); -}; - -TEST(ObjectFactoryJson, oneTemplatedObject) -{ - core::ObjectFactory o; - - EXPECT_EQ(core::RegisterObject("foo") - .add< DummyComponent >().commitTo(&o), 1); - - const auto dump = core::ObjectFactoryJson::dump(&o); - const auto vec3name = core::objectmodel::BaseClassNameHelper::getTypeName(); - const std::string expectedDump = R"x([{"className":"DummyComponent","creator":{"Vec3f":{"class":{"categories":["_Miscellaneous"],"className":"DummyComponent","namespaceName":"sofa","parents":["BaseComponent"],"shortName":"dummyComponent","templateName":"Vec3f","typeName":"DummyComponent<)x" + std::string{vec3name} + R"x(>"},"object":{"data":[{"defaultValue":"unnamed","group":"","help":"object name","name":"name","type":"string"},{"defaultValue":"0","group":"","help":"if true, emits extra messages at runtime.","name":"printLog","type":"bool"},{"defaultValue":"","group":"","help":"list of the subsets the object belongs to","name":"tags","type":"TagSet"},{"defaultValue":"","group":"","help":"this object bounding box","name":"bbox","type":"BoundingBox"},{"defaultValue":"Undefined","group":"","help":"The state of the component among (Dirty, Valid, Undefined, Loading, Invalid).","name":"componentState","type":"ComponentState"},{"defaultValue":"0","group":"","help":"if true, handle the events, otherwise ignore the events","name":"listening","type":"bool"}],"link":[{"destinationTypeName":"BaseContext","help":"Graph Node containing this object (or BaseContext::getDefault() if no graph is used)","name":"context"},{"destinationTypeName":"BaseComponent","help":"Sub-objects used internally by this object","name":"slaves"},{"destinationTypeName":"BaseComponent","help":"nullptr for regular objects, or master object for which this object is one sub-objects","name":"master"}]},"target":""}},"description":"foo\n"}])x"; - EXPECT_EQ(dump, expectedDump); -} - -TEST(ObjectFactoryJson, mainInstance) -{ - EXPECT_TRUE(sofa::simpleapi::importPlugin(Sofa.Component)); - const auto dump = core::ObjectFactoryJson::dump(core::ObjectFactory::getInstance()); - EXPECT_NE(dump.find("MechanicalObject"), std::string::npos); -} -} +// /****************************************************************************** +// * 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 +// { +// TEST(ObjectFactoryJson, noObject) +// { +// core::ObjectFactory o; +// const auto dump = core::ObjectFactoryJson::dump(&o); +// EXPECT_EQ(dump, "[]"); +// } +// +// TEST(ObjectFactoryJson, oneObject) +// { +// core::ObjectFactory o; +// +// EXPECT_EQ(core::RegisterObject("foo") +// .add< simulation::DefaultAnimationLoop >().commitTo(&o), 1); +// +// const auto dump = core::ObjectFactoryJson::dump(&o); +// const std::string expectedDump = R"x([{"className":"DefaultAnimationLoop","creator":{"":{"class":{"categories":["AnimationLoop"],"className":"DefaultAnimationLoop","namespaceName":"sofa::simulation","parents":["BaseAnimationLoop"],"shortName":"defaultAnimationLoop","templateName":"","typeName":"DefaultAnimationLoop"},"object":{"data":[{"defaultValue":"unnamed","group":"","help":"object name","name":"name","type":"string"},{"defaultValue":"0","group":"","help":"if true, emits extra messages at runtime.","name":"printLog","type":"bool"},{"defaultValue":"","group":"","help":"list of the subsets the object belongs to","name":"tags","type":"TagSet"},{"defaultValue":"","group":"","help":"this object bounding box","name":"bbox","type":"BoundingBox"},{"defaultValue":"Undefined","group":"","help":"The state of the component among (Dirty, Valid, Undefined, Loading, Invalid).","name":"componentState","type":"ComponentState"},{"defaultValue":"0","group":"","help":"if true, handle the events, otherwise ignore the events","name":"listening","type":"bool"},{"defaultValue":"1","group":"","help":"If true, compute the global bounding box of the scene at each time step. Used mostly for rendering.","name":"computeBoundingBox","type":"bool"},{"defaultValue":"0","group":"","help":"If true, solves all the ODEs in parallel","name":"parallelODESolving","type":"bool"}],"link":[{"destinationTypeName":"BaseContext","help":"Graph Node containing this object (or BaseContext::getDefault() if no graph is used)","name":"context"},{"destinationTypeName":"BaseComponent","help":"Sub-objects used internally by this object","name":"slaves"},{"destinationTypeName":"BaseComponent","help":"nullptr for regular objects, or master object for which this object is one sub-objects","name":"master"},{"destinationTypeName":"BaseNode","help":"Link to the scene's node that will be processed by the loop","name":"targetNode"}]},"target":""}},"description":"foo\n"}])x"; +// EXPECT_EQ(dump, expectedDump); +// } +// +// template +// class DummyComponent : public core::objectmodel::BaseComponent +// { +// public: +// SOFA_CLASS(DummyComponent, BaseObject); +// }; +// +// TEST(ObjectFactoryJson, oneTemplatedObject) +// { +// core::ObjectFactory o; +// +// EXPECT_EQ(core::RegisterObject("foo") +// .add< DummyComponent >().commitTo(&o), 1); +// +// const auto dump = core::ObjectFactoryJson::dump(&o); +// const auto vec3name = core::objectmodel::BaseClassNameHelper::getTypeName(); +// const std::string expectedDump = R"x([{"className":"DummyComponent","creator":{"Vec3f":{"class":{"categories":["_Miscellaneous"],"className":"DummyComponent","namespaceName":"sofa","parents":["BaseComponent"],"shortName":"dummyComponent","templateName":"Vec3f","typeName":"DummyComponent<)x" + std::string{vec3name} + R"x(>"},"object":{"data":[{"defaultValue":"unnamed","group":"","help":"object name","name":"name","type":"string"},{"defaultValue":"0","group":"","help":"if true, emits extra messages at runtime.","name":"printLog","type":"bool"},{"defaultValue":"","group":"","help":"list of the subsets the object belongs to","name":"tags","type":"TagSet"},{"defaultValue":"","group":"","help":"this object bounding box","name":"bbox","type":"BoundingBox"},{"defaultValue":"Undefined","group":"","help":"The state of the component among (Dirty, Valid, Undefined, Loading, Invalid).","name":"componentState","type":"ComponentState"},{"defaultValue":"0","group":"","help":"if true, handle the events, otherwise ignore the events","name":"listening","type":"bool"}],"link":[{"destinationTypeName":"BaseContext","help":"Graph Node containing this object (or BaseContext::getDefault() if no graph is used)","name":"context"},{"destinationTypeName":"BaseComponent","help":"Sub-objects used internally by this object","name":"slaves"},{"destinationTypeName":"BaseComponent","help":"nullptr for regular objects, or master object for which this object is one sub-objects","name":"master"}]},"target":""}},"description":"foo\n"}])x"; +// EXPECT_EQ(dump, expectedDump); +// } +// +// TEST(ObjectFactoryJson, mainInstance) +// { +// EXPECT_TRUE(sofa::simpleapi::importPlugin(Sofa.Component)); +// const auto dump = core::ObjectFactoryJson::dump(core::ObjectFactory::getInstance()); +// EXPECT_NE(dump.find("MechanicalObject"), std::string::npos); +// } +// } diff --git a/Sofa/framework/Core/test/ObjectFactory_test.cpp b/Sofa/framework/Core/test/ObjectFactory_test.cpp index b5a3c0e4d3f..fa37532a67e 100644 --- a/Sofa/framework/Core/test/ObjectFactory_test.cpp +++ b/Sofa/framework/Core/test/ObjectFactory_test.cpp @@ -1,119 +1,119 @@ -/****************************************************************************** -* 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 -using sofa::core::ObjectFactory; -using sofa::core::RegisterObject; - -#include -using sofa::testing::BaseTest ; - -namespace -{ - -template -class TestObject : public sofa::core::objectmodel::BaseComponent -{ -public: - SOFA_CLASS(SOFA_TEMPLATE(TestObject, Type), sofa::core::objectmodel::BaseComponent); -}; - -template -class TestObject2 : public sofa::core::objectmodel::BaseComponent -{ -public: - SOFA_CLASS(SOFA_TEMPLATE(TestObject2, Type), sofa::core::objectmodel::BaseComponent); -}; - -int A = RegisterObject("Dummy test object.") - .add< TestObject >(); -int B1 = RegisterObject("Dummy test object.") - .add< TestObject >(); -int B2 = RegisterObject("Dummy test object.") - .add< TestObject >(); -int B3 = RegisterObject("Dummy test object.") - .add< TestObject2 >(); - -class ObjectFactory_test: public BaseTest -{ -public: - void testDuplicatedRegistration() - { - EXPECT_MSG_EMIT(Warning); - const int C = RegisterObject("Already registered object.") - .add< TestObject >(); - SOFA_UNUSED(C); - } - - void testValidAlias() - { - ASSERT_TRUE(ObjectFactory::getInstance()->addAlias("FirstAlias", "TestObject")); - } - - void testInvalidAlias() - { - EXPECT_MSG_EMIT(Error); - ASSERT_FALSE(ObjectFactory::getInstance()->addAlias("InvalidAlias", "NoWhere")); - } - - void testDuplicatedAlias() - { - EXPECT_MSG_EMIT(Error); - ASSERT_TRUE(ObjectFactory::getInstance()->addAlias("DuplicatedAlias", "TestObject")); - ASSERT_FALSE(ObjectFactory::getInstance()->addAlias("DuplicatedAlias", "TestObject")); - } - - void testHasCreator() - { - // validate the hasCreator method with use of alias when the alias is pointing - // to two different entries in the factory - ASSERT_TRUE(ObjectFactory::HasCreator("TestObject")); - ASSERT_TRUE(ObjectFactory::HasCreator("TestObject2")); - } -}; - -TEST_F(ObjectFactory_test, testDuplicatedRegistration) -{ - this->testDuplicatedRegistration(); -} - -TEST_F(ObjectFactory_test, testValidAlias ) -{ - this->testValidAlias(); -} - -TEST_F(ObjectFactory_test, testInvalidAlias ) -{ - this->testInvalidAlias(); -} - -TEST_F(ObjectFactory_test, testDuplicatedAlias ) -{ - this->testDuplicatedAlias(); -} - - -TEST_F(ObjectFactory_test, testHasCreator ) -{ - this->testHasCreator(); -} - -}// namespace sofa +// /****************************************************************************** +// * 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 +// using sofa::core::ObjectFactory; +// using sofa::core::RegisterObject; +// +// #include +// using sofa::testing::BaseTest ; +// +// namespace +// { +// +// template +// class TestObject : public sofa::core::objectmodel::BaseComponent +// { +// public: +// SOFA_CLASS(SOFA_TEMPLATE(TestObject, Type), sofa::core::objectmodel::BaseComponent); +// }; +// +// template +// class TestObject2 : public sofa::core::objectmodel::BaseComponent +// { +// public: +// SOFA_CLASS(SOFA_TEMPLATE(TestObject2, Type), sofa::core::objectmodel::BaseComponent); +// }; +// +// int A = RegisterObject("Dummy test object.") +// .add< TestObject >(); +// int B1 = RegisterObject("Dummy test object.") +// .add< TestObject >(); +// int B2 = RegisterObject("Dummy test object.") +// .add< TestObject >(); +// int B3 = RegisterObject("Dummy test object.") +// .add< TestObject2 >(); +// +// class ObjectFactory_test: public BaseTest +// { +// public: +// void testDuplicatedRegistration() +// { +// EXPECT_MSG_EMIT(Warning); +// const int C = RegisterObject("Already registered object.") +// .add< TestObject >(); +// SOFA_UNUSED(C); +// } +// +// void testValidAlias() +// { +// ASSERT_TRUE(ObjectFactory::getInstance()->addAlias("FirstAlias", "TestObject")); +// } +// +// void testInvalidAlias() +// { +// EXPECT_MSG_EMIT(Error); +// ASSERT_FALSE(ObjectFactory::getInstance()->addAlias("InvalidAlias", "NoWhere")); +// } +// +// void testDuplicatedAlias() +// { +// EXPECT_MSG_EMIT(Error); +// ASSERT_TRUE(ObjectFactory::getInstance()->addAlias("DuplicatedAlias", "TestObject")); +// ASSERT_FALSE(ObjectFactory::getInstance()->addAlias("DuplicatedAlias", "TestObject")); +// } +// +// void testHasCreator() +// { +// // validate the hasCreator method with use of alias when the alias is pointing +// // to two different entries in the factory +// ASSERT_TRUE(ObjectFactory::HasCreator("TestObject")); +// ASSERT_TRUE(ObjectFactory::HasCreator("TestObject2")); +// } +// }; +// +// TEST_F(ObjectFactory_test, testDuplicatedRegistration) +// { +// this->testDuplicatedRegistration(); +// } +// +// TEST_F(ObjectFactory_test, testValidAlias ) +// { +// this->testValidAlias(); +// } +// +// TEST_F(ObjectFactory_test, testInvalidAlias ) +// { +// this->testInvalidAlias(); +// } +// +// TEST_F(ObjectFactory_test, testDuplicatedAlias ) +// { +// this->testDuplicatedAlias(); +// } +// +// +// TEST_F(ObjectFactory_test, testHasCreator ) +// { +// this->testHasCreator(); +// } +// +// }// namespace sofa diff --git a/Sofa/framework/Helper/test/system/FailingPlugin/ComponentFailingPlugin.cpp b/Sofa/framework/Helper/test/system/FailingPlugin/ComponentFailingPlugin.cpp index f85cd1910c7..a5fdb1f2a50 100644 --- a/Sofa/framework/Helper/test/system/FailingPlugin/ComponentFailingPlugin.cpp +++ b/Sofa/framework/Helper/test/system/FailingPlugin/ComponentFailingPlugin.cpp @@ -36,9 +36,14 @@ ComponentFailingPlugin::~ComponentFailingPlugin() { } - -int ComponentFailingPluginClass = core::RegisterObject("ComponentFailingPlugin").add< ComponentFailingPlugin >(); - +void registerComponent(sofa::core::ObjectFactory* factory) +{ + factory->registerComponent( + core::CreateComponent("ComponentFailingPlugin") + .withModule("FailingPlugin") + .withDescription("dummy component") + ); +} } // namespace sofa::test diff --git a/Sofa/framework/Helper/test/system/FailingPlugin/init.cpp b/Sofa/framework/Helper/test/system/FailingPlugin/init.cpp index 96fbe8751e6..f7d1c80b06d 100644 --- a/Sofa/framework/Helper/test/system/FailingPlugin/init.cpp +++ b/Sofa/framework/Helper/test/system/FailingPlugin/init.cpp @@ -20,6 +20,12 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #include +#include + +namespace sofa::test +{ +extern void registerComponent(sofa::core::ComponentFactory* factory); +} extern "C" { @@ -67,6 +73,11 @@ SOFA_FAILINGPLUGIN_API const char* getModuleComponentList() return "ComponentFailingPlugin"; } +void registerObjects(sofa::core::ComponentFactory* factory) +{ + sofa::test::registerComponent(factory); +} + } // extern "C" namespace failingplugin diff --git a/Sofa/framework/Helper/test/system/PluginManager_test.cpp b/Sofa/framework/Helper/test/system/PluginManager_test.cpp index 453c9ccb243..1a255758cd0 100644 --- a/Sofa/framework/Helper/test/system/PluginManager_test.cpp +++ b/Sofa/framework/Helper/test/system/PluginManager_test.cpp @@ -331,17 +331,4 @@ TEST_F(PluginManager_test, failingPlugin) "registered the object has been unloaded, preventing the object creation.") != std::string::npos; }), description.getErrors().end()); - - std::vector entries; - sofa::core::ObjectFactory::getInstance()->getAllEntries(entries, false); - EXPECT_NE( - std::find_if(entries.begin(), entries.end(), [](const auto& entry){ return entry->className == "ComponentFailingPlugin";}), - entries.end() - ); - - sofa::core::ObjectFactory::getInstance()->getAllEntries(entries, true); - EXPECT_EQ( - std::find_if(entries.begin(), entries.end(), [](const auto& entry){ return entry->className == "ComponentFailingPlugin";}), - entries.end() - ); } diff --git a/Sofa/framework/Helper/test/system/TestPluginA/ComponentA.cpp b/Sofa/framework/Helper/test/system/TestPluginA/ComponentA.cpp index 091eb502526..1c7a80f7021 100644 --- a/Sofa/framework/Helper/test/system/TestPluginA/ComponentA.cpp +++ b/Sofa/framework/Helper/test/system/TestPluginA/ComponentA.cpp @@ -21,7 +21,7 @@ ******************************************************************************/ #include "ComponentA.h" -#include +#include namespace sofa::test @@ -36,9 +36,14 @@ ComponentA::~ComponentA() { } - -int ComponentAClass = core::RegisterObject("Component A").add< ComponentA >(); - +void registerComponentA(sofa::core::ComponentFactory* factory) +{ + factory->registerComponent( + core::CreateComponent("ComponentA") + .withModule("TestPluginA") + .withDescription("dummy component") + ); +} } // namespace sofa::test diff --git a/Sofa/framework/Helper/test/system/TestPluginA/ComponentB.cpp b/Sofa/framework/Helper/test/system/TestPluginA/ComponentB.cpp index 18573f62896..35656f6f837 100644 --- a/Sofa/framework/Helper/test/system/TestPluginA/ComponentB.cpp +++ b/Sofa/framework/Helper/test/system/TestPluginA/ComponentB.cpp @@ -41,12 +41,22 @@ ComponentB::~ComponentB() { } -int ComponentBClass = sofa::core::RegisterObject("Component B") - .add< ComponentB >() - .add< ComponentB >() - .add< ComponentB >() +template +void registerComponent(sofa::core::ComponentFactory* factory) +{ + factory->registerComponent( + core::CreateComponent>("ComponentB") + .withModule("TestPluginA") + .withDescription("dummy component") + ); +} -; +void registerComponentB(sofa::core::ComponentFactory* factory) +{ + registerComponent>(factory); + registerComponent>(factory); + registerComponent>(factory); +} template class SOFA_TESTPLUGINA_API ComponentB; template class SOFA_TESTPLUGINA_API ComponentB; diff --git a/Sofa/framework/Helper/test/system/TestPluginA/initTestPluginA.cpp b/Sofa/framework/Helper/test/system/TestPluginA/initTestPluginA.cpp index cac7864f0ba..89659de8147 100644 --- a/Sofa/framework/Helper/test/system/TestPluginA/initTestPluginA.cpp +++ b/Sofa/framework/Helper/test/system/TestPluginA/initTestPluginA.cpp @@ -20,6 +20,13 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #include +#include + +namespace sofa::test +{ +extern void registerComponentA(sofa::core::ComponentFactory* factory); +extern void registerComponentB(sofa::core::ComponentFactory* factory); +} extern "C" { @@ -61,6 +68,12 @@ SOFA_TESTPLUGINA_API const char* getModuleComponentList() return "ComponentA, ComponentB"; } +void registerObjects(sofa::core::ComponentFactory* factory) +{ + sofa::test::registerComponentA(factory); + sofa::test::registerComponentB(factory); +} + } // extern "C" namespace testplugina 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/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp index a804cd092a0..35e360610b4 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp @@ -35,8 +35,11 @@ namespace sofa::simulation void registerRequiredPlugin(sofa::core::ObjectFactory* factory) { - factory->registerObjects(core::ObjectRegistrationData("Load the SOFA modules and/or plugins required to run a simulation.") - .add< RequiredPlugin >()); + factory->registerComponent( + sofa::core::CreateComponent("RequiredPlugin") + .withModule("Sofa.Simulation.Core") + .withDescription("Load the SOFA modules and/or plugins required to run a simulation.") + ); } RequiredPlugin::RequiredPlugin() diff --git a/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.h b/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.h index 6ffa39dac11..4fa396ad4b0 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.h +++ b/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.h @@ -64,7 +64,7 @@ class DataExchange : public virtual objectmodel::BaseComponent protected: - DataExchange( const char* from, const char* to ); + DataExchange(); ~DataExchange() override; @@ -83,55 +83,15 @@ class DataExchange : public virtual objectmodel::BaseComponent return sofa::defaulttype::DataTypeName::name(); } - template - static typename T::SPtr create(T*, core::objectmodel::BaseContext* context, core::objectmodel::BaseObjectDescription* arg) - { - std::string fromPath; - std::string toPath; - - if(arg) - { - fromPath = arg->getAttribute(std::string("from"), "" ); - toPath = arg->getAttribute(std::string("to"), "" ); - } - - //context->findLinkDest(stout, fromPath, NULL); - //context->findLinkDest(stout, toPath, NULL); - - typename T::SPtr obj = sofa::core::objectmodel::New(fromPath.c_str(), toPath.c_str() ); - if (context) - { - context->addObject(obj); - } - if (arg) - { - obj->parse(arg); - } - return obj; - } - - Data mSource; ///< source object to copy Data mDestination; ///< destination object to copy private: - - /// source - //SingleLink< DataExchange, Data, BaseLink::FLAG_DATALINK|BaseLink::FLAG_DUPLICATE> mSourceObject; - /// dest - //SingleLink< DataExchange, Data, BaseLink::FLAG_DATALINK|BaseLink::FLAG_DUPLICATE> mDestinationObject; - - - DataTypes* mSourcePtr; DataTypes* mDestinationPtr; //VecCoord mDataCopy; - std::string fromPath; - std::string toPath; - //core::objectmodel::BaseObjectDescription* desc; - std::size_t mSizeInBytes; }; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.inl b/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.inl index e8501ae6626..de1081f0638 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.inl +++ b/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.inl @@ -27,18 +27,14 @@ namespace sofa::core { template -DataExchange::DataExchange( const char* from, const char* to ) +DataExchange::DataExchange() : BaseObject() , mSource(initData(&mSource,"from","source object to copy")) , mDestination(initData(&mDestination,"to","destination object to copy")) , mSourcePtr(nullptr) , mDestinationPtr(nullptr) - , fromPath(from) - , toPath(to) , mSizeInBytes(0) -{ - //f_listening.setValue(true); -} +{} template DataExchange::~DataExchange() = default; @@ -63,8 +59,8 @@ void DataExchange::init() mSource.beginEdit(); mDestination.beginEdit(); - parseField( std::string("from"), fromPath ); - parseField( std::string("to"), toPath ); + // parseField( std::string("from"), fromPath ); + // parseField( std::string("to"), toPath ); core::objectmodel::BaseData* tempParent = mSource.getParent(); tempParent = mDestination.getParent(); diff --git a/applications/plugins/MultiThreading/src/MultiThreading/SceneCheckMultithreading.cpp b/applications/plugins/MultiThreading/src/MultiThreading/SceneCheckMultithreading.cpp index 0cadd90f28b..3da3efae55e 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/SceneCheckMultithreading.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/SceneCheckMultithreading.cpp @@ -68,24 +68,9 @@ void SceneCheckMultithreading::doCheckOn(sofa::simulation::Node* node) if (!parallelImplementation.empty()) { - if (sofa::core::ObjectFactory::getInstance()->hasCreator(parallelImplementation)) + if (sofa::core::MainComponentFactory::HasCreator(parallelImplementation)) { - const auto& entry = sofa::core::ObjectFactory::getInstance()->getEntry(parallelImplementation); - auto it = entry.creatorMap.find(object->getTemplateName()); - if (it != entry.creatorMap.end()) - { - std::string seq = object->getClassName(); - if (!object->getTemplateName().empty()) - { - seq += "[" + object->getTemplateName() + "]"; - } - std::string par = entry.className; - if (!it->first.empty()) - { - par += "[" + it->first + "]"; - } - m_summary.insert({seq, par }); - } + m_summary.insert({object->d_factoryName.getValue(), parallelImplementation }); } else { 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()