00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "class_loader/class_loader_core.hpp"
00031 #include "class_loader/class_loader.hpp"
00032
00033 #include <Poco/SharedLibrary.h>
00034
00035 #include <cassert>
00036 #include <string>
00037 #include <vector>
00038
00039 namespace class_loader
00040 {
00041 namespace class_loader_private
00042 {
00043
00044
00045
00046
00047
00048
00049
00050 boost::recursive_mutex & getLoadedLibraryVectorMutex()
00051
00052 {
00053 static boost::recursive_mutex m;
00054 return m;
00055 }
00056
00057 boost::recursive_mutex & getPluginBaseToFactoryMapMapMutex()
00058
00059 {
00060 static boost::recursive_mutex m;
00061 return m;
00062 }
00063
00064 BaseToFactoryMapMap & getGlobalPluginBaseToFactoryMapMap()
00065
00066 {
00067 static BaseToFactoryMapMap instance;
00068 return instance;
00069 }
00070
00071 FactoryMap & getFactoryMapForBaseClass(const std::string & typeid_base_class_name)
00072
00073 {
00074 BaseToFactoryMapMap & factoryMapMap = getGlobalPluginBaseToFactoryMapMap();
00075 std::string base_class_name = typeid_base_class_name;
00076 if (factoryMapMap.find(base_class_name) == factoryMapMap.end()) {
00077 factoryMapMap[base_class_name] = FactoryMap();
00078 }
00079
00080 return factoryMapMap[base_class_name];
00081 }
00082
00083 MetaObjectVector & getMetaObjectGraveyard()
00084
00085 {
00086 static MetaObjectVector instance;
00087 return instance;
00088 }
00089
00090 LibraryVector & getLoadedLibraryVector()
00091
00092 {
00093 static LibraryVector instance;
00094 return instance;
00095 }
00096
00097 std::string & getCurrentlyLoadingLibraryNameReference()
00098
00099 {
00100 static std::string library_name;
00101 return library_name;
00102 }
00103
00104 std::string getCurrentlyLoadingLibraryName()
00105
00106 {
00107 return getCurrentlyLoadingLibraryNameReference();
00108 }
00109
00110 void setCurrentlyLoadingLibraryName(const std::string & library_name)
00111
00112 {
00113 std::string & library_name_ref = getCurrentlyLoadingLibraryNameReference();
00114 library_name_ref = library_name;
00115 }
00116
00117 ClassLoader * & getCurrentlyActiveClassLoaderReference()
00118
00119 {
00120 static ClassLoader * loader = NULL;
00121 return loader;
00122 }
00123
00124 ClassLoader * getCurrentlyActiveClassLoader()
00125
00126 {
00127 return getCurrentlyActiveClassLoaderReference();
00128 }
00129
00130 void setCurrentlyActiveClassLoader(ClassLoader * loader)
00131
00132 {
00133 ClassLoader * & loader_ref = getCurrentlyActiveClassLoaderReference();
00134 loader_ref = loader;
00135 }
00136
00137 bool & hasANonPurePluginLibraryBeenOpenedReference()
00138
00139 {
00140 static bool hasANonPurePluginLibraryBeenOpenedReference = false;
00141 return hasANonPurePluginLibraryBeenOpenedReference;
00142 }
00143
00144 bool hasANonPurePluginLibraryBeenOpened()
00145
00146 {
00147 return hasANonPurePluginLibraryBeenOpenedReference();
00148 }
00149
00150 void hasANonPurePluginLibraryBeenOpened(bool hasIt)
00151
00152 {
00153 hasANonPurePluginLibraryBeenOpenedReference() = hasIt;
00154 }
00155
00156
00157
00158
00159
00160
00161
00162 MetaObjectVector allMetaObjects(const FactoryMap & factories)
00163
00164 {
00165 MetaObjectVector all_meta_objs;
00166 for (
00167 FactoryMap::const_iterator factoryItr = factories.begin();
00168 factoryItr != factories.end(); factoryItr++
00169 )
00170 {
00171 all_meta_objs.push_back(factoryItr->second);
00172 }
00173 return all_meta_objs;
00174 }
00175
00176 MetaObjectVector allMetaObjects()
00177
00178 {
00179 boost::recursive_mutex::scoped_lock lock(getPluginBaseToFactoryMapMapMutex());
00180
00181 MetaObjectVector all_meta_objs;
00182 BaseToFactoryMapMap & factory_map_map = getGlobalPluginBaseToFactoryMapMap();
00183 BaseToFactoryMapMap::iterator itr;
00184
00185 for (itr = factory_map_map.begin(); itr != factory_map_map.end(); itr++) {
00186 MetaObjectVector objs = allMetaObjects(itr->second);
00187 all_meta_objs.insert(all_meta_objs.end(), objs.begin(), objs.end());
00188 }
00189 return all_meta_objs;
00190 }
00191
00192 MetaObjectVector
00193 filterAllMetaObjectsOwnedBy(const MetaObjectVector & to_filter, const ClassLoader * owner)
00194
00195 {
00196 MetaObjectVector filtered_objs;
00197 for (unsigned int c = 0; c < to_filter.size(); c++) {
00198 if (to_filter.at(c)->isOwnedBy(owner)) {
00199 filtered_objs.push_back(to_filter.at(c));
00200 }
00201 }
00202 return filtered_objs;
00203 }
00204
00205 MetaObjectVector
00206 filterAllMetaObjectsAssociatedWithLibrary(
00207 const MetaObjectVector & to_filter, const std::string & library_path)
00208
00209 {
00210 MetaObjectVector filtered_objs;
00211 for (unsigned int c = 0; c < to_filter.size(); c++) {
00212 if (to_filter.at(c)->getAssociatedLibraryPath() == library_path) {
00213 filtered_objs.push_back(to_filter.at(c));
00214 }
00215 }
00216 return filtered_objs;
00217 }
00218
00219 MetaObjectVector
00220 allMetaObjectsForClassLoader(const ClassLoader * owner)
00221
00222 {
00223 return filterAllMetaObjectsOwnedBy(allMetaObjects(), owner);
00224 }
00225
00226 MetaObjectVector
00227 allMetaObjectsForLibrary(const std::string & library_path)
00228
00229 {
00230 return filterAllMetaObjectsAssociatedWithLibrary(allMetaObjects(), library_path);
00231 }
00232
00233 MetaObjectVector
00234 allMetaObjectsForLibraryOwnedBy(const std::string & library_path, const ClassLoader * owner)
00235
00236 {
00237 return filterAllMetaObjectsOwnedBy(allMetaObjectsForLibrary(library_path), owner);
00238 }
00239
00240 void insertMetaObjectIntoGraveyard(AbstractMetaObjectBase * meta_obj)
00241
00242 {
00243 CONSOLE_BRIDGE_logDebug(
00244 "class_loader.class_loader_private: "
00245 "Inserting MetaObject (class = %s, base_class = %s, ptr = %p) into graveyard",
00246 meta_obj->className().c_str(), meta_obj->baseClassName().c_str(), meta_obj);
00247 getMetaObjectGraveyard().push_back(meta_obj);
00248 }
00249
00250 void destroyMetaObjectsForLibrary(
00251 const std::string & library_path, FactoryMap & factories, const ClassLoader * loader)
00252
00253 {
00254 FactoryMap::iterator factory_itr = factories.begin();
00255 while (factory_itr != factories.end()) {
00256 AbstractMetaObjectBase * meta_obj = factory_itr->second;
00257 if (meta_obj->getAssociatedLibraryPath() == library_path && meta_obj->isOwnedBy(loader)) {
00258 meta_obj->removeOwningClassLoader(loader);
00259 if (!meta_obj->isOwnedByAnybody()) {
00260 FactoryMap::iterator factory_itr_copy = factory_itr;
00261 factory_itr++;
00262
00263
00264
00265 factories.erase(factory_itr_copy);
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 insertMetaObjectIntoGraveyard(meta_obj);
00276 } else {
00277 factory_itr++;
00278 }
00279 } else {
00280 factory_itr++;
00281 }
00282 }
00283 }
00284
00285 void destroyMetaObjectsForLibrary(const std::string & library_path, const ClassLoader * loader)
00286
00287 {
00288 boost::recursive_mutex::scoped_lock lock(getPluginBaseToFactoryMapMapMutex());
00289
00290 CONSOLE_BRIDGE_logDebug(
00291 "class_loader.class_loader_private: "
00292 "Removing MetaObjects associated with library %s and class loader %p from global "
00293 "plugin-to-factorymap map.\n",
00294 library_path.c_str(), loader);
00295
00296
00297 BaseToFactoryMapMap & factory_map_map = getGlobalPluginBaseToFactoryMapMap();
00298 BaseToFactoryMapMap::iterator itr;
00299 for (itr = factory_map_map.begin(); itr != factory_map_map.end(); itr++) {
00300 destroyMetaObjectsForLibrary(library_path, itr->second, loader);
00301 }
00302
00303 CONSOLE_BRIDGE_logDebug("%s", "class_loader.class_loader_private: Metaobjects removed.");
00304 }
00305
00306 bool areThereAnyExistingMetaObjectsForLibrary(const std::string & library_path)
00307
00308 {
00309 return allMetaObjectsForLibrary(library_path).size() > 0;
00310 }
00311
00312
00313
00314
00315
00316 LibraryVector::iterator findLoadedLibrary(const std::string & library_path)
00317
00318 {
00319 LibraryVector & open_libraries = getLoadedLibraryVector();
00320 LibraryVector::iterator itr;
00321 for (itr = open_libraries.begin(); itr != open_libraries.end(); itr++) {
00322 if (itr->first == library_path) {
00323 break;
00324 }
00325 }
00326 return itr;
00327 }
00328
00329 bool isLibraryLoadedByAnybody(const std::string & library_path)
00330
00331 {
00332 boost::recursive_mutex::scoped_lock lock(getLoadedLibraryVectorMutex());
00333
00334 LibraryVector & open_libraries = getLoadedLibraryVector();
00335 LibraryVector::iterator itr = findLoadedLibrary(library_path);
00336
00337 if (itr != open_libraries.end()) {
00338 assert(itr->second->isLoaded() == true);
00339 return true;
00340 } else {
00341 return false;
00342 }
00343 }
00344
00345 bool isLibraryLoaded(const std::string & library_path, ClassLoader * loader)
00346
00347 {
00348 bool is_lib_loaded_by_anyone = isLibraryLoadedByAnybody(library_path);
00349 int num_meta_objs_for_lib = allMetaObjectsForLibrary(library_path).size();
00350 int num_meta_objs_for_lib_bound_to_loader =
00351 allMetaObjectsForLibraryOwnedBy(library_path, loader).size();
00352 bool are_meta_objs_bound_to_loader =
00353 (0 == num_meta_objs_for_lib) ? true : (
00354 num_meta_objs_for_lib_bound_to_loader <= num_meta_objs_for_lib);
00355
00356 return is_lib_loaded_by_anyone && are_meta_objs_bound_to_loader;
00357 }
00358
00359 std::vector<std::string> getAllLibrariesUsedByClassLoader(const ClassLoader * loader)
00360
00361 {
00362 MetaObjectVector all_loader_meta_objs = allMetaObjectsForClassLoader(loader);
00363 std::vector<std::string> all_libs;
00364 for (unsigned int c = 0; c < all_loader_meta_objs.size(); c++) {
00365 std::string lib_path = all_loader_meta_objs.at(c)->getAssociatedLibraryPath();
00366 if (std::find(all_libs.begin(), all_libs.end(), lib_path) == all_libs.end()) {
00367 all_libs.push_back(lib_path);
00368 }
00369 }
00370 return all_libs;
00371 }
00372
00373
00374
00375
00376
00377
00378
00379 void addClassLoaderOwnerForAllExistingMetaObjectsForLibrary(
00380 const std::string & library_path, ClassLoader * loader)
00381
00382 {
00383 MetaObjectVector all_meta_objs = allMetaObjectsForLibrary(library_path);
00384 for (unsigned int c = 0; c < all_meta_objs.size(); c++) {
00385 AbstractMetaObjectBase * meta_obj = all_meta_objs.at(c);
00386 CONSOLE_BRIDGE_logDebug(
00387 "class_loader.class_loader_private: "
00388 "Tagging existing MetaObject %p (base = %s, derived = %s) with "
00389 "class loader %p (library path = %s).",
00390 meta_obj, meta_obj->baseClassName().c_str(), meta_obj->className().c_str(),
00391 loader, loader ? loader->getLibraryPath().c_str() : "NULL");
00392 all_meta_objs.at(c)->addOwningClassLoader(loader);
00393 }
00394 }
00395
00396 void revivePreviouslyCreateMetaobjectsFromGraveyard(
00397 const std::string & library_path, ClassLoader * loader)
00398
00399 {
00400 boost::recursive_mutex::scoped_lock b2fmm_lock(getPluginBaseToFactoryMapMapMutex());
00401 MetaObjectVector & graveyard = getMetaObjectGraveyard();
00402
00403 for (MetaObjectVector::iterator itr = graveyard.begin(); itr != graveyard.end(); itr++) {
00404 AbstractMetaObjectBase * obj = *itr;
00405 if (obj->getAssociatedLibraryPath() == library_path) {
00406 CONSOLE_BRIDGE_logDebug(
00407 "class_loader.class_loader_private: "
00408 "Resurrected factory metaobject from graveyard, class = %s, base_class = %s ptr = %p..."
00409 "bound to ClassLoader %p (library path = %s)",
00410 obj->className().c_str(), obj->baseClassName().c_str(), obj,
00411 loader, loader ? loader->getLibraryPath().c_str() : "NULL");
00412
00413 obj->addOwningClassLoader(loader);
00414 assert(obj->typeidBaseClassName() != "UNSET");
00415 FactoryMap & factory = getFactoryMapForBaseClass(obj->typeidBaseClassName());
00416 factory[obj->className()] = obj;
00417 }
00418 }
00419 }
00420
00421 void purgeGraveyardOfMetaobjects(
00422 const std::string & library_path, ClassLoader * loader, bool delete_objs)
00423
00424 {
00425 MetaObjectVector all_meta_objs = allMetaObjects();
00426
00427 boost::recursive_mutex::scoped_lock b2fmm_lock(getPluginBaseToFactoryMapMapMutex());
00428
00429 MetaObjectVector & graveyard = getMetaObjectGraveyard();
00430 MetaObjectVector::iterator itr = graveyard.begin();
00431
00432 while (itr != graveyard.end()) {
00433 AbstractMetaObjectBase * obj = *itr;
00434 if (obj->getAssociatedLibraryPath() == library_path) {
00435 CONSOLE_BRIDGE_logDebug(
00436 "class_loader.class_loader_private: "
00437 "Purging factory metaobject from graveyard, class = %s, base_class = %s ptr = %p.."
00438 ".bound to ClassLoader %p (library path = %s)",
00439 obj->className().c_str(), obj->baseClassName().c_str(), obj,
00440 loader, loader ? loader->getLibraryPath().c_str() : "NULL");
00441
00442 bool is_address_in_graveyard_same_as_global_factory_map =
00443 std::find(all_meta_objs.begin(), all_meta_objs.end(), *itr) != all_meta_objs.end();
00444 itr = graveyard.erase(itr);
00445 if (delete_objs) {
00446 if (is_address_in_graveyard_same_as_global_factory_map) {
00447 CONSOLE_BRIDGE_logDebug("%s",
00448 "class_loader.class_loader_private: "
00449 "Newly created metaobject factory in global factory map map has same address as "
00450 "one in graveyard -- metaobject has been purged from graveyard but not deleted.");
00451 } else {
00452 assert(hasANonPurePluginLibraryBeenOpened() == false);
00453 CONSOLE_BRIDGE_logDebug(
00454 "class_loader.class_loader_private: "
00455 "Also destroying metaobject %p (class = %s, base_class = %s, library_path = %s) "
00456 "in addition to purging it from graveyard.",
00457 obj, obj->className().c_str(), obj->baseClassName().c_str(),
00458 obj->getAssociatedLibraryPath().c_str());
00459 delete (obj);
00460 }
00461 }
00462 } else {
00463 itr++;
00464 }
00465 }
00466 }
00467
00468 void loadLibrary(const std::string & library_path, ClassLoader * loader)
00469
00470 {
00471 static boost::recursive_mutex loader_mutex;
00472 CONSOLE_BRIDGE_logDebug(
00473 "class_loader.class_loader_private: "
00474 "Attempting to load library %s on behalf of ClassLoader handle %p...\n",
00475 library_path.c_str(), loader);
00476 boost::recursive_mutex::scoped_lock loader_lock(loader_mutex);
00477
00478
00479 if (isLibraryLoadedByAnybody(library_path)) {
00480 boost::recursive_mutex::scoped_lock lock(getPluginBaseToFactoryMapMapMutex());
00481 CONSOLE_BRIDGE_logDebug("%s",
00482 "class_loader.class_loader_private: "
00483 "Library already in memory, but binding existing MetaObjects to loader if necesesary.\n");
00484 addClassLoaderOwnerForAllExistingMetaObjectsForLibrary(library_path, loader);
00485 return;
00486 }
00487
00488 Poco::SharedLibrary * library_handle = NULL;
00489
00490 {
00491 try {
00492 setCurrentlyActiveClassLoader(loader);
00493 setCurrentlyLoadingLibraryName(library_path);
00494 library_handle = new Poco::SharedLibrary(library_path);
00495 } catch (const Poco::LibraryLoadException & e) {
00496 setCurrentlyLoadingLibraryName("");
00497 setCurrentlyActiveClassLoader(NULL);
00498 throw(class_loader::LibraryLoadException(
00499 "Could not load library (Poco exception = " + std::string(e.message()) + ")"));
00500 } catch (const Poco::LibraryAlreadyLoadedException & e) {
00501 setCurrentlyLoadingLibraryName("");
00502 setCurrentlyActiveClassLoader(NULL);
00503 throw(class_loader::LibraryLoadException(
00504 "Library already loaded (Poco exception = " + std::string(e.message()) + ")"));
00505 } catch (const Poco::NotFoundException & e) {
00506 setCurrentlyLoadingLibraryName("");
00507 setCurrentlyActiveClassLoader(NULL);
00508 throw(class_loader::LibraryLoadException(
00509 "Library not found (Poco exception = " + std::string(e.message()) + ")"));
00510 }
00511
00512 setCurrentlyLoadingLibraryName("");
00513 setCurrentlyActiveClassLoader(NULL);
00514 }
00515
00516 assert(library_handle != NULL);
00517 CONSOLE_BRIDGE_logDebug(
00518 "class_loader.class_loader_private: "
00519 "Successfully loaded library %s into memory (Poco::SharedLibrary handle = %p).",
00520 library_path.c_str(), library_handle);
00521
00522
00523 unsigned int num_lib_objs = allMetaObjectsForLibrary(library_path).size();
00524 if (0 == num_lib_objs) {
00525 CONSOLE_BRIDGE_logDebug(
00526 "class_loader.class_loader_private: "
00527 "Though the library %s was just loaded, it seems no factory metaobjects were registered. "
00528 "Checking factory graveyard for previously loaded metaobjects...",
00529 library_path.c_str());
00530 revivePreviouslyCreateMetaobjectsFromGraveyard(library_path, loader);
00531
00532 purgeGraveyardOfMetaobjects(library_path, loader, false);
00533 } else {
00534 CONSOLE_BRIDGE_logDebug(
00535 "class_loader.class_loader_private: "
00536 "Library %s generated new factory metaobjects on load. "
00537 "Destroying graveyarded objects from previous loads...",
00538 library_path.c_str());
00539 purgeGraveyardOfMetaobjects(library_path, loader, true);
00540 }
00541
00542
00543 boost::recursive_mutex::scoped_lock llv_lock(getLoadedLibraryVectorMutex());
00544 LibraryVector & open_libraries = getLoadedLibraryVector();
00545
00546 open_libraries.push_back(LibraryPair(library_path, library_handle));
00547 }
00548
00549 void unloadLibrary(const std::string & library_path, ClassLoader * loader)
00550
00551 {
00552 if (hasANonPurePluginLibraryBeenOpened()) {
00553 CONSOLE_BRIDGE_logDebug(
00554 "class_loader.class_loader_private: "
00555 "Cannot unload %s or ANY other library as a non-pure plugin library was opened. "
00556 "As class_loader has no idea which libraries class factories were exported from, "
00557 "it can safely close any library without potentially unlinking symbols that are still "
00558 "actively being used. "
00559 "You must refactor your plugin libraries to be made exclusively of plugins "
00560 "in order for this error to stop happening.",
00561 library_path.c_str());
00562 } else {
00563 CONSOLE_BRIDGE_logDebug(
00564 "class_loader.class_loader_private: "
00565 "Unloading library %s on behalf of ClassLoader %p...",
00566 library_path.c_str(), loader);
00567 boost::recursive_mutex::scoped_lock lock(getLoadedLibraryVectorMutex());
00568 LibraryVector & open_libraries = getLoadedLibraryVector();
00569 LibraryVector::iterator itr = findLoadedLibrary(library_path);
00570 if (itr != open_libraries.end()) {
00571 Poco::SharedLibrary * library = itr->second;
00572 std::string library_path = itr->first;
00573 try {
00574 destroyMetaObjectsForLibrary(library_path, loader);
00575
00576
00577 if (!areThereAnyExistingMetaObjectsForLibrary(library_path)) {
00578 CONSOLE_BRIDGE_logDebug(
00579 "class_loader.class_loader_private: "
00580 "There are no more MetaObjects left for %s so unloading library and "
00581 "removing from loaded library vector.\n",
00582 library_path.c_str());
00583 library->unload();
00584 assert(library->isLoaded() == false);
00585 delete (library);
00586 itr = open_libraries.erase(itr);
00587 } else {
00588 CONSOLE_BRIDGE_logDebug(
00589 "class_loader.class_loader_private: "
00590 "MetaObjects still remain in memory meaning other ClassLoaders are still using library"
00591 ", keeping library %s open.",
00592 library_path.c_str());
00593 }
00594 return;
00595 } catch (const Poco::RuntimeException & e) {
00596 delete (library);
00597 throw(class_loader::LibraryUnloadException(
00598 "Could not unload library (Poco exception = " + std::string(e.message()) + ")"));
00599 }
00600 }
00601 throw(class_loader::LibraryUnloadException(
00602 "Attempt to unload library that class_loader is unaware of."));
00603 }
00604 }
00605
00606
00607
00608
00609
00610
00611
00612 void printDebugInfoToScreen()
00613
00614 {
00615 printf("*******************************************************************************\n");
00616 printf("***** class_loader_private DEBUG INFORMATION *****\n");
00617 printf("*******************************************************************************\n");
00618
00619 printf("OPEN LIBRARIES IN MEMORY:\n");
00620 printf("--------------------------------------------------------------------------------\n");
00621 boost::recursive_mutex::scoped_lock lock(getLoadedLibraryVectorMutex());
00622 LibraryVector libs = getLoadedLibraryVector();
00623 for (unsigned int c = 0; c < libs.size(); c++) {
00624 printf(
00625 "Open library %i = %s (Poco SharedLibrary handle = %p)\n",
00626 c, (libs.at(c)).first.c_str(), (libs.at(c)).second);
00627 }
00628
00629 printf("METAOBJECTS (i.e. FACTORIES) IN MEMORY:\n");
00630 printf("--------------------------------------------------------------------------------\n");
00631 MetaObjectVector meta_objs = allMetaObjects();
00632 for (unsigned int c = 0; c < meta_objs.size(); c++) {
00633 AbstractMetaObjectBase * obj = meta_objs.at(c);
00634 printf("Metaobject %i (ptr = %p):\n TypeId = %s\n Associated Library = %s\n",
00635 c,
00636 obj,
00637 (typeid(*obj).name()),
00638 obj->getAssociatedLibraryPath().c_str());
00639
00640 ClassLoaderVector loaders = obj->getAssociatedClassLoaders();
00641 for (unsigned int i = 0; i < loaders.size(); i++) {
00642 printf(" Associated Loader %i = %p\n", i, loaders.at(i));
00643 }
00644 printf("--------------------------------------------------------------------------------\n");
00645 }
00646
00647 printf("********************************** END DEBUG **********************************\n");
00648 printf("*******************************************************************************\n\n");
00649 }
00650
00651
00652 }
00653 }