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
35 namespace MBSim {
36
37 /* A tree of DOMEvalException's which store the tree of failed objects
38 * creations of the object factory */
39 class DOMEvalExceptionStack : public MBXMLUtils::DOMEvalException {
40 public:
41 DOMEvalExceptionStack(const xercesc::DOMElement *element) : MBXMLUtils::DOMEvalException("", element) {}
42 DOMEvalExceptionStack(const DOMEvalExceptionStack &src) : MBXMLUtils::DOMEvalException(src), exVec(src.exVec) {}
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 */
55 class DOMEvalExceptionWrongType : public MBXMLUtils::DOMEvalException {
56 public:
57 DOMEvalExceptionWrongType(const std::string &type, const xercesc::DOMElement *element) :
58 MBXMLUtils::DOMEvalException(type, element) {}
59 DOMEvalExceptionWrongType(const DOMEvalExceptionWrongType &src) = default;
60 ~DOMEvalExceptionWrongType() noexcept override = default;
61 };
62
66 class ObjectFactory {
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
102 template<class ContainerType>
103 ContainerType* 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 }
137 catch(MBXMLUtils::DOMEvalException &ex) {
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
155 template<class CreateType>
156 struct 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
170 struct Deallocate : public DeallocateBase {
171 // deallocate a object using delete
172 void operator()(fmatvec::Atom *obj) const override {
173 delete obj;
174 }
175 };
176
180 template<class CreateType>
181 class ObjectFactoryRegisterClassHelper {
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
199 ~ObjectFactoryRegisterClassHelper() {
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
219 template<class EnumType>
220 class EnumFactory {
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
241 ~EnumFactory() {
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
269 template<class EV>
270 void registerEnum_internal(const MBXMLUtils::FQN &name, const EV& value) {
271 EnumFactory<EV>::regmap().insert(std::make_pair(name, std::ref(value)));
272 }
273
274 template<class EV>
275 void deregisterEnum_internal(const MBXMLUtils::FQN &name) {
276 EnumFactory<EV>::regmap().erase(name);
277 }
278
279 // fix local xml name (remove template and namespace)
280 std::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
MBXMLUtils::FQN
MBSim::EnumFactory::EnumFactory
EnumFactory(const EnumType &enumVar, MBXMLUtils::FQN fqn_)
Definition: objectfactory.h:228
MBSim::DOMEvalExceptionStack
Definition: objectfactory.h:39
MBSim::ObjectFactoryRegisterClassHelper
Definition: objectfactory.h:181
MBSim::ObjectFactoryRegisterClassHelper::~ObjectFactoryRegisterClassHelper
~ObjectFactoryRegisterClassHelper()
Definition: objectfactory.h:199
MBSim::EnumFactory::get
static const EnumType & get(const MBXMLUtils::FQN &fqn, const xercesc::DOMElement *e=nullptr)
Definition: objectfactory.h:254
MBSim::DeallocateBase
Definition: objectfactory_part.h:49
MBSim::Allocate
Definition: objectfactory.h:156
MBSim::ObjectFactory::createAndInit
static ContainerType * createAndInit(const xercesc::DOMElement *element)
Definition: objectfactory.h:103
MBSim::ObjectFactoryRegisterClassHelper::ObjectFactoryRegisterClassHelper
ObjectFactoryRegisterClassHelper(MBXMLUtils::FQN name_) noexcept
Definition: objectfactory.h:186
MBSim::EnumFactory::~EnumFactory
~EnumFactory()
Definition: objectfactory.h:241
MBXMLUtils::DOMEvalException
MBSim::Deallocate
Definition: objectfactory.h:170
MBSim::ObjectFactory
Definition: objectfactory.h:66
MBSim::AllocateBase
Definition: objectfactory_part.h:37
MBSim::DOMEvalExceptionWrongType
Definition: objectfactory.h:55
MBSim::Allocate::operator()
fmatvec::Atom * operator()() const override
Implement this function to allocate a new object.
Definition: objectfactory.h:158
MBSim::EnumFactory
Definition: objectfactory.h:220
MBSim::Deallocate::operator()
void operator()(fmatvec::Atom *obj) const override
Implement this function to deallocate the object obj.
Definition: objectfactory.h:172
MBSim
namespace MBSim
Definition: bilateral_constraint.cc:30
MBSim::Allocate::isEqual
bool isEqual(const AllocateBase &other) const override
Definition: objectfactory.h:164