33 #include <Poco/SharedLibrary.h> 50 static boost::recursive_mutex m;
56 static boost::recursive_mutex m;
69 std::string base_class_name = typeid_base_class_name;
70 if (factoryMapMap.find(base_class_name) == factoryMapMap.end()) {
74 return factoryMapMap[base_class_name];
91 static std::string library_name;
103 library_name_ref = library_name;
145 for (
auto & it : factories) {
146 all_meta_objs.push_back(it.second);
148 return all_meta_objs;
157 BaseToFactoryMapMap::iterator itr;
159 for (
auto & it : factory_map_map) {
161 all_meta_objs.insert(all_meta_objs.end(), objs.begin(), objs.end());
163 return all_meta_objs;
170 for (
auto & f : to_filter) {
171 if (f->isOwnedBy(owner)) {
172 filtered_objs.push_back(f);
175 return filtered_objs;
183 for (
auto & f : to_filter) {
184 if (f->getAssociatedLibraryPath() == library_path) {
185 filtered_objs.push_back(f);
188 return filtered_objs;
211 CONSOLE_BRIDGE_logDebug(
212 "class_loader.impl: " 213 "Inserting MetaObject (class = %s, base_class = %s, ptr = %p) into graveyard",
215 reinterpret_cast<void *
>(meta_obj));
222 FactoryMap::iterator factory_itr = factories.begin();
223 while (factory_itr != factories.end()) {
228 FactoryMap::iterator factory_itr_copy = factory_itr;
233 factories.erase(factory_itr_copy);
257 CONSOLE_BRIDGE_logDebug(
258 "class_loader.impl: " 259 "Removing MetaObjects associated with library %s and class loader %p from global " 260 "plugin-to-factorymap map.\n",
261 library_path.c_str(),
reinterpret_cast<const void *
>(loader));
265 for (
auto & it : factory_map_map) {
269 CONSOLE_BRIDGE_logDebug(
"%s",
"class_loader.impl: Metaobjects removed.");
281 for (
auto it = open_libraries.begin(); it != open_libraries.end(); ++it) {
282 if (it->first == library_path) {
286 return open_libraries.end();
296 if (itr != open_libraries.end()) {
297 assert(itr->second->isLoaded() ==
true);
308 size_t num_meta_objs_for_lib_bound_to_loader =
310 bool are_meta_objs_bound_to_loader =
311 (0 == num_meta_objs_for_lib) ?
true : (
312 num_meta_objs_for_lib_bound_to_loader <= num_meta_objs_for_lib);
314 return is_lib_loaded_by_anyone && are_meta_objs_bound_to_loader;
320 std::vector<std::string> all_libs;
321 for (
auto & meta_obj : all_loader_meta_objs) {
322 std::string lib_path = meta_obj->getAssociatedLibraryPath();
323 if (std::find(all_libs.begin(), all_libs.end(), lib_path) == all_libs.end()) {
324 all_libs.push_back(lib_path);
334 const std::string & library_path,
ClassLoader * loader)
337 for (
auto & meta_obj : all_meta_objs) {
338 CONSOLE_BRIDGE_logDebug(
339 "class_loader.impl: " 340 "Tagging existing MetaObject %p (base = %s, derived = %s) with " 341 "class loader %p (library path = %s).",
342 reinterpret_cast<void *>(meta_obj), meta_obj->baseClassName().c_str(),
343 meta_obj->className().c_str(),
344 reinterpret_cast<void *
>(loader),
346 meta_obj->addOwningClassLoader(loader);
351 const std::string & library_path,
ClassLoader * loader)
356 for (
auto & obj : graveyard) {
357 if (obj->getAssociatedLibraryPath() == library_path) {
358 CONSOLE_BRIDGE_logDebug(
359 "class_loader.impl: " 360 "Resurrected factory metaobject from graveyard, class = %s, base_class = %s ptr = %p..." 361 "bound to ClassLoader %p (library path = %s)",
362 obj->className().c_str(), obj->baseClassName().c_str(),
reinterpret_cast<void *
>(obj),
363 reinterpret_cast<void *>(loader),
366 obj->addOwningClassLoader(loader);
367 assert(obj->typeidBaseClassName() !=
"UNSET");
369 factory[obj->className()] = obj;
375 const std::string & library_path,
ClassLoader * loader,
bool delete_objs)
382 MetaObjectVector::iterator itr = graveyard.begin();
384 while (itr != graveyard.end()) {
387 CONSOLE_BRIDGE_logDebug(
388 "class_loader.impl: " 389 "Purging factory metaobject from graveyard, class = %s, base_class = %s ptr = %p.." 390 ".bound to ClassLoader %p (library path = %s)",
392 reinterpret_cast<void *>(loader),
395 bool is_address_in_graveyard_same_as_global_factory_map =
396 std::find(all_meta_objs.begin(), all_meta_objs.end(), *itr) != all_meta_objs.end();
397 itr = graveyard.erase(itr);
399 if (is_address_in_graveyard_same_as_global_factory_map) {
400 CONSOLE_BRIDGE_logDebug(
"%s",
401 "class_loader.impl: " 402 "Newly created metaobject factory in global factory map map has same address as " 403 "one in graveyard -- metaobject has been purged from graveyard but not deleted.");
406 CONSOLE_BRIDGE_logDebug(
407 "class_loader.impl: " 408 "Also destroying metaobject %p (class = %s, base_class = %s, library_path = %s) " 409 "in addition to purging it from graveyard.",
413 #pragma GCC diagnostic push 414 #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" 418 #pragma GCC diagnostic pop 430 static boost::recursive_mutex loader_mutex;
431 CONSOLE_BRIDGE_logDebug(
432 "class_loader.impl: " 433 "Attempting to load library %s on behalf of ClassLoader handle %p...\n",
434 library_path.c_str(),
reinterpret_cast<void *
>(loader));
435 boost::recursive_mutex::scoped_lock loader_lock(loader_mutex);
440 CONSOLE_BRIDGE_logDebug(
"%s",
441 "class_loader.impl: " 442 "Library already in memory, but binding existing MetaObjects to loader if necesesary.\n");
447 Poco::SharedLibrary * library_handle =
nullptr;
453 library_handle =
new Poco::SharedLibrary(library_path);
454 }
catch (
const Poco::LibraryLoadException & e) {
458 "Could not load library (Poco exception = " + std::string(e.message()) +
")");
459 }
catch (
const Poco::LibraryAlreadyLoadedException & e) {
463 "Library already loaded (Poco exception = " + std::string(e.message()) +
")");
464 }
catch (
const Poco::NotFoundException & e) {
468 "Library not found (Poco exception = " + std::string(e.message()) +
")");
475 assert(library_handle !=
nullptr);
476 CONSOLE_BRIDGE_logDebug(
477 "class_loader.impl: " 478 "Successfully loaded library %s into memory (Poco::SharedLibrary handle = %p).",
479 library_path.c_str(),
reinterpret_cast<void *
>(library_handle));
483 if (0 == num_lib_objs) {
484 CONSOLE_BRIDGE_logDebug(
485 "class_loader.impl: " 486 "Though the library %s was just loaded, it seems no factory metaobjects were registered. " 487 "Checking factory graveyard for previously loaded metaobjects...",
488 library_path.c_str());
493 CONSOLE_BRIDGE_logDebug(
494 "class_loader.impl: " 495 "Library %s generated new factory metaobjects on load. " 496 "Destroying graveyarded objects from previous loads...",
497 library_path.c_str());
505 open_libraries.push_back(
LibraryPair(library_path, library_handle));
511 CONSOLE_BRIDGE_logDebug(
512 "class_loader.impl: " 513 "Cannot unload %s or ANY other library as a non-pure plugin library was opened. " 514 "As class_loader has no idea which libraries class factories were exported from, " 515 "it can safely close any library without potentially unlinking symbols that are still " 516 "actively being used. " 517 "You must refactor your plugin libraries to be made exclusively of plugins " 518 "in order for this error to stop happening.",
519 library_path.c_str());
521 CONSOLE_BRIDGE_logDebug(
522 "class_loader.impl: " 523 "Unloading library %s on behalf of ClassLoader %p...",
524 library_path.c_str(),
reinterpret_cast<void *
>(loader));
528 if (itr != open_libraries.end()) {
529 Poco::SharedLibrary * library = itr->second;
530 std::string library_path = itr->first;
536 CONSOLE_BRIDGE_logDebug(
537 "class_loader.impl: " 538 "There are no more MetaObjects left for %s so unloading library and " 539 "removing from loaded library vector.\n",
540 library_path.c_str());
542 assert(library->isLoaded() ==
false);
544 itr = open_libraries.erase(itr);
546 CONSOLE_BRIDGE_logDebug(
547 "class_loader.impl: " 548 "MetaObjects still remain in memory meaning other ClassLoaders are still using library" 549 ", keeping library %s open.",
550 library_path.c_str());
553 }
catch (
const Poco::RuntimeException & e) {
556 "Could not unload library (Poco exception = " + std::string(e.message()) +
")");
560 "Attempt to unload library that class_loader is unaware of.");
569 printf(
"*******************************************************************************\n");
570 printf(
"***** class_loader impl DEBUG INFORMATION *****\n");
571 printf(
"*******************************************************************************\n");
573 printf(
"OPEN LIBRARIES IN MEMORY:\n");
574 printf(
"--------------------------------------------------------------------------------\n");
577 for (
size_t c = 0; c < libs.size(); c++) {
579 "Open library %zu = %s (Poco SharedLibrary handle = %p)\n",
580 c, (libs.at(c)).first.c_str(),
reinterpret_cast<void *
>((libs.at(c)).second));
583 printf(
"METAOBJECTS (i.e. FACTORIES) IN MEMORY:\n");
584 printf(
"--------------------------------------------------------------------------------\n");
586 for (
size_t c = 0; c < meta_objs.size(); c++) {
588 printf(
"Metaobject %zu (ptr = %p):\n TypeId = %s\n Associated Library = %s\n",
590 reinterpret_cast<void *>(obj),
591 (
typeid(*obj).name()),
595 for (
size_t i = 0; i < loaders.size(); i++) {
596 printf(
" Associated Loader %zu = %p\n", i, reinterpret_cast<void *>(loaders.at(i)));
598 printf(
"--------------------------------------------------------------------------------\n");
601 printf(
"********************************** END DEBUG **********************************\n");
602 printf(
"*******************************************************************************\n\n");
An exception class thrown when class_loader is unable to load a runtime library.
CLASS_LOADER_PUBLIC void loadLibrary(const std::string &library_path, ClassLoader *loader)
Loads a library into memory if it has not already been done so. Attempting to load an already loaded ...
std::vector< class_loader::ClassLoader * > ClassLoaderVector
MetaObjectVector allMetaObjectsForLibrary(const std::string &library_path)
CLASS_LOADER_PUBLIC ClassLoader * getCurrentlyActiveClassLoader()
Gets the ClassLoader currently in scope which used when a library is being loaded.
MetaObjectVector allMetaObjectsForLibraryOwnedBy(const std::string &library_path, const ClassLoader *owner)
bool & hasANonPurePluginLibraryBeenOpenedReference()
CLASS_LOADER_PUBLIC LibraryVector & getLoadedLibraryVector()
Gets a handle to a list of open libraries in the form of LibraryPairs which encode the library path+n...
MetaObjectVector filterAllMetaObjectsAssociatedWithLibrary(const MetaObjectVector &to_filter, const std::string &library_path)
CLASS_LOADER_PUBLIC std::string getCurrentlyLoadingLibraryName()
When a library is being loaded, in order for factories to know which library they are being associate...
CLASS_LOADER_PUBLIC void unloadLibrary(const std::string &library_path, ClassLoader *loader)
Unloads a library if it loaded in memory and cleans up its corresponding class factories. If it is not loaded, the function has no effect.
void addClassLoaderOwnerForAllExistingMetaObjectsForLibrary(const std::string &library_path, ClassLoader *loader)
CLASS_LOADER_PUBLIC bool hasANonPurePluginLibraryBeenOpened()
Indicates if a library containing more than just plugins has been opened by the running process...
This class allows loading and unloading of dynamically linked libraries which contain class definitio...
CLASS_LOADER_PUBLIC boost::recursive_mutex & getLoadedLibraryVectorMutex()
To provide thread safety, all exposed plugin functions can only be run serially by multiple threads...
std::pair< LibraryPath, Poco::SharedLibrary * > LibraryPair
CLASS_LOADER_PUBLIC boost::recursive_mutex & getPluginBaseToFactoryMapMapMutex()
CLASS_LOADER_PUBLIC std::vector< std::string > getAllLibrariesUsedByClassLoader(const ClassLoader *loader)
This function returns the names of all libraries in use by a given class loader.
CLASS_LOADER_PUBLIC bool isLibraryLoaded(const std::string &library_path, ClassLoader *loader)
Indicates if passed library loaded within scope of a ClassLoader. The library maybe loaded in memory...
MetaObjectVector filterAllMetaObjectsOwnedBy(const MetaObjectVector &to_filter, const ClassLoader *owner)
std::map< ClassName, impl::AbstractMetaObjectBase * > FactoryMap
CLASS_LOADER_PUBLIC BaseToFactoryMapMap & getGlobalPluginBaseToFactoryMapMap()
Gets a handle to a global data structure that holds a map of base class names (Base class describes p...
std::vector< LibraryPair > LibraryVector
std::string & getCurrentlyLoadingLibraryNameReference()
LibraryVector::iterator findLoadedLibrary(const std::string &library_path)
void insertMetaObjectIntoGraveyard(AbstractMetaObjectBase *meta_obj)
ClassLoader *& getCurrentlyActiveClassLoaderReference()
MetaObjectVector & getMetaObjectGraveyard()
CLASS_LOADER_PUBLIC FactoryMap & getFactoryMapForBaseClass(const std::string &typeid_base_class_name)
This function extracts a reference to the FactoryMap for appropriate base class out of the global plu...
CLASS_LOADER_PUBLIC std::string getLibraryPath()
Gets the full-qualified path and name of the library associated with this class loader.
MetaObjectVector allMetaObjectsForClassLoader(const ClassLoader *owner)
std::map< BaseClassName, FactoryMap > BaseToFactoryMapMap
void destroyMetaObjectsForLibrary(const std::string &library_path, FactoryMap &factories, const ClassLoader *loader)
std::vector< AbstractMetaObjectBase * > MetaObjectVector
void revivePreviouslyCreateMetaobjectsFromGraveyard(const std::string &library_path, ClassLoader *loader)
MetaObjectVector allMetaObjects(const FactoryMap &factories)
void purgeGraveyardOfMetaobjects(const std::string &library_path, ClassLoader *loader, bool delete_objs)
CLASS_LOADER_PUBLIC void setCurrentlyLoadingLibraryName(const std::string &library_name)
When a library is being loaded, in order for factories to know which library they are being associate...
CLASS_LOADER_PUBLIC void setCurrentlyActiveClassLoader(ClassLoader *loader)
Sets the ClassLoader currently in scope which used when a library is being loaded.
CLASS_LOADER_PUBLIC bool isLibraryLoadedByAnybody(const std::string &library_path)
Indicates if passed library has been loaded by ANY ClassLoader.
CLASS_LOADER_PUBLIC void printDebugInfoToScreen()
bool areThereAnyExistingMetaObjectsForLibrary(const std::string &library_path)
An exception class thrown when class_loader is unable to unload a runtime library.