client.h
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 #ifndef RVIZ_RPC_CLIENT_H
00031 #define RVIZ_RPC_CLIENT_H
00032 
00033 
00034 #include "exceptions.h"
00035 #include "request_wrapper.h"
00036 #include "response_wrapper.h"
00037 #include "method_response.h"
00038 #include <rve_common/uuid.h>
00039 
00040 #include <string>
00041 #include <boost/shared_ptr.hpp>
00042 #include <boost/make_shared.hpp>
00043 #include <boost/function.hpp>
00044 #include <boost/bind.hpp>
00045 
00046 namespace ros
00047 {
00048 class NodeHandle;
00049 }
00050 
00051 namespace rve_rpc
00052 {
00053 
00054 template<typename Req, typename Res>
00055 class Method
00056 {
00057 private:
00058   struct SyncCallHelper
00059   {
00060     SyncCallHelper()
00061     : received(false)
00062     {}
00063 
00064     void cb(const MethodResponse<Res>& res)
00065     {
00066       response = res;
00067       received = true;
00068     }
00069 
00070     bool received;
00071     MethodResponse<Res> response;
00072   };
00073 
00074 public:
00075   typedef boost::shared_ptr<Req> ReqPtr;
00076   typedef boost::shared_ptr<Req const> ReqConstPtr;
00077   typedef boost::shared_ptr<Res> ResPtr;
00078   typedef boost::shared_ptr<Res const> ResConstPtr;
00079 
00080   typedef boost::function<void(const RequestWrapperPtr&, const boost::function<void(const ResponseWrapperConstPtr&)>)> CallFn;
00081   typedef boost::function<void(const MethodResponse<Res>&)> ResponseCallback;
00082   typedef boost::function<void()> PumpFn;
00083 
00084   Method() {}
00085 
00086   Method(const std::string& name, const CallFn& c, const PumpFn& pump)
00087   {
00088     name_ = name;
00089     call_fn_ = c;
00090     pump_fn_ = pump;
00091   }
00092 
00093   void callAsync(const ReqConstPtr& req, const ResponseCallback& cb)
00094   {
00095     ROS_ASSERT(!name_.empty());
00096 
00097     RequestWrapperPtr request(boost::make_shared<RequestWrapper>());
00098     request->method = name_;
00099     request->message.message = req;
00100     request->message.serialize = serialize<Req>;
00101     request->message.serialized_length = serializedLength<Req>;
00102     request->message.ti = &typeid(Req);
00103 
00104     call_fn_(request, boost::bind(&Method::responseCallback, this, _1, cb));
00105   }
00106 
00107   void callAsync(const ReqConstPtr& req)
00108   {
00109     callAsync(req, ResponseCallback());
00110   }
00111 
00112   ResConstPtr call(const ReqConstPtr& req)
00113   {
00114     SyncCallHelper h;
00115     callAsync(req, boost::bind(&SyncCallHelper::cb, &h, _1));
00116 
00117     while (!h.received)
00118     {
00119       pump_fn_();
00120     }
00121 
00122     uint32_t error_code = h.response.error_code;
00123     if (error_code == Response::SUCCESS)
00124     {
00125       return h.response.response;
00126     }
00127     else if (error_code == Response::EXCEPTION)
00128     {
00129       throw CallException(h.response.error_string);
00130     }
00131     else if (error_code == Response::UNKNOWN_METHOD)
00132     {
00133       std::stringstream ss;
00134       ss << "Server does not have method [" << h.response.error_string << "]";
00135       throw CallException(ss.str());
00136     }
00137     else
00138     {
00139       std::stringstream ss;
00140       ss << "Unknown error code [" << error_code << "]";
00141       throw CallException(ss.str());
00142     }
00143   }
00144 
00145 private:
00146   void responseCallback(const ResponseWrapperConstPtr& res, const ResponseCallback& cb)
00147   {
00148     if (cb)
00149     {
00150       MethodResponse<Res> mr;
00151       if (res->error_code == 0)
00152       {
00153         mr.response = res->instantiate<Res>();
00154       }
00155       mr.error_code = res->error_code;
00156       mr.error_string = res->error_string;
00157       cb(mr);
00158     }
00159   }
00160 
00161   CallFn call_fn_;
00162   PumpFn pump_fn_;
00163   std::string name_;
00164 };
00165 
00166 class Client
00167 {
00168 private:
00169   struct MethodInfo
00170   {
00171     std::string name;
00172     std::string request_md5sum;
00173     std::string request_datatype;
00174     std::string request_definition;
00175     std::string response_md5sum;
00176     std::string response_datatype;
00177     std::string response_definition;
00178   };
00179 
00180 public:
00181   Client(const std::string& name, const ros::NodeHandle& nh);
00182   void connect();
00183   void connectAsync();
00184   void disconnect();
00185   void waitForConnection();
00186   bool isConnected();
00187   void flush();
00188 
00189   template<typename Req, typename Res>
00190   Method<Req, Res> addMethod(const std::string& name)
00191   {
00192     Method<Req, Res> method(name, boost::bind(&Client::call, this, _1, _2), boost::bind(&Client::pump, this));
00193     MethodInfo info;
00194     info.name = name;
00195     info.request_md5sum = ros::message_traits::md5sum<Req>();
00196     info.request_datatype = ros::message_traits::datatype<Req>();
00197     info.request_definition = ros::message_traits::definition<Req>();
00198     info.response_md5sum = ros::message_traits::md5sum<Res>();
00199     info.response_datatype = ros::message_traits::datatype<Res>();
00200     info.response_definition = ros::message_traits::definition<Res>();
00201     addMethod(info);
00202     return method;
00203   }
00204 
00205 private:
00206   void addMethod(const MethodInfo& name);
00207   void call(const RequestWrapperPtr& req, const boost::function<void(const ResponseWrapperConstPtr&)>& response_cb);
00208   void pump();
00209 
00210   struct Impl;
00211   typedef boost::shared_ptr<Impl> ImplPtr;
00212   ImplPtr impl_;
00213 };
00214 typedef boost::shared_ptr<Client> ClientPtr;
00215 
00216 } // namespace rve_rpc
00217 
00218 #endif // RVIZ_RPC_CLIENT_H


rve_rpc
Author(s): Josh Faust
autogenerated on Wed Dec 11 2013 14:30:53