class_loader_core.h
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2012, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
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 //#include <vector>
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; //Forward declaration
00051 
00052 namespace class_loader_private
00053 {
00054 
00055 //Typedefs
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 //Debug 
00067 /*****************************************************************************/
00068 void printDebugInfoToScreen();
00069 
00070 //Global storage
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 //Plugin Functions
00147 /*****************************************************************************/
00148 
00156 template <typename Derived, typename Base> 
00157 void registerPlugin(const std::string& class_name, const std::string& base_class_name)
00158 {
00159   //Note: This function will be automatically invoked when a dlopen() call
00160   //opens a library. Normally it will happen within the scope of loadLibrary(),
00161   //but that may not be guaranteed.
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   //Create factory
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   //Add it to global factory map map
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) //Was never created
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   //Added classes not associated with a class loader (Which can happen through
00253   //an unexpected dlopen() to the library)
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 } //End namespace class_loader_private
00296 } //End namespace class_loader
00297 
00298 #endif


class_loader
Author(s): Mirza Shah
autogenerated on Sun Oct 5 2014 22:50:57