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