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 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 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 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 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 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 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 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 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 logDebug("class_loader.class_loader_private: Attempting to load library %s on behalf of ClassLoader handle %p...\n", library_path.c_str(), loader);
00419
00420
00421 if(isLibraryLoadedByAnybody(library_path))
00422 {
00423 logDebug("class_loader.class_loader_private: Library already in memory, but binding existing MetaObjects to loader if necesesary.\n");
00424 addClassLoaderOwnerForAllExistingMetaObjectsForLibrary(library_path, loader);
00425 return;
00426 }
00427
00428 Poco::SharedLibrary* library_handle = NULL;
00429 static boost::recursive_mutex loader_mutex;
00430
00431 {
00432 boost::recursive_mutex::scoped_lock loader_lock(loader_mutex);
00433
00434 try
00435 {
00436 setCurrentlyActiveClassLoader(loader);
00437 setCurrentlyLoadingLibraryName(library_path);
00438 library_handle = new Poco::SharedLibrary(library_path);
00439 }
00440 catch(const Poco::LibraryLoadException& e)
00441 {
00442 setCurrentlyLoadingLibraryName("");
00443 setCurrentlyActiveClassLoader(NULL);
00444 throw(class_loader::LibraryLoadException("Could not load library (Poco exception = " + std::string(e.message()) + ")"));
00445 }
00446 catch(const Poco::LibraryAlreadyLoadedException& e)
00447 {
00448 setCurrentlyLoadingLibraryName("");
00449 setCurrentlyActiveClassLoader(NULL);
00450 throw(class_loader::LibraryLoadException("Library already loaded (Poco exception = " + std::string(e.message()) + ")"));
00451 }
00452 catch(const Poco::NotFoundException& e)
00453 {
00454 setCurrentlyLoadingLibraryName("");
00455 setCurrentlyActiveClassLoader(NULL);
00456 throw(class_loader::LibraryLoadException("Library not found (Poco exception = " + std::string(e.message()) + ")"));
00457 }
00458
00459 setCurrentlyLoadingLibraryName("");
00460 setCurrentlyActiveClassLoader(NULL);
00461 }
00462
00463 assert(library_handle != NULL);
00464 logDebug("class_loader.class_loader_private: Successfully loaded library %s into memory (Poco::SharedLibrary handle = %p).", library_path.c_str(), library_handle);
00465
00466
00467 unsigned int num_lib_objs = allMetaObjectsForLibrary(library_path).size();
00468 if(num_lib_objs == 0)
00469 {
00470 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());
00471 revivePreviouslyCreateMetaobjectsFromGraveyard(library_path, loader);
00472 purgeGraveyardOfMetaobjects(library_path, loader, false);
00473 }
00474 else
00475 {
00476 logDebug("class_loader.class_loader_private: Library %s generated new factory metaobjects on load. Destroying graveyarded objects from previous loads...", library_path.c_str());
00477 purgeGraveyardOfMetaobjects(library_path, loader, true);
00478 }
00479
00480
00481 boost::recursive_mutex::scoped_lock llv_lock(getLoadedLibraryVectorMutex());
00482 LibraryVector& open_libraries = getLoadedLibraryVector();
00483 open_libraries.push_back(LibraryPair(library_path, library_handle));
00484 }
00485
00486 void unloadLibrary(const std::string& library_path, ClassLoader* loader)
00487
00488 {
00489 if(hasANonPurePluginLibraryBeenOpened())
00490 {
00491 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());
00492 }
00493 else
00494 {
00495 logDebug("class_loader.class_loader_private: Unloading library %s on behalf of ClassLoader %p...", library_path.c_str(), loader);
00496 boost::recursive_mutex::scoped_lock lock(getLoadedLibraryVectorMutex());
00497 LibraryVector& open_libraries = getLoadedLibraryVector();
00498 LibraryVector::iterator itr = findLoadedLibrary(library_path);
00499 if(itr != open_libraries.end())
00500 {
00501 Poco::SharedLibrary* library = itr->second;
00502 std::string library_path = itr->first;
00503 try
00504 {
00505 destroyMetaObjectsForLibrary(library_path, loader);
00506
00507
00508 if(!areThereAnyExistingMetaObjectsForLibrary(library_path))
00509 {
00510 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());
00511 library->unload();
00512 assert(library->isLoaded() == false);
00513 delete(library);
00514 itr = open_libraries.erase(itr);
00515 }
00516 else
00517 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());
00518 return;
00519 }
00520 catch(const Poco::RuntimeException& e)
00521 {
00522 delete(library);
00523 throw(class_loader::LibraryUnloadException("Could not unload library (Poco exception = " + std::string(e.message()) + ")"));
00524 }
00525 }
00526 throw(class_loader::LibraryUnloadException("Attempt to unload library that class_loader is unaware of."));
00527 }
00528 }
00529
00530
00531
00532
00533
00534
00535
00536 void printDebugInfoToScreen()
00537
00538 {
00539 printf("*******************************************************************************\n");
00540 printf("***** class_loader_private DEBUG INFORMATION *****\n");
00541 printf("*******************************************************************************\n");
00542
00543 printf("OPEN LIBRARIES IN MEMORY:\n");
00544 printf("--------------------------------------------------------------------------------\n");
00545 boost::recursive_mutex::scoped_lock lock(getLoadedLibraryVectorMutex());
00546 LibraryVector libs = getLoadedLibraryVector();
00547 for(unsigned int c = 0; c < libs.size(); c++)
00548 printf("Open library %i = %s (Poco SharedLibrary handle = %p)\n", c, (libs.at(c)).first.c_str(), (libs.at(c)).second);
00549
00550 printf("METAOBJECTS (i.e. FACTORIES) IN MEMORY:\n");
00551 printf("--------------------------------------------------------------------------------\n");
00552 MetaObjectVector meta_objs = allMetaObjects();
00553 for(unsigned int c = 0; c < meta_objs.size(); c++)
00554 {
00555 AbstractMetaObjectBase* obj = meta_objs.at(c);
00556 printf("Metaobject %i (ptr = %p):\n TypeId = %s\n Associated Library = %s\n",
00557 c,
00558 obj,
00559 (typeid(*obj).name()),
00560 obj->getAssociatedLibraryPath().c_str());
00561
00562 ClassLoaderVector loaders = obj->getAssociatedClassLoaders();
00563 for(unsigned int i = 0; i < loaders.size(); i++)
00564 printf(" Associated Loader %i = %p\n", i, loaders.at(i));
00565 printf("--------------------------------------------------------------------------------\n");
00566 }
00567
00568 printf("********************************** END DEBUG **********************************\n");
00569 printf("*******************************************************************************\n\n");
00570 }
00571
00572
00573
00574
00575 }
00576 }