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