Go to the documentation of this file.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
00031
00032 #ifndef CLASS_LOADER__CLASS_LOADER_CORE_HPP_
00033 #define CLASS_LOADER__CLASS_LOADER_CORE_HPP_
00034
00035 #include <boost/thread/recursive_mutex.hpp>
00036 #include <cstdio>
00037 #include <map>
00038 #include <string>
00039 #include <typeinfo>
00040 #include <utility>
00041 #include <vector>
00042
00043 #include "Poco/SharedLibrary.h"
00044
00045 #include "class_loader/exceptions.hpp"
00046 #include "class_loader/meta_object.hpp"
00047
00052 namespace class_loader
00053 {
00054
00055 class ClassLoader;
00056
00057 namespace class_loader_private
00058 {
00059
00060
00061
00062 typedef std::string LibraryPath;
00063 typedef std::string ClassName;
00064 typedef std::string BaseClassName;
00065 typedef std::map<ClassName, class_loader_private::AbstractMetaObjectBase *> FactoryMap;
00066 typedef std::map<BaseClassName, FactoryMap> BaseToFactoryMapMap;
00067 typedef std::pair<LibraryPath, Poco::SharedLibrary *> LibraryPair;
00068 typedef std::vector<LibraryPair> LibraryVector;
00069 typedef std::vector<AbstractMetaObjectBase *> MetaObjectVector;
00070
00071
00072
00073 void printDebugInfoToScreen();
00074
00075
00076
00077
00082 BaseToFactoryMapMap & getGlobalPluginBaseToFactoryMapMap();
00083
00088 LibraryVector & getLoadedLibraryVector();
00089
00094 std::string getCurrentlyLoadingLibraryName();
00095
00100 void setCurrentlyLoadingLibraryName(const std::string & library_name);
00101
00102
00107 ClassLoader * getCurrentlyActiveClassLoader();
00108
00113 void setCurrentlyActiveClassLoader(ClassLoader * loader);
00114
00115
00120 FactoryMap & getFactoryMapForBaseClass(const std::string & typeid_base_class_name);
00121
00126 template<typename Base>
00127 FactoryMap & getFactoryMapForBaseClass()
00128 {
00129 return getFactoryMapForBaseClass(typeid(Base).name());
00130 }
00131
00136 boost::recursive_mutex & getLoadedLibraryVectorMutex();
00137 boost::recursive_mutex & getPluginBaseToFactoryMapMapMutex();
00138
00143 bool hasANonPurePluginLibraryBeenOpened();
00144
00149 void hasANonPurePluginLibraryBeenOpened(bool hasIt);
00150
00151
00152
00153
00161 template<typename Derived, typename Base>
00162 void registerPlugin(const std::string & class_name, const std::string & base_class_name)
00163 {
00164
00165
00166
00167 CONSOLE_BRIDGE_logDebug(
00168 "class_loader.class_loader_private: "
00169 "Registering plugin factory for class = %s, ClassLoader* = %p and library name %s.",
00170 class_name.c_str(), getCurrentlyActiveClassLoader(),
00171 getCurrentlyLoadingLibraryName().c_str());
00172
00173 if (NULL == getCurrentlyActiveClassLoader()) {
00174 CONSOLE_BRIDGE_logDebug("%s",
00175 "class_loader.impl: ALERT!!! "
00176 "A library containing plugins has been opened through a means other than through the "
00177 "class_loader or pluginlib package. "
00178 "This can happen if you build plugin libraries that contain more than just plugins "
00179 "(i.e. normal code your app links against). "
00180 "This inherently will trigger a dlopen() prior to main() and cause problems as class_loader "
00181 "is not aware of plugin factories that autoregister under the hood. "
00182 "The class_loader package can compensate, but you may run into namespace collision problems "
00183 "(e.g. if you have the same plugin class in two different libraries and you load them both "
00184 "at the same time). "
00185 "The biggest problem is that library can now no longer be safely unloaded as the "
00186 "ClassLoader does not know when non-plugin code is still in use. "
00187 "In fact, no ClassLoader instance in your application will be unable to unload any library "
00188 "once a non-pure one has been opened. "
00189 "Please refactor your code to isolate plugins into their own libraries.");
00190 hasANonPurePluginLibraryBeenOpened(true);
00191 }
00192
00193
00194 class_loader_private::AbstractMetaObject<Base> * new_factory =
00195 new class_loader_private::MetaObject<Derived, Base>(class_name, base_class_name);
00196 new_factory->addOwningClassLoader(getCurrentlyActiveClassLoader());
00197 new_factory->setAssociatedLibraryPath(getCurrentlyLoadingLibraryName());
00198
00199
00200
00201 getPluginBaseToFactoryMapMapMutex().lock();
00202 FactoryMap & factoryMap = getFactoryMapForBaseClass<Base>();
00203 if (factoryMap.find(class_name) != factoryMap.end()) {
00204 CONSOLE_BRIDGE_logWarn(
00205 "class_loader.impl: SEVERE WARNING!!! "
00206 "A namespace collision has occured with plugin factory for class %s. "
00207 "New factory will OVERWRITE existing one. "
00208 "This situation occurs when libraries containing plugins are directly linked against an "
00209 "executable (the one running right now generating this message). "
00210 "Please separate plugins out into their own library or just don't link against the library "
00211 "and use either class_loader::ClassLoader/MultiLibraryClassLoader to open.",
00212 class_name.c_str());
00213 }
00214 factoryMap[class_name] = new_factory;
00215 getPluginBaseToFactoryMapMapMutex().unlock();
00216
00217 CONSOLE_BRIDGE_logDebug(
00218 "class_loader.class_loader_private: "
00219 "Registration of %s complete (Metaobject Address = %p)",
00220 class_name.c_str(), new_factory);
00221 }
00222
00229 template<typename Base>
00230 Base * createInstance(const std::string & derived_class_name, ClassLoader * loader)
00231 {
00232 AbstractMetaObject<Base> * factory = NULL;
00233
00234 getPluginBaseToFactoryMapMapMutex().lock();
00235 FactoryMap & factoryMap = getFactoryMapForBaseClass<Base>();
00236 if (factoryMap.find(derived_class_name) != factoryMap.end()) {
00237 factory = dynamic_cast<class_loader_private::AbstractMetaObject<Base> *>(
00238 factoryMap[derived_class_name]);
00239 } else {
00240 CONSOLE_BRIDGE_logError(
00241 "class_loader.class_loader_private: No metaobject exists for class type %s.",
00242 derived_class_name.c_str());
00243 }
00244 getPluginBaseToFactoryMapMapMutex().unlock();
00245
00246 Base * obj = NULL;
00247 if (factory != NULL && factory->isOwnedBy(loader)) {
00248 obj = factory->create();
00249 }
00250
00251 if (NULL == obj) {
00252 if (factory && factory->isOwnedBy(NULL)) {
00253 CONSOLE_BRIDGE_logDebug("%s",
00254 "class_loader.impl: ALERT!!! "
00255 "A metaobject (i.e. factory) exists for desired class, but has no owner. "
00256 "This implies that the library containing the class was dlopen()ed by means other than "
00257 "through the class_loader interface. "
00258 "This can happen if you build plugin libraries that contain more than just plugins "
00259 "(i.e. normal code your app links against) -- that intrinsically will trigger a dlopen() "
00260 "prior to main(). "
00261 "You should isolate your plugins into their own library, otherwise it will not be "
00262 "possible to shutdown the library!");
00263
00264 obj = factory->create();
00265 } else {
00266 throw(class_loader::CreateClassException(
00267 "Could not create instance of type " + derived_class_name));
00268 }
00269 }
00270
00271 CONSOLE_BRIDGE_logDebug(
00272 "class_loader.class_loader_private: "
00273 "Created instance of type %s and object pointer = %p",
00274 (typeid(obj).name()), obj);
00275
00276 return obj;
00277 }
00278
00284 template<typename Base>
00285 std::vector<std::string> getAvailableClasses(ClassLoader * loader)
00286 {
00287 boost::recursive_mutex::scoped_lock lock(getPluginBaseToFactoryMapMapMutex());
00288
00289 FactoryMap & factory_map = getFactoryMapForBaseClass<Base>();
00290 std::vector<std::string> classes;
00291 std::vector<std::string> classes_with_no_owner;
00292
00293 for (FactoryMap::const_iterator itr = factory_map.begin(); itr != factory_map.end(); ++itr) {
00294 AbstractMetaObjectBase * factory = itr->second;
00295 if (factory->isOwnedBy(loader)) {
00296 classes.push_back(itr->first);
00297 } else if (factory->isOwnedBy(NULL)) {
00298 classes_with_no_owner.push_back(itr->first);
00299 }
00300 }
00301
00302
00303
00304 classes.insert(classes.end(), classes_with_no_owner.begin(), classes_with_no_owner.end());
00305 return classes;
00306 }
00307
00313 std::vector<std::string> getAllLibrariesUsedByClassLoader(const ClassLoader * loader);
00314
00321 bool isLibraryLoaded(const std::string & library_path, ClassLoader * loader);
00322
00328 bool isLibraryLoadedByAnybody(const std::string & library_path);
00329
00335 void loadLibrary(const std::string & library_path, ClassLoader * loader);
00336
00342 void unloadLibrary(const std::string & library_path, ClassLoader * loader);
00343
00344
00345 }
00346 }
00347
00348 #endif // CLASS_LOADER__CLASS_LOADER_CORE_HPP_