33 #include <boost/filesystem.hpp>
35 #include <Poco/SharedLibrary.h>
52 static boost::recursive_mutex m;
58 static boost::recursive_mutex m;
71 std::string base_class_name = typeid_base_class_name;
72 if (factoryMapMap.find(base_class_name) == factoryMapMap.end()) {
76 return factoryMapMap[base_class_name];
93 static std::string library_name;
105 library_name_ref = library_name;
147 for (
auto & it : factories) {
148 all_meta_objs.push_back(it.second);
150 return all_meta_objs;
159 BaseToFactoryMapMap::iterator itr;
161 for (
auto & it : factory_map_map) {
163 all_meta_objs.insert(all_meta_objs.end(), objs.begin(), objs.end());
165 return all_meta_objs;
172 for (
auto & f : to_filter) {
173 if (f->isOwnedBy(owner)) {
174 filtered_objs.push_back(f);
177 return filtered_objs;
185 for (
auto & f : to_filter) {
186 if (f->getAssociatedLibraryPath() == library_path) {
187 filtered_objs.push_back(f);
190 return filtered_objs;
213 CONSOLE_BRIDGE_logDebug(
214 "class_loader.impl: "
215 "Inserting MetaObject (class = %s, base_class = %s, ptr = %p) into graveyard",
217 reinterpret_cast<void *
>(meta_obj));
224 FactoryMap::iterator factory_itr = factories.begin();
225 while (factory_itr != factories.end()) {
230 FactoryMap::iterator factory_itr_copy = factory_itr;
235 factories.erase(factory_itr_copy);
259 CONSOLE_BRIDGE_logDebug(
260 "class_loader.impl: "
261 "Removing MetaObjects associated with library %s and class loader %p from global "
262 "plugin-to-factorymap map.\n",
263 library_path.c_str(),
reinterpret_cast<const void *
>(loader));
267 for (
auto & it : factory_map_map) {
271 CONSOLE_BRIDGE_logDebug(
"%s",
"class_loader.impl: Metaobjects removed.");
283 for (
auto it = open_libraries.begin(); it != open_libraries.end(); ++it) {
284 if (it->first == library_path) {
288 return open_libraries.end();
298 if (itr != open_libraries.end()) {
299 assert(itr->second->isLoaded() ==
true);
310 size_t num_meta_objs_for_lib_bound_to_loader =
312 bool are_meta_objs_bound_to_loader =
313 (0 == num_meta_objs_for_lib) ?
true : (
314 num_meta_objs_for_lib_bound_to_loader <= num_meta_objs_for_lib);
316 return is_lib_loaded_by_anyone && are_meta_objs_bound_to_loader;
322 std::vector<std::string> all_libs;
323 for (
auto & meta_obj : all_loader_meta_objs) {
324 std::string lib_path = meta_obj->getAssociatedLibraryPath();
325 if (std::find(all_libs.begin(), all_libs.end(), lib_path) == all_libs.end()) {
326 all_libs.push_back(lib_path);
336 const std::string & library_path,
ClassLoader * loader)
339 for (
auto & meta_obj : all_meta_objs) {
340 CONSOLE_BRIDGE_logDebug(
341 "class_loader.impl: "
342 "Tagging existing MetaObject %p (base = %s, derived = %s) with "
343 "class loader %p (library path = %s).",
344 reinterpret_cast<void *
>(meta_obj), meta_obj->baseClassName().c_str(),
345 meta_obj->className().c_str(),
346 reinterpret_cast<void *
>(loader),
348 meta_obj->addOwningClassLoader(loader);
353 const std::string & library_path,
ClassLoader * loader)
358 for (
auto & obj : graveyard) {
359 if (obj->getAssociatedLibraryPath() == library_path) {
360 CONSOLE_BRIDGE_logDebug(
361 "class_loader.impl: "
362 "Resurrected factory metaobject from graveyard, class = %s, base_class = %s ptr = %p..."
363 "bound to ClassLoader %p (library path = %s)",
364 obj->className().c_str(), obj->baseClassName().c_str(),
reinterpret_cast<void *
>(obj),
365 reinterpret_cast<void *
>(loader),
368 obj->addOwningClassLoader(loader);
369 assert(obj->typeidBaseClassName() !=
"UNSET");
371 factory[obj->className()] = obj;
377 const std::string & library_path,
ClassLoader * loader,
bool delete_objs)
384 MetaObjectVector::iterator itr = graveyard.begin();
386 while (itr != graveyard.end()) {
389 CONSOLE_BRIDGE_logDebug(
390 "class_loader.impl: "
391 "Purging factory metaobject from graveyard, class = %s, base_class = %s ptr = %p.."
392 ".bound to ClassLoader %p (library path = %s)",
394 reinterpret_cast<void *
>(loader),
397 bool is_address_in_graveyard_same_as_global_factory_map =
398 std::find(all_meta_objs.begin(), all_meta_objs.end(), *itr) != all_meta_objs.end();
399 itr = graveyard.erase(itr);
401 if (is_address_in_graveyard_same_as_global_factory_map) {
402 CONSOLE_BRIDGE_logDebug(
"%s",
403 "class_loader.impl: "
404 "Newly created metaobject factory in global factory map map has same address as "
405 "one in graveyard -- metaobject has been purged from graveyard but not deleted.");
408 CONSOLE_BRIDGE_logDebug(
409 "class_loader.impl: "
410 "Also destroying metaobject %p (class = %s, base_class = %s, library_path = %s) "
411 "in addition to purging it from graveyard.",
415 #pragma GCC diagnostic push
416 #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
420 #pragma GCC diagnostic pop
432 static boost::recursive_mutex loader_mutex;
433 CONSOLE_BRIDGE_logDebug(
434 "class_loader.impl: "
435 "Attempting to load library %s on behalf of ClassLoader handle %p...\n",
436 library_path.c_str(),
reinterpret_cast<void *
>(loader));
437 boost::recursive_mutex::scoped_lock loader_lock(loader_mutex);
442 CONSOLE_BRIDGE_logDebug(
"%s",
443 "class_loader.impl: "
444 "Library already in memory, but binding existing MetaObjects to loader if necesesary.\n");
449 Poco::SharedLibrary * library_handle =
nullptr;
458 boost::system::error_code error_code;
459 const auto absolute_library_path = boost::filesystem::canonical(library_path, error_code);
461 auto library_path_to_load = library_path;
462 if (error_code.value() == boost::system::errc::success) {
463 library_path_to_load = absolute_library_path.string();
466 library_handle =
new Poco::SharedLibrary(library_path_to_load);
467 }
catch (
const Poco::LibraryLoadException & e) {
471 "Could not load library (Poco exception = " + std::string(e.message()) +
")");
472 }
catch (
const Poco::LibraryAlreadyLoadedException & e) {
476 "Library already loaded (Poco exception = " + std::string(e.message()) +
")");
477 }
catch (
const Poco::NotFoundException & e) {
481 "Library not found (Poco exception = " + std::string(e.message()) +
")");
488 assert(library_handle !=
nullptr);
489 CONSOLE_BRIDGE_logDebug(
490 "class_loader.impl: "
491 "Successfully loaded library %s into memory (Poco::SharedLibrary handle = %p).",
492 library_path.c_str(),
reinterpret_cast<void *
>(library_handle));
496 if (0 == num_lib_objs) {
497 CONSOLE_BRIDGE_logDebug(
498 "class_loader.impl: "
499 "Though the library %s was just loaded, it seems no factory metaobjects were registered. "
500 "Checking factory graveyard for previously loaded metaobjects...",
501 library_path.c_str());
506 CONSOLE_BRIDGE_logDebug(
507 "class_loader.impl: "
508 "Library %s generated new factory metaobjects on load. "
509 "Destroying graveyarded objects from previous loads...",
510 library_path.c_str());
518 open_libraries.push_back(
LibraryPair(library_path, library_handle));
524 CONSOLE_BRIDGE_logDebug(
525 "class_loader.impl: "
526 "Cannot unload %s or ANY other library as a non-pure plugin library was opened. "
527 "As class_loader has no idea which libraries class factories were exported from, "
528 "it can safely close any library without potentially unlinking symbols that are still "
529 "actively being used. "
530 "You must refactor your plugin libraries to be made exclusively of plugins "
531 "in order for this error to stop happening.",
532 library_path.c_str());
534 CONSOLE_BRIDGE_logDebug(
535 "class_loader.impl: "
536 "Unloading library %s on behalf of ClassLoader %p...",
537 library_path.c_str(),
reinterpret_cast<void *
>(loader));
541 if (itr != open_libraries.end()) {
542 Poco::SharedLibrary * library = itr->second;
543 std::string library_path = itr->first;
549 CONSOLE_BRIDGE_logDebug(
550 "class_loader.impl: "
551 "There are no more MetaObjects left for %s so unloading library and "
552 "removing from loaded library vector.\n",
553 library_path.c_str());
555 assert(library->isLoaded() ==
false);
557 itr = open_libraries.erase(itr);
559 CONSOLE_BRIDGE_logDebug(
560 "class_loader.impl: "
561 "MetaObjects still remain in memory meaning other ClassLoaders are still using library"
562 ", keeping library %s open.",
563 library_path.c_str());
566 }
catch (
const Poco::RuntimeException & e) {
569 "Caught a poco exception while unloading library " + library_path +
": " + e.message());
573 "Attempt to unload library that class_loader is unaware of: " + library_path);
582 printf(
"*******************************************************************************\n");
583 printf(
"***** class_loader impl DEBUG INFORMATION *****\n");
584 printf(
"*******************************************************************************\n");
586 printf(
"OPEN LIBRARIES IN MEMORY:\n");
587 printf(
"--------------------------------------------------------------------------------\n");
590 for (
size_t c = 0; c < libs.size(); c++) {
592 "Open library %zu = %s (Poco SharedLibrary handle = %p)\n",
593 c, (libs.at(c)).first.c_str(),
reinterpret_cast<void *
>((libs.at(c)).second));
596 printf(
"METAOBJECTS (i.e. FACTORIES) IN MEMORY:\n");
597 printf(
"--------------------------------------------------------------------------------\n");
599 for (
size_t c = 0; c < meta_objs.size(); c++) {
601 printf(
"Metaobject %zu (ptr = %p):\n TypeId = %s\n Associated Library = %s\n",
603 reinterpret_cast<void *
>(obj),
604 (
typeid(*obj).name()),
608 for (
size_t i = 0; i < loaders.size(); i++) {
609 printf(
" Associated Loader %zu = %p\n", i,
reinterpret_cast<void *
>(loaders.at(i)));
611 printf(
"--------------------------------------------------------------------------------\n");
614 printf(
"********************************** END DEBUG **********************************\n");
615 printf(
"*******************************************************************************\n\n");