00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #ifndef PLUGINLIB_CLASS_LOADER_IMP_H_
00041 #define PLUGINLIB_CLASS_LOADER_IMP_H_
00042
00043 #include <stdexcept>
00044
00045 namespace pluginlib {
00046 template <class T>
00047 ClassLoader<T>::ClassLoader(std::string package, std::string base_class, std::string attrib_name) : base_class_(base_class)
00048 {
00049
00050 std::vector<std::string> paths;
00051 ros::package::getPlugins(package, attrib_name, paths);
00052 if (paths.size() == 0)
00053 {
00054 std::string error_string = "rospack could not find the " + package + " package containing " + base_class;
00055 throw LibraryLoadException(error_string);
00056 }
00057
00058
00059 for (std::vector<std::string>::iterator it = paths.begin(); it != paths.end(); ++it)
00060 {
00061 TiXmlDocument document;
00062 document.LoadFile(*it);
00063 TiXmlElement * config = document.RootElement();
00064 if (config == NULL)
00065 {
00066 ROS_ERROR("XML Document \"%s\" had no Root Element. This likely means the XML is malformed or missing.", it->c_str());
00067 return;
00068 }
00069 if (config->ValueStr() != "library" &&
00070 config->ValueStr() != "class_libraries")
00071 {
00072 ROS_ERROR("The XML given to add must have either \"library\" or \
00073 \"class_libraries\" as the root tag");
00074 return ;
00075 }
00076
00077 if (config->ValueStr() == "class_libraries")
00078 {
00079 config = config->FirstChildElement("library");
00080 }
00081
00082 TiXmlElement* library = config;
00083 while ( library != NULL)
00084 {
00085 std::string library_path = library->Attribute("path");
00086 if (library_path.size() == 0)
00087 {
00088 ROS_ERROR("Failed to find Path Attirbute in library element in %s", it->c_str());
00089 continue;
00090 }
00091
00092
00093 std::string package_name = pluginlib::getPackageFromLibraryPath(*it);
00094 if (package_name == "")
00095 ROS_ERROR("Could not find package name for class %s", it->c_str());
00096
00097 std::string parent_dir = ros::package::getPath(package_name);
00098 std::string full_library_path = joinPaths(parent_dir , library_path);
00099
00100 TiXmlElement* class_element = library->FirstChildElement("class");
00101 while (class_element)
00102 {
00103 std::string base_class_type = class_element->Attribute("base_class_type");
00104 std::string lookup_name = class_element->Attribute("name");
00105 std::string derived_class = class_element->Attribute("type");
00106
00107
00108
00109 if(base_class_type == base_class){
00110
00111
00112 TiXmlElement* description = class_element->FirstChildElement("description");
00113 std::string description_str;
00114 if (description)
00115 description_str = description->GetText() ? description->GetText() : "";
00116 else
00117 description_str = "No 'description' tag for this plugin in plugin description file.";
00118
00119 classes_available_.insert(std::pair<std::string, ClassDesc>(lookup_name, ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str, full_library_path)));
00120 ROS_DEBUG("MATCHED Base type for class with name: %s type: %s base_class_type: %s Expecting base_class_type %s",
00121 lookup_name.c_str(), derived_class.c_str(), base_class_type.c_str(), base_class.c_str());
00122 }
00123 else
00124 {
00125 ROS_DEBUG("UNMATCHED Base type for class with name: %s type: %s base_class_type: %s Expecting base_class_type %s",
00126 lookup_name.c_str(), derived_class.c_str(), base_class_type.c_str(), base_class.c_str());
00127
00128 }
00129
00130 class_element = class_element->NextSiblingElement( "class" );
00131 }
00132 library = library->NextSiblingElement( "library" );
00133 }
00134 }
00135 }
00136
00137 template <class T>
00138 void ClassLoader<T>::loadLibraryForClass(const std::string & lookup_name)
00139 {
00140 std::string library_path;
00141 ClassMapIterator it = classes_available_.find(lookup_name);
00142 if (it != classes_available_.end()){
00143 library_path = it->second.library_path_;
00144 }
00145 else
00146 {
00147
00148 std::string declared_types;
00149 std::vector<std::string> types = getDeclaredClasses();
00150 for ( unsigned int i = 0; i < types.size(); i ++)
00151 {
00152 declared_types = declared_types + std::string(" ") + types[i];
00153 }
00154 std::string error_string = "According to the loaded plugin descriptions the class " + lookup_name
00155 + " with base class type " + base_class_ + " does not exist. Declared types are " + declared_types;
00156 throw LibraryLoadException(error_string);
00157 }
00158 library_path.append(Poco::SharedLibrary::suffix());
00159 try
00160 {
00161 ROS_DEBUG("Attempting to load library %s for class %s",
00162 library_path.c_str(), lookup_name.c_str());
00163
00164 loadClassLibraryInternal(library_path, lookup_name);
00165 }
00166 catch (Poco::LibraryLoadException &ex)
00167 {
00168 std::string error_string = "Failed to load library " + library_path + ". Make sure that you are calling the PLUGINLIB_REGISTER_CLASS macro in the library code, and that names are consistent between this macro and your XML. Error string: " + ex.displayText();
00169 throw LibraryLoadException(error_string);
00170 }
00171 catch (Poco::NotFoundException &ex)
00172 {
00173 std::string error_string = "Failed to find library " + library_path + ". Are you sure that the library you need has been built? Error string: " + ex.displayText();
00174 throw LibraryLoadException(error_string);
00175 }
00176 }
00177
00178 template <class T>
00179 ClassLoader<T>::~ClassLoader()
00180 {
00181 for (LibraryCountMap::iterator it = loaded_libraries_.begin(); it != loaded_libraries_.end(); ++it)
00182 {
00183 if ( it->second > 0)
00184 unloadClassLibrary(it->first);
00185 }
00186 }
00187
00188
00189 template <class T>
00190 bool ClassLoader<T>::isClassLoaded(const std::string& lookup_name)
00191 {
00192 try
00193 {
00194 return poco_class_loader_.canCreate(getClassType(lookup_name));
00195 }
00196 catch (Poco::RuntimeException &ex)
00197 {
00198 return false;
00199 }
00200 }
00201
00202 template <class T>
00203 std::vector<std::string> ClassLoader<T>::getDeclaredClasses()
00204 {
00205 std::vector<std::string> lookup_names;
00206 for (ClassMapIterator it = classes_available_.begin(); it != classes_available_.end(); ++it)
00207 {
00208 lookup_names.push_back(it->first);
00209 }
00210 return lookup_names;
00211 }
00212
00213 template <class T>
00214 std::string ClassLoader<T>::getName(const std::string& lookup_name)
00215 {
00216
00217 std::vector<std::string> split;
00218 boost::split(split, lookup_name, boost::is_any_of("/"));
00219 return split.back();
00220 }
00221
00222 template <class T>
00223 bool ClassLoader<T>::isClassAvailable(const std::string& lookup_name)
00224 {
00225 return classes_available_.find(lookup_name) != classes_available_.end();
00226 }
00227
00228 template <class T>
00229 std::string ClassLoader<T>::getClassType(const std::string& lookup_name)
00230 {
00231 ClassMapIterator it = classes_available_.find(lookup_name);
00232 if (it != classes_available_.end())
00233 return it->second.derived_class_;
00234 return "";
00235 }
00236
00237 template <class T>
00238 std::string ClassLoader<T>::getClassDescription(const std::string& lookup_name)
00239 {
00240 ClassMapIterator it = classes_available_.find(lookup_name);
00241 if (it != classes_available_.end())
00242 return it->second.description_;
00243 return "";
00244 }
00245
00246 template <class T>
00247 std::string ClassLoader<T>::getBaseClassType() const
00248 {
00249 return base_class_;
00250 }
00251
00252 template <class T>
00253 std::string ClassLoader<T>::getClassLibraryPath(const std::string& lookup_name)
00254 {
00255 ClassMapIterator it = classes_available_.find(lookup_name);
00256 if (it != classes_available_.end())
00257 return it->second.library_path_;
00258 return "";
00259 }
00260
00261 template <class T>
00262 std::string ClassLoader<T>::getClassPackage(const std::string& lookup_name)
00263 {
00264 ClassMapIterator it = classes_available_.find(lookup_name);
00265 if (it != classes_available_.end())
00266 return it->second.package_;
00267 return "";
00268 }
00269
00270 template <class T>
00271 T* ClassLoader<T>::createClassInstance(const std::string& lookup_name, bool auto_load)
00272 {
00273 if(auto_load && !isClassLoaded(lookup_name))
00274 loadLibraryForClass(lookup_name);
00275
00276 try{
00277 return poco_class_loader_.create(getClassType(lookup_name));
00278 }
00279 catch(const Poco::RuntimeException& ex){
00280 std::string error_string = "The class " + lookup_name + " could not be loaded. Error: " + ex.displayText();
00281 throw CreateClassException(error_string);
00282 }
00283 }
00284
00285 template <class T>
00286 bool ClassLoader<T>::unloadClassLibrary(const std::string& library_path)
00287 {
00288 LibraryCountMap::iterator it = loaded_libraries_.find(library_path);
00289 if (it == loaded_libraries_.end())
00290 {
00291 ROS_DEBUG("unable to unload library which is not loaded");
00292 return false;
00293 }
00294 else if (it-> second > 1)
00295 (it->second)--;
00296 else
00297 poco_class_loader_.unloadLibrary(library_path);
00298
00299 return true;
00300
00301 }
00302
00303 template <class T>
00304 bool ClassLoader<T>::loadClassLibrary(const std::string& library_path){
00305 try
00306 {
00307 loadClassLibraryInternal(library_path);
00308 }
00309 catch (Poco::LibraryLoadException &ex)
00310 {
00311 return false;
00312 }
00313 catch (Poco::NotFoundException &ex)
00314 {
00315 return false;
00316 }
00317 return true;
00318 }
00319
00320 template <class T>
00321 void ClassLoader<T>::loadClassLibraryInternal(const std::string& library_path, const std::string& list_name_arg) {
00322 std::string list_name = list_name_arg;
00323 boost::replace_first(list_name, "/", "__");
00324
00325 poco_class_loader_.loadLibrary(library_path, list_name);
00326 LibraryCountMap::iterator it = loaded_libraries_.find(library_path);
00327 if (it == loaded_libraries_.end())
00328 loaded_libraries_[library_path] = 1;
00329 else
00330 loaded_libraries_[library_path] = loaded_libraries_[library_path] + 1;
00331 }
00332
00333 template <class T>
00334 std::vector<std::string> ClassLoader<T>::getClassesInLibrary(const std::string & library_path)
00335 {
00336 std::vector<std::string> lookup_names;
00337
00338
00339 const Poco::Manifest<T> * manifest = poco_class_loader_.findManifest(library_path);
00340 if (manifest == NULL)
00341 return lookup_names;
00342
00343 for (typename Poco::Manifest<T>::Iterator it = manifest->begin(); it != manifest->end(); ++it)
00344 {
00345 std::string name = it->name();
00346 boost::replace_first(name, "__", "/");
00347 lookup_names.push_back(name);
00348 }
00349 return lookup_names;
00350 }
00351
00352 template <class T>
00353 std::vector<std::string> ClassLoader<T>::getRegisteredLibraries()
00354 {
00355 std::vector<std::string> library_names;
00356 for (ClassMapIterator it = classes_available_.begin(); it != classes_available_.end(); it++){
00357 bool duplicate = false;
00358 for (unsigned int i=0; i<library_names.size(); i++)
00359 if (it->second.library_path_ == library_names[i])
00360 duplicate = true;
00361 if (!duplicate)
00362 library_names.push_back(it->second.library_path_);
00363 }
00364 return library_names;
00365 }
00366
00367
00368 template <class T>
00369 std::vector<std::string> ClassLoader<T>::getLoadedLibraries()
00370 {
00371 std::vector<std::string> library_names;
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 LibraryCountMap::iterator it;
00382 for (it = loaded_libraries_.begin(); it != loaded_libraries_.end(); it++)
00383 {
00384 if (it->second > 0)
00385 library_names.push_back(it->first);
00386 }
00387 return library_names;
00388 }
00389 };
00390
00391 #endif