property_node.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, 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_properties/property_node.h>
00031 
00032 #include <boost/algorithm/string/split.hpp>
00033 #include <boost/algorithm/string/join.hpp>
00034 #include <boost/algorithm/string/trim.hpp>
00035 #include <boost/bind.hpp>
00036 
00037 #include <vector>
00038 
00039 #include <ros/assert.h>
00040 
00041 #include <ros/callback_queue_interface.h>
00042 
00043 namespace rve_properties
00044 {
00045 
00046 PropertyNode::PropertyNode()
00047 : parent_(0)
00048 , children_(0)
00049 , change_callbacks_(0)
00050 {
00051 }
00052 
00053 PropertyNode::~PropertyNode()
00054 {
00055   delete children_;
00056   delete change_callbacks_;
00057 }
00058 
00059 void PropertyNode::setParent(PropertyNode* parent, const std::string& name, bool remove_from_previous)
00060 {
00061   PropertyNodePtr this_ptr = shared_from_this();
00062 
00063   if (parent_)
00064   {
00065     parent_->fireChanged(this_ptr, name_, PropertyRemoved);
00066 
00067     if (remove_from_previous)
00068     {
00069       parent_->removeNode(name_);
00070     }
00071   }
00072 
00073   parent_ = parent;
00074   name_ = name;
00075 
00076   if (parent_)
00077   {
00078     parent_->fireChanged(this_ptr, name_, PropertyAdded);
00079   }
00080 }
00081 
00082 bool PropertyNode::hasValue()
00083 {
00084   return data_.value.filled();
00085 }
00086 
00087 PropertyNodePtr PropertyNode::getNode(const std::string& _path, bool create_if_necessary)
00088 {
00089   std::string path = _path;
00090   boost::trim(path);
00091   if (path.empty())
00092   {
00093     return shared_from_this();
00094   }
00095 
00096   typedef std::vector<std::string> V_string;
00097   V_string split_path;
00098   boost::split(split_path, path, boost::is_any_of("/"), boost::token_compress_on);
00099 
00100   if (split_path.empty())
00101   {
00102     return shared_from_this();
00103   }
00104 
00105   PropertyNodePtr node = shared_from_this();
00106 
00107   V_string::iterator it = split_path.begin();
00108   V_string::iterator end = split_path.end();
00109   for (; it != end; ++it)
00110   {
00111     const std::string& prop = *it;
00112 
00113     bool created_new_node = false;
00114     PropertyNodePtr parent;
00115     {
00116       boost::recursive_mutex::scoped_lock lock(node->mutex_);
00117 
00118       if (!node->children_)
00119       {
00120         if (!create_if_necessary)
00121         {
00122           return PropertyNodePtr();
00123         }
00124 
00125         node->children_ = new M_PropertyNode;
00126       }
00127 
00128       M_PropertyNode::iterator child_it = node->children_->find(prop);
00129       if (child_it != node->children_->end())
00130       {
00131         node = child_it->second;
00132       }
00133       else
00134       {
00135         if (!create_if_necessary)
00136         {
00137           return PropertyNodePtr();
00138         }
00139 
00140         PropertyNodePtr new_node(new PropertyNode);
00141         node->children_->insert(std::make_pair(prop, new_node));
00142         parent = node;
00143         node = new_node;
00144         created_new_node = true;
00145       }
00146     }
00147 
00148     if (created_new_node)
00149     {
00150       node->setParent(parent.get(), prop, true);
00151     }
00152   }
00153 
00154   return node;
00155 }
00156 
00157 std::pair<PropertyNodePtr, std::string> PropertyNode::getParentOf(const std::string& _path)
00158 {
00159   std::string path = _path;
00160   boost::trim(path);
00161   if (path.empty())
00162   {
00163     throw BadPathException("Cannot get the parent of the current node!");
00164   }
00165 
00166   // This is an inefficient way of doing this
00167   typedef std::vector<std::string> V_string;
00168   V_string split_path;
00169   boost::split(split_path, path, boost::is_any_of("/"), boost::token_compress_on);
00170   std::string final_name = split_path.back();
00171   split_path.pop_back();
00172 
00173   if (split_path.empty())
00174   {
00175     return std::make_pair(shared_from_this(), final_name);
00176   }
00177   else
00178   {
00179     std::string parent_path = boost::join(split_path, "/");
00180     return std::make_pair(getNode(parent_path), final_name);
00181   }
00182 }
00183 
00184 void PropertyNode::setChild(const std::string& name, const PropertyNodePtr& node)
00185 {
00186   boost::recursive_mutex::scoped_lock lock(mutex_);
00187 
00188   if (!children_)
00189   {
00190     children_ = new M_PropertyNode;
00191   }
00192 
00193   M_PropertyNode::iterator it = children_->find(name);
00194   if (it != children_->end())
00195   {
00196     it->second = node;
00197   }
00198   else
00199   {
00200     children_->insert(std::make_pair(name, node));
00201   }
00202 
00203   node->setParent(this, name, true);
00204 }
00205 
00206 void PropertyNode::setNode(const std::string& _path, const PropertyNodePtr& node)
00207 {
00208   std::string path = _path;
00209   boost::trim(path);
00210   if (path.empty())
00211   {
00212     throw BadPathException("Cannot set the pointer for the current node");
00213   }
00214 
00215   std::pair<PropertyNodePtr, std::string> pair = getParentOf(path);
00216   const PropertyNodePtr& parent = pair.first;
00217   const std::string& child_name = pair.second;
00218   parent->setChild(child_name, node);
00219 }
00220 
00221 void PropertyNode::removeNode(const std::string& _path)
00222 {
00223   std::string path = _path;
00224   boost::trim(path);
00225   if (path.empty())
00226   {
00227     throw BadPathException("Cannot delete the current node!");
00228   }
00229 
00230   std::pair<PropertyNodePtr, std::string> pair = getParentOf(path);
00231   const PropertyNodePtr& parent = pair.first;
00232   const std::string& child_name = pair.second;
00233 
00234   PropertyNodePtr child;
00235 
00236   {
00237     boost::recursive_mutex::scoped_lock lock(mutex_);
00238     if (!parent->children_)
00239     {
00240       return;
00241     }
00242 
00243     M_PropertyNode::iterator it = parent->children_->find(child_name);
00244     if (it != parent->children_->end())
00245     {
00246       PropertyNodePtr child = it->second;
00247       parent->children_->erase(it);
00248     }
00249   }
00250 
00251   if (child)
00252   {
00253     child->setParent(0, "", false);
00254   }
00255 }
00256 
00257 bool PropertyNode::exists(const std::string& path)
00258 {
00259   return getNode(path, false);
00260 }
00261 
00262 PropertyNodePtr PropertyNode::getParent()
00263 {
00264   if (!parent_)
00265   {
00266     return PropertyNodePtr();
00267   }
00268 
00269   return parent_->shared_from_this();
00270 }
00271 
00272 struct CBQueueChangeCallback : public ros::CallbackInterface
00273 {
00274 public:
00275   CBQueueChangeCallback(const PropertyChangeCallback& cb, const PropertyNodePtr& node, const std::string& path, PropertyChangeType type)
00276   : cb_(cb)
00277   , node_(node)
00278   , path_(path)
00279   , type_(type)
00280   {}
00281 
00282   virtual CallResult call()
00283   {
00284     cb_(node_, path_, type_);
00285     return Success;
00286   }
00287 
00288 private:
00289   PropertyChangeCallback cb_;
00290   PropertyNodePtr node_;
00291   std::string path_;
00292   PropertyChangeType type_;
00293 };
00294 
00295 void PropertyNode::fireChanged(const PropertyNodePtr& node, const std::string& path, PropertyChangeType type)
00296 {
00297   boost::recursive_mutex::scoped_lock lock(mutex_);
00298   std::string full_path;
00299   if (path.empty())
00300   {
00301     full_path = name_;
00302   }
00303   else
00304   {
00305     if (name_.empty())
00306     {
00307       ROS_ASSERT(!parent_);
00308       full_path = path;
00309     }
00310     else
00311     {
00312       full_path = name_ + "/" + path;
00313     }
00314   }
00315 
00316   if (parent_)
00317   {
00318     parent_->childChanged(node, full_path, type);
00319   }
00320 
00321   if (!change_callbacks_)
00322   {
00323     return;
00324   }
00325 
00326   V_ChangeCallback::iterator it = change_callbacks_->begin();
00327   V_ChangeCallback::iterator end = change_callbacks_->end();
00328   for (; it != end; ++it)
00329   {
00330     const ChangeCallback& cc = *it;
00331     if (cc.queue)
00332     {
00333       cc.queue->addCallback(ros::CallbackInterfacePtr(new CBQueueChangeCallback(cc.cb, node, path, type)), (uint64_t)cc.owner);
00334     }
00335     else
00336     {
00337       cc.cb(node, full_path, type);
00338     }
00339   }
00340 }
00341 
00342 void PropertyNode::childChanged(const PropertyNodePtr& child, const std::string& child_path, PropertyChangeType type)
00343 {
00344   fireChanged(child, child_path, type);
00345 }
00346 
00347 void PropertyNode::addChangeCallback(const PropertyChangeCallback& cb, void* owner, ros::CallbackQueueInterface* callback_queue)
00348 {
00349   boost::recursive_mutex::scoped_lock lock(mutex_);
00350 
00351   if (!change_callbacks_)
00352   {
00353     change_callbacks_ = new V_ChangeCallback;
00354   }
00355 
00356   ChangeCallback cc;
00357   cc.owner = owner;
00358   cc.cb = cb;
00359   cc.queue = callback_queue;
00360   change_callbacks_->push_back(cc);
00361 }
00362 
00363 void PropertyNode::removeChangeCallback(void* owner)
00364 {
00365   boost::recursive_mutex::scoped_lock lock(mutex_);
00366 
00367   if (!change_callbacks_)
00368   {
00369     return;
00370   }
00371 
00372   V_ChangeCallback::iterator it = change_callbacks_->begin();
00373   for (; it != change_callbacks_->end();)
00374   {
00375     const ChangeCallback& cc = *it;
00376     if (cc.owner == owner)
00377     {
00378       if (cc.queue)
00379       {
00380         cc.queue->removeByID((uint64_t)cc.owner);
00381       }
00382       it = change_callbacks_->erase(it);
00383     }
00384     else
00385     {
00386       ++it;
00387     }
00388   }
00389 }
00390 
00391 } // namespace rve_properties


rve_properties
Author(s): Josh Faust
autogenerated on Wed Dec 11 2013 14:31:27