class_loader_imp.hpp
Go to the documentation of this file.
1 /*********************************************************************
2 *
3 * Software License Agreement (BSD License)
4 *
5 * Copyright (c) 2008, Willow Garage, Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of Willow Garage, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 *********************************************************************/
36 
37 #ifndef PLUGINLIB__CLASS_LOADER_IMP_HPP_
38 #define PLUGINLIB__CLASS_LOADER_IMP_HPP_
39 
40 #include <cstdlib>
41 #include <list>
42 #include <map>
43 #include <memory>
44 #include <sstream>
45 #include <stdexcept>
46 #include <string>
47 #include <utility>
48 #include <vector>
49 
50 #include "boost/algorithm/string.hpp"
51 #include "boost/bind.hpp"
52 #include "boost/filesystem.hpp"
53 #include "boost/foreach.hpp"
55 
56 #include "ros/package.h"
57 
58 #include "./class_loader.hpp"
59 
60 #ifdef _WIN32
61 const std::string os_pathsep(";"); // NOLINT
62 #else
63 const std::string os_pathsep(":"); // NOLINT
64 #endif
65 
66 namespace pluginlib
67 {
68 template<class T>
70  std::string package, std::string base_class, std::string attrib_name,
71  std::vector<std::string> plugin_xml_paths)
72 : plugin_xml_paths_(plugin_xml_paths),
73  package_(package),
74  base_class_(base_class),
75  attrib_name_(attrib_name),
76  // NOTE: The parameter to the class loader enables/disables on-demand class
77  // loading/unloading.
78  // Leaving it off for now... libraries will be loaded immediately and won't
79  // be unloaded until class loader is destroyed or force unload.
80  lowlevel_class_loader_(false)
81  /***************************************************************************/
82 {
83  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Creating ClassLoader, base = %s, address = %p",
84  base_class.c_str(), this);
85  if (ros::package::getPath(package_).empty()) {
86  throw pluginlib::ClassLoaderException("Unable to find package: " + package_);
87  }
88 
89  if (0 == plugin_xml_paths_.size()) {
91  }
93  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
94  "Finished constructring ClassLoader, base = %s, address = %p",
95  base_class.c_str(), this);
96 }
97 
98 template<class T>
100 /***************************************************************************/
101 {
102  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Destroying ClassLoader, base = %s, address = %p",
103  getBaseClassType().c_str(), this);
104 }
105 
106 
107 template<class T>
108 T * ClassLoader<T>::createClassInstance(const std::string & lookup_name, bool auto_load)
109 /***************************************************************************/
110 {
111  // Note: This method is deprecated
112  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
113  "In deprecated call createClassInstance(), lookup_name = %s, auto_load = %i.",
114  (lookup_name.c_str()), auto_load);
115 
116  if (auto_load && !isClassLoaded(lookup_name)) {
117  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
118  "Autoloading class library before attempting to create instance.");
119  loadLibraryForClass(lookup_name);
120  }
121 
122  try {
123  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
124  "Attempting to create instance through low-level MultiLibraryClassLoader...");
126  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Instance created with object pointer = %p", obj);
127 
128  return obj;
129  } catch (const class_loader::CreateClassException & ex) {
130  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "CreateClassException about to be raised for class %s",
131  lookup_name.c_str());
132  throw pluginlib::CreateClassException(ex.what());
133  }
134 }
135 
136 template<class T>
137 boost::shared_ptr<T> ClassLoader<T>::createInstance(const std::string & lookup_name)
138 /***************************************************************************/
139 {
140  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to create managed instance for class %s.",
141  lookup_name.c_str());
142 
143  if (!isClassLoaded(lookup_name)) {
144  loadLibraryForClass(lookup_name);
145  }
146 
147  try {
148  std::string class_type = getClassType(lookup_name);
149  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "%s maps to real class type %s",
150  lookup_name.c_str(), class_type.c_str());
151 
153 
154  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "boost::shared_ptr to object of real type %s created.",
155  class_type.c_str());
156 
157  return obj;
158  } catch (const class_loader::CreateClassException & ex) {
159  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
160  "Exception raised by low-level multi-library class loader when attempting "
161  "to create instance of class %s.",
162  lookup_name.c_str());
163  throw pluginlib::CreateClassException(ex.what());
164  }
165 }
166 
167 #if __cplusplus >= 201103L
168 template<class T>
169 UniquePtr<T> ClassLoader<T>::createUniqueInstance(const std::string & lookup_name)
170 {
171  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
172  "Attempting to create managed (unique) instance for class %s.",
173  lookup_name.c_str());
174 
175  if (!isClassLoaded(lookup_name)) {
176  loadLibraryForClass(lookup_name);
177  }
178 
179  try {
180  std::string class_type = getClassType(lookup_name);
181  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "%s maps to real class type %s",
182  lookup_name.c_str(), class_type.c_str());
183 
184  UniquePtr<T> obj = lowlevel_class_loader_.createUniqueInstance<T>(class_type);
185 
186  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "std::unique_ptr to object of real type %s created.",
187  class_type.c_str());
188 
189  return obj;
190  } catch (const class_loader::CreateClassException & ex) {
191  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
192  "Exception raised by low-level multi-library class loader when attempting "
193  "to create instance of class %s.",
194  lookup_name.c_str());
195  throw pluginlib::CreateClassException(ex.what());
196  }
197 }
198 #endif
199 
200 template<class T>
201 T * ClassLoader<T>::createUnmanagedInstance(const std::string & lookup_name)
202 /***************************************************************************/
203 {
204  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to create UNMANAGED instance for class %s.",
205  lookup_name.c_str());
206 
207  if (!isClassLoaded(lookup_name)) {
208  loadLibraryForClass(lookup_name);
209  }
210 
211  T * instance = 0;
212  try {
213  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
214  "Attempting to create instance through low level multi-library class loader.");
215  std::string class_type = getClassType(lookup_name);
216  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "%s maps to real class type %s",
217  lookup_name.c_str(), class_type.c_str());
218  instance = lowlevel_class_loader_.createUnmanagedInstance<T>(class_type);
219  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Instance of type %s created.", class_type.c_str());
220  } catch (const class_loader::CreateClassException & ex) {
221  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
222  "Exception raised by low-level multi-library class loader when attempting "
223  "to create UNMANAGED instance of class %s.",
224  lookup_name.c_str());
225  throw pluginlib::CreateClassException(ex.what());
226  }
227  return instance;
228 }
229 
230 template<class T>
231 std::vector<std::string> ClassLoader<T>::getPluginXmlPaths(
232  const std::string & package,
233  const std::string & attrib_name,
234  bool force_recrawl)
235 /***************************************************************************/
236 {
237  // Pull possible files from manifests of packages which depend on this package and export class
238  std::vector<std::string> paths;
239  ros::package::getPlugins(package, attrib_name, paths, force_recrawl);
240  return paths;
241 }
242 
243 template<class T>
244 std::map<std::string, ClassDesc> ClassLoader<T>::determineAvailableClasses(
245  const std::vector<std::string> & plugin_xml_paths)
246 /***************************************************************************/
247 {
248  // mas - This method requires major refactoring...
249  // not only is it really long and confusing but a lot of the comments do not
250  // seem to be correct.
251  // With time I keep correcting small things, but a good rewrite is needed.
252 
253  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Entering determineAvailableClasses()...");
254  std::map<std::string, ClassDesc> classes_available;
255 
256  // Walk the list of all plugin XML files (variable "paths") that are exported by the build system
257  for (std::vector<std::string>::const_iterator it = plugin_xml_paths.begin();
258  it != plugin_xml_paths.end(); ++it)
259  {
260  try {
261  processSingleXMLPluginFile(*it, classes_available);
262  } catch (const pluginlib::InvalidXMLException & e) {
263  ROS_ERROR_NAMED("pluginlib.ClassLoader",
264  "Skipped loading plugin with error: %s.",
265  e.what());
266  }
267  }
268 
269  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Exiting determineAvailableClasses()...");
270  return classes_available;
271 }
272 
273 template<class T>
274 std::string ClassLoader<T>::extractPackageNameFromPackageXML(const std::string & package_xml_path)
275 /***************************************************************************/
276 {
277  tinyxml2::XMLDocument document;
278  document.LoadFile(package_xml_path.c_str());
279  tinyxml2::XMLElement * doc_root_node = document.FirstChildElement("package");
280  if (NULL == doc_root_node) {
281  ROS_ERROR_NAMED("pluginlib.ClassLoader",
282  "Could not find a root element for package manifest at %s.",
283  package_xml_path.c_str());
284  return "";
285  }
286 
287  assert(document.RootElement() == doc_root_node);
288 
289  tinyxml2::XMLElement * package_name_node = doc_root_node->FirstChildElement("name");
290  if (NULL == package_name_node) {
291  ROS_ERROR_NAMED("pluginlib.ClassLoader",
292  "package.xml at %s does not have a <name> tag! Cannot determine package "
293  "which exports plugin.",
294  package_xml_path.c_str());
295  return "";
296  }
297 
298  return package_name_node->GetText();
299 }
300 
301 template<class T>
302 std::vector<std::string> ClassLoader<T>::getCatkinLibraryPaths()
303 /***************************************************************************/
304 {
305  std::vector<std::string> lib_paths;
306  const char * env = std::getenv("CMAKE_PREFIX_PATH");
307  if (env) {
308  std::string env_catkin_prefix_paths(env);
309  std::vector<std::string> catkin_prefix_paths;
310  boost::split(catkin_prefix_paths, env_catkin_prefix_paths, boost::is_any_of(os_pathsep));
311  BOOST_FOREACH(std::string catkin_prefix_path, catkin_prefix_paths) {
312  boost::filesystem::path path(catkin_prefix_path);
313  boost::filesystem::path lib("lib");
314  lib_paths.push_back((path / lib).string());
315  }
316  }
317  return lib_paths;
318 }
319 
320 template<class T>
322  const std::string & library_name,
323  const std::string & exporting_package_name)
324 /***************************************************************************/
325 {
326  // Catkin-rosbuild Backwards Compatability Rules - Note library_name may be prefixed with
327  // relative path (e.g. "/lib/libFoo")
328  // 1. Try catkin library paths (catkin_find --libs) + library_name + extension
329  // 2. Try catkin library paths
330  // (catkin_find -- libs) + stripAllButFileFromPath(library_name) + extension
331  // 3. Try export_pkg/library_name + extension
332 
333  std::vector<std::string> all_paths;
334  std::vector<std::string> all_paths_without_extension = getCatkinLibraryPaths();
335  all_paths_without_extension.push_back(getROSBuildLibraryPath(exporting_package_name));
336  bool debug_library_suffix = (0 == class_loader::systemLibrarySuffix().compare(0, 1, "d"));
337  std::string non_debug_suffix;
338  if (debug_library_suffix) {
339  non_debug_suffix = class_loader::systemLibrarySuffix().substr(1);
340  } else {
341  non_debug_suffix = class_loader::systemLibrarySuffix();
342  }
343  std::string library_name_with_extension = library_name + non_debug_suffix;
344  std::string stripped_library_name = stripAllButFileFromPath(library_name);
345  std::string stripped_library_name_with_extension = stripped_library_name + non_debug_suffix;
346 
347  const std::string path_separator = getPathSeparator();
348 
349  for (unsigned int c = 0; c < all_paths_without_extension.size(); c++) {
350  std::string current_path = all_paths_without_extension.at(c);
351  all_paths.push_back(current_path + path_separator + library_name_with_extension);
352  all_paths.push_back(current_path + path_separator + stripped_library_name_with_extension);
353  // We're in debug mode, try debug libraries as well
354  if (debug_library_suffix) {
355  all_paths.push_back(
356  current_path + path_separator + library_name + class_loader::systemLibrarySuffix());
357  all_paths.push_back(
358  current_path + path_separator + stripped_library_name +
360  }
361  }
362 
363  return all_paths;
364 }
365 
366 template<class T>
367 bool ClassLoader<T>::isClassLoaded(const std::string & lookup_name)
368 /***************************************************************************/
369 {
370  return lowlevel_class_loader_.isClassAvailable<T>(getClassType(lookup_name));
371 }
372 
373 template<class T>
375 /***************************************************************************/
376 {
377  return base_class_;
378 }
379 
380 template<class T>
381 std::string ClassLoader<T>::getClassDescription(const std::string & lookup_name)
382 /***************************************************************************/
383 {
384  ClassMapIterator it = classes_available_.find(lookup_name);
385  if (it != classes_available_.end()) {
386  return it->second.description_;
387  }
388  return "";
389 }
390 
391 template<class T>
392 std::string ClassLoader<T>::getClassType(const std::string & lookup_name)
393 /***************************************************************************/
394 {
395  ClassMapIterator it = classes_available_.find(lookup_name);
396  if (it != classes_available_.end()) {
397  return it->second.derived_class_;
398  }
399  return "";
400 }
401 
402 template<class T>
403 std::string ClassLoader<T>::getClassLibraryPath(const std::string & lookup_name)
404 /***************************************************************************/
405 {
406  if (classes_available_.find(lookup_name) == classes_available_.end()) {
407  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s has no mapping in classes_available_.",
408  lookup_name.c_str());
409  return "";
410  }
411  ClassMapIterator it = classes_available_.find(lookup_name);
412  std::string library_name = it->second.library_name_;
413  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s maps to library %s in classes_available_.",
414  lookup_name.c_str(), library_name.c_str());
415 
416  std::vector<std::string> paths_to_try =
417  getAllLibraryPathsToTry(library_name, it->second.package_);
418 
419  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
420  "Iterating through all possible paths where %s could be located...",
421  library_name.c_str());
422  for (std::vector<std::string>::const_iterator it = paths_to_try.begin(); it != paths_to_try.end();
423  it++)
424  {
425  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Checking path %s ", it->c_str());
426  if (boost::filesystem::exists(*it)) {
427  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Library %s found at explicit path %s.",
428  library_name.c_str(), it->c_str());
429  return *it;
430  }
431  }
432  return "";
433 }
434 
435 template<class T>
436 std::string ClassLoader<T>::getClassPackage(const std::string & lookup_name)
437 /***************************************************************************/
438 {
439  ClassMapIterator it = classes_available_.find(lookup_name);
440  if (it != classes_available_.end()) {
441  return it->second.package_;
442  }
443  return "";
444 }
445 
446 template<class T>
447 std::vector<std::string> ClassLoader<T>::getPluginXmlPaths()
448 /***************************************************************************/
449 {
450  return plugin_xml_paths_;
451 }
452 
453 template<class T>
454 std::vector<std::string> ClassLoader<T>::getDeclaredClasses()
455 /***************************************************************************/
456 {
457  std::vector<std::string> lookup_names;
458  for (ClassMapIterator it = classes_available_.begin(); it != classes_available_.end(); ++it) {
459  lookup_names.push_back(it->first);
460  }
461 
462  return lookup_names;
463 }
464 
465 template<class T>
466 std::string ClassLoader<T>::getErrorStringForUnknownClass(const std::string & lookup_name)
467 /***************************************************************************/
468 {
469  std::string declared_types;
470  std::vector<std::string> types = getDeclaredClasses();
471  for (unsigned int i = 0; i < types.size(); i++) {
472  declared_types = declared_types + std::string(" ") + types[i];
473  }
474  return "According to the loaded plugin descriptions the class " + lookup_name +
475  " with base class type " + base_class_ + " does not exist. Declared types are " +
476  declared_types;
477 }
478 
479 template<class T>
480 std::string ClassLoader<T>::getName(const std::string & lookup_name)
481 /***************************************************************************/
482 {
483  // remove the package name to get the raw plugin name
484  std::vector<std::string> split;
485  boost::split(split, lookup_name, boost::is_any_of("/:"));
486  return split.back();
487 }
488 
489 template<class T>
490 std::string
491 ClassLoader<T>::getPackageFromPluginXMLFilePath(const std::string & plugin_xml_file_path)
492 /***************************************************************************/
493 {
494  // Note: This method takes an input a path to a plugin xml file and must determine which
495  // package the XML file came from. This is not necessariliy the same thing as the member
496  // variable "package_". The plugin xml file can be located anywhere in the source tree for a
497  // package
498 
499  // rosbuild:
500  // 1. Find nearest encasing manifest.xml
501  // 2. Once found, the name of the folder containg the manifest should be the
502  // package name we are looking for
503  // 3. Confirm package is findable with rospack
504 
505  // catkin:
506  // 1. Find nearest encasing package.xml
507  // 2. Extract name of package from package.xml
508 
509  std::string package_name;
510  boost::filesystem::path p(plugin_xml_file_path);
511  boost::filesystem::path parent = p.parent_path();
512 
513  // Figure out exactly which package the passed XML file is exported by.
514  while (true) {
515  if (boost::filesystem::exists(parent / "package.xml")) {
516  std::string package_file_path = (boost::filesystem::path(parent / "package.xml")).string();
517  return extractPackageNameFromPackageXML(package_file_path);
518  } else if (boost::filesystem::exists(parent / "manifest.xml")) {
519 #if BOOST_FILESYSTEM_VERSION >= 3
520  std::string package = parent.filename().string();
521 #else
522  std::string package = parent.filename();
523 #endif
524  std::string package_path = ros::package::getPath(package);
525 
526  // package_path is a substr of passed plugin xml path
527  if (0 == plugin_xml_file_path.find(package_path)) {
528  package_name = package;
529  break;
530  }
531  }
532 
533  // Recursive case - hop one folder up
534  parent = parent.parent_path().string();
535 
536  // Base case - reached root and cannot find what we're looking for
537  if (parent.string().empty()) {
538  return "";
539  }
540  }
541 
542  return package_name;
543 }
544 
545 template<class T>
547 /***************************************************************************/
548 {
549 #if BOOST_FILESYSTEM_VERSION >= 3
550 # ifdef _WIN32
551  return boost::filesystem::path("/").string();
552 # else
553  return boost::filesystem::path("/").native();
554 # endif
555 #else
556  return boost::filesystem::path("/").external_file_string();
557 #endif
558 }
559 
560 
561 template<class T>
562 std::string ClassLoader<T>::getPluginManifestPath(const std::string & lookup_name)
563 /***************************************************************************/
564 {
565  ClassMapIterator it = classes_available_.find(lookup_name);
566  if (it != classes_available_.end()) {
567  return it->second.plugin_manifest_path_;
568  }
569  return "";
570 }
571 
572 
573 template<class T>
574 std::vector<std::string> ClassLoader<T>::getRegisteredLibraries()
575 /***************************************************************************/
576 {
578 }
579 
580 template<class T>
581 std::string ClassLoader<T>::getROSBuildLibraryPath(const std::string & exporting_package_name)
582 /***************************************************************************/
583 {
584  return ros::package::getPath(exporting_package_name);
585 }
586 
587 template<class T>
588 bool ClassLoader<T>::isClassAvailable(const std::string & lookup_name)
589 /***************************************************************************/
590 {
591  return classes_available_.find(lookup_name) != classes_available_.end();
592 }
593 
594 template<class T>
595 std::string ClassLoader<T>::joinPaths(const std::string & path1, const std::string & path2)
596 /***************************************************************************/
597 {
598  boost::filesystem::path p1(path1);
599  return (p1 / path2).string();
600 }
601 
602 template<class T>
603 void ClassLoader<T>::loadLibraryForClass(const std::string & lookup_name)
604 /***************************************************************************/
605 {
606  ClassMapIterator it = classes_available_.find(lookup_name);
607  if (it == classes_available_.end()) {
608  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s has no mapping in classes_available_.",
609  lookup_name.c_str());
611  }
612 
613  std::string library_path = getClassLibraryPath(lookup_name);
614  if ("" == library_path) {
615  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "No path could be found to the library containing %s.",
616  lookup_name.c_str());
617  std::ostringstream error_msg;
618  error_msg << "Could not find library corresponding to plugin " << lookup_name <<
619  ". Make sure the plugin description XML file has the correct name of the "
620  "library and that the library actually exists.";
621  throw pluginlib::LibraryLoadException(error_msg.str());
622  }
623 
624  try {
625  lowlevel_class_loader_.loadLibrary(library_path);
626  it->second.resolved_library_path_ = library_path;
627  } catch (const class_loader::LibraryLoadException & ex) {
628  std::string error_string =
629  "Failed to load library " + library_path + ". "
630  "Make sure that you are calling the PLUGINLIB_EXPORT_CLASS macro in the "
631  "library code, and that names are consistent between this macro and your XML. "
632  "Error string: " + ex.what();
633  throw pluginlib::LibraryLoadException(error_string);
634  }
635 }
636 
637 template<class T>
639  const std::string & xml_file, std::map<std::string,
640  ClassDesc> & classes_available)
641 /***************************************************************************/
642 {
643  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Processing xml file %s...", xml_file.c_str());
644  tinyxml2::XMLDocument document;
645  document.LoadFile(xml_file.c_str());
646  tinyxml2::XMLElement * config = document.RootElement();
647  if (NULL == config) {
649  "XML Document '" + xml_file +
650  "' has no Root Element. This likely means the XML is malformed or missing.");
651  return;
652  }
653  if (!(strcmp(config->Value(), "library") == 0 ||
654  strcmp(config->Value(), "class_libraries") == 0))
655  {
657  "The XML document '" + xml_file + "' given to add must have either \"library\" or "
658  "\"class_libraries\" as the root tag");
659  return;
660  }
661  // Step into the filter list if necessary
662  if (strcmp(config->Value(), "class_libraries") == 0) {
663  config = config->FirstChildElement("library");
664  }
665 
666  tinyxml2::XMLElement * library = config;
667  while (library != NULL) {
668  std::string library_path = library->Attribute("path");
669  if (0 == library_path.size()) {
670  ROS_ERROR_NAMED("pluginlib.ClassLoader",
671  "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str());
672  continue;
673  }
674 
675  std::string package_name = getPackageFromPluginXMLFilePath(xml_file);
676  if ("" == package_name) {
677  ROS_ERROR_NAMED("pluginlib.ClassLoader",
678  "Could not find package manifest (neither package.xml or deprecated "
679  "manifest.xml) at same directory level as the plugin XML file %s. "
680  "Plugins will likely not be exported properly.\n)",
681  xml_file.c_str());
682  }
683 
684  tinyxml2::XMLElement * class_element = library->FirstChildElement("class");
685  while (class_element) {
686  std::string derived_class;
687  if (class_element->Attribute("type") != NULL) {
688  derived_class = std::string(class_element->Attribute("type"));
689  } else {
691  "Class could not be loaded. Attribute 'type' in class tag is missing.");
692  }
693 
694  std::string base_class_type;
695  if (class_element->Attribute("base_class_type") != NULL) {
696  base_class_type = std::string(class_element->Attribute("base_class_type"));
697  } else {
699  "Class could not be loaded. Attribute 'base_class_type' in class tag is missing.");
700  }
701 
702  std::string lookup_name;
703  if (class_element->Attribute("name") != NULL) {
704  lookup_name = class_element->Attribute("name");
705  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
706  "XML file specifies lookup name (i.e. magic name) = %s.",
707  lookup_name.c_str());
708  } else {
709  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
710  "XML file has no lookup name (i.e. magic name) for class %s, "
711  "assuming lookup_name == real class name.",
712  derived_class.c_str());
713  lookup_name = derived_class;
714  }
715 
716  // make sure that this class is of the right type before registering it
717  if (base_class_type == base_class_) {
718  // register class here
719  tinyxml2::XMLElement * description = class_element->FirstChildElement("description");
720  std::string description_str;
721  if (description) {
722  description_str = description->GetText() ? description->GetText() : "";
723  } else {
724  description_str = "No 'description' tag for this plugin in plugin description file.";
725  }
726 
727  classes_available.insert(std::pair<std::string, ClassDesc>(lookup_name,
728  ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str,
729  library_path, xml_file)));
730  }
731 
732  // step to next class_element
733  class_element = class_element->NextSiblingElement("class");
734  }
735  library = library->NextSiblingElement("library");
736  }
737 }
738 
739 template<class T>
741 /***************************************************************************/
742 {
743  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Refreshing declared classes.");
744  // determine classes not currently loaded for removal
745  std::list<std::string> remove_classes;
746  for (std::map<std::string, ClassDesc>::const_iterator it = classes_available_.begin();
747  it != classes_available_.end(); it++)
748  {
749  std::string resolved_library_path = it->second.resolved_library_path_;
750  std::vector<std::string> open_libs = lowlevel_class_loader_.getRegisteredLibraries();
751  if (std::find(open_libs.begin(), open_libs.end(), resolved_library_path) != open_libs.end()) {
752  remove_classes.push_back(it->first);
753  }
754  }
755 
756  while (!remove_classes.empty()) {
757  classes_available_.erase(remove_classes.front());
758  remove_classes.pop_front();
759  }
760 
761  // add new classes
763  std::map<std::string, ClassDesc> updated_classes = determineAvailableClasses(plugin_xml_paths_);
764  for (std::map<std::string, ClassDesc>::const_iterator it = updated_classes.begin();
765  it != updated_classes.end(); it++)
766  {
767  if (classes_available_.find(it->first) == classes_available_.end()) {
768  classes_available_.insert(std::pair<std::string, ClassDesc>(it->first, it->second));
769  }
770  }
771 }
772 
773 template<class T>
774 std::string ClassLoader<T>::stripAllButFileFromPath(const std::string & path)
775 /***************************************************************************/
776 {
777  std::string only_file;
778  size_t c = path.find_last_of(getPathSeparator());
779  if (std::string::npos == c) {
780  return path;
781  } else {
782  return path.substr(c, path.size());
783  }
784 }
785 
786 template<class T>
787 int ClassLoader<T>::unloadLibraryForClass(const std::string & lookup_name)
788 /***************************************************************************/
789 {
790  ClassMapIterator it = classes_available_.find(lookup_name);
791  if (it != classes_available_.end() && it->second.resolved_library_path_ != "UNRESOLVED") {
792  std::string library_path = it->second.resolved_library_path_;
793  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to unload library %s for class %s",
794  library_path.c_str(), lookup_name.c_str());
795  return unloadClassLibraryInternal(library_path);
796  } else {
798  }
799 }
800 
801 template<class T>
802 int ClassLoader<T>::unloadClassLibraryInternal(const std::string & library_path)
803 /***************************************************************************/
804 {
805  return lowlevel_class_loader_.unloadLibrary(library_path);
806 }
807 
808 } // namespace pluginlib
809 
810 #endif // PLUGINLIB__CLASS_LOADER_IMP_HPP_
virtual std::string getClassType(const std::string &lookup_name)
Given the lookup name of a class, return the type of the derived class associated with it...
virtual std::string getPluginManifestPath(const std::string &lookup_name)
Given the name of a class, return the path of the associated plugin manifest.
ClassLoader::UniquePtr< Base > createUniqueInstance(const std::string &class_name)
std::map< std::string, ClassDesc > determineAvailableClasses(const std::vector< std::string > &plugin_xml_paths)
Return the available classes.
const std::string os_pathsep(":")
Thrown when pluginlib is unable to instantiate a class loader.
Definition: exceptions.hpp:76
string package
class_loader::MultiLibraryClassLoader lowlevel_class_loader_
std::string getPathSeparator()
Get the standard path separator for the native OS (e.g. "/" on *nix, "\" on Windows).
std::string getPackageFromPluginXMLFilePath(const std::string &path)
Get the package name from a path to a plugin XML file.
std::string getROSBuildLibraryPath(const std::string &exporting_package_name)
Given a package name, return the path where rosbuild thinks plugins are installed.
virtual int unloadLibraryForClass(const std::string &lookup_name)
Decrement the counter for the library containing a class with a given name.
virtual std::string getClassDescription(const std::string &lookup_name)
Given the lookup name of a class, return its description.
boost::shared_ptr< T > createInstance(const std::string &lookup_name)
Create an instance of a desired class.
T * createClassInstance(const std::string &lookup_name, bool auto_load=true)
Create an instance of a desired class, optionally loading the associated library too.
int unloadLibrary(const std::string &library_path)
virtual void loadLibraryForClass(const std::string &lookup_name)
Attempt to load the library containing a class with a given name.
virtual std::string getClassLibraryPath(const std::string &lookup_name)
Given the name of a class, return the path to its associated library.
T * createUnmanagedInstance(const std::string &lookup_name)
Create an instance of a desired class.
std::vector< std::string > plugin_xml_paths_
virtual std::string getBaseClassType() const
Given the lookup name of a class, return the type of the associated base class.
virtual std::string getClassPackage(const std::string &lookup_name)
Given the name of a class, return name of the containing package.
CLASS_LOADER_PUBLIC std::string systemLibrarySuffix()
bool isClassLoaded(const std::string &lookup_name)
Check if the library for a given class is currently loaded.
std::string extractPackageNameFromPackageXML(const std::string &package_xml_path)
Open a package.xml file and extract the package name (i.e. contents of <name> tag).
std::map< std::string, ClassDesc >::iterator ClassMapIterator
#define ROS_DEBUG_NAMED(name,...)
Storage for information about a given class.
Definition: class_desc.hpp:46
void loadLibrary(const std::string &library_path)
Thrown when pluginlib is unable to unload the library associated with a given plugin.
Definition: exceptions.hpp:87
virtual void refreshDeclaredClasses()
Refresh the list of all available classes for this ClassLoader&#39;s base class type. ...
std::string joinPaths(const std::string &path1, const std::string &path2)
Join two filesystem paths together utilzing appropriate path separator.
std::vector< std::string > getDeclaredClasses()
Return a list of all available classes for this ClassLoader&#39;s base class type.
std::vector< std::string > getAllLibraryPathsToTry(const std::string &library_name, const std::string &exporting_package_name)
Get a list of paths to try to find a library.
std::vector< std::string > getCatkinLibraryPaths()
Return the paths where libraries are installed according to the Catkin build system.
std::vector< std::string > getRegisteredLibraries()
virtual std::vector< std::string > getRegisteredLibraries()
Return the libraries that are registered and can be loaded.
Thrown when pluginlib is unable to load a plugin XML file.
Definition: exceptions.hpp:54
virtual std::string getName(const std::string &lookup_name)
Strip the package name off of a lookup name.
ROSLIB_DECL std::string getPath(const std::string &package_name)
ROSLIB_DECL void getPlugins(const std::string &package, const std::string &attribute, V_string &plugins, bool force_recrawl=false)
std::vector< std::string > getPluginXmlPaths()
Return a list of all available plugin manifest paths for this ClassLoader&#39;s base class type...
std::string stripAllButFileFromPath(const std::string &path)
Strip all but the filename from an explicit file path.
ClassLoader(std::string package, std::string base_class, std::string attrib_name=std::string("plugin"), std::vector< std::string > plugin_xml_paths=std::vector< std::string >())
#define ROS_ERROR_NAMED(name,...)
A class to help manage and load classes.
Thrown when pluginlib is unable to load the library associated with a given plugin.
Definition: exceptions.hpp:65
virtual bool isClassAvailable(const std::string &lookup_name)
Check if the class associated with a plugin name is available to be loaded.
std::map< std::string, ClassDesc > classes_available_
int unloadClassLibraryInternal(const std::string &library_path)
Helper function for unloading a shared library.
Thrown when pluginlib is unable to create the class associated with a given plugin.
Definition: exceptions.hpp:98
boost::shared_ptr< Base > createInstance(const std::string &class_name)
std::string getErrorStringForUnknownClass(const std::string &lookup_name)
Return an error message for an unknown class.
void processSingleXMLPluginFile(const std::string &xml_file, std::map< std::string, ClassDesc > &class_available)
Parse a plugin XML file.
bool isClassAvailable(const std::string &class_name)
Base * createUnmanagedInstance(const std::string &class_name)


pluginlib
Author(s): Eitan Marder-Eppstein, Tully Foote, Dirk Thomas, Mirza Shah
autogenerated on Thu Jun 6 2019 22:03:47