[80] | 1 | // |
---|
| 2 | // ClassLoader.h |
---|
| 3 | // |
---|
| 4 | // $Id: //poco/1.3/Foundation/include/Poco/ClassLoader.h#2 $ |
---|
| 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 | // Permission is hereby granted, free of charge, to any person or organization |
---|
| 16 | // obtaining a copy of the software and accompanying documentation covered by |
---|
| 17 | // this license (the "Software") to use, reproduce, display, distribute, |
---|
| 18 | // execute, and transmit the Software, and to prepare derivative works of the |
---|
| 19 | // Software, and to permit third-parties to whom the Software is furnished to |
---|
| 20 | // do so, all subject to the following: |
---|
| 21 | // |
---|
| 22 | // The copyright notices in the Software and this entire statement, including |
---|
| 23 | // the above license grant, this restriction and the following disclaimer, |
---|
| 24 | // must be included in all copies of the Software, in whole or in part, and |
---|
| 25 | // all derivative works of the Software, unless such copies or derivative |
---|
| 26 | // works are solely in the form of machine-executable object code generated by |
---|
| 27 | // a source language processor. |
---|
| 28 | // |
---|
| 29 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
---|
| 30 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
---|
| 31 | // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT |
---|
| 32 | // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE |
---|
| 33 | // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, |
---|
| 34 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
| 35 | // DEALINGS IN THE SOFTWARE. |
---|
| 36 | // |
---|
| 37 | |
---|
| 38 | |
---|
| 39 | #ifndef Foundation_ClassLoader_INCLUDED |
---|
| 40 | #define Foundation_ClassLoader_INCLUDED |
---|
| 41 | |
---|
| 42 | |
---|
| 43 | #include "Poco/Foundation.h" |
---|
| 44 | #include "Poco/MetaObject.h" |
---|
| 45 | #include "Poco/Manifest.h" |
---|
| 46 | #include "Poco/SharedLibrary.h" |
---|
| 47 | #include "Poco/Mutex.h" |
---|
| 48 | #include "Poco/Exception.h" |
---|
| 49 | #include <map> |
---|
| 50 | |
---|
| 51 | |
---|
| 52 | namespace Poco { |
---|
| 53 | |
---|
| 54 | |
---|
| 55 | template <class Base> |
---|
| 56 | class ClassLoader |
---|
| 57 | /// The ClassLoader loads C++ classes from shared libraries |
---|
| 58 | /// at runtime. It must be instantiated with a root class |
---|
| 59 | /// of the loadable classes. |
---|
| 60 | /// For a class to be loadable from a library, the library |
---|
| 61 | /// must provide a Manifest of all the classes it contains. |
---|
| 62 | /// The Manifest for a shared library can be easily built |
---|
| 63 | /// with the help of the macros in the header file |
---|
| 64 | /// "Foundation/ClassLibrary.h". |
---|
| 65 | /// |
---|
| 66 | /// Starting with POCO release 1.3, a class library can |
---|
| 67 | /// export multiple manifests. In addition to the default |
---|
| 68 | /// (unnamed) manifest, multiple named manifests can |
---|
| 69 | /// be exported, each having a different base class. |
---|
| 70 | /// |
---|
| 71 | /// There is one important restriction: one instance of |
---|
| 72 | /// ClassLoader can only load one manifest from a class |
---|
| 73 | /// library. |
---|
| 74 | { |
---|
| 75 | public: |
---|
| 76 | typedef AbstractMetaObject<Base> Meta; |
---|
| 77 | typedef Manifest<Base> Manif; |
---|
| 78 | typedef void (*InitializeLibraryFunc)(); |
---|
| 79 | typedef void (*UninitializeLibraryFunc)(); |
---|
| 80 | typedef bool (*BuildManifestFunc)(ManifestBase*); |
---|
| 81 | |
---|
| 82 | struct LibraryInfo |
---|
| 83 | { |
---|
| 84 | SharedLibrary* pLibrary; |
---|
| 85 | const Manif* pManifest; |
---|
| 86 | int refCount; |
---|
| 87 | }; |
---|
| 88 | typedef std::map<std::string, LibraryInfo> LibraryMap; |
---|
| 89 | |
---|
| 90 | class Iterator |
---|
| 91 | /// The ClassLoader's very own iterator class. |
---|
| 92 | { |
---|
| 93 | public: |
---|
| 94 | typedef std::pair<std::string, const Manif*> Pair; |
---|
| 95 | |
---|
| 96 | Iterator(const typename LibraryMap::const_iterator& it) |
---|
| 97 | { |
---|
| 98 | _it = it; |
---|
| 99 | } |
---|
| 100 | Iterator(const Iterator& it) |
---|
| 101 | { |
---|
| 102 | _it = it._it; |
---|
| 103 | } |
---|
| 104 | ~Iterator() |
---|
| 105 | { |
---|
| 106 | } |
---|
| 107 | Iterator& operator = (const Iterator& it) |
---|
| 108 | { |
---|
| 109 | _it = it._it; |
---|
| 110 | return *this; |
---|
| 111 | } |
---|
| 112 | inline bool operator == (const Iterator& it) const |
---|
| 113 | { |
---|
| 114 | return _it == it._it; |
---|
| 115 | } |
---|
| 116 | inline bool operator != (const Iterator& it) const |
---|
| 117 | { |
---|
| 118 | return _it != it._it; |
---|
| 119 | } |
---|
| 120 | Iterator& operator ++ () // prefix |
---|
| 121 | { |
---|
| 122 | ++_it; |
---|
| 123 | return *this; |
---|
| 124 | } |
---|
| 125 | Iterator operator ++ (int) // postfix |
---|
| 126 | { |
---|
| 127 | Iterator result(_it); |
---|
| 128 | ++_it; |
---|
| 129 | return result; |
---|
| 130 | } |
---|
| 131 | inline const Pair* operator * () const |
---|
| 132 | { |
---|
| 133 | _pair.first = _it->first; |
---|
| 134 | _pair.second = _it->second.pManifest; |
---|
| 135 | return &_pair; |
---|
| 136 | } |
---|
| 137 | inline const Pair* operator -> () const |
---|
| 138 | { |
---|
| 139 | _pair.first = _it->first; |
---|
| 140 | _pair.second = _it->second.pManifest; |
---|
| 141 | return &_pair; |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | private: |
---|
| 145 | typename LibraryMap::const_iterator _it; |
---|
| 146 | mutable Pair _pair; |
---|
| 147 | }; |
---|
| 148 | |
---|
| 149 | ClassLoader() |
---|
| 150 | /// Creates the ClassLoader. |
---|
| 151 | { |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | virtual ~ClassLoader() |
---|
| 155 | /// Destroys the ClassLoader. |
---|
| 156 | { |
---|
| 157 | for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it) |
---|
| 158 | { |
---|
| 159 | delete it->second.pLibrary; |
---|
| 160 | delete it->second.pManifest; |
---|
| 161 | } |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | void loadLibrary(const std::string& path, const std::string& manifest) |
---|
| 165 | /// Loads a library from the given path, using the given manifest. |
---|
| 166 | /// Does nothing if the library is already loaded. |
---|
| 167 | /// Throws a LibraryLoadException if the library |
---|
| 168 | /// cannot be loaded or does not have a Manifest. |
---|
| 169 | /// If the library exports a function named "pocoInitializeLibrary", |
---|
| 170 | /// this function is executed. |
---|
| 171 | /// If called multiple times for the same library, |
---|
| 172 | /// the number of calls to unloadLibrary() must be the same |
---|
| 173 | /// for the library to become unloaded. |
---|
| 174 | { |
---|
| 175 | FastMutex::ScopedLock lock(_mutex); |
---|
| 176 | |
---|
| 177 | typename LibraryMap::iterator it = _map.find(path); |
---|
| 178 | if (it == _map.end()) |
---|
| 179 | { |
---|
| 180 | LibraryInfo li; |
---|
| 181 | li.pLibrary = new SharedLibrary(path); |
---|
| 182 | li.pManifest = new Manif(); |
---|
| 183 | li.refCount = 1; |
---|
| 184 | try |
---|
| 185 | { |
---|
| 186 | std::string pocoBuildManifestSymbol("pocoBuildManifest"); |
---|
| 187 | pocoBuildManifestSymbol.append(manifest); |
---|
| 188 | if (li.pLibrary->hasSymbol("pocoInitializeLibrary")) |
---|
| 189 | { |
---|
| 190 | InitializeLibraryFunc initializeLibrary = (InitializeLibraryFunc) li.pLibrary->getSymbol("pocoInitializeLibrary"); |
---|
| 191 | initializeLibrary(); |
---|
| 192 | } |
---|
| 193 | if (li.pLibrary->hasSymbol(pocoBuildManifestSymbol)) |
---|
| 194 | { |
---|
| 195 | BuildManifestFunc buildManifest = (BuildManifestFunc) li.pLibrary->getSymbol(pocoBuildManifestSymbol); |
---|
| 196 | if (buildManifest(const_cast<Manif*>(li.pManifest))) |
---|
| 197 | _map[path] = li; |
---|
| 198 | else |
---|
| 199 | throw LibraryLoadException(std::string("Manifest class mismatch in ") + path, manifest); |
---|
| 200 | } |
---|
| 201 | else throw LibraryLoadException(std::string("No manifest in ") + path, manifest); |
---|
| 202 | } |
---|
| 203 | catch (...) |
---|
| 204 | { |
---|
| 205 | delete li.pLibrary; |
---|
| 206 | delete li.pManifest; |
---|
| 207 | throw; |
---|
| 208 | } |
---|
| 209 | } |
---|
| 210 | else |
---|
| 211 | { |
---|
| 212 | ++it->second.refCount; |
---|
| 213 | } |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | void loadLibrary(const std::string& path) |
---|
| 217 | /// Loads a library from the given path. Does nothing |
---|
| 218 | /// if the library is already loaded. |
---|
| 219 | /// Throws a LibraryLoadException if the library |
---|
| 220 | /// cannot be loaded or does not have a Manifest. |
---|
| 221 | /// If the library exports a function named "pocoInitializeLibrary", |
---|
| 222 | /// this function is executed. |
---|
| 223 | /// If called multiple times for the same library, |
---|
| 224 | /// the number of calls to unloadLibrary() must be the same |
---|
| 225 | /// for the library to become unloaded. |
---|
| 226 | /// |
---|
| 227 | /// Equivalent to loadLibrary(path, ""). |
---|
| 228 | { |
---|
| 229 | loadLibrary(path, ""); |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | void unloadLibrary(const std::string& path) |
---|
| 233 | /// Unloads the given library. |
---|
| 234 | /// Be extremely cautious when unloading shared libraries. |
---|
| 235 | /// If objects from the library are still referenced somewhere, |
---|
| 236 | /// a total crash is very likely. |
---|
| 237 | /// If the library exports a function named "pocoUninitializeLibrary", |
---|
| 238 | /// this function is executed before it is unloaded. |
---|
| 239 | /// If loadLibrary() has been called multiple times for the same |
---|
| 240 | /// library, the number of calls to unloadLibrary() must be the same |
---|
| 241 | /// for the library to become unloaded. |
---|
| 242 | { |
---|
| 243 | FastMutex::ScopedLock lock(_mutex); |
---|
| 244 | |
---|
| 245 | typename LibraryMap::iterator it = _map.find(path); |
---|
| 246 | if (it != _map.end()) |
---|
| 247 | { |
---|
| 248 | if (--it->second.refCount == 0) |
---|
| 249 | { |
---|
| 250 | if (it->second.pLibrary->hasSymbol("pocoUninitializeLibrary")) |
---|
| 251 | { |
---|
| 252 | UninitializeLibraryFunc uninitializeLibrary = (UninitializeLibraryFunc) it->second.pLibrary->getSymbol("pocoUninitializeLibrary"); |
---|
| 253 | uninitializeLibrary(); |
---|
| 254 | } |
---|
| 255 | delete it->second.pManifest; |
---|
| 256 | it->second.pLibrary->unload(); |
---|
| 257 | delete it->second.pLibrary; |
---|
| 258 | _map.erase(it); |
---|
| 259 | } |
---|
| 260 | } |
---|
| 261 | else throw NotFoundException(path); |
---|
| 262 | } |
---|
| 263 | |
---|
| 264 | const Meta* findClass(const std::string& className) const |
---|
| 265 | /// Returns a pointer to the MetaObject for the given |
---|
| 266 | /// class, or a null pointer if the class is not known. |
---|
| 267 | { |
---|
| 268 | FastMutex::ScopedLock lock(_mutex); |
---|
| 269 | |
---|
| 270 | for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it) |
---|
| 271 | { |
---|
| 272 | const Manif* pManif = it->second.pManifest; |
---|
| 273 | typename Manif::Iterator itm = pManif->find(className); |
---|
| 274 | if (itm != pManif->end()) |
---|
| 275 | return *itm; |
---|
| 276 | } |
---|
| 277 | return 0; |
---|
| 278 | } |
---|
| 279 | |
---|
| 280 | const Meta& classFor(const std::string& className) const |
---|
| 281 | /// Returns a reference to the MetaObject for the given |
---|
| 282 | /// class. Throws a NotFoundException if the class |
---|
| 283 | /// is not known. |
---|
| 284 | { |
---|
| 285 | const Meta* pMeta = findClass(className); |
---|
| 286 | if (pMeta) |
---|
| 287 | return *pMeta; |
---|
| 288 | else |
---|
| 289 | throw NotFoundException(className); |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | Base* create(const std::string& className) const |
---|
| 293 | /// Creates an instance of the given class. |
---|
| 294 | /// Throws a NotFoundException if the class |
---|
| 295 | /// is not known. |
---|
| 296 | { |
---|
| 297 | return classFor(className).create(); |
---|
| 298 | } |
---|
| 299 | |
---|
| 300 | Base& instance(const std::string& className) const |
---|
| 301 | /// Returns a reference to the sole instance of |
---|
| 302 | /// the given class. The class must be a singleton, |
---|
| 303 | /// otherwise an InvalidAccessException will be thrown. |
---|
| 304 | /// Throws a NotFoundException if the class |
---|
| 305 | /// is not known. |
---|
| 306 | { |
---|
| 307 | return classFor(className).instance(); |
---|
| 308 | } |
---|
| 309 | |
---|
| 310 | bool canCreate(const std::string& className) const |
---|
| 311 | /// Returns true if create() can create new instances |
---|
| 312 | /// of the class. |
---|
| 313 | { |
---|
| 314 | return classFor(className).canCreate(); |
---|
| 315 | } |
---|
| 316 | |
---|
| 317 | void destroy(const std::string& className, Base* pObject) const |
---|
| 318 | /// Destroys the object pObject points to. |
---|
| 319 | /// Does nothing if object is not found. |
---|
| 320 | { |
---|
| 321 | classFor(className).destroy(pObject); |
---|
| 322 | } |
---|
| 323 | |
---|
| 324 | bool isAutoDelete(const std::string& className, Base* pObject) const |
---|
| 325 | /// Returns true if the object is automatically |
---|
| 326 | /// deleted by its meta object. |
---|
| 327 | { |
---|
| 328 | return classFor(className).isAutoDelete(pObject); |
---|
| 329 | } |
---|
| 330 | |
---|
| 331 | const Manif* findManifest(const std::string& path) const |
---|
| 332 | /// Returns a pointer to the Manifest for the given |
---|
| 333 | /// library, or a null pointer if the library has not been loaded. |
---|
| 334 | { |
---|
| 335 | FastMutex::ScopedLock lock(_mutex); |
---|
| 336 | |
---|
| 337 | typename LibraryMap::const_iterator it = _map.find(path); |
---|
| 338 | if (it != _map.end()) |
---|
| 339 | return it->second.pManifest; |
---|
| 340 | else |
---|
| 341 | return 0; |
---|
| 342 | } |
---|
| 343 | |
---|
| 344 | const Manif& manifestFor(const std::string& path) const |
---|
| 345 | /// Returns a reference to the Manifest for the given library |
---|
| 346 | /// Throws a NotFoundException if the library has not been loaded. |
---|
| 347 | { |
---|
| 348 | const Manif* pManif = findManifest(path); |
---|
| 349 | if (pManif) |
---|
| 350 | return *pManif; |
---|
| 351 | else |
---|
| 352 | throw NotFoundException(path); |
---|
| 353 | } |
---|
| 354 | |
---|
| 355 | bool isLibraryLoaded(const std::string& path) const |
---|
| 356 | /// Returns true if the library with the given name |
---|
| 357 | /// has already been loaded. |
---|
| 358 | { |
---|
| 359 | return findManifest(path) != 0; |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | Iterator begin() const |
---|
| 363 | { |
---|
| 364 | FastMutex::ScopedLock lock(_mutex); |
---|
| 365 | |
---|
| 366 | return Iterator(_map.begin()); |
---|
| 367 | } |
---|
| 368 | |
---|
| 369 | Iterator end() const |
---|
| 370 | { |
---|
| 371 | FastMutex::ScopedLock lock(_mutex); |
---|
| 372 | |
---|
| 373 | return Iterator(_map.end()); |
---|
| 374 | } |
---|
| 375 | |
---|
| 376 | private: |
---|
| 377 | LibraryMap _map; |
---|
| 378 | mutable FastMutex _mutex; |
---|
| 379 | }; |
---|
| 380 | |
---|
| 381 | |
---|
| 382 | } // namespace Poco |
---|
| 383 | |
---|
| 384 | |
---|
| 385 | #endif // Foundation_ClassLoader_INCLUDED |
---|