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
30namespace Poco {
31
32
33template <class Base>
34class 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{
53public:
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
356private:
357 LibraryMap _map;
358 mutable FastMutex _mutex;
359};
360
361
362} // namespace Poco
363
364
365#endif // Foundation_ClassLoader_INCLUDED
366