$search
00001 /* 00002 * Copyright (c) 2009, Willow Garage, Inc. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the Willow Garage, Inc. nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "plugin.h" 00031 #include "type_registry.h" 00032 00033 #include <iostream> 00034 #include <fstream> 00035 #include <yaml-cpp/yaml.h> 00036 00037 #include <ros/console.h> 00038 #include <ros/package.h> 00039 00040 #include <boost/filesystem.hpp> 00041 00042 namespace fs = boost::filesystem; 00043 00044 namespace rviz 00045 { 00046 00047 Plugin::Plugin() 00048 : loaded_(false) 00049 , auto_load_(true) 00050 , auto_load_tried_(false) 00051 , doc_(0) 00052 { 00053 00054 } 00055 00056 Plugin::~Plugin() 00057 { 00058 unload(); 00059 00060 delete doc_; 00061 } 00062 00063 void Plugin::loadDescription(const std::string& description_path) 00064 { 00065 description_path_ = description_path; 00066 00067 std::ifstream fin(description_path.c_str()); 00068 00069 try 00070 { 00071 YAML::Parser parser(fin); 00072 doc_ = new YAML::Node; 00073 YAML::Node& doc = *doc_; 00074 parser.GetNextDocument(doc); 00075 00076 std::string library; 00077 doc["library"] >> library; 00078 00079 fs::path p(description_path); 00080 fs::path parent = p.parent_path(); 00081 // figure out the package this plugin is part of 00082 while (true) 00083 { 00084 if (fs::exists(parent / "manifest.xml")) 00085 { 00086 #if BOOST_FILESYSTEM_VERSION == 3 00087 std::string package = parent.filename().string(); 00088 #else 00089 std::string package = parent.filename(); 00090 #endif 00091 std::string package_path = ros::package::getPath(package); 00092 if (description_path.find(package_path) == 0) 00093 { 00094 package_name_ = package; 00095 break; 00096 } 00097 } 00098 00099 parent = parent.parent_path(); 00100 00101 if (parent.string().empty()) 00102 { 00103 ROS_ERROR("Could not find package name for plugin [%s]", description_path.c_str()); 00104 break; 00105 } 00106 } 00107 00108 library_path_ = (p.parent_path() / fs::path((const char*)wxDynamicLibrary::CanonicalizeName(wxString::FromAscii(library.c_str()), wxDL_LIBRARY).char_str())).string(); 00109 00110 // wxMac returns .bundle, we want .so for now (until I figure out how to get cmake to build bundles) 00111 #if __WXMAC__ 00112 fs::path mac_path(library_path_); 00113 mac_path.replace_extension(".so"); 00114 library_path_ = mac_path.string(); 00115 #endif 00116 00117 doc["name"] >> name_; 00118 00119 const YAML::Node& displays = doc["displays"]; 00120 for (uint32_t i = 0; i < displays.size(); ++i) 00121 { 00122 const YAML::Node& n = displays[i]; 00123 DisplayTypeInfoPtr info(new DisplayTypeInfo); 00124 info->package = package_name_; 00125 00126 //n.Write(std::cout, 0, true, false); 00127 00128 n["class_name"] >> info->class_name; 00129 n["display_name"] >> info->display_name; 00130 n["description"] >> info->help_description; 00131 00132 display_info_.push_back(info); 00133 } 00134 00135 // find old display class name mappings 00136 try 00137 { 00138 const YAML::Node& n = doc["display_class_mapping"]; 00139 for (uint32_t i = 0; i < n.size(); ++i) 00140 { 00141 const YAML::Node& mapping = n[i]; 00142 std::string old_class, new_class; 00143 mapping["old_class"] >> old_class; 00144 mapping["new_class"] >> new_class; 00145 display_class_mappings_[old_class] = new_class; 00146 } 00147 } 00148 catch (YAML::RepresentationException& e) 00149 { 00150 } 00151 00152 // find old display name mappings 00153 try 00154 { 00155 const YAML::Node& n = doc["display_name_mapping"]; 00156 for (uint32_t i = 0; i < n.size(); ++i) 00157 { 00158 const YAML::Node& mapping = n[i]; 00159 std::string old_class, new_class; 00160 mapping["old_name"] >> old_class; 00161 mapping["new_name"] >> new_class; 00162 display_name_mappings_[old_class] = new_class; 00163 } 00164 } 00165 catch (YAML::RepresentationException& e) 00166 { 00167 } 00168 } 00169 catch (YAML::ParserException& e) 00170 { 00171 throw PluginParseException(description_path, e.msg); 00172 } 00173 catch (YAML::RepresentationException& e) 00174 { 00175 throw PluginParseException(description_path, e.msg); 00176 } 00177 } 00178 00179 void Plugin::load() 00180 { 00181 if (loaded_) 00182 { 00183 return; 00184 } 00185 00186 loading_signal_(PluginStatus(this)); 00187 00188 if (!fs::exists(library_path_)) 00189 { 00190 throw LibraryDoesNotExistException(library_path_); 00191 } 00192 00193 if (!library_.Load(wxString::FromAscii(library_path_.c_str()))) 00194 { 00195 throw UnableToLoadLibraryException(library_path_); 00196 } 00197 00198 if (!library_.HasSymbol(wxT("rvizPluginInit"))) 00199 { 00200 throw NoPluginInitFunctionException(library_path_); 00201 } 00202 00203 typedef void (*InitFunc)(TypeRegistry*); 00204 InitFunc init = reinterpret_cast<InitFunc>(library_.GetSymbol(wxT("rvizPluginInit"))); 00205 00206 TypeRegistry reg; 00207 (*init)(®); 00208 00209 { 00210 L_DisplayEntry::const_iterator it = reg.getDisplayEntries().begin(); 00211 L_DisplayEntry::const_iterator end = reg.getDisplayEntries().end(); 00212 for (; it != end; ++it) 00213 { 00214 const DisplayEntry& ent = *it; 00215 DisplayTypeInfoPtr info = getDisplayTypeInfo(ent.class_name); 00216 if (!info) 00217 { 00218 ROS_ERROR("Display with class name [%s] did not exist in the plugin yaml file.", ent.class_name.c_str()); 00219 info.reset(new DisplayTypeInfo); 00220 info->class_name = ent.class_name; 00221 } 00222 00223 if (info->display_name.empty()) 00224 { 00225 info->display_name = info->class_name; 00226 } 00227 00228 info->creator = ent.creator; 00229 } 00230 } 00231 00232 { 00233 M_ClassEntry::const_iterator it = reg.getClassEntries().begin(); 00234 M_ClassEntry::const_iterator end = reg.getClassEntries().end(); 00235 for (; it != end; ++it) 00236 { 00237 const std::string& base_class = it->first; 00238 const L_ClassEntry& entries = it->second; 00239 L_ClassEntry::const_iterator ent_it = entries.begin(); 00240 L_ClassEntry::const_iterator ent_end = entries.end(); 00241 for (; ent_it != ent_end; ++ent_it) 00242 { 00243 const ClassEntry& ent = *ent_it; 00244 ClassTypeInfoPtr info(new ClassTypeInfo); 00245 info->base_class_name = base_class; 00246 info->class_name = ent.class_name; 00247 info->readable_name = ent.readable_name; 00248 info->creator = ent.creator; 00249 info->package = package_name_; 00250 class_info_[base_class].push_back(info); 00251 } 00252 } 00253 } 00254 00255 loaded_ = true; 00256 loaded_signal_(PluginStatus(this)); 00257 } 00258 00259 const L_ClassTypeInfo* Plugin::getClassTypeInfoList(const std::string& base_class) const 00260 { 00261 M_ClassTypeInfo::const_iterator it = class_info_.find(base_class); 00262 if (it == class_info_.end()) 00263 { 00264 return 0; 00265 } 00266 00267 return &it->second; 00268 } 00269 00270 void Plugin::unload() 00271 { 00272 if (!loaded_) 00273 { 00274 return; 00275 } 00276 00277 unloading_signal_(PluginStatus(this)); 00278 00279 { 00280 L_DisplayTypeInfo::iterator it = display_info_.begin(); 00281 L_DisplayTypeInfo::iterator end = display_info_.end(); 00282 for (; it != end; ++it) 00283 { 00284 (*it)->creator.reset(); 00285 } 00286 } 00287 00288 class_info_.clear(); 00289 00290 library_.Unload(); 00291 loaded_ = false; 00292 00293 unloaded_signal_(PluginStatus(this)); 00294 } 00295 00296 bool Plugin::isLoaded() 00297 { 00298 return loaded_; 00299 } 00300 00301 bool Plugin::isAutoLoad() 00302 { 00303 return auto_load_; 00304 } 00305 00306 void Plugin::setAutoLoad(bool autoload) 00307 { 00308 auto_load_ = autoload; 00309 } 00310 00311 const std::string& Plugin::mapDisplayClassName(const std::string& class_name) const 00312 { 00313 M_string::const_iterator it = display_class_mappings_.find(class_name); 00314 if (it == display_class_mappings_.end()) 00315 { 00316 return class_name; 00317 } 00318 00319 return it->second; 00320 } 00321 00322 DisplayTypeInfoPtr Plugin::getDisplayTypeInfo(const std::string& class_name) const 00323 { 00324 std::string mapped_name = mapDisplayClassName(class_name); 00325 L_DisplayTypeInfo::const_iterator it = display_info_.begin(); 00326 L_DisplayTypeInfo::const_iterator end = display_info_.end(); 00327 for (; it != end; ++it) 00328 { 00329 const DisplayTypeInfoPtr& info = *it; 00330 if (info->class_name == mapped_name) 00331 { 00332 return info; 00333 } 00334 } 00335 00336 return DisplayTypeInfoPtr(); 00337 } 00338 00339 const std::string& Plugin::mapDisplayName(const std::string& name) const 00340 { 00341 M_string::const_iterator it = display_name_mappings_.find(name); 00342 if (it == display_name_mappings_.end()) 00343 { 00344 return name; 00345 } 00346 00347 return it->second; 00348 } 00349 00350 DisplayTypeInfoPtr Plugin::getDisplayTypeInfoByDisplayName(const std::string& display_name) const 00351 { 00352 std::string mapped_name = mapDisplayName(display_name); 00353 L_DisplayTypeInfo::const_iterator it = display_info_.begin(); 00354 L_DisplayTypeInfo::const_iterator end = display_info_.end(); 00355 for (; it != end; ++it) 00356 { 00357 const DisplayTypeInfoPtr& info = *it; 00358 if (info->display_name == mapped_name) 00359 { 00360 return info; 00361 } 00362 } 00363 00364 return DisplayTypeInfoPtr(); 00365 } 00366 00367 void Plugin::autoLoad() 00368 { 00369 if (auto_load_tried_ || loaded_ || !auto_load_) 00370 { 00371 return; 00372 } 00373 00374 try 00375 { 00376 load(); 00377 } 00378 catch (LibraryDoesNotExistException&) 00379 { 00380 } 00381 catch (std::runtime_error& e) 00382 { 00383 ROS_ERROR("%s", e.what()); 00384 } 00385 } 00386 00387 Display* Plugin::createDisplay(const std::string& class_name, const std::string& name, VisualizationManager* manager) 00388 { 00389 autoLoad(); 00390 00391 DisplayTypeInfoPtr typeinfo = getDisplayTypeInfo(class_name); 00392 if (!typeinfo || !typeinfo->creator) 00393 { 00394 return 0; 00395 } 00396 00397 return typeinfo->creator->create(name, manager); 00398 } 00399 00400 }