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


class_loader
Author(s): Mirza Shah
autogenerated on Thu Dec 7 2017 04:48:01