1 // Libiqxmlrpc - an object-oriented XML-RPC solution. 2 // Copyright (C) 2011 Anton Dedov 3 4 #ifndef _iqxmlrpc_method_h_ 5 #define _iqxmlrpc_method_h_ 6 7 #include "except.h" 8 #include "inet_addr.h" 9 #include "value.h" 10 11 #include <boost/utility.hpp> 12 #include <boost/scoped_ptr.hpp> 13 14 #include <map> 15 #include <string> 16 17 namespace iqxmlrpc 18 { 19 class Server; 20 class Interceptor; 21 class Method; 22 class Method_dispatcher_base; 23 24 //! Method's parameters type 25 typedef std::vector<Value> Param_list; 26 27 //! Type of pointer to function that can be used as server method. 28 typedef void (*Method_function)(Method*, const Param_list&, Value&); 29 30 //! This clas provides restricted interface of class Server for Method's needs. 31 class LIBIQXMLRPC_API Server_feedback { 32 Server* server_; 33 34 public: 35 // Do not use objects constructed with default ctor! Server_feedback()36 Server_feedback(): 37 server_(0) {} 38 Server_feedback(Server * s)39 Server_feedback(Server* s): 40 server_(s) {} 41 42 void set_exit_flag(); 43 void log_message( const std::string& ); 44 }; 45 46 //! Abstract base for server method. 47 //! Inherit it to create actual server method. 48 class LIBIQXMLRPC_API Method { 49 public: 50 struct Data { 51 std::string method_name; 52 iqnet::Inet_addr peer_addr; 53 Server_feedback server_face; 54 }; 55 56 private: 57 friend class Method_dispatcher_base; 58 Data data_; 59 std::string authname_; 60 61 public: ~Method()62 virtual ~Method() {} 63 64 //! Calls customized execute() and optionally wraps it with interceptors. 65 //! Is is called by a server object. 66 void process_execution(Interceptor*, const Param_list& params, Value& response); 67 name()68 const std::string& name() const { return data_.method_name; } peer_addr()69 const iqnet::Inet_addr& peer_addr() const { return data_.peer_addr; } server()70 Server_feedback& server() { return data_.server_face; } 71 authenticated()72 bool authenticated() const { return !authname_.empty(); } authname()73 const std::string& authname() const { return authname_; } authname(const std::string & n)74 void authname(const std::string& n) { authname_ = n; } 75 76 private: 77 //! Replace it with your actual code. 78 virtual void execute( const Param_list& params, Value& response ) = 0; 79 }; 80 81 #ifdef _MSC_VER 82 #pragma warning(push) 83 #pragma warning(disable: 4251) 84 #pragma warning(disable: 4275) 85 #endif 86 87 //! Interceptor's base class 88 /*! One can use interceptors in order to wrap actual XML-RPC calls 89 * on server side with code that supports particular aspect. 90 * E.g. logging or catch/re-throw internal exceptions, etc. 91 * 92 * Interceptors are stacked inside of server and are being called 93 * in order of LIFO. 94 * 95 * Also note that interceptors are shared between method that executed 96 * in the same time. So the synchronization of internal state of 97 * user-defined interceptor is up to it's creator. 98 */ 99 class LIBIQXMLRPC_API Interceptor: boost::noncopyable { 100 public: ~Interceptor()101 virtual ~Interceptor() {} 102 nest(Interceptor * ic)103 void nest(Interceptor* ic) 104 { 105 nested.reset(ic); 106 } 107 108 //! User defined interceptor's code goes here. 109 /*! This method is called by library as soon it resolved target XML-RPC 110 * method on a server side. This method must call actual XML-RPC method 111 * (along with other stacked interceptors) via calling yield() member 112 */ 113 virtual void process(Method*, const Param_list&, Value&) = 0; 114 115 protected: 116 //! Yield the control to specific XML-RPC method. 117 /*! This function <b>must</b> be called by process() method function 118 * unless it meaningfuly decided not to call actual server method. 119 */ yield(Method * m,const Param_list & params,Value & result)120 void yield(Method* m, const Param_list& params, Value& result) 121 { 122 m->process_execution(nested.get(), params, result); 123 } 124 125 private: 126 boost::scoped_ptr<Interceptor> nested; 127 }; 128 129 #ifdef _MSC_VER 130 #pragma warning(pop) 131 #endif 132 133 //! Adapter that allows make server method from plain function. 134 //! \see Method_function 135 class LIBIQXMLRPC_API Method_function_adapter: public Method { 136 public: Method_function_adapter(Method_function f)137 Method_function_adapter(Method_function f): 138 function(f) {} 139 140 private: execute(const Param_list & params,Value & result)141 void execute(const Param_list& params, Value& result) 142 { 143 function(this, params, result); 144 } 145 146 Method_function function; 147 }; 148 149 //! Abstract factory for Method. 150 /*! Method_dispatcher uses it to create Method object on demand. 151 Inherit it to create your specific factory. 152 \see Method_factory 153 */ 154 class LIBIQXMLRPC_API Method_factory_base { 155 public: ~Method_factory_base()156 virtual ~Method_factory_base() {} 157 158 virtual Method* create() = 0; 159 }; 160 161 162 //! Template for simple Method factory. 163 template <class T> 164 class Method_factory: public Method_factory_base { 165 public: create()166 T* create() { return new T(); } 167 }; 168 169 170 //! Specialization for funciton adapters. 171 template <> 172 class Method_factory<Method_function_adapter>: public Method_factory_base { 173 public: Method_factory(Method_function fn)174 Method_factory(Method_function fn): 175 function(fn) {} 176 create()177 Method* create() { return new Method_function_adapter(function); } 178 179 private: 180 Method_function function; 181 }; 182 183 184 //! Method dispatcher base class. 185 class LIBIQXMLRPC_API Method_dispatcher_base { 186 public: ~Method_dispatcher_base()187 virtual ~Method_dispatcher_base() {} 188 create_method(const Method::Data & data)189 Method* create_method(const Method::Data& data) 190 { 191 Method *method = do_create_method(data.method_name); 192 if (method) 193 method->data_ = data; 194 195 return method; 196 } 197 get_methods_list(Array & retval)198 void get_methods_list(Array& retval) const 199 { 200 do_get_methods_list(retval); 201 } 202 203 private: 204 virtual Method* 205 do_create_method(const std::string&) = 0; 206 207 virtual void 208 do_get_methods_list(Array&) const = 0; 209 }; 210 211 } // namespace iqxmlrpc 212 213 #endif 214 // vim:ts=2:sw=2:et 215