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 #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
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 }