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 #ifndef class_loader_private_H_DEFINED
00031 #define class_loader_private_H_DEFINED
00032
00033 #include <Poco/SharedLibrary.h>
00034 #include <boost/thread/recursive_mutex.hpp>
00035
00036 #include <map>
00037 #include <typeinfo>
00038 #include <string>
00039 #include "class_loader/meta_object.h"
00040 #include "class_loader/class_loader_exceptions.h"
00041 #include <cstdio>
00042
00047 namespace class_loader
00048 {
00049
00050 class ClassLoader;
00051
00052 namespace class_loader_private
00053 {
00054
00055
00056
00057 typedef std::string LibraryPath;
00058 typedef std::string ClassName;
00059 typedef std::string BaseClassName;
00060 typedef std::map<ClassName, class_loader_private::AbstractMetaObjectBase*> FactoryMap;
00061 typedef std::map<BaseClassName, FactoryMap> BaseToFactoryMapMap;
00062 typedef std::pair<LibraryPath, Poco::SharedLibrary*> LibraryPair;
00063 typedef std::vector<LibraryPair> LibraryVector;
00064 typedef std::vector<AbstractMetaObjectBase*> MetaObjectVector;
00065
00066
00067
00068 void printDebugInfoToScreen();
00069
00070
00071
00072
00077 BaseToFactoryMapMap& getGlobalPluginBaseToFactoryMapMap();
00078
00083 LibraryVector& getLoadedLibraryVector();
00084
00089 std::string getCurrentlyLoadingLibraryName();
00090
00095 void setCurrentlyLoadingLibraryName(const std::string& library_name);
00096
00097
00102 ClassLoader* getCurrentlyActiveClassLoader();
00103
00108 void setCurrentlyActiveClassLoader(ClassLoader* loader);
00109
00110
00115 FactoryMap& getFactoryMapForBaseClass(const std::string& typeid_base_class_name);
00116
00121 template <typename Base>
00122 FactoryMap& getFactoryMapForBaseClass()
00123 {
00124 return(getFactoryMapForBaseClass(typeid(Base).name()));
00125 }
00126
00131 boost::recursive_mutex& getLoadedLibraryVectorMutex();
00132 boost::recursive_mutex& getPluginBaseToFactoryMapMapMutex();
00133
00138 bool hasANonPurePluginLibraryBeenOpened();
00139
00144 void hasANonPurePluginLibraryBeenOpened(bool hasIt);
00145
00146
00147
00148
00156 template <typename Derived, typename Base>
00157 void registerPlugin(const std::string& class_name, const std::string& base_class_name)
00158 {
00159
00160
00161
00162 logDebug("class_loader.class_loader_private: Registering plugin factory for class = %s, ClassLoader* = %p and library name %s.", class_name.c_str(), getCurrentlyActiveClassLoader(), getCurrentlyLoadingLibraryName().c_str());
00163
00164 if(getCurrentlyActiveClassLoader() == NULL)
00165 {
00166 logDebug("class_loader.class_loader_private: ALERT!!! A library containing plugins has been opened through a means other than through the class_loader or pluginlib package. This can happen if you build plugin libraries that contain more than just plugins (i.e. normal code your app links against). This inherently will trigger a dlopen() prior to main() and cause problems as class_loader is not aware of plugin factories that autoregister under the hood. The class_loader package can compensate, but you may run into namespace collision problems (e.g. if you have the same plugin class in two different libraries and you load them both at the same time). The biggest problem is that library can now no longer be safely unloaded as the ClassLoader does not know when non-plugin code is still in use. In fact, no ClassLoader instance in your application will be unable to unload any library once a non-pure one has been opened. Please refactor your code to isolate plugins into their own libraries.");
00167 hasANonPurePluginLibraryBeenOpened(true);
00168 }
00169
00170
00171 class_loader_private::AbstractMetaObject<Base>* new_factory = new class_loader_private::MetaObject<Derived, Base>(class_name, base_class_name);
00172 new_factory->addOwningClassLoader(getCurrentlyActiveClassLoader());
00173 new_factory->setAssociatedLibraryPath(getCurrentlyLoadingLibraryName());
00174
00175
00176
00177 getPluginBaseToFactoryMapMapMutex().lock();
00178 FactoryMap& factoryMap = getFactoryMapForBaseClass<Base>();
00179 if(factoryMap.find(class_name) != factoryMap.end())
00180 logWarn("class_loader.class_loader_private: SEVERE WARNING!!! A namespace collision has occured with plugin factory for class %s. New factory will OVERWRITE existing one. This situation occurs when libraries containing plugins are directly linked against an executable (the one running right now generating this message). Please separate plugins out into their own library or just don't link against the library and use either class_loader::ClassLoader/MultiLibraryClassLoader to open.", class_name.c_str());
00181 factoryMap[class_name] = new_factory;
00182 getPluginBaseToFactoryMapMapMutex().unlock();
00183
00184 logDebug("class_loader.class_loader_private: Registration of %s complete (Metaobject Address = %p)", class_name.c_str(), new_factory);
00185 }
00186
00193 template <typename Base>
00194 Base* createInstance(const std::string& derived_class_name, ClassLoader* loader)
00195 {
00196 AbstractMetaObject<Base>* factory = NULL;
00197
00198 getPluginBaseToFactoryMapMapMutex().lock();
00199 FactoryMap& factoryMap = getFactoryMapForBaseClass<Base>();
00200 if(factoryMap.find(derived_class_name) != factoryMap.end())
00201 factory = dynamic_cast<class_loader_private::AbstractMetaObject<Base>*>(factoryMap[derived_class_name]);
00202 else
00203 {
00204 logError("class_loader.class_loader_private: No metaobject exists for class type %s.", derived_class_name.c_str());
00205 }
00206 getPluginBaseToFactoryMapMapMutex().unlock();
00207
00208 Base* obj = NULL;
00209 if(factory != NULL && factory->isOwnedBy(loader))
00210 obj = factory->create();
00211
00212 if(obj == NULL)
00213 {
00214 if(factory && factory->isOwnedBy(NULL))
00215 {
00216 logDebug("class_loader.class_loader_private: ALERT!!! A metaobject (i.e. factory) exists for desired class, but has no owner. This implies that the library containing the class was dlopen()ed by means other than through the class_loader interface. This can happen if you build plugin libraries that contain more than just plugins (i.e. normal code your app links against) -- that intrinsically will trigger a dlopen() prior to main(). You should isolate your plugins into their own library, otherwise it will not be possible to shutdown the library!");
00217
00218 obj = factory->create();
00219 }
00220 else
00221 throw(class_loader::CreateClassException("Could not create instance of type " + derived_class_name));
00222 }
00223
00224 logDebug("class_loader.class_loader_private: Created instance of type %s and object pointer = %p", (typeid(obj).name()), obj);
00225
00226 return(obj);
00227 }
00228
00234 template <typename Base>
00235 std::vector<std::string> getAvailableClasses(ClassLoader* loader)
00236 {
00237 boost::recursive_mutex::scoped_lock lock(getPluginBaseToFactoryMapMapMutex());
00238
00239 FactoryMap& factory_map = getFactoryMapForBaseClass<Base>();
00240 std::vector<std::string> classes;
00241 std::vector<std::string> classes_with_no_owner;
00242
00243 for(FactoryMap::const_iterator itr = factory_map.begin(); itr != factory_map.end(); ++itr)
00244 {
00245 AbstractMetaObjectBase* factory = itr->second;
00246 if(factory->isOwnedBy(loader))
00247 classes.push_back(itr->first);
00248 else if(factory->isOwnedBy(NULL))
00249 classes_with_no_owner.push_back(itr->first);
00250 }
00251
00252
00253
00254 classes.insert(classes.end(), classes_with_no_owner.begin(), classes_with_no_owner.end());
00255 return(classes);
00256 }
00257
00263 std::vector<std::string> getAllLibrariesUsedByClassLoader(const ClassLoader* loader);
00264
00271 bool isLibraryLoaded(const std::string& library_path, ClassLoader* loader);
00272
00278 bool isLibraryLoadedByAnybody(const std::string& library_path);
00279
00285 void loadLibrary(const std::string& library_path, ClassLoader* loader);
00286
00292 void unloadLibrary(const std::string& library_path, ClassLoader* loader);
00293
00294
00295 }
00296 }
00297
00298 #endif