ClassLoader.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. //
  2. // ClassLoader.h
  3. //
  4. // $Id: //poco/1.4/Foundation/include/Poco/ClassLoader.h#1 $
  5. //
  6. // Library: Foundation
  7. // Package: SharedLibrary
  8. // Module: ClassLoader
  9. //
  10. // Definition of the ClassLoader class.
  11. //
  12. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  13. // and Contributors.
  14. //
  15. // SPDX-License-Identifier: BSL-1.0
  16. //
  17. #ifndef Foundation_ClassLoader_INCLUDED
  18. #define Foundation_ClassLoader_INCLUDED
  19. #include "Poco/Foundation.h"
  20. #include "Poco/MetaObject.h"
  21. #include "Poco/Manifest.h"
  22. #include "Poco/SharedLibrary.h"
  23. #include "Poco/Mutex.h"
  24. #include "Poco/Exception.h"
  25. #include <map>
  26. namespace Poco {
  27. template <class Base>
  28. class ClassLoader
  29. /// The ClassLoader loads C++ classes from shared libraries
  30. /// at runtime. It must be instantiated with a root class
  31. /// of the loadable classes.
  32. /// For a class to be loadable from a library, the library
  33. /// must provide a Manifest of all the classes it contains.
  34. /// The Manifest for a shared library can be easily built
  35. /// with the help of the macros in the header file
  36. /// "Foundation/ClassLibrary.h".
  37. ///
  38. /// Starting with POCO release 1.3, a class library can
  39. /// export multiple manifests. In addition to the default
  40. /// (unnamed) manifest, multiple named manifests can
  41. /// be exported, each having a different base class.
  42. ///
  43. /// There is one important restriction: one instance of
  44. /// ClassLoader can only load one manifest from a class
  45. /// library.
  46. {
  47. public:
  48. typedef AbstractMetaObject<Base> Meta;
  49. typedef Manifest<Base> Manif;
  50. typedef void (*InitializeLibraryFunc)();
  51. typedef void (*UninitializeLibraryFunc)();
  52. typedef bool (*BuildManifestFunc)(ManifestBase*);
  53. struct LibraryInfo
  54. {
  55. SharedLibrary* pLibrary;
  56. const Manif* pManifest;
  57. int refCount;
  58. };
  59. typedef std::map<std::string, LibraryInfo> LibraryMap;
  60. class Iterator
  61. /// The ClassLoader's very own iterator class.
  62. {
  63. public:
  64. typedef std::pair<std::string, const Manif*> Pair;
  65. Iterator(const typename LibraryMap::const_iterator& it)
  66. {
  67. _it = it;
  68. }
  69. Iterator(const Iterator& it)
  70. {
  71. _it = it._it;
  72. }
  73. ~Iterator()
  74. {
  75. }
  76. Iterator& operator = (const Iterator& it)
  77. {
  78. _it = it._it;
  79. return *this;
  80. }
  81. inline bool operator == (const Iterator& it) const
  82. {
  83. return _it == it._it;
  84. }
  85. inline bool operator != (const Iterator& it) const
  86. {
  87. return _it != it._it;
  88. }
  89. Iterator& operator ++ () // prefix
  90. {
  91. ++_it;
  92. return *this;
  93. }
  94. Iterator operator ++ (int) // postfix
  95. {
  96. Iterator result(_it);
  97. ++_it;
  98. return result;
  99. }
  100. inline const Pair* operator * () const
  101. {
  102. _pair.first = _it->first;
  103. _pair.second = _it->second.pManifest;
  104. return &_pair;
  105. }
  106. inline const Pair* operator -> () const
  107. {
  108. _pair.first = _it->first;
  109. _pair.second = _it->second.pManifest;
  110. return &_pair;
  111. }
  112. private:
  113. typename LibraryMap::const_iterator _it;
  114. mutable Pair _pair;
  115. };
  116. ClassLoader()
  117. /// Creates the ClassLoader.
  118. {
  119. }
  120. virtual ~ClassLoader()
  121. /// Destroys the ClassLoader.
  122. {
  123. for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it)
  124. {
  125. delete it->second.pLibrary;
  126. delete it->second.pManifest;
  127. }
  128. }
  129. void loadLibrary(const std::string& path, const std::string& manifest)
  130. /// Loads a library from the given path, using the given manifest.
  131. /// Does nothing if the library is already loaded.
  132. /// Throws a LibraryLoadException if the library
  133. /// cannot be loaded or does not have a Manifest.
  134. /// If the library exports a function named "pocoInitializeLibrary",
  135. /// this function is executed.
  136. /// If called multiple times for the same library,
  137. /// the number of calls to unloadLibrary() must be the same
  138. /// for the library to become unloaded.
  139. {
  140. FastMutex::ScopedLock lock(_mutex);
  141. typename LibraryMap::iterator it = _map.find(path);
  142. if (it == _map.end())
  143. {
  144. LibraryInfo li;
  145. li.pLibrary = new SharedLibrary(path);
  146. li.pManifest = new Manif();
  147. li.refCount = 1;
  148. try
  149. {
  150. std::string pocoBuildManifestSymbol("pocoBuildManifest");
  151. pocoBuildManifestSymbol.append(manifest);
  152. if (li.pLibrary->hasSymbol("pocoInitializeLibrary"))
  153. {
  154. InitializeLibraryFunc initializeLibrary = (InitializeLibraryFunc) li.pLibrary->getSymbol("pocoInitializeLibrary");
  155. initializeLibrary();
  156. }
  157. if (li.pLibrary->hasSymbol(pocoBuildManifestSymbol))
  158. {
  159. BuildManifestFunc buildManifest = (BuildManifestFunc) li.pLibrary->getSymbol(pocoBuildManifestSymbol);
  160. if (buildManifest(const_cast<Manif*>(li.pManifest)))
  161. _map[path] = li;
  162. else
  163. throw LibraryLoadException(std::string("Manifest class mismatch in ") + path, manifest);
  164. }
  165. else throw LibraryLoadException(std::string("No manifest in ") + path, manifest);
  166. }
  167. catch (...)
  168. {
  169. delete li.pLibrary;
  170. delete li.pManifest;
  171. throw;
  172. }
  173. }
  174. else
  175. {
  176. ++it->second.refCount;
  177. }
  178. }
  179. void loadLibrary(const std::string& path)
  180. /// Loads a library from the given path. Does nothing
  181. /// if the library is already loaded.
  182. /// Throws a LibraryLoadException if the library
  183. /// cannot be loaded or does not have a Manifest.
  184. /// If the library exports a function named "pocoInitializeLibrary",
  185. /// this function is executed.
  186. /// If called multiple times for the same library,
  187. /// the number of calls to unloadLibrary() must be the same
  188. /// for the library to become unloaded.
  189. ///
  190. /// Equivalent to loadLibrary(path, "").
  191. {
  192. loadLibrary(path, "");
  193. }
  194. void unloadLibrary(const std::string& path)
  195. /// Unloads the given library.
  196. /// Be extremely cautious when unloading shared libraries.
  197. /// If objects from the library are still referenced somewhere,
  198. /// a total crash is very likely.
  199. /// If the library exports a function named "pocoUninitializeLibrary",
  200. /// this function is executed before it is unloaded.
  201. /// If loadLibrary() has been called multiple times for the same
  202. /// library, the number of calls to unloadLibrary() must be the same
  203. /// for the library to become unloaded.
  204. {
  205. FastMutex::ScopedLock lock(_mutex);
  206. typename LibraryMap::iterator it = _map.find(path);
  207. if (it != _map.end())
  208. {
  209. if (--it->second.refCount == 0)
  210. {
  211. if (it->second.pLibrary->hasSymbol("pocoUninitializeLibrary"))
  212. {
  213. UninitializeLibraryFunc uninitializeLibrary = (UninitializeLibraryFunc) it->second.pLibrary->getSymbol("pocoUninitializeLibrary");
  214. uninitializeLibrary();
  215. }
  216. delete it->second.pManifest;
  217. it->second.pLibrary->unload();
  218. delete it->second.pLibrary;
  219. _map.erase(it);
  220. }
  221. }
  222. else throw NotFoundException(path);
  223. }
  224. const Meta* findClass(const std::string& className) const
  225. /// Returns a pointer to the MetaObject for the given
  226. /// class, or a null pointer if the class is not known.
  227. {
  228. FastMutex::ScopedLock lock(_mutex);
  229. for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it)
  230. {
  231. const Manif* pManif = it->second.pManifest;
  232. typename Manif::Iterator itm = pManif->find(className);
  233. if (itm != pManif->end())
  234. return *itm;
  235. }
  236. return 0;
  237. }
  238. const Meta& classFor(const std::string& className) const
  239. /// Returns a reference to the MetaObject for the given
  240. /// class. Throws a NotFoundException if the class
  241. /// is not known.
  242. {
  243. const Meta* pMeta = findClass(className);
  244. if (pMeta)
  245. return *pMeta;
  246. else
  247. throw NotFoundException(className);
  248. }
  249. Base* create(const std::string& className) const
  250. /// Creates an instance of the given class.
  251. /// Throws a NotFoundException if the class
  252. /// is not known.
  253. {
  254. return classFor(className).create();
  255. }
  256. Base& instance(const std::string& className) const
  257. /// Returns a reference to the sole instance of
  258. /// the given class. The class must be a singleton,
  259. /// otherwise an InvalidAccessException will be thrown.
  260. /// Throws a NotFoundException if the class
  261. /// is not known.
  262. {
  263. return classFor(className).instance();
  264. }
  265. bool canCreate(const std::string& className) const
  266. /// Returns true if create() can create new instances
  267. /// of the class.
  268. {
  269. return classFor(className).canCreate();
  270. }
  271. void destroy(const std::string& className, Base* pObject) const
  272. /// Destroys the object pObject points to.
  273. /// Does nothing if object is not found.
  274. {
  275. classFor(className).destroy(pObject);
  276. }
  277. bool isAutoDelete(const std::string& className, Base* pObject) const
  278. /// Returns true if the object is automatically
  279. /// deleted by its meta object.
  280. {
  281. return classFor(className).isAutoDelete(pObject);
  282. }
  283. const Manif* findManifest(const std::string& path) const
  284. /// Returns a pointer to the Manifest for the given
  285. /// library, or a null pointer if the library has not been loaded.
  286. {
  287. FastMutex::ScopedLock lock(_mutex);
  288. typename LibraryMap::const_iterator it = _map.find(path);
  289. if (it != _map.end())
  290. return it->second.pManifest;
  291. else
  292. return 0;
  293. }
  294. const Manif& manifestFor(const std::string& path) const
  295. /// Returns a reference to the Manifest for the given library
  296. /// Throws a NotFoundException if the library has not been loaded.
  297. {
  298. const Manif* pManif = findManifest(path);
  299. if (pManif)
  300. return *pManif;
  301. else
  302. throw NotFoundException(path);
  303. }
  304. bool isLibraryLoaded(const std::string& path) const
  305. /// Returns true if the library with the given name
  306. /// has already been loaded.
  307. {
  308. return findManifest(path) != 0;
  309. }
  310. Iterator begin() const
  311. {
  312. FastMutex::ScopedLock lock(_mutex);
  313. return Iterator(_map.begin());
  314. }
  315. Iterator end() const
  316. {
  317. FastMutex::ScopedLock lock(_mutex);
  318. return Iterator(_map.end());
  319. }
  320. private:
  321. LibraryMap _map;
  322. mutable FastMutex _mutex;
  323. };
  324. } // namespace Poco
  325. #endif // Foundation_ClassLoader_INCLUDED