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