introspection.cpp
Go to the documentation of this file.
00001 //=================================================================================================
00002 // Copyright (c) 2011, Johannes Meyer, TU Darmstadt
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 //     * Redistributions of source code must retain the above copyright
00008 //       notice, this list of conditions and the following disclaimer.
00009 //     * Redistributions in binary form must reproduce the above copyright
00010 //       notice, this list of conditions and the following disclaimer in the
00011 //       documentation and/or other materials provided with the distribution.
00012 //     * Neither the name of the Flight Systems and Automatic Control group,
00013 //       TU Darmstadt, nor the names of its contributors may be used to
00014 //       endorse or promote products derived from this software without
00015 //       specific prior written permission.
00016 
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //=================================================================================================
00028 
00029 #include <introspection/field.h>
00030 #include <introspection/type.h>
00031 #include <introspection/introspection.h>
00032 #include <introspection/message_expansion.h>
00033 
00034 #include <dlfcn.h>
00035 
00036 #define BOOST_FILESYSTEM_VERSION 3
00037 #include <boost/filesystem.hpp>
00038 
00039 namespace cpp_introspection {
00040 
00041   static M_Package g_packages;
00042   static V_Package g_repository;
00043   static M_Message g_messages_by_name;
00044   static M_Message g_messages_by_md5sum;
00045   static M_TypeInfo_Message g_messages_by_typeid;
00046   static V_string g_loaded_libraries;
00047 
00048   PackagePtr package(const std::string& pkg)
00049   {
00050     if (!g_packages.count(pkg)) return PackagePtr();
00051     return g_packages[pkg].lock();
00052   }
00053 
00054   const V_Package &packages() {
00055     return g_repository;
00056   }
00057 
00058   MessagePtr messageByDataType(const std::string& data_type, const std::string& package)
00059   {
00060     if (!package.empty()) return messageByDataType(package + "/" + data_type);
00061     if (data_type == "Header") return g_messages_by_name[ros::message_traits::datatype<std_msgs::Header>()].lock();
00062     if (!g_messages_by_name.count(data_type)) return MessagePtr();
00063     return g_messages_by_name[data_type].lock();
00064   }
00065 
00066   MessagePtr messageByMD5Sum(const std::string& md5sum)
00067   {
00068     if (!g_messages_by_md5sum.count(md5sum)) return MessagePtr();
00069     return g_messages_by_md5sum[md5sum].lock();
00070   }
00071 
00072   MessagePtr messageByTypeId(const std::type_info &type_info) {
00073     if (!g_messages_by_typeid.count(&type_info)) return MessagePtr();
00074     return g_messages_by_typeid[&type_info].lock();
00075   }
00076 
00077   PackagePtr Package::add(const PackagePtr& package)
00078   {
00079     if (g_packages.count(package->getName())) return g_packages[package->getName()].lock();
00080     g_repository.push_back(package);
00081     g_packages[package->getName()] = package;
00082     return package;
00083   }
00084 
00085   std::vector<std::string> Package::getMessages() const
00086   {
00087     std::vector<std::string> messages;
00088     for(std::vector<MessagePtr>::const_iterator it = messages_.begin(); it != messages_.end(); ++it)
00089       messages.push_back((*it)->getName());
00090 
00091     return messages;
00092   }
00093 
00094   MessagePtr Package::message(const std::string& message) const
00095   {
00096     return messageByDataType(std::string(getName()) + "/" + message);
00097   }
00098 
00099   MessagePtr Package::add(const MessagePtr& message)
00100   {
00101     if (g_messages_by_name.count(message->getDataType())) return g_messages_by_name[message->getDataType()].lock();
00102     messages_.push_back(message);
00103     g_messages_by_name[message->getDataType()] = message;
00104     g_messages_by_md5sum[message->getMD5Sum()] = message;
00105     g_messages_by_typeid[&(message->getTypeId())] = message;
00106     return message;
00107   }
00108 
00109   MessagePtr expand(const MessagePtr& message, const std::string &separator, const std::string &prefix)
00110   {
00111     return MessagePtr(new ExpandedMessage(message, separator, prefix));
00112   }
00113 
00114   void ExpandedMessage::expand(const MessagePtr &message, const std::string& prefix) {
00115     for(Message::const_iterator i = message->begin(); i != message->end(); i++) {
00116       FieldPtr field = *i;
00117 
00118       for(std::size_t j = 0; j < field->size(); j++) {
00119         std::string field_name = (!prefix.empty() ? prefix + separator_ : "") + field->getName();
00120         if (field->isContainer()) field_name += boost::lexical_cast<std::string>(j);
00121 
00122         if (field->isMessage()) {
00123           MessagePtr expanded(field->expand(j));
00124           if (!expanded) {
00125             ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00126             continue;
00127           }
00128           expand(expanded, field_name);
00129         } else {
00130           FieldPtr expanded(new ExpandedField(*field, field_name, j));
00131           fields_.push_back(expanded);
00132           fields_by_name_[field_name] = expanded;
00133           field_names_.push_back(expanded->getName());
00134         }
00135       }
00136     }
00137   }
00138 
00139   V_string Message::getFields(bool expand, const std::string& separator, const std::string& prefix) const
00140   {
00141     V_string fields;
00142     return getFields(fields, expand, separator, prefix);
00143   }
00144 
00145   V_string& Message::getFields(V_string& fields, bool expand, const std::string& separator, const std::string& prefix) const
00146   {
00147     for(const_iterator it = begin(); it != end(); ++it) {
00148       FieldPtr field = *it;
00149       std::string base(prefix + field->getName());
00150 
00151       for (std::size_t index = 0; index < field->size(); ++index) {
00152         std::string name(base);
00153         if (field->isArray()) name = name + boost::lexical_cast<std::string>(index);
00154 
00155         if (expand && field->isMessage()) {
00156           MessagePtr expanded = field->expand(index);
00157           if (!expanded) {
00158             ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00159             continue;
00160           }
00161           expanded->getFields(fields, expand, separator, name + separator);
00162 
00163         } else {
00164           fields.push_back(name);
00165         }
00166       }
00167     }
00168 
00169     return fields;
00170   }
00171 
00172   V_string Message::getTypes(bool expand) const
00173   {
00174     V_string types;
00175     return getTypes(types, expand);
00176   }
00177 
00178   V_string& Message::getTypes(V_string& types, bool expand) const
00179   {
00180     for(const_iterator it = begin(); it != end(); ++it) {
00181       FieldPtr field = *it;
00182 
00183       for (std::size_t index = 0; index < field->size(); ++index) {
00184         if (expand && field->isMessage()) {
00185           MessagePtr expanded = field->expand(index);
00186           if (!expanded) {
00187             ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00188             continue;
00189           }
00190           expanded->getTypes(types, expand);
00191 
00192         } else {
00193           types.push_back(field->isArray() ? field->getValueType() : field->getDataType());
00194         }
00195       }
00196     }
00197 
00198     return types;
00199   }
00200 
00201   std::vector<boost::any> Message::getValues(bool expand) const
00202   {
00203     std::vector<boost::any> values;
00204     return getValues(values, expand);
00205   }
00206 
00207   std::vector<boost::any>& Message::getValues(std::vector<boost::any>& values, bool expand) const
00208   {
00209     if (!hasInstance()) return values;
00210 
00211     for(const_iterator it = begin(); it != end(); ++it) {
00212       FieldPtr field = *it;
00213 
00214       for (std::size_t index = 0; index < field->size(); ++index) {
00215         if (expand && field->isMessage()) {
00216           MessagePtr expanded = field->expand(index);
00217           if (!expanded) {
00218             ROS_WARN("Expansion of %s failed: Could not expand field %s with unknown type %s", getDataType(), field->getName(), field->getDataType());
00219             continue;
00220           }
00221           expanded->getValues(values, expand);
00222 
00223         } else {
00224           values.push_back(field->get(index));
00225         }
00226       }
00227     }
00228 
00229     return values;
00230   }
00231 
00232   MessagePtr Field::expand(std::size_t i) const {
00233     if (!isMessage()) return MessagePtr();
00234     return messageByTypeId(this->getTypeId());
00235   }
00236 
00237   PackagePtr loadPackage(const std::string &package_name)
00238   {
00239     PackagePtr p = package(package_name);
00240     if (p) return p;
00241     return load("libintrospection_" + package_name + ".so");
00242   }
00243 
00244   using namespace boost::filesystem;
00245   PackagePtr load(const std::string& package_or_library_or_path)
00246   {
00247     path path(package_or_library_or_path);
00248     if (is_directory(path)) {
00249       ROS_DEBUG_STREAM_NAMED(ROS_PACKAGE_NAME, "Searching directory " << path << "...");
00250       for(directory_iterator entry(path); entry != directory_iterator(); ++entry) {
00251         ROS_DEBUG_STREAM_NAMED(ROS_PACKAGE_NAME, "  " << *entry << "...");
00252         if (is_regular_file(entry->path())) load(entry->path().string());
00253       }
00254 
00255       return PackagePtr();
00256     }
00257 
00258     if (path.extension() != ".so") {
00259       loadPackage(package_or_library_or_path);
00260       return PackagePtr();
00261     }
00262     ROS_DEBUG_STREAM_NAMED(ROS_PACKAGE_NAME, "Loading " << path << "...");
00263 
00264     if (std::find(g_loaded_libraries.begin(), g_loaded_libraries.end(), path.filename()) != g_loaded_libraries.end()) {
00265       ROS_WARN_STREAM_NAMED(ROS_PACKAGE_NAME, "library " << path << " already loaded");
00266       return PackagePtr();
00267     }
00268 
00269     void *library = dlopen(path.string().c_str(), RTLD_NOW | RTLD_GLOBAL);
00270     const char *error = dlerror();
00271     if (error || !library) {
00272       ROS_ERROR("%s", error);
00273       return PackagePtr();
00274     }
00275 
00276     typedef PackagePtr (*LoadFunction)();
00277     LoadFunction load_fcn = (LoadFunction) dlsym(library, "cpp_introspection_load_package");
00278     error = dlerror();
00279     if (error || !load_fcn) {
00280       ROS_WARN_NAMED(ROS_PACKAGE_NAME, "%s", error);
00281       dlclose(library);
00282       return PackagePtr();
00283     }
00284     PackagePtr package __attribute__((unused)) = (*load_fcn)();
00285 
00286     ROS_INFO_STREAM_NAMED(ROS_PACKAGE_NAME, "Successfully loaded cpp_introspection library " << path);
00287     g_loaded_libraries.push_back(path.filename().string());
00288 
00289 //      for(Package::const_iterator it = package->begin(); it != package->end(); ++it) {
00290 //        ROS_INFO_STREAM_NAMED(ROS_PACKAGE_NAME, "Package " << package->getName() << " contains message " << (*it)->getName() << ":");
00291 //        V_string types = (*it)->getTypes();
00292 //        V_string names = (*it)->getFields();
00293 //        for(V_string::const_iterator it_type = types.begin(), it_name = names.begin(); it_type != types.end() && it_name != names.end(); ++it_type, ++it_name) {
00294 //          ROS_INFO("  %s %s", it_type->c_str(), it_name->c_str());
00295 //        }
00296 //      }
00297 
00298     return package;
00299   }
00300 
00301 } // namespace cpp_introspection


cpp_introspection
Author(s): Johannes Meyer
autogenerated on Sun Oct 5 2014 23:17:53