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  const char* package_name_node_txt = package_name_node->GetText();
299  if (NULL == package_name_node_txt) {
300  ROS_ERROR_NAMED("pluginlib.ClassLoader",
301  "package.xml at %s has an invalid <name> tag! Cannot determine package "
302  "which exports plugin.",
303  package_xml_path.c_str());
304  return "";
305  }
306 
307  return package_name_node_txt;
308 }
309 
310 template<class T>
311 std::vector<std::string> ClassLoader<T>::getCatkinLibraryPaths()
312 /***************************************************************************/
313 {
314  std::vector<std::string> lib_paths;
315  const char * env = std::getenv("CMAKE_PREFIX_PATH");
316  if (env) {
317  std::string env_catkin_prefix_paths(env);
318  std::vector<std::string> catkin_prefix_paths;
319  boost::split(catkin_prefix_paths, env_catkin_prefix_paths, boost::is_any_of(os_pathsep));
320  BOOST_FOREACH(std::string catkin_prefix_path, catkin_prefix_paths) {
321  boost::filesystem::path path(catkin_prefix_path);
322 #if _WIN32
323  boost::filesystem::path bin("bin");
324  lib_paths.push_back((path / bin).string());
325 #endif
326  boost::filesystem::path lib("lib");
327  lib_paths.push_back((path / lib).string());
328  }
329  }
330  return lib_paths;
331 }
332 
333 template<class T>
335  const std::string & library_name,
336  const std::string & exporting_package_name)
337 /***************************************************************************/
338 {
339  // Catkin-rosbuild Backwards Compatability Rules - Note library_name may be prefixed with
340  // relative path (e.g. "/lib/libFoo")
341  // 1. Try catkin library paths (catkin_find --libs) + library_name + extension
342  // 2. Try catkin library paths
343  // (catkin_find -- libs) + stripAllButFileFromPath(library_name) + extension
344  // 3. Try export_pkg/library_name + extension
345 
346  std::vector<std::string> all_paths;
347  std::vector<std::string> all_paths_without_extension = getCatkinLibraryPaths();
348  all_paths_without_extension.push_back(getROSBuildLibraryPath(exporting_package_name));
349  bool debug_library_suffix = (0 == class_loader::systemLibrarySuffix().compare(0, 1, "d"));
350  std::string non_debug_suffix;
351  if (debug_library_suffix) {
352  non_debug_suffix = class_loader::systemLibrarySuffix().substr(1);
353  } else {
354  non_debug_suffix = class_loader::systemLibrarySuffix();
355  }
356  std::string library_name_with_extension = library_name + non_debug_suffix;
357  std::string stripped_library_name = stripAllButFileFromPath(library_name);
358  std::string stripped_library_name_with_extension = stripped_library_name + non_debug_suffix;
359 
360  const std::string path_separator = getPathSeparator();
361 
362  for (unsigned int c = 0; c < all_paths_without_extension.size(); c++) {
363  std::string current_path = all_paths_without_extension.at(c);
364  all_paths.push_back(current_path + path_separator + library_name_with_extension);
365  all_paths.push_back(current_path + path_separator + stripped_library_name_with_extension);
366  // We're in debug mode, try debug libraries as well
367  if (debug_library_suffix) {
368  all_paths.push_back(
369  current_path + path_separator + library_name + class_loader::systemLibrarySuffix());
370  all_paths.push_back(
371  current_path + path_separator + stripped_library_name +
373  }
374  }
375 
376  return all_paths;
377 }
378 
379 template<class T>
380 bool ClassLoader<T>::isClassLoaded(const std::string & lookup_name)
381 /***************************************************************************/
382 {
383  return lowlevel_class_loader_.isClassAvailable<T>(getClassType(lookup_name));
384 }
385 
386 template<class T>
388 /***************************************************************************/
389 {
390  return base_class_;
391 }
392 
393 template<class T>
394 std::string ClassLoader<T>::getClassDescription(const std::string & lookup_name)
395 /***************************************************************************/
396 {
397  ClassMapIterator it = classes_available_.find(lookup_name);
398  if (it != classes_available_.end()) {
399  return it->second.description_;
400  }
401  return "";
402 }
403 
404 template<class T>
405 std::string ClassLoader<T>::getClassType(const std::string & lookup_name)
406 /***************************************************************************/
407 {
408  ClassMapIterator it = classes_available_.find(lookup_name);
409  if (it != classes_available_.end()) {
410  return it->second.derived_class_;
411  }
412  return "";
413 }
414 
415 template<class T>
416 std::string ClassLoader<T>::getClassLibraryPath(const std::string & lookup_name)
417 /***************************************************************************/
418 {
419  if (classes_available_.find(lookup_name) == classes_available_.end()) {
420  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s has no mapping in classes_available_.",
421  lookup_name.c_str());
422  return "";
423  }
424  ClassMapIterator it = classes_available_.find(lookup_name);
425  std::string library_name = it->second.library_name_;
426  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s maps to library %s in classes_available_.",
427  lookup_name.c_str(), library_name.c_str());
428 
429  std::vector<std::string> paths_to_try =
430  getAllLibraryPathsToTry(library_name, it->second.package_);
431 
432  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
433  "Iterating through all possible paths where %s could be located...",
434  library_name.c_str());
435  for (std::vector<std::string>::const_iterator it = paths_to_try.begin(); it != paths_to_try.end();
436  it++)
437  {
438  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Checking path %s ", it->c_str());
439  if (boost::filesystem::exists(*it)) {
440  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Library %s found at explicit path %s.",
441  library_name.c_str(), it->c_str());
442  return *it;
443  }
444  }
445  return "";
446 }
447 
448 template<class T>
449 std::string ClassLoader<T>::getClassPackage(const std::string & lookup_name)
450 /***************************************************************************/
451 {
452  ClassMapIterator it = classes_available_.find(lookup_name);
453  if (it != classes_available_.end()) {
454  return it->second.package_;
455  }
456  return "";
457 }
458 
459 template<class T>
460 std::vector<std::string> ClassLoader<T>::getPluginXmlPaths()
461 /***************************************************************************/
462 {
463  return plugin_xml_paths_;
464 }
465 
466 template<class T>
467 std::vector<std::string> ClassLoader<T>::getDeclaredClasses()
468 /***************************************************************************/
469 {
470  std::vector<std::string> lookup_names;
471  for (ClassMapIterator it = classes_available_.begin(); it != classes_available_.end(); ++it) {
472  lookup_names.push_back(it->first);
473  }
474 
475  return lookup_names;
476 }
477 
478 template<class T>
479 std::string ClassLoader<T>::getErrorStringForUnknownClass(const std::string & lookup_name)
480 /***************************************************************************/
481 {
482  std::string declared_types;
483  std::vector<std::string> types = getDeclaredClasses();
484  for (unsigned int i = 0; i < types.size(); i++) {
485  declared_types = declared_types + std::string(" ") + types[i];
486  }
487  return "According to the loaded plugin descriptions the class " + lookup_name +
488  " with base class type " + base_class_ + " does not exist. Declared types are " +
489  declared_types;
490 }
491 
492 template<class T>
493 std::string ClassLoader<T>::getName(const std::string & lookup_name)
494 /***************************************************************************/
495 {
496  // remove the package name to get the raw plugin name
497  std::vector<std::string> split;
498  boost::split(split, lookup_name, boost::is_any_of("/:"));
499  return split.back();
500 }
501 
502 template<class T>
503 std::string
504 ClassLoader<T>::getPackageFromPluginXMLFilePath(const std::string & plugin_xml_file_path)
505 /***************************************************************************/
506 {
507  // Note: This method takes an input a path to a plugin xml file and must determine which
508  // package the XML file came from. This is not necessariliy the same thing as the member
509  // variable "package_". The plugin xml file can be located anywhere in the source tree for a
510  // package
511 
512  // rosbuild:
513  // 1. Find nearest encasing manifest.xml
514  // 2. Once found, the name of the folder containg the manifest should be the
515  // package name we are looking for
516  // 3. Confirm package is findable with rospack
517 
518  // catkin:
519  // 1. Find nearest encasing package.xml
520  // 2. Extract name of package from package.xml
521 
522  std::string package_name;
523  boost::filesystem::path p(plugin_xml_file_path);
524  boost::filesystem::path parent = p.parent_path();
525 
526  // Figure out exactly which package the passed XML file is exported by.
527  while (true) {
528  if (boost::filesystem::exists(parent / "package.xml")) {
529  std::string package_file_path = (boost::filesystem::path(parent / "package.xml")).string();
530  return extractPackageNameFromPackageXML(package_file_path);
531  } else if (boost::filesystem::exists(parent / "manifest.xml")) {
532 #if BOOST_FILESYSTEM_VERSION >= 3
533  std::string package = parent.filename().string();
534 #else
535  std::string package = parent.filename();
536 #endif
537  std::string package_path = ros::package::getPath(package);
538 
539  // package_path is a substr of passed plugin xml path
540  if (0 == plugin_xml_file_path.find(package_path)) {
541  package_name = package;
542  break;
543  }
544  }
545 
546  // Recursive case - hop one folder up
547  parent = parent.parent_path().string();
548 
549  // Base case - reached root and cannot find what we're looking for
550  if (parent.string().empty()) {
551  return "";
552  }
553  }
554 
555  return package_name;
556 }
557 
558 template<class T>
560 /***************************************************************************/
561 {
562 #if BOOST_FILESYSTEM_VERSION >= 3
563 # ifdef _WIN32
564  return boost::filesystem::path("/").string();
565 # else
566  return boost::filesystem::path("/").native();
567 # endif
568 #else
569  return boost::filesystem::path("/").external_file_string();
570 #endif
571 }
572 
573 
574 template<class T>
575 std::string ClassLoader<T>::getPluginManifestPath(const std::string & lookup_name)
576 /***************************************************************************/
577 {
578  ClassMapIterator it = classes_available_.find(lookup_name);
579  if (it != classes_available_.end()) {
580  return it->second.plugin_manifest_path_;
581  }
582  return "";
583 }
584 
585 
586 template<class T>
587 std::vector<std::string> ClassLoader<T>::getRegisteredLibraries()
588 /***************************************************************************/
589 {
591 }
592 
593 template<class T>
594 std::string ClassLoader<T>::getROSBuildLibraryPath(const std::string & exporting_package_name)
595 /***************************************************************************/
596 {
597  return ros::package::getPath(exporting_package_name);
598 }
599 
600 template<class T>
601 bool ClassLoader<T>::isClassAvailable(const std::string & lookup_name)
602 /***************************************************************************/
603 {
604  return classes_available_.find(lookup_name) != classes_available_.end();
605 }
606 
607 template<class T>
608 std::string ClassLoader<T>::joinPaths(const std::string & path1, const std::string & path2)
609 /***************************************************************************/
610 {
611  boost::filesystem::path p1(path1);
612  return (p1 / path2).string();
613 }
614 
615 template<class T>
616 void ClassLoader<T>::loadLibraryForClass(const std::string & lookup_name)
617 /***************************************************************************/
618 {
619  ClassMapIterator it = classes_available_.find(lookup_name);
620  if (it == classes_available_.end()) {
621  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Class %s has no mapping in classes_available_.",
622  lookup_name.c_str());
624  }
625 
626  std::string library_path = getClassLibraryPath(lookup_name);
627  if ("" == library_path) {
628  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "No path could be found to the library containing %s.",
629  lookup_name.c_str());
630  std::ostringstream error_msg;
631  error_msg << "Could not find library corresponding to plugin " << lookup_name <<
632  ". Make sure the plugin description XML file has the correct name of the "
633  "library and that the library actually exists.";
634  throw pluginlib::LibraryLoadException(error_msg.str());
635  }
636 
637  try {
638  lowlevel_class_loader_.loadLibrary(library_path);
639  it->second.resolved_library_path_ = library_path;
640  } catch (const class_loader::LibraryLoadException & ex) {
641  std::string error_string =
642  "Failed to load library " + library_path + ". "
643  "Make sure that you are calling the PLUGINLIB_EXPORT_CLASS macro in the "
644  "library code, and that names are consistent between this macro and your XML. "
645  "Error string: " + ex.what();
646  throw pluginlib::LibraryLoadException(error_string);
647  }
648 }
649 
650 template<class T>
652  const std::string & xml_file, std::map<std::string,
653  ClassDesc> & classes_available)
654 /***************************************************************************/
655 {
656  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Processing xml file %s...", xml_file.c_str());
657  tinyxml2::XMLDocument document;
658  document.LoadFile(xml_file.c_str());
659  tinyxml2::XMLElement * config = document.RootElement();
660  if (NULL == config) {
662  "XML Document '" + xml_file +
663  "' has no Root Element. This likely means the XML is malformed or missing.");
664  return;
665  }
666  const char* config_value = config->Value();
667  if (NULL == config_value) {
669  "XML Document '" + xml_file +
670  "' has an invalid Root Element. This likely means the XML is malformed or missing.");
671  return;
672  }
673  if (!(strcmp(config_value, "library") == 0 ||
674  strcmp(config_value, "class_libraries") == 0))
675  {
677  "The XML document '" + xml_file + "' given to add must have either \"library\" or "
678  "\"class_libraries\" as the root tag");
679  return;
680  }
681  // Step into the filter list if necessary
682  if (strcmp(config_value, "class_libraries") == 0) {
683  config = config->FirstChildElement("library");
684  }
685 
686  tinyxml2::XMLElement * library = config;
687  while (library != NULL) {
688  const char* path = library->Attribute("path");
689  if (NULL == path) {
690  ROS_ERROR_NAMED("pluginlib.ClassLoader",
691  "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str());
692  continue;
693  }
694  std::string library_path(path);
695  if (0 == library_path.size()) {
696  ROS_ERROR_NAMED("pluginlib.ClassLoader",
697  "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str());
698  continue;
699  }
700 
701  std::string package_name = getPackageFromPluginXMLFilePath(xml_file);
702  if ("" == package_name) {
703  ROS_ERROR_NAMED("pluginlib.ClassLoader",
704  "Could not find package manifest (neither package.xml or deprecated "
705  "manifest.xml) at same directory level as the plugin XML file %s. "
706  "Plugins will likely not be exported properly.\n)",
707  xml_file.c_str());
708  }
709 
710  tinyxml2::XMLElement * class_element = library->FirstChildElement("class");
711  while (class_element) {
712  std::string derived_class;
713  if (class_element->Attribute("type") != NULL) {
714  derived_class = std::string(class_element->Attribute("type"));
715  } else {
717  "Class could not be loaded. Attribute 'type' in class tag is missing.");
718  }
719 
720  std::string base_class_type;
721  if (class_element->Attribute("base_class_type") != NULL) {
722  base_class_type = std::string(class_element->Attribute("base_class_type"));
723  } else {
725  "Class could not be loaded. Attribute 'base_class_type' in class tag is missing.");
726  }
727 
728  std::string lookup_name;
729  if (class_element->Attribute("name") != NULL) {
730  lookup_name = class_element->Attribute("name");
731  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
732  "XML file specifies lookup name (i.e. magic name) = %s.",
733  lookup_name.c_str());
734  } else {
735  ROS_DEBUG_NAMED("pluginlib.ClassLoader",
736  "XML file has no lookup name (i.e. magic name) for class %s, "
737  "assuming lookup_name == real class name.",
738  derived_class.c_str());
739  lookup_name = derived_class;
740  }
741 
742  // make sure that this class is of the right type before registering it
743  if (base_class_type == base_class_) {
744  // register class here
745  tinyxml2::XMLElement * description = class_element->FirstChildElement("description");
746  std::string description_str;
747  if (description) {
748  description_str = description->GetText() ? description->GetText() : "";
749  } else {
750  description_str = "No 'description' tag for this plugin in plugin description file.";
751  }
752 
753  classes_available.insert(std::pair<std::string, ClassDesc>(lookup_name,
754  ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str,
755  library_path, xml_file)));
756  }
757 
758  // step to next class_element
759  class_element = class_element->NextSiblingElement("class");
760  }
761  library = library->NextSiblingElement("library");
762  }
763 }
764 
765 template<class T>
767 /***************************************************************************/
768 {
769  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Refreshing declared classes.");
770  // determine classes not currently loaded for removal
771  std::list<std::string> remove_classes;
772  for (std::map<std::string, ClassDesc>::const_iterator it = classes_available_.begin();
773  it != classes_available_.end(); it++)
774  {
775  std::string resolved_library_path = it->second.resolved_library_path_;
776  std::vector<std::string> open_libs = lowlevel_class_loader_.getRegisteredLibraries();
777  if (std::find(open_libs.begin(), open_libs.end(), resolved_library_path) != open_libs.end()) {
778  remove_classes.push_back(it->first);
779  }
780  }
781 
782  while (!remove_classes.empty()) {
783  classes_available_.erase(remove_classes.front());
784  remove_classes.pop_front();
785  }
786 
787  // add new classes
789  std::map<std::string, ClassDesc> updated_classes = determineAvailableClasses(plugin_xml_paths_);
790  for (std::map<std::string, ClassDesc>::const_iterator it = updated_classes.begin();
791  it != updated_classes.end(); it++)
792  {
793  if (classes_available_.find(it->first) == classes_available_.end()) {
794  classes_available_.insert(std::pair<std::string, ClassDesc>(it->first, it->second));
795  }
796  }
797 }
798 
799 template<class T>
800 std::string ClassLoader<T>::stripAllButFileFromPath(const std::string & path)
801 /***************************************************************************/
802 {
803  std::string only_file;
804  size_t c = path.find_last_of(getPathSeparator());
805  if (std::string::npos == c) {
806  return path;
807  } else {
808  return path.substr(c, path.size());
809  }
810 }
811 
812 template<class T>
813 int ClassLoader<T>::unloadLibraryForClass(const std::string & lookup_name)
814 /***************************************************************************/
815 {
816  ClassMapIterator it = classes_available_.find(lookup_name);
817  if (it != classes_available_.end() && it->second.resolved_library_path_ != "UNRESOLVED") {
818  std::string library_path = it->second.resolved_library_path_;
819  ROS_DEBUG_NAMED("pluginlib.ClassLoader", "Attempting to unload library %s for class %s",
820  library_path.c_str(), lookup_name.c_str());
821  return unloadClassLibraryInternal(library_path);
822  } else {
824  }
825 }
826 
827 template<class T>
828 int ClassLoader<T>::unloadClassLibraryInternal(const std::string & library_path)
829 /***************************************************************************/
830 {
831  return lowlevel_class_loader_.unloadLibrary(library_path);
832 }
833 
834 } // namespace pluginlib
835 
836 #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 Mon Feb 28 2022 23:12:03