mbsim  4.0.0
MBSim Kernel
objectfactory.h
1/* Copyright (C) 2004-2010 MBSim Development Team
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 *
17 * Contact: friedrich.at.gc@googlemail.com
18 */
19
20#ifndef _MBSIM_OBJECTFACTORY_H_
21#define _MBSIM_OBJECTFACTORY_H_
22
23#include "objectfactory_part.h"
24#include <utility>
25#include <vector>
26#include <functional>
27#include <stdexcept>
28#include <typeinfo>
29#include <mbsim/mbsim_event.h>
30#include <xercesc/dom/DOMAttr.hpp>
31#include <mbxmlutilshelper/utils.h>
32#include "fmatvec/atom.h"
33#include <boost/core/demangle.hpp>
34
35namespace MBSim {
36
37/* A tree of DOMEvalException's which store the tree of failed objects
38 * creations of the object factory */
40 public:
41 DOMEvalExceptionStack(const xercesc::DOMElement *element) : MBXMLUtils::DOMEvalException("", element) {}
43 ~DOMEvalExceptionStack() noexcept override = default;
44 void add(const std::string &type, const std::shared_ptr<MBXMLUtils::DOMEvalException> &ex);
45 const char* what() const noexcept override;
46 std::vector<std::pair<std::string, std::shared_ptr<MBXMLUtils::DOMEvalException>>> &getExceptionVector();
47 protected:
48 std::vector<std::pair<std::string, std::shared_ptr<MBXMLUtils::DOMEvalException>>> exVec;
49 mutable std::string whatStr;
50 void generateWhat(std::stringstream &str, const std::string &indent) const;
51};
52
53/* Just to distinguish a wrong type (not castable) error of the object factory
54 * from others */
56 public:
57 DOMEvalExceptionWrongType(const std::string &type, const xercesc::DOMElement *element) :
58 MBXMLUtils::DOMEvalException(type, element) {}
60 ~DOMEvalExceptionWrongType() noexcept override = default;
61};
62
67
68 friend void registerClass_internal(const MBXMLUtils::FQN &name, const AllocateBase *alloc, const DeallocateBase *dealloc);
69 friend void deregisterClass_internal(const MBXMLUtils::FQN &name, const AllocateBase *alloc);
70
71 public:
72
75 template<class ContainerType>
76 static ContainerType* createAndInit(const xercesc::DOMElement *element);
77
78 static void addErrorMsg(const std::string &msg);
79 static std::string getAndClearErrorMsg();
80
81 private:
82
83 // convinence typedefs
84 typedef std::pair<const AllocateBase*, const DeallocateBase*> AllocDeallocPair;
85 typedef std::vector<AllocDeallocPair> AllocDeallocVector;
86 typedef AllocDeallocVector::iterator AllocDeallocVectorIt;
87 typedef std::map<MBXMLUtils::FQN, AllocDeallocVector> NameMap;
88 typedef NameMap::iterator NameMapIt;
89
90 // private ctor
91 ObjectFactory() = default;
92
93 // create an singleton instance of the object factory.
94 static ObjectFactory& instance();
95
96 // a vector of all registered types
97 NameMap registeredType;
98
99 static std::string errorMsg;
100};
101
102template<class ContainerType>
103ContainerType* ObjectFactory::createAndInit(const xercesc::DOMElement *element) {
104 // just check if ContainerType is derived from fmatvec::Atom if not throw a compile error
105 static_assert(std::is_convertible<ContainerType*, fmatvec::Atom*>::value,
106 "In MBSim::ObjectFactory::create<ContainerType>(...) ContainerType must be derived from fmatvec::Atom.");
107 // throw error if NULL is supplied as element
108 if(element==nullptr)
109 throw std::runtime_error("Internal error: NULL argument specified.");
110 // get all allocate functions for the given name
111 MBXMLUtils::FQN fqn=MBXMLUtils::E(element)->getTagName();
112 auto nameIt=instance().registeredType.find(fqn);
113 if(nameIt==instance().registeredType.end())
114 throw MBXMLUtils::DOMEvalException("Internal error: No objects of name {"+fqn.first+"}"+fqn.second+" registred", element);
115 DOMEvalExceptionStack allErrors(static_cast<xercesc::DOMElement*>(element->getParentNode()));
116 // try to create and init a object which each of the allocate function
117 for(auto & allocDeallocIt : nameIt->second) {
118 // create element
119 fmatvec::Atom *ele=(*allocDeallocIt.first)();
120 // try to cast the element to ContainerType
121 auto *ret=dynamic_cast<ContainerType*>(ele);
122 if(!ret) {
123 // cast not possible -> deallocate again and try next
124 allErrors.add(boost::core::demangle(typeid(*ele).name()),
125 std::make_shared<DOMEvalExceptionWrongType>(
126 boost::core::demangle(typeid(ContainerType).name()), element));
127 (*allocDeallocIt.second)(ele);
128 continue;
129 }
130 try {
131 ret->initializeUsingXML(const_cast<xercesc::DOMElement*>(element));
132 return ret;
133 }
134 catch(DOMEvalExceptionStack &ex) {
135 allErrors.add(boost::core::demangle(typeid(*ele).name()), std::make_shared<DOMEvalExceptionStack>(ex));
136 }
138 allErrors.add(boost::core::demangle(typeid(*ele).name()), std::make_shared<MBXMLUtils::DOMEvalException>(ex));
139 }
140 catch(std::exception &ex) { // handles also MBSimError
141 allErrors.add(boost::core::demangle(typeid(*ele).name()),
142 std::make_shared<MBXMLUtils::DOMEvalException>(ex.what(), element));
143 }
144 catch(...) {
145 allErrors.add(boost::core::demangle(typeid(*ele).name()),
146 std::make_shared<MBXMLUtils::DOMEvalException>("Unknwon exception", element));
147 }
148 (*allocDeallocIt.second)(ele);
149 }
150 // if all failed -> return errors of all trys
151 throw allErrors;
152}
153
154// a wrapper to allocate an object of type CreateType
155template<class CreateType>
156struct Allocate : public AllocateBase {
157 // create a new object of type CreateType using new
158 fmatvec::Atom* operator()() const override {
159 return new CreateType;
160 }
161 // check if this Allocator allocates the same object as other.
162 // This is the case if the type of this template class matches
163 // the type of other.
164 bool isEqual(const AllocateBase& other) const override {
165 return typeid(*this)==typeid(other);
166 }
167};
168
169// a wrapper to deallocate an object created by allocate
170struct Deallocate : public DeallocateBase {
171 // deallocate a object using delete
172 void operator()(fmatvec::Atom *obj) const override {
173 delete obj;
174 }
175};
176
180template<class CreateType>
182
183 public:
184
186 ObjectFactoryRegisterClassHelper(MBXMLUtils::FQN name_) noexcept : name(std::move(name_)) {
187 try {
188 MBSim::registerClass_internal(name, new Allocate<CreateType>(), new Deallocate());
189 }
190 catch(std::exception &ex) {
191 ObjectFactory::addErrorMsg(ex.what());
192 }
193 catch(...) {
194 ObjectFactory::addErrorMsg("Unknown error");
195 }
196 }
197
200 try {
201 MBSim::deregisterClass_internal(name, new Allocate<CreateType>());
202 }
203 catch(std::exception &ex) {
204 fprintf(stderr, "%s\n", ex.what());
205 }
206 catch(...) {
207 fprintf(stderr, "%s\n", "Unknown error");
208 }
209 }
210
211 private:
212 MBXMLUtils::FQN name;
213
214};
215
219template<class EnumType>
221
222 template<class EV> friend void registerEnum_internal(const MBXMLUtils::FQN &name, const EV& value);
223 template<class EV> friend void deregisterEnum_internal(const MBXMLUtils::FQN &name);
224
225 public:
226
228 EnumFactory(const EnumType &enumVar, MBXMLUtils::FQN fqn_) : fqn(std::move(fqn_)) {
229 try {
230 registerEnum_internal<EnumType>(fqn, enumVar);
231 }
232 catch(std::exception &ex) {
233 ObjectFactory::addErrorMsg(ex.what());
234 }
235 catch(...) {
236 ObjectFactory::addErrorMsg("Unknown error");
237 }
238 }
239
242 try {
243 deregisterEnum_internal<EnumType>(fqn);
244 }
245 catch(std::exception &ex) {
246 fprintf(stderr, "%s\n", ex.what());
247 }
248 catch(...) {
249 fprintf(stderr, "%s\n", "Unknown error");
250 }
251 }
252
254 static const EnumType& get(const MBXMLUtils::FQN &fqn, const xercesc::DOMElement *e=nullptr) {
255 auto it=regmap().find(fqn);
256 if(it==regmap().end())
257 throw MBXMLUtils::DOMEvalException("No enumeration value named {"+fqn.first+"}"+fqn.second+" registred", e);
258 return it->second.get();
259 }
260
261 private:
262 MBXMLUtils::FQN fqn;
263
264 // return the register map of the enum factory.
265 // (note: this function must not be defined in this file to avoid any imlicit instantation)
266 static std::map<MBXMLUtils::FQN, std::reference_wrapper<const EnumType>>& regmap();
267};
268
269template<class EV>
270void registerEnum_internal(const MBXMLUtils::FQN &name, const EV& value) {
271 EnumFactory<EV>::regmap().insert(std::make_pair(name, std::ref(value)));
272}
273
274template<class EV>
275void deregisterEnum_internal(const MBXMLUtils::FQN &name) {
276 EnumFactory<EV>::regmap().erase(name);
277}
278
279// fix local xml name (remove template and namespace)
280std::string fixXMLLocalName(std::string name);
281
282}
283
287#define MBSIM_OBJECTFACTORY_REGISTERCLASS(NS, Class) \
288 static MBSim::ObjectFactoryRegisterClassHelper<Class> \
289 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)((NS)%MBSim::fixXMLLocalName(#Class));
290
293#define MBSIM_OBJECTFACTORY_REGISTERCLASS_AND_INSTANTIATE(NS, Class) \
294 template class Class; \
295 static MBSim::ObjectFactoryRegisterClassHelper<Class> \
296 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)((NS)%MBSim::fixXMLLocalName(#Class));
297
300#define MBSIM_OBJECTFACTORY_REGISTERCLASSWITHTEMPLATENAME_AND_INSTANTIATE(NS, Class, TemplateName) \
301 template class Class; \
302 static MBSim::ObjectFactoryRegisterClassHelper<Class> \
303 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)((NS)%(MBSim::fixXMLLocalName(#Class)+"_"+#TemplateName));
304
306#define MBSIM_OBJECTFACTORY_REGISTERENUM(EnumType, NS, enumName) \
307 static MBSim::EnumFactory<EnumType> \
308 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)(enumName, (NS)%#enumName);
309
310#endif
Definition: objectfactory.h:39
Definition: objectfactory.h:55
Definition: objectfactory.h:220
EnumFactory(const EnumType &enumVar, MBXMLUtils::FQN fqn_)
Definition: objectfactory.h:228
static const EnumType & get(const MBXMLUtils::FQN &fqn, const xercesc::DOMElement *e=nullptr)
Definition: objectfactory.h:254
~EnumFactory()
Definition: objectfactory.h:241
Definition: objectfactory.h:181
~ObjectFactoryRegisterClassHelper()
Definition: objectfactory.h:199
ObjectFactoryRegisterClassHelper(MBXMLUtils::FQN name_) noexcept
Definition: objectfactory.h:186
Definition: objectfactory.h:66
static ContainerType * createAndInit(const xercesc::DOMElement *element)
Definition: objectfactory.h:103
namespace MBSim
Definition: bilateral_constraint.cc:30
Definition: objectfactory_part.h:37
Definition: objectfactory.h:156
fmatvec::Atom * operator()() const override
Implement this function to allocate a new object.
Definition: objectfactory.h:158
bool isEqual(const AllocateBase &other) const override
Definition: objectfactory.h:164
Definition: objectfactory_part.h:49
Definition: objectfactory.h:170
void operator()(fmatvec::Atom *obj) const override
Implement this function to deallocate the object obj.
Definition: objectfactory.h:172