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


class_loader
Author(s): Mirza Shah
autogenerated on Mon Oct 22 2018 05:20:55