plugin.cpp
Go to the documentation of this file.
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 "rve_pluginloader/plugin.h"
00031 #include "rve_pluginloader/type_registry.h"
00032 
00033 #include <iostream>
00034 #include <fstream>
00035 #include <yaml-cpp/yaml.h>
00036 
00037 #include <ros/assert.h>
00038 #include <ros/package.h>
00039 #include <ros/debug.h>
00040 
00041 #include <boost/filesystem.hpp>
00042 
00043 namespace fs = boost::filesystem;
00044 
00045 namespace rve_pluginloader
00046 {
00047 
00048 Plugin::Plugin()
00049 : loaded_(false)
00050 , doc_(0)
00051 {
00052 
00053 }
00054 
00055 Plugin::~Plugin()
00056 {
00057   unload(false);
00058 
00059   delete doc_;
00060 }
00061 
00062 void Plugin::loadDescription(const std::string& description_path)
00063 {
00064   description_path_ = description_path;
00065 
00066   std::ifstream fin(description_path.c_str());
00067 
00068   try
00069   {
00070     YAML::Parser parser(fin);
00071     doc_ = new YAML::Node;
00072     YAML::Node& doc = *doc_;
00073     parser.GetNextDocument(doc);
00074 
00075     std::string library;
00076     doc["library"] >> library;
00077 
00078     fs::path p(description_path);
00079     fs::path parent = p.parent_path();
00080     // figure out the package this plugin is part of
00081     while (true)
00082     {
00083       if (fs::exists(parent / "manifest.xml"))
00084       {
00085         std::string package = parent.filename();
00086         std::string package_path = ros::package::getPath(package);
00087         if (description_path.find(package_path) == 0)
00088         {
00089           package_name_ = package;
00090           package_path_ = package_path;
00091           break;
00092         }
00093       }
00094 
00095       parent = parent.parent_path();
00096 
00097       if (parent.string().empty())
00098       {
00099         ROS_ERROR("Could not find package name for plugin [%s]", description_path.c_str());
00100         break;
00101       }
00102     }
00103 
00104     std::string library_dir = (fs::path(package_path_) / (fs::path(library).parent_path())).string();
00105     std::string library_name = fs::path(library).filename();
00106     library_path_ = (fs::path(library_dir) / fs::path(rve_dynlib::prefix() + library_name + rve_dynlib::suffix())).string();
00107 
00108     doc["name"] >> name_;
00109   }
00110   catch (YAML::ParserException& e)
00111   {
00112     throw PluginParseException(description_path, e.msg);
00113   }
00114   catch (YAML::RepresentationException& e)
00115   {
00116     throw PluginParseException(description_path, e.msg);
00117   }
00118 }
00119 
00120 void Plugin::load()
00121 {
00122   if (loaded_)
00123   {
00124     return;
00125   }
00126 
00127   loading_signal_(PluginStatus(this));
00128 
00129   if (!fs::exists(library_path_))
00130   {
00131     throw LibraryDoesNotExistException(library_path_);
00132   }
00133 
00134   try
00135   {
00136     library_ = rve_dynlib::load(library_path_);
00137   }
00138   catch (rve_dynlib::LibraryLoadException& e)
00139   {
00140     throw LibraryLoadException(library_path_, e.what());
00141   }
00142 
00143   if (!rve_dynlib::hasSymbol(library_, "rvePluginRegister"))
00144   {
00145     throw NoPluginRegisterFunctionException(library_path_);
00146   }
00147 
00148   typedef void (*RegisterFunc)(TypeRegistry*);
00149   RegisterFunc init = reinterpret_cast<RegisterFunc>(rve_dynlib::getSymbol(library_, "rvePluginRegister"));
00150 
00151   TypeRegistry reg(package_name_);
00152   (*init)(&reg);
00153 
00154   class_entries_ = reg.getClassEntries();
00155 
00156   loaded_ = true;
00157   loaded_signal_(PluginStatus(this));
00158 }
00159 
00160 const V_ClassEntry* Plugin::getClassEntries(const std::string& base_class) const
00161 {
00162   M_ClassEntry::const_iterator it = class_entries_.find(base_class);
00163   if (it == class_entries_.end())
00164   {
00165     return 0;
00166   }
00167 
00168   return &it->second;
00169 }
00170 
00171 void Plugin::unload()
00172 {
00173   unload(true);
00174 }
00175 
00176 void Plugin::unload(bool allow_throw)
00177 {
00178   if (!loaded_)
00179   {
00180     return;
00181   }
00182 
00183   unloading_signal_(PluginStatus(this));
00184 
00185   // Check for outstanding allocations.  At this point no class created from this plugin should still exist.
00186   // Otherwise a crash is very likely when the library gets unloaded
00187   if (!allocations_.empty())
00188   {
00189     std::stringstream ss;
00190     ss << "Plugin loaded from [" << description_path_ << "] still has outstanding allocations:\n";
00191 
00192     M_AllocationInfo::iterator it = allocations_.begin();
00193     M_AllocationInfo::iterator end = allocations_.end();
00194     for (; it != end; ++it)
00195     {
00196       AllocationInfo& info = it->second;
00197       ss << "====================================================\n";
00198       ss << "Base Class: " << info.base_class << "\n";
00199       ss << "Derived Class: " << info.derived_class << "\n";
00200       ss << "Pointer Address: " << info.pointer << "\n";
00201 
00202       std::string backtrace  = ros::debug::backtraceToString(info.backtrace);
00203       ss << "Allocated from:\n";
00204       ss << backtrace;
00205     }
00206 
00207     if (allow_throw)
00208     {
00209       throw OutstandingAllocationException(ss.str());
00210     }
00211     else
00212     {
00213       ROS_ERROR_STREAM(ss.str());
00214     }
00215   }
00216 
00217   class_entries_.clear();
00218 
00219   rve_dynlib::unload(library_);
00220   loaded_ = false;
00221 
00222   unloaded_signal_(PluginStatus(this));
00223 }
00224 
00225 bool Plugin::isLoaded()
00226 {
00227   return loaded_;
00228 }
00229 
00230 bool Plugin::hasClass(const std::string& base_class, const std::string& derived_class) const
00231 {
00232   try
00233   {
00234     getClassEntry(base_class, derived_class);
00235   }
00236   catch (PluginDoesNotContainClassException&)
00237   {
00238     return false;
00239   }
00240 
00241   return true;
00242 }
00243 
00244 const ClassEntryPtr& Plugin::getClassEntry(const std::string& base_class, const std::string& derived_class) const
00245 {
00246   M_ClassEntry::const_iterator it = class_entries_.find(base_class);
00247   if (it == class_entries_.end())
00248   {
00249     throw PluginDoesNotContainClassException(package_name_, derived_class);
00250   }
00251 
00252   V_ClassEntry::const_iterator lit = it->second.begin();
00253   V_ClassEntry::const_iterator lend = it->second.end();
00254   for (; lit != lend; ++lit)
00255   {
00256     const ClassEntryPtr& entry = *lit;
00257     if (entry->class_name == derived_class)
00258     {
00259       return entry;
00260     }
00261   }
00262 
00263   throw PluginDoesNotContainClassException(package_name_, derived_class);
00264 }
00265 
00266 void* Plugin::create(const std::string& base_class, const std::string& derived_class)
00267 {
00268   const ClassEntryPtr& ent = getClassEntry(base_class, derived_class);
00269   void* mem = ent->creator->create();
00270   AllocationInfo info;
00271   info.base_class = base_class;
00272   info.derived_class = derived_class;
00273   info.pointer = mem;
00274   ros::debug::getBacktrace(info.backtrace);
00275   allocations_.insert(std::make_pair(mem, info));
00276   return mem;
00277 }
00278 
00279 struct ClassDeleter
00280 {
00281   ClassDeleter(Plugin* plugin)
00282   : plugin_(plugin)
00283   {}
00284 
00285   void operator()(void* mem)
00286   {
00287     plugin_->destroy(mem);
00288   }
00289 
00290   Plugin* plugin_;
00291 };
00292 
00293 boost::shared_ptr<void> Plugin::createShared(const std::string& base_class, const std::string& derived_class)
00294 {
00295   return boost::shared_ptr<void>(create(base_class, derived_class), ClassDeleter(this));
00296 }
00297 
00298 void Plugin::destroy(void* mem)
00299 {
00300   M_AllocationInfo::iterator it = allocations_.find(mem);
00301   ROS_ASSERT(it != allocations_.end());
00302   allocations_.erase(it);
00303 }
00304 
00305 bool Plugin::ownsAllocation(void* mem)
00306 {
00307   M_AllocationInfo::iterator it = allocations_.find(mem);
00308   return it != allocations_.end();
00309 }
00310 
00311 }


rve_pluginloader
Author(s): Josh Faust
autogenerated on Wed Dec 11 2013 14:31:46