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, bool &normalErrorFound) 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(MBSimError &ex) {
141 // do not use ex.what(), but ex.getErrorMessage(), since ex.what() may be HTML encoded and polluted with location information
142 // the location information is useless since we already add here the error location of element.
143 allErrors.add(boost::core::demangle(typeid(*ele).name()),
144 std::make_shared<MBXMLUtils::DOMEvalException>(ex.getErrorMessage(), element));
145 }
146 catch(std::exception &ex) {
147 allErrors.add(boost::core::demangle(typeid(*ele).name()),
148 std::make_shared<MBXMLUtils::DOMEvalException>(ex.what(), element));
149 }
150 catch(...) {
151 allErrors.add(boost::core::demangle(typeid(*ele).name()),
152 std::make_shared<MBXMLUtils::DOMEvalException>("Unknwon exception", element));
153 }
154 (*allocDeallocIt.second)(ele);
155 }
156 // if all failed -> return errors of all trys
157 throw allErrors;
158}
159
160// a wrapper to allocate an object of type CreateType
161template<class CreateType>
162struct Allocate : public AllocateBase {
163 // create a new object of type CreateType using new
164 fmatvec::Atom* operator()() const override {
165 return new CreateType;
166 }
167 // check if this Allocator allocates the same object as other.
168 // This is the case if the type of this template class matches
169 // the type of other.
170 bool isEqual(const AllocateBase& other) const override {
171 return typeid(*this)==typeid(other);
172 }
173};
174
175// a wrapper to deallocate an object created by allocate
176struct Deallocate : public DeallocateBase {
177 // deallocate a object using delete
178 void operator()(fmatvec::Atom *obj) const override {
179 delete obj;
180 }
181};
182
186template<class CreateType>
188
189 public:
190
192 ObjectFactoryRegisterClassHelper(MBXMLUtils::FQN name_) noexcept : name(std::move(name_)) {
193 try {
194 MBSim::registerClass_internal(name, new Allocate<CreateType>(), new Deallocate());
195 }
196 catch(std::exception &ex) {
197 ObjectFactory::addErrorMsg(ex.what());
198 }
199 catch(...) {
200 ObjectFactory::addErrorMsg("Unknown error");
201 }
202 }
203
206 try {
207 MBSim::deregisterClass_internal(name, new Allocate<CreateType>());
208 }
209 catch(std::exception &ex) {
210 fprintf(stderr, "%s\n", ex.what());
211 }
212 catch(...) {
213 fprintf(stderr, "%s\n", "Unknown error");
214 }
215 }
216
217 private:
218 MBXMLUtils::FQN name;
219
220};
221
225template<class EnumType>
227
228 template<class EV> friend void registerEnum_internal(const MBXMLUtils::FQN &name, const EV& value);
229 template<class EV> friend void deregisterEnum_internal(const MBXMLUtils::FQN &name);
230
231 public:
232
234 EnumFactory(const EnumType &enumVar, MBXMLUtils::FQN fqn_) : fqn(std::move(fqn_)) {
235 try {
236 registerEnum_internal<EnumType>(fqn, enumVar);
237 }
238 catch(std::exception &ex) {
239 ObjectFactory::addErrorMsg(ex.what());
240 }
241 catch(...) {
242 ObjectFactory::addErrorMsg("Unknown error");
243 }
244 }
245
248 try {
249 deregisterEnum_internal<EnumType>(fqn);
250 }
251 catch(std::exception &ex) {
252 fprintf(stderr, "%s\n", ex.what());
253 }
254 catch(...) {
255 fprintf(stderr, "%s\n", "Unknown error");
256 }
257 }
258
260 static const EnumType& get(const MBXMLUtils::FQN &fqn, const xercesc::DOMElement *e=nullptr) {
261 auto it=regmap().find(fqn);
262 if(it==regmap().end())
263 throw MBXMLUtils::DOMEvalException("No enumeration value named {"+fqn.first+"}"+fqn.second+" registred", e);
264 return it->second.get();
265 }
266
267 private:
268 MBXMLUtils::FQN fqn;
269
270 // return the register map of the enum factory.
271 // (note: this function must not be defined in this file to avoid any imlicit instantation)
272 static std::map<MBXMLUtils::FQN, std::reference_wrapper<const EnumType>>& regmap();
273};
274
275template<class EV>
276void registerEnum_internal(const MBXMLUtils::FQN &name, const EV& value) {
277 EnumFactory<EV>::regmap().insert(std::make_pair(name, std::ref(value)));
278}
279
280template<class EV>
281void deregisterEnum_internal(const MBXMLUtils::FQN &name) {
282 EnumFactory<EV>::regmap().erase(name);
283}
284
285// fix local xml name (remove template and namespace)
286std::string fixXMLLocalName(std::string name);
287
288}
289
293#define MBSIM_OBJECTFACTORY_REGISTERCLASS(NS, Class) \
294 static MBSim::ObjectFactoryRegisterClassHelper<Class> \
295 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)((NS)%MBSim::fixXMLLocalName(#Class));
296
299#define MBSIM_OBJECTFACTORY_REGISTERCLASS_AND_INSTANTIATE(NS, Class) \
300 template class Class; \
301 static MBSim::ObjectFactoryRegisterClassHelper<Class> \
302 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)((NS)%MBSim::fixXMLLocalName(#Class));
303
306#define MBSIM_OBJECTFACTORY_REGISTERCLASSWITHTEMPLATENAME_AND_INSTANTIATE(NS, Class, TemplateName) \
307 template class Class; \
308 static MBSim::ObjectFactoryRegisterClassHelper<Class> \
309 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)((NS)%(MBSim::fixXMLLocalName(#Class)+"_"+#TemplateName));
310
312#define MBSIM_OBJECTFACTORY_REGISTERENUM(EnumType, NS, enumName) \
313 static MBSim::EnumFactory<EnumType> \
314 BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)(enumName, (NS)%#enumName);
315
316#endif
Definition: objectfactory.h:39
Definition: objectfactory.h:55
Definition: objectfactory.h:226
EnumFactory(const EnumType &enumVar, MBXMLUtils::FQN fqn_)
Definition: objectfactory.h:234
static const EnumType & get(const MBXMLUtils::FQN &fqn, const xercesc::DOMElement *e=nullptr)
Definition: objectfactory.h:260
~EnumFactory()
Definition: objectfactory.h:247
basic error class for mbsim
Definition: mbsim_event.h:39
Definition: objectfactory.h:187
~ObjectFactoryRegisterClassHelper()
Definition: objectfactory.h:205
ObjectFactoryRegisterClassHelper(MBXMLUtils::FQN name_) noexcept
Definition: objectfactory.h:192
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:162
fmatvec::Atom * operator()() const override
Implement this function to allocate a new object.
Definition: objectfactory.h:164
bool isEqual(const AllocateBase &other) const override
Definition: objectfactory.h:170
Definition: objectfactory_part.h:49
Definition: objectfactory.h:176
void operator()(fmatvec::Atom *obj) const override
Implement this function to deallocate the object obj.
Definition: objectfactory.h:178