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