.. _program_listing_file_include_class_loader_class_loader_core.hpp: Program Listing for File class_loader_core.hpp ============================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/class_loader/class_loader_core.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* * Software License Agreement (BSD License) * * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef CLASS_LOADER__CLASS_LOADER_CORE_HPP_ #define CLASS_LOADER__CLASS_LOADER_CORE_HPP_ #include #include #include #include #include #include #include #include #include // TODO(mikaelarguedas) remove this once console_bridge complies with this // see https://github.com/ros/console_bridge/issues/55 #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" #endif #include "console_bridge/console.h" #ifdef __clang__ # pragma clang diagnostic pop #endif #include "class_loader/exceptions.hpp" #include "class_loader/meta_object.hpp" #include "class_loader/visibility_control.hpp" #include "rcpputils/shared_library.hpp" namespace class_loader { class ClassLoader; // Forward declaration namespace impl { // Typedefs typedef std::string LibraryPath; typedef std::string ClassName; typedef std::string BaseClassName; typedef std::map FactoryMap; typedef std::map BaseToFactoryMapMap; typedef std::pair> LibraryPair; typedef std::vector LibraryVector; typedef std::vector MetaObjectVector; CLASS_LOADER_PUBLIC void printDebugInfoToScreen(); // Global storage CLASS_LOADER_PUBLIC BaseToFactoryMapMap & getGlobalPluginBaseToFactoryMapMap(); CLASS_LOADER_PUBLIC LibraryVector & getLoadedLibraryVector(); CLASS_LOADER_PUBLIC std::string getCurrentlyLoadingLibraryName(); CLASS_LOADER_PUBLIC void setCurrentlyLoadingLibraryName(const std::string & library_name); CLASS_LOADER_PUBLIC ClassLoader * getCurrentlyActiveClassLoader(); CLASS_LOADER_PUBLIC void setCurrentlyActiveClassLoader(ClassLoader * loader); CLASS_LOADER_PUBLIC FactoryMap & getFactoryMapForBaseClass(const std::string & typeid_base_class_name); template FactoryMap & getFactoryMapForBaseClass() { return getFactoryMapForBaseClass(typeid(Base).name()); } CLASS_LOADER_PUBLIC std::recursive_mutex & getLoadedLibraryVectorMutex(); CLASS_LOADER_PUBLIC std::recursive_mutex & getPluginBaseToFactoryMapMapMutex(); CLASS_LOADER_PUBLIC bool hasANonPurePluginLibraryBeenOpened(); CLASS_LOADER_PUBLIC void hasANonPurePluginLibraryBeenOpened(bool hasIt); // Plugin Functions template void registerPlugin(const std::string & class_name, const std::string & base_class_name) { // Note: This function will be automatically invoked when a dlopen() call // opens a library. Normally it will happen within the scope of loadLibrary(), // but that may not be guaranteed. CONSOLE_BRIDGE_logDebug( "class_loader.impl: " "Registering plugin factory for class = %s, ClassLoader* = %p and library name %s.", class_name.c_str(), getCurrentlyActiveClassLoader(), getCurrentlyLoadingLibraryName().c_str()); if (nullptr == getCurrentlyActiveClassLoader()) { CONSOLE_BRIDGE_logDebug( "%s", "class_loader.impl: 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."); hasANonPurePluginLibraryBeenOpened(true); } // Create factory impl::AbstractMetaObject * new_factory = new impl::MetaObject(class_name, base_class_name); new_factory->addOwningClassLoader(getCurrentlyActiveClassLoader()); new_factory->setAssociatedLibraryPath(getCurrentlyLoadingLibraryName()); // Add it to global factory map map getPluginBaseToFactoryMapMapMutex().lock(); FactoryMap & factoryMap = getFactoryMapForBaseClass(); if (factoryMap.find(class_name) != factoryMap.end()) { CONSOLE_BRIDGE_logWarn( "class_loader.impl: SEVERE WARNING!!! " "A namespace collision has occurred 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()); } factoryMap[class_name] = new_factory; getPluginBaseToFactoryMapMapMutex().unlock(); CONSOLE_BRIDGE_logDebug( "class_loader.impl: " "Registration of %s complete (Metaobject Address = %p)", class_name.c_str(), reinterpret_cast(new_factory)); } template Base * createInstance(const std::string & derived_class_name, ClassLoader * loader) { AbstractMetaObject * factory = nullptr; getPluginBaseToFactoryMapMapMutex().lock(); FactoryMap & factoryMap = getFactoryMapForBaseClass(); if (factoryMap.find(derived_class_name) != factoryMap.end()) { factory = dynamic_cast *>(factoryMap[derived_class_name]); } else { CONSOLE_BRIDGE_logError( "class_loader.impl: No metaobject exists for class type %s.", derived_class_name.c_str()); } getPluginBaseToFactoryMapMapMutex().unlock(); Base * obj = nullptr; if (factory != nullptr && factory->isOwnedBy(loader)) { obj = factory->create(); } if (nullptr == obj) { // Was never created if (factory && factory->isOwnedBy(nullptr)) { CONSOLE_BRIDGE_logDebug( "%s", "class_loader.impl: 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!"); obj = factory->create(); } else { throw class_loader::CreateClassException( "Could not create instance of type " + derived_class_name); } } CONSOLE_BRIDGE_logDebug( "class_loader.impl: Created instance of type %s and object pointer = %p", (typeid(obj).name()), obj); return obj; } template std::vector getAvailableClasses(const ClassLoader * loader) { std::lock_guard lock(getPluginBaseToFactoryMapMapMutex()); FactoryMap & factory_map = getFactoryMapForBaseClass(); std::vector classes; std::vector classes_with_no_owner; for (auto & it : factory_map) { AbstractMetaObjectBase * factory = it.second; if (factory->isOwnedBy(loader)) { classes.push_back(it.first); } else if (factory->isOwnedBy(nullptr)) { classes_with_no_owner.push_back(it.first); } } // Added classes not associated with a class loader (Which can happen through // an unexpected dlopen() to the library) classes.insert(classes.end(), classes_with_no_owner.begin(), classes_with_no_owner.end()); return classes; } CLASS_LOADER_PUBLIC std::vector getAllLibrariesUsedByClassLoader(const ClassLoader * loader); CLASS_LOADER_PUBLIC bool isLibraryLoaded(const std::string & library_path, const ClassLoader * loader); CLASS_LOADER_PUBLIC bool isLibraryLoadedByAnybody(const std::string & library_path); CLASS_LOADER_PUBLIC void loadLibrary(const std::string & library_path, ClassLoader * loader); CLASS_LOADER_PUBLIC void unloadLibrary(const std::string & library_path, ClassLoader * loader); } // namespace impl } // namespace class_loader #endif // CLASS_LOADER__CLASS_LOADER_CORE_HPP_