.. _program_listing_file__tmp_ws_src_pluginlib_pluginlib_include_pluginlib_class_loader_imp.hpp: Program Listing for File class_loader_imp.hpp ============================================= |exhale_lsh| :ref:`Return to documentation for file ` (``/tmp/ws/src/pluginlib/pluginlib/include/pluginlib/class_loader_imp.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /********************************************************************* * * Software License Agreement (BSD License) * * Copyright (c) 2008, 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 Willow Garage, Inc. 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 PLUGINLIB__CLASS_LOADER_IMP_HPP_ #define PLUGINLIB__CLASS_LOADER_IMP_HPP_ #include #include #include #include #include #include #include #include #include #include "ament_index_cpp/get_package_prefix.hpp" #include "ament_index_cpp/get_package_share_directory.hpp" #include "ament_index_cpp/get_resource.hpp" #include "ament_index_cpp/get_resources.hpp" #include "class_loader/class_loader.hpp" #include "rcpputils/filesystem_helper.hpp" #include "rcpputils/shared_library.hpp" #include "rcutils/logging_macros.h" #include "./class_loader.hpp" #include "./impl/split.hpp" #ifdef _WIN32 #define CLASS_LOADER_IMPL_OS_PATHSEP ";" #else #define CLASS_LOADER_IMPL_OS_PATHSEP ":" #endif namespace pluginlib { template ClassLoader::ClassLoader( std::string package, std::string base_class, std::string attrib_name, std::vector plugin_xml_paths) : plugin_xml_paths_(plugin_xml_paths), package_(package), base_class_(base_class), attrib_name_(attrib_name), // NOTE: The parameter to the class loader enables/disables on-demand class // loading/unloading. // Leaving it off for now... libraries will be loaded immediately and won't // be unloaded until class loader is destroyed or force unload. lowlevel_class_loader_(false) /***************************************************************************/ { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Creating ClassLoader, base = %s, address = %p", base_class.c_str(), static_cast(this)); try { ament_index_cpp::get_package_prefix(package_); } catch (const ament_index_cpp::PackageNotFoundError & exception) { // rethrow as class loader exception, package name is in the error message already. throw pluginlib::ClassLoaderException(exception.what()); } if (0 == plugin_xml_paths_.size()) { plugin_xml_paths_ = getPluginXmlPaths(package_, attrib_name_); } classes_available_ = determineAvailableClasses(plugin_xml_paths_); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Finished constructring ClassLoader, base = %s, address = %p", base_class.c_str(), static_cast(this)); } template ClassLoader::~ClassLoader() /***************************************************************************/ { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Destroying ClassLoader, base = %s, address = %p", getBaseClassType().c_str(), static_cast(this)); } template T * ClassLoader::createClassInstance(const std::string & lookup_name, bool auto_load) /***************************************************************************/ { // Note: This method is deprecated RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "In deprecated call createClassInstance(), lookup_name = %s, auto_load = %i.", (lookup_name.c_str()), auto_load); if (auto_load && !isClassLoaded(lookup_name)) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Autoloading class library before attempting to create instance."); loadLibraryForClass(lookup_name); } try { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to create instance through low-level MultiLibraryClassLoader..."); T * obj = lowlevel_class_loader_.createUnmanagedInstance(getClassType(lookup_name)); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Instance created with object pointer = %p", static_cast(obj)); return obj; } catch (const class_loader::CreateClassException & ex) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "CreateClassException about to be raised for class %s", lookup_name.c_str()); throw pluginlib::CreateClassException(ex.what()); } } template std::shared_ptr ClassLoader::createSharedInstance(const std::string & lookup_name) /***************************************************************************/ { return createUniqueInstance(lookup_name); } template UniquePtr ClassLoader::createUniqueInstance(const std::string & lookup_name) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to create managed (unique) instance for class %s.", lookup_name.c_str()); if (!isClassLoaded(lookup_name)) { loadLibraryForClass(lookup_name); } try { std::string class_type = getClassType(lookup_name); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "%s maps to real class type %s", lookup_name.c_str(), class_type.c_str()); UniquePtr obj = lowlevel_class_loader_.createUniqueInstance(class_type); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "std::unique_ptr to object of real type %s created.", class_type.c_str()); return obj; } catch (const class_loader::CreateClassException & ex) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Exception raised by low-level multi-library class loader when attempting " "to create instance of class %s.", lookup_name.c_str()); throw pluginlib::CreateClassException(ex.what()); } } template T * ClassLoader::createUnmanagedInstance(const std::string & lookup_name) /***************************************************************************/ { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to create UNMANAGED instance for class %s.", lookup_name.c_str()); if (!isClassLoaded(lookup_name)) { loadLibraryForClass(lookup_name); } T * instance = 0; try { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to create instance through low level multi-library class loader."); std::string class_type = getClassType(lookup_name); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "%s maps to real class type %s", lookup_name.c_str(), class_type.c_str()); instance = lowlevel_class_loader_.createUnmanagedInstance(class_type); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Instance of type %s created.", class_type.c_str()); } catch (const class_loader::CreateClassException & ex) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Exception raised by low-level multi-library class loader when attempting " "to create UNMANAGED instance of class %s.", lookup_name.c_str()); throw pluginlib::CreateClassException(ex.what()); } return instance; } template std::vector ClassLoader::getPluginXmlPaths( const std::string & package, const std::string & attrib_name) /***************************************************************************/ { // Pull possible files from manifests of packages which depend on this package and export class std::vector paths; { // the convention is to create an ament resource which a concatenation of // the package name, "pluginlib", and the attribute being exported // __ is used as the concatenation delimiter because it cannot be in a // package name std::string resource_name = package + "__pluginlib__" + attrib_name; auto plugin_packages_with_prefixes = ament_index_cpp::get_resources(resource_name); for (const auto & package_prefix_pair : plugin_packages_with_prefixes) { // it is also convention to place the relative path to the plugin xml in // the ament resource file std::string resource_content; { using ament_index_cpp::get_resource; if (!get_resource(resource_name, package_prefix_pair.first, resource_content)) { RCUTILS_LOG_WARN_NAMED("pluginlib.ClassLoader", "unexpectedly not able to find ament resource '%s' for package '%s'", resource_name.c_str(), package_prefix_pair.first.c_str() ); continue; } } // the content may contain multiple plugin description files std::stringstream ss(resource_content); std::string line; while (std::getline(ss, line, '\n')) { if (!line.empty()) { // store the prefix for the package with a plugin and the relative path // to the plugin xml file paths.push_back(package_prefix_pair.second + "/" + line); } } } } return paths; } template std::map ClassLoader::determineAvailableClasses( const std::vector & plugin_xml_paths) /***************************************************************************/ { // mas - This method requires major refactoring... // not only is it really long and confusing but a lot of the comments do not // seem to be correct. // With time I keep correcting small things, but a good rewrite is needed. RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Entering determineAvailableClasses()..."); std::map classes_available; // Walk the list of all plugin XML files (variable "paths") that are exported by the build system for (std::vector::const_iterator it = plugin_xml_paths.begin(); it != plugin_xml_paths.end(); ++it) { try { processSingleXMLPluginFile(*it, classes_available); } catch (const pluginlib::InvalidXMLException & e) { RCUTILS_LOG_ERROR_NAMED("pluginlib.ClassLoader", "Skipped loading plugin with error: %s.", e.what()); } } RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Exiting determineAvailableClasses()..."); return classes_available; } template std::string ClassLoader::extractPackageNameFromPackageXML(const std::string & package_xml_path) /***************************************************************************/ { tinyxml2::XMLDocument document; document.LoadFile(package_xml_path.c_str()); tinyxml2::XMLElement * doc_root_node = document.FirstChildElement("package"); if (NULL == doc_root_node) { RCUTILS_LOG_ERROR_NAMED("pluginlib.ClassLoader", "Could not find a root element for package manifest at %s.", package_xml_path.c_str()); return ""; } assert(document.RootElement() == doc_root_node); tinyxml2::XMLElement * package_name_node = doc_root_node->FirstChildElement("name"); if (NULL == package_name_node) { RCUTILS_LOG_ERROR_NAMED("pluginlib.ClassLoader", "package.xml at %s does not have a tag! Cannot determine package " "which exports plugin.", package_xml_path.c_str()); return ""; } const char* package_name_node_txt = package_name_node->GetText(); if (NULL == package_name_node_txt) { RCUTILS_LOG_ERROR_NAMED("pluginlib.ClassLoader", "package.xml at %s has an invalid tag! Cannot determine package " "which exports plugin.", package_xml_path.c_str()); return ""; } return package_name_node_txt; } template std::vector ClassLoader::getAllLibraryPathsToTry( const std::string & library_name, const std::string & exporting_package_name) /***************************************************************************/ { // To determine the common prefix of the paths to try, the prefix of the // exporting package is retrieved. // To that, various library folder names are added (lib, lib64, etc...) // Additionally, "libexec" like folders are checked, using the package name // as the libexec folder name within the library name. // Finally the library name (just the file name, stripped of extra relative) // with various extensions is concatenated to the various library directories. // // For example, if the package was 'rviz' and the library_name was // 'librviz_default_plugins', these paths might be tried: // // - /lib/librviz_default_plugins.so // - /lib64/librviz_default_plugins.so // - /bin/rviz_default_plugins.dll // - /lib/rviz/librviz_default_plugins.so // - /lib64/rviz/librviz_default_plugins.so // // The extension, e.g. `.so`, might be different based on the operating // system, e.g. it might be `.dylib` on macOS or `.dll` on Windows. // Similarly, the library might have the `lib` prefix added or removed. // Also, the library name might have a `d` added if the library is built // debug, depending on the system. // TODO(wjwwood): probably should avoid "searching" and just embed the // relative path to the libraries in the ament index, since CMake knows it // at build time... const std::string path_separator = getPathSeparator(); std::vector all_paths; // result of all pairs to search std::string package_prefix = ament_index_cpp::get_package_prefix(exporting_package_name); // Setup the directories to look in. std::vector all_search_paths = { // for now just try lib and lib64 (and their respective "libexec" directories) package_prefix + path_separator + "lib", package_prefix + path_separator + "lib64", package_prefix + path_separator + "bin", // also look in bin, for dll's on Windows package_prefix + path_separator + "lib" + path_separator + exporting_package_name, package_prefix + path_separator + "lib64" + path_separator + exporting_package_name, package_prefix + path_separator + "bin" + path_separator + exporting_package_name, }; std::string stripped_library_name = stripAllButFileFromPath(library_name); std::string library_name_alternative; // either lib or without lib prefix const char * lib_prefix = "lib"; if (library_name.rfind(lib_prefix, 0) == 0) { library_name_alternative = library_name.substr(strlen(lib_prefix)); RCUTILS_LOG_WARN_NAMED("pluginlib.ClassLoader", "given plugin name '%s' should be '%s' for better portability", library_name.c_str(), library_name_alternative.c_str()); } else { library_name_alternative = lib_prefix + library_name; } std::string stripped_library_name_alternative = stripAllButFileFromPath(library_name_alternative); try { // Setup the relative file paths to pair with the search directories above. std::vector all_relative_library_paths = { rcpputils::get_platform_library_name(library_name), rcpputils::get_platform_library_name(library_name_alternative), rcpputils::get_platform_library_name(stripped_library_name), rcpputils::get_platform_library_name(stripped_library_name_alternative) }; std::vector all_relative_debug_library_paths = { rcpputils::get_platform_library_name(library_name, true), rcpputils::get_platform_library_name(library_name_alternative, true), rcpputils::get_platform_library_name(stripped_library_name, true), rcpputils::get_platform_library_name(stripped_library_name_alternative, true) }; for (auto && current_search_path : all_search_paths) { for (auto && current_library_path : all_relative_library_paths) { all_paths.push_back(current_search_path + path_separator + current_library_path); } for (auto && current_library_path : all_relative_debug_library_paths) { all_paths.push_back(current_search_path + path_separator + current_library_path); } } } catch (const std::runtime_error & ex) { throw std::runtime_error{ex.what()}; } for (auto && path : all_paths) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "[search path for '%s']: '%s'", library_name.c_str(), path.c_str()); } return all_paths; } template bool ClassLoader::isClassLoaded(const std::string & lookup_name) /***************************************************************************/ { return lowlevel_class_loader_.isClassAvailable(getClassType(lookup_name)); } template std::string ClassLoader::getBaseClassType() const /***************************************************************************/ { return base_class_; } template std::string ClassLoader::getClassDescription(const std::string & lookup_name) /***************************************************************************/ { ClassMapIterator it = classes_available_.find(lookup_name); if (it != classes_available_.end()) { return it->second.description_; } return ""; } template std::string ClassLoader::getClassType(const std::string & lookup_name) /***************************************************************************/ { ClassMapIterator it = classes_available_.find(lookup_name); if (it != classes_available_.end()) { return it->second.derived_class_; } return ""; } template std::string ClassLoader::getClassLibraryPath(const std::string & lookup_name) /***************************************************************************/ { if (classes_available_.find(lookup_name) == classes_available_.end()) { std::ostringstream error_msg; error_msg << "Could not find library corresponding to plugin " << lookup_name << ". Make sure the plugin description XML file has the correct name of the library."; throw pluginlib::LibraryLoadException(error_msg.str()); } ClassMapIterator it = classes_available_.find(lookup_name); std::string library_name = it->second.library_name_; RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s maps to library %s in classes_available_.", lookup_name.c_str(), library_name.c_str()); std::vector paths_to_try = getAllLibraryPathsToTry(library_name, it->second.package_); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Iterating through all possible paths where %s could be located...", library_name.c_str()); for (auto it = paths_to_try.begin(); it != paths_to_try.end(); it++) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Checking path %s ", it->c_str()); if (rcpputils::fs::exists(*it)) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Library %s found at explicit path %s.", library_name.c_str(), it->c_str()); return *it; } } std::ostringstream error_msg; error_msg << "Could not find library corresponding to plugin " << lookup_name << ". Make sure that the library '" << library_name << "' actually exists."; throw pluginlib::LibraryLoadException(error_msg.str()); } template std::string ClassLoader::getClassPackage(const std::string & lookup_name) /***************************************************************************/ { ClassMapIterator it = classes_available_.find(lookup_name); if (it != classes_available_.end()) { return it->second.package_; } return ""; } template std::vector ClassLoader::getPluginXmlPaths() /***************************************************************************/ { return plugin_xml_paths_; } template std::vector ClassLoader::getDeclaredClasses() /***************************************************************************/ { std::vector lookup_names; for (ClassMapIterator it = classes_available_.begin(); it != classes_available_.end(); ++it) { lookup_names.push_back(it->first); } return lookup_names; } template std::string ClassLoader::getErrorStringForUnknownClass(const std::string & lookup_name) /***************************************************************************/ { std::string declared_types; std::vector types = getDeclaredClasses(); for (unsigned int i = 0; i < types.size(); i++) { declared_types = declared_types + std::string(" ") + types[i]; } return "According to the loaded plugin descriptions the class " + lookup_name + " with base class type " + base_class_ + " does not exist. Declared types are " + declared_types; } template std::string ClassLoader::getName(const std::string & lookup_name) /***************************************************************************/ { // remove the package name to get the raw plugin name std::vector result = pluginlib::impl::split(lookup_name, "/|:"); return result.back(); } template std::string ClassLoader::getPackageFromPluginXMLFilePath(const std::string & plugin_xml_file_path) /***************************************************************************/ { // Note: This method takes an input a path to a plugin xml file and must determine which // package the XML file came from. This is not necessarily the same thing as the member // variable "package_". The plugin xml file can be located anywhere in the source tree for a // package // catkin and ament: // 1. Find nearest encasing package.xml // 2. Extract name of package from package.xml std::string package_name; rcpputils::fs::path p(plugin_xml_file_path); rcpputils::fs::path parent = p.parent_path(); // Figure out exactly which package the passed XML file is exported by. while (true) { if (rcpputils::fs::exists(parent / "package.xml")) { std::string package_file_path = (parent / "package.xml").string(); return extractPackageNameFromPackageXML(package_file_path); } // Recursive case - hop one folder up and store current parent // parent_path() returns the current path if we reached the root. p = parent; parent = parent.parent_path(); // Base case - reached root and cannot find what we're looking for if (parent.string().empty() || (p == parent)) { return ""; } } return package_name; } template std::string ClassLoader::getPathSeparator() /***************************************************************************/ { return std::string(1, rcpputils::fs::kPreferredSeparator); } template std::string ClassLoader::getPluginManifestPath(const std::string & lookup_name) /***************************************************************************/ { ClassMapIterator it = classes_available_.find(lookup_name); if (it != classes_available_.end()) { return it->second.plugin_manifest_path_; } return ""; } template std::vector ClassLoader::getRegisteredLibraries() /***************************************************************************/ { return lowlevel_class_loader_.getRegisteredLibraries(); } template bool ClassLoader::isClassAvailable(const std::string & lookup_name) /***************************************************************************/ { return classes_available_.find(lookup_name) != classes_available_.end(); } template std::string ClassLoader::joinPaths(const std::string & path1, const std::string & path2) /***************************************************************************/ { rcpputils::fs::path p1(path1); return (p1 / path2).string(); } template void ClassLoader::loadLibraryForClass(const std::string & lookup_name) /***************************************************************************/ { ClassMapIterator it = classes_available_.find(lookup_name); if (it == classes_available_.end()) { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s has no mapping in classes_available_.", lookup_name.c_str()); throw pluginlib::LibraryLoadException(getErrorStringForUnknownClass(lookup_name)); } std::string library_path = getClassLibraryPath(lookup_name); try { lowlevel_class_loader_.loadLibrary(library_path); it->second.resolved_library_path_ = library_path; } catch (const class_loader::LibraryLoadException & ex) { std::string error_string = "Failed to load library " + library_path + ". " "Make sure that you are calling the PLUGINLIB_EXPORT_CLASS macro in the " "library code, and that names are consistent between this macro and your XML. " "Error string: " + ex.what(); throw pluginlib::LibraryLoadException(error_string); } } template void ClassLoader::processSingleXMLPluginFile( const std::string & xml_file, std::map & classes_available) /***************************************************************************/ { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Processing xml file %s...", xml_file.c_str()); tinyxml2::XMLDocument document; document.LoadFile(xml_file.c_str()); tinyxml2::XMLElement * config = document.RootElement(); if (NULL == config) { throw pluginlib::InvalidXMLException( "XML Document '" + xml_file + "' has no Root Element. This likely means the XML is malformed or missing."); return; } const char* config_value = config->Value(); if (NULL == config_value) { throw pluginlib::InvalidXMLException( "XML Document '" + xml_file + "' has an invalid Root Element. This likely means the XML is malformed or missing."); return; } if (!(strcmp(config_value, "library") == 0 || strcmp(config_value, "class_libraries") == 0)) { throw pluginlib::InvalidXMLException( "The XML document '" + xml_file + "' given to add must have either \"library\" or " "\"class_libraries\" as the root tag"); return; } // Step into the filter list if necessary if (strcmp(config_value, "class_libraries") == 0) { config = config->FirstChildElement("library"); } tinyxml2::XMLElement * library = config; while (library != NULL) { const char* path = library->Attribute("path"); if (NULL == path) { RCUTILS_LOG_ERROR_NAMED("pluginlib.ClassLoader", "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str()); continue; } std::string library_path(path); if (0 == library_path.size()) { RCUTILS_LOG_ERROR_NAMED("pluginlib.ClassLoader", "Failed to find Path Attirbute in library element in %s", xml_file.c_str()); continue; } std::string package_name = getPackageFromPluginXMLFilePath(xml_file); if ("" == package_name) { RCUTILS_LOG_ERROR_NAMED("pluginlib.ClassLoader", "Could not find package manifest (neither package.xml or deprecated " "manifest.xml) at same directory level as the plugin XML file %s. " "Plugins will likely not be exported properly.\n)", xml_file.c_str()); } tinyxml2::XMLElement * class_element = library->FirstChildElement("class"); while (class_element) { std::string derived_class; if (class_element->Attribute("type") != NULL) { derived_class = std::string(class_element->Attribute("type")); } else { throw pluginlib::ClassLoaderException( "Class could not be loaded. Attribute 'type' in class tag is missing."); } std::string base_class_type; if (class_element->Attribute("base_class_type") != NULL) { base_class_type = std::string(class_element->Attribute("base_class_type")); } else { throw pluginlib::ClassLoaderException( "Class could not be loaded. Attribute 'base_class_type' in class tag is missing."); } std::string lookup_name; if (class_element->Attribute("name") != NULL) { lookup_name = class_element->Attribute("name"); RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "XML file specifies lookup name (i.e. magic name) = %s.", lookup_name.c_str()); } else { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "XML file has no lookup name (i.e. magic name) for class %s, " "assuming lookup_name == real class name.", derived_class.c_str()); lookup_name = derived_class; } // make sure that this class is of the right type before registering it if (base_class_type == base_class_) { // register class here tinyxml2::XMLElement * description = class_element->FirstChildElement("description"); std::string description_str; if (description) { description_str = description->GetText() ? description->GetText() : ""; } else { description_str = "No 'description' tag for this plugin in plugin description file."; } classes_available.insert(std::pair(lookup_name, ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str, library_path, xml_file))); } // step to next class_element class_element = class_element->NextSiblingElement("class"); } library = library->NextSiblingElement("library"); } } template void ClassLoader::refreshDeclaredClasses() /***************************************************************************/ { RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Refreshing declared classes."); // determine classes not currently loaded for removal std::list remove_classes; for (std::map::const_iterator it = classes_available_.begin(); it != classes_available_.end(); it++) { std::string resolved_library_path = it->second.resolved_library_path_; std::vector open_libs = lowlevel_class_loader_.getRegisteredLibraries(); if (std::find(open_libs.begin(), open_libs.end(), resolved_library_path) != open_libs.end()) { remove_classes.push_back(it->first); } } while (!remove_classes.empty()) { classes_available_.erase(remove_classes.front()); remove_classes.pop_front(); } // add new classes plugin_xml_paths_ = getPluginXmlPaths(package_, attrib_name_); std::map updated_classes = determineAvailableClasses(plugin_xml_paths_); for (std::map::const_iterator it = updated_classes.begin(); it != updated_classes.end(); it++) { if (classes_available_.find(it->first) == classes_available_.end()) { classes_available_.insert(std::pair(it->first, it->second)); } } } template std::string ClassLoader::stripAllButFileFromPath(const std::string & path) /***************************************************************************/ { std::string only_file; size_t c = path.find_last_of(getPathSeparator()); if (std::string::npos == c) { return path; } else { return path.substr(c, path.size()); } } template int ClassLoader::unloadLibraryForClass(const std::string & lookup_name) /***************************************************************************/ { ClassMapIterator it = classes_available_.find(lookup_name); if (it != classes_available_.end() && it->second.resolved_library_path_ != "UNRESOLVED") { std::string library_path = it->second.resolved_library_path_; RCUTILS_LOG_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to unload library %s for class %s", library_path.c_str(), lookup_name.c_str()); return unloadClassLibraryInternal(library_path); } else { throw pluginlib::LibraryUnloadException(getErrorStringForUnknownClass(lookup_name)); } } template int ClassLoader::unloadClassLibraryInternal(const std::string & library_path) /***************************************************************************/ { return lowlevel_class_loader_.unloadLibrary(library_path); } } // namespace pluginlib #endif // PLUGINLIB__CLASS_LOADER_IMP_HPP_