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 |
---|