| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- //
- // ClassLoader.h
- //
- // $Id: //poco/1.4/Foundation/include/Poco/ClassLoader.h#1 $
- //
- // Library: Foundation
- // Package: SharedLibrary
- // Module: ClassLoader
- //
- // Definition of the ClassLoader class.
- //
- // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
- // and Contributors.
- //
- // SPDX-License-Identifier: BSL-1.0
- //
- #ifndef Foundation_ClassLoader_INCLUDED
- #define Foundation_ClassLoader_INCLUDED
- #include "Poco/Foundation.h"
- #include "Poco/MetaObject.h"
- #include "Poco/Manifest.h"
- #include "Poco/SharedLibrary.h"
- #include "Poco/Mutex.h"
- #include "Poco/Exception.h"
- #include <map>
- namespace Poco {
- template <class Base>
- class ClassLoader
- /// The ClassLoader loads C++ classes from shared libraries
- /// at runtime. It must be instantiated with a root class
- /// of the loadable classes.
- /// For a class to be loadable from a library, the library
- /// must provide a Manifest of all the classes it contains.
- /// The Manifest for a shared library can be easily built
- /// with the help of the macros in the header file
- /// "Foundation/ClassLibrary.h".
- ///
- /// Starting with POCO release 1.3, a class library can
- /// export multiple manifests. In addition to the default
- /// (unnamed) manifest, multiple named manifests can
- /// be exported, each having a different base class.
- ///
- /// There is one important restriction: one instance of
- /// ClassLoader can only load one manifest from a class
- /// library.
- {
- public:
- typedef AbstractMetaObject<Base> Meta;
- typedef Manifest<Base> Manif;
- typedef void (*InitializeLibraryFunc)();
- typedef void (*UninitializeLibraryFunc)();
- typedef bool (*BuildManifestFunc)(ManifestBase*);
- struct LibraryInfo
- {
- SharedLibrary* pLibrary;
- const Manif* pManifest;
- int refCount;
- };
- typedef std::map<std::string, LibraryInfo> LibraryMap;
- class Iterator
- /// The ClassLoader's very own iterator class.
- {
- public:
- typedef std::pair<std::string, const Manif*> Pair;
- Iterator(const typename LibraryMap::const_iterator& it)
- {
- _it = it;
- }
- Iterator(const Iterator& it)
- {
- _it = it._it;
- }
- ~Iterator()
- {
- }
- Iterator& operator = (const Iterator& it)
- {
- _it = it._it;
- return *this;
- }
- inline bool operator == (const Iterator& it) const
- {
- return _it == it._it;
- }
- inline bool operator != (const Iterator& it) const
- {
- return _it != it._it;
- }
- Iterator& operator ++ () // prefix
- {
- ++_it;
- return *this;
- }
- Iterator operator ++ (int) // postfix
- {
- Iterator result(_it);
- ++_it;
- return result;
- }
- inline const Pair* operator * () const
- {
- _pair.first = _it->first;
- _pair.second = _it->second.pManifest;
- return &_pair;
- }
- inline const Pair* operator -> () const
- {
- _pair.first = _it->first;
- _pair.second = _it->second.pManifest;
- return &_pair;
- }
- private:
- typename LibraryMap::const_iterator _it;
- mutable Pair _pair;
- };
- ClassLoader()
- /// Creates the ClassLoader.
- {
- }
- virtual ~ClassLoader()
- /// Destroys the ClassLoader.
- {
- for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it)
- {
- delete it->second.pLibrary;
- delete it->second.pManifest;
- }
- }
- void loadLibrary(const std::string& path, const std::string& manifest)
- /// Loads a library from the given path, using the given manifest.
- /// Does nothing if the library is already loaded.
- /// Throws a LibraryLoadException if the library
- /// cannot be loaded or does not have a Manifest.
- /// If the library exports a function named "pocoInitializeLibrary",
- /// this function is executed.
- /// If called multiple times for the same library,
- /// the number of calls to unloadLibrary() must be the same
- /// for the library to become unloaded.
- {
- FastMutex::ScopedLock lock(_mutex);
- typename LibraryMap::iterator it = _map.find(path);
- if (it == _map.end())
- {
- LibraryInfo li;
- li.pLibrary = new SharedLibrary(path);
- li.pManifest = new Manif();
- li.refCount = 1;
- try
- {
- std::string pocoBuildManifestSymbol("pocoBuildManifest");
- pocoBuildManifestSymbol.append(manifest);
- if (li.pLibrary->hasSymbol("pocoInitializeLibrary"))
- {
- InitializeLibraryFunc initializeLibrary = (InitializeLibraryFunc) li.pLibrary->getSymbol("pocoInitializeLibrary");
- initializeLibrary();
- }
- if (li.pLibrary->hasSymbol(pocoBuildManifestSymbol))
- {
- BuildManifestFunc buildManifest = (BuildManifestFunc) li.pLibrary->getSymbol(pocoBuildManifestSymbol);
- if (buildManifest(const_cast<Manif*>(li.pManifest)))
- _map[path] = li;
- else
- throw LibraryLoadException(std::string("Manifest class mismatch in ") + path, manifest);
- }
- else throw LibraryLoadException(std::string("No manifest in ") + path, manifest);
- }
- catch (...)
- {
- delete li.pLibrary;
- delete li.pManifest;
- throw;
- }
- }
- else
- {
- ++it->second.refCount;
- }
- }
- void loadLibrary(const std::string& path)
- /// Loads a library from the given path. Does nothing
- /// if the library is already loaded.
- /// Throws a LibraryLoadException if the library
- /// cannot be loaded or does not have a Manifest.
- /// If the library exports a function named "pocoInitializeLibrary",
- /// this function is executed.
- /// If called multiple times for the same library,
- /// the number of calls to unloadLibrary() must be the same
- /// for the library to become unloaded.
- ///
- /// Equivalent to loadLibrary(path, "").
- {
- loadLibrary(path, "");
- }
-
- void unloadLibrary(const std::string& path)
- /// Unloads the given library.
- /// Be extremely cautious when unloading shared libraries.
- /// If objects from the library are still referenced somewhere,
- /// a total crash is very likely.
- /// If the library exports a function named "pocoUninitializeLibrary",
- /// this function is executed before it is unloaded.
- /// If loadLibrary() has been called multiple times for the same
- /// library, the number of calls to unloadLibrary() must be the same
- /// for the library to become unloaded.
- {
- FastMutex::ScopedLock lock(_mutex);
- typename LibraryMap::iterator it = _map.find(path);
- if (it != _map.end())
- {
- if (--it->second.refCount == 0)
- {
- if (it->second.pLibrary->hasSymbol("pocoUninitializeLibrary"))
- {
- UninitializeLibraryFunc uninitializeLibrary = (UninitializeLibraryFunc) it->second.pLibrary->getSymbol("pocoUninitializeLibrary");
- uninitializeLibrary();
- }
- delete it->second.pManifest;
- it->second.pLibrary->unload();
- delete it->second.pLibrary;
- _map.erase(it);
- }
- }
- else throw NotFoundException(path);
- }
- const Meta* findClass(const std::string& className) const
- /// Returns a pointer to the MetaObject for the given
- /// class, or a null pointer if the class is not known.
- {
- FastMutex::ScopedLock lock(_mutex);
- for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it)
- {
- const Manif* pManif = it->second.pManifest;
- typename Manif::Iterator itm = pManif->find(className);
- if (itm != pManif->end())
- return *itm;
- }
- return 0;
- }
-
- const Meta& classFor(const std::string& className) const
- /// Returns a reference to the MetaObject for the given
- /// class. Throws a NotFoundException if the class
- /// is not known.
- {
- const Meta* pMeta = findClass(className);
- if (pMeta)
- return *pMeta;
- else
- throw NotFoundException(className);
- }
-
- Base* create(const std::string& className) const
- /// Creates an instance of the given class.
- /// Throws a NotFoundException if the class
- /// is not known.
- {
- return classFor(className).create();
- }
-
- Base& instance(const std::string& className) const
- /// Returns a reference to the sole instance of
- /// the given class. The class must be a singleton,
- /// otherwise an InvalidAccessException will be thrown.
- /// Throws a NotFoundException if the class
- /// is not known.
- {
- return classFor(className).instance();
- }
-
- bool canCreate(const std::string& className) const
- /// Returns true if create() can create new instances
- /// of the class.
- {
- return classFor(className).canCreate();
- }
- void destroy(const std::string& className, Base* pObject) const
- /// Destroys the object pObject points to.
- /// Does nothing if object is not found.
- {
- classFor(className).destroy(pObject);
- }
- bool isAutoDelete(const std::string& className, Base* pObject) const
- /// Returns true if the object is automatically
- /// deleted by its meta object.
- {
- return classFor(className).isAutoDelete(pObject);
- }
-
- const Manif* findManifest(const std::string& path) const
- /// Returns a pointer to the Manifest for the given
- /// library, or a null pointer if the library has not been loaded.
- {
- FastMutex::ScopedLock lock(_mutex);
- typename LibraryMap::const_iterator it = _map.find(path);
- if (it != _map.end())
- return it->second.pManifest;
- else
- return 0;
- }
-
- const Manif& manifestFor(const std::string& path) const
- /// Returns a reference to the Manifest for the given library
- /// Throws a NotFoundException if the library has not been loaded.
- {
- const Manif* pManif = findManifest(path);
- if (pManif)
- return *pManif;
- else
- throw NotFoundException(path);
- }
- bool isLibraryLoaded(const std::string& path) const
- /// Returns true if the library with the given name
- /// has already been loaded.
- {
- return findManifest(path) != 0;
- }
- Iterator begin() const
- {
- FastMutex::ScopedLock lock(_mutex);
- return Iterator(_map.begin());
- }
- Iterator end() const
- {
- FastMutex::ScopedLock lock(_mutex);
- return Iterator(_map.end());
- }
- private:
- LibraryMap _map;
- mutable FastMutex _mutex;
- };
- } // namespace Poco
- #endif // Foundation_ClassLoader_INCLUDED
|