client_wrapper.hxx, socket_wrapper.hxx: reorder member initialization order
[libt2n] / src / client_wrapper.hxx
CommitLineData
19facd85
TJ
1/*
2Copyright (C) 2006 by Intra2net AG - Gerd v. Egidy
3
4The software in this package is distributed under the GNU General
5Public License version 2 (with a special exception described below).
6
7A copy of GNU General Public License (GPL) is included in this distribution,
8in the file COPYING.GPL.
9
10As a special exception, if other files instantiate templates or use macros
11or inline functions from this file, or you compile this file and link it
12with other works to produce a work based on this file, this file
13does not by itself cause the resulting work to be covered
14by the GNU General Public License.
15
16However the source code for this file must still be made available
17in accordance with section (3) of the GNU General Public License.
18
19This exception does not invalidate any other reasons why a work based
20on this file might be covered by the GNU General Public License.
21*/
45508d07
GE
22#ifndef __LIBT2N_CLIENT_WRAPPER
23#define __LIBT2N_CLIENT_WRAPPER
24
25#include <functional>
26
27#include <boost/config.hpp>
45508d07
GE
28#include <boost/bind.hpp>
29#include <boost/function.hpp>
30#include <boost/preprocessor.hpp>
31
32#include <client.hxx>
33#include <command_client.hxx>
34
0ea6d528
GE
35#ifndef T2N_SINGLETON_WRAPPER_MAX_ARGS
36#define T2N_SINGLETON_WRAPPER_MAX_ARGS 9
45508d07
GE
37#endif
38
39namespace libt2n
40{
41
e162ddf2
GE
42/** @brief provide access to client_connection singletons and call-handling function
43
44 This is an abstact base class for use with T2nSingletonWrapper. It provides access
45 to the singleton-client_connection and offers a handle-method which is used for
46 every call to a method on a t2n-server.
47*/
0ea6d528 48class ConnectionWrapper
45508d07 49{
e1614a6d
GE
50 private:
51 long long command_timeout_usec;
52 long long hello_timeout_usec;
45508d07 53
e1614a6d
GE
54 protected:
55 log_level_values log_level;
56 std::ostream *logstream;
57 void set_logging_on_connection(client_connection& c);
45508d07 58
e1614a6d
GE
59 public:
60 ConnectionWrapper()
44b4600f
PG
61 : command_timeout_usec(command_client::command_timeout_usec_default),
62 hello_timeout_usec(command_client::hello_timeout_usec_default),
63 log_level(none),
64 logstream(NULL)
e1614a6d 65 { }
45508d07 66
e1614a6d
GE
67 virtual ~ConnectionWrapper()
68 { }
69
e162ddf2
GE
70 /** @brief return active connection, create new one if not existing
71
72 Return a pointer to an active client_connection. Use detail-data
73 stored within the derived class to create a new connection if needed,
74 otherwise return an alredy active connection. The derived class has
75 to take care of destroying the connection when not needed anymore.
76 */
e1614a6d 77 virtual client_connection* get_connection()=0;
0ea6d528 78
e162ddf2
GE
79 /** @brief this function is called on every execution of a method on a server
80
81 @param stubBase pointer to the command_client executing the call
82 @param f boost::function object containing the method to call and all parameters
83 @retval true if the call was successful and the original return-value of the called function can be used
84 false if T2nSingletonWrapper has to create a return-value with the default-constructor
85
86 T2nSingletonWrapper will call this function on every execution of a server-side
87 method. This version will just call the function without any special treatment.
88 You can overload this function to implement different error handling strategies.
89 */
fb3345ad 90 virtual bool handle(command_client* stubBase, boost::function< void() > f)
45508d07
GE
91 {
92 f();
fb3345ad 93 return true;
45508d07 94 }
0ea6d528 95
e1614a6d
GE
96 long long get_command_timeout_usec(void)
97 { return command_timeout_usec; }
98
99 void set_command_timeout_usec(long long _command_timeout_usec)
100 { command_timeout_usec=_command_timeout_usec; }
101
102 long long get_hello_timeout_usec(void)
103 { return hello_timeout_usec; }
104
105 void set_hello_timeout_usec(long long _hello_timeout_usec)
106 { hello_timeout_usec=_hello_timeout_usec; }
107
2a956e65 108 virtual void set_logging(std::ostream *_logstream, log_level_values _log_level);
e1614a6d
GE
109
110 std::ostream* get_logstream(log_level_values level);
45508d07
GE
111};
112
113// contains the internal stuff needed for T2nWrapper
114namespace detail
115{
116
117 template< typename T >
118 struct TypeWrap
119 {
120 typedef T type;
121 };
122
123 template< >
124 struct TypeWrap< void >
125 {
126 typedef int type;
127 };
128
129 template< typename R >
130 struct Call
131 {
132 typedef boost::function< R() > FuncType;
133
134 FuncType function;
135 R& result;
136
137 Call( FuncType f, R& res ) : function(f), result( res ) {}
138
139 void operator()()
140 {
141 result= function();
142 }
143 };
144
145 template< >
146 struct Call<void>
147 {
148 typedef boost::function< void() > FuncType;
149 typedef TypeWrap< void >::type ResultType;
150
151 FuncType function;
152 ResultType& result;
153
154 Call( FuncType f, ResultType& res ) : function(f), result( res ) {}
155
156 void operator()()
157 {
158 function();
159 result= ResultType();
160 }
161 };
162} // eo namespace detail
163
0ea6d528 164class T2nSingletonWrapperMessages
45508d07 165{
0ea6d528
GE
166 protected:
167 static const char* NotInitializedMessage;
168};
45508d07 169
e162ddf2
GE
170/** @brief wrap calls to server-side-functions with different error-handling strategies
171
172 Template class to access a process-wide singleton server-connection and to wrap all
173 calls using this connection with an error-handling strategy (e.g. to reconnect when
174 the connection broke). The source looks very complicated due to heavy use of templates,
175 look at the 3rd codegen example to see how to use it.
9a5d7790
GE
176
177 @par Example
178 Calling remote methods is usually done via t2n_exec, this saves you from always
179 specifying which T2nSingletonWrapper-template to use when calling T2nSingletonWrapper::exec
180 @code
181 t2n_exec(&cmd_group_t2nexample_client::testfunc)("the answer is %d",42)
182 @endcode
e162ddf2 183*/
0ea6d528
GE
184template< class Client >
185class T2nSingletonWrapper : public T2nSingletonWrapperMessages
186{
187 private:
188 std::auto_ptr<Client> Stub;
45508d07 189
0ea6d528
GE
190 static std::auto_ptr<T2nSingletonWrapper> SingletonObject;
191 static std::auto_ptr<ConnectionWrapper> WrappedConnection;
45508d07 192
9a5d7790 193 /// @cond
45508d07
GE
194 // create a prep-method for each possible number of parameters
195#define _GEN_ARG(z,n,d) Arg ## n arg ##n
196#define _GEN_PREP(z,n,d) \
197 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
198 static boost::function< R(Client*) > prep \
199 ( \
200 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
201 BOOST_PP_COMMA_IF(n) \
202 BOOST_PP_ENUM( n, _GEN_ARG, ~ ) \
203 ) \
204 { \
205 return boost::bind< R > \
206 ( \
207 f, _1 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,arg) \
208 ); \
209 } // eo prep
210
0ea6d528 211 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ )
45508d07
GE
212
213#undef _GEN_PREP
214#undef _GEN_ARG
9a5d7790 215 /// @endcond
45508d07 216
a64066eb
GE
217 T2nSingletonWrapper(std::auto_ptr<Client> stub)
218 {
219 Stub=stub;
220 }
221
222 static void init()
45508d07 223 {
0ea6d528
GE
224 if (WrappedConnection.get() == NULL)
225 throw std::logic_error(NotInitializedMessage);
45508d07 226
fb3345ad 227 std::auto_ptr<Client> stub(new Client(WrappedConnection->get_connection(),
0ea6d528
GE
228 WrappedConnection->get_command_timeout_usec(),
229 WrappedConnection->get_hello_timeout_usec()));
a64066eb
GE
230
231 SingletonObject=std::auto_ptr<T2nSingletonWrapper>(new T2nSingletonWrapper(stub));
45508d07
GE
232 }
233
234 template< typename R >
235 static
236 typename detail::TypeWrap<R>::type real_exec( boost::function< R(Client*) > f)
237 {
0ea6d528 238 ensure_singleton_there();
45508d07
GE
239
240 typename detail::TypeWrap<R>::type result;
fb3345ad
GE
241
242 // bind our Client-object and the local result
0ea6d528 243 detail::Call<R> call( boost::bind( f, SingletonObject->Stub.get()), result );
fb3345ad
GE
244
245 // let the wrapper-handler call the fully-bound function
246 if (!WrappedConnection->handle(SingletonObject->Stub.get(),call))
247 {
248 // create an result with default-constructor if the handler could not
249 // successfully do a call but no exception occured
250 result=typename detail::TypeWrap<R>::type();
251 }
45508d07
GE
252 return result;
253 }
254
255 public:
256
9a5d7790
GE
257 /** @brief tell the wrapper which connection to use
258 @param wrappedConnection the connection to establish when needed
259 */
0ea6d528
GE
260 static void set_connection(std::auto_ptr<ConnectionWrapper> wrappedConnection)
261 {
262 WrappedConnection=wrappedConnection;
263
264 // reset the singleton to NULL because the singleton must be constructed with current WrappedConnection
265 if (SingletonObject.get() != NULL)
266 SingletonObject.reset();
267 }
9a5d7790
GE
268
269 /// return a pointer to the ConnectionWrapper currently in use
e1614a6d 270 static ConnectionWrapper* get_connection_wrapper(void)
0ea6d528 271 { return WrappedConnection.get(); }
45508d07 272
9a5d7790 273 /// manually establish the connection without actually executing a call
0ea6d528 274 static void ensure_singleton_there(void)
45508d07 275 {
0ea6d528 276 if (SingletonObject.get() == NULL)
a64066eb 277 init();
45508d07
GE
278 }
279
9a5d7790 280 /// @cond
45508d07
GE
281 // create an exec-method for each possible number of parameters
282#define _GEN_PLACEHOLDER(z,n,d) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
283#define _GEN_EXEC(z,n,d) \
284 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
285 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > exec \
286 ( \
287 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
288 ) \
289 { \
290 boost::function<R(Client*)>(*p)(R(Client::*)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
291 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg)) \
0ea6d528 292 = &T2nSingletonWrapper::template prep<R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg) >; \
45508d07
GE
293 return boost::bind \
294 ( \
0ea6d528 295 T2nSingletonWrapper::template real_exec<R>, \
45508d07
GE
296 boost::bind( p, f BOOST_PP_COMMA_IF(n) \
297 BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \
298 ); \
299 } // eo exec
300
0ea6d528 301 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
45508d07
GE
302
303#undef _GEN_EXEC
304#undef _GEN_PLACEHOLDER
9a5d7790 305 /// @endcond
45508d07
GE
306
307};
308
9a5d7790 309/// @cond
0ea6d528
GE
310// create an t2n_exec-method for each possible number of parameters
311#define _GEN_EXEC(z,n,d) \
312 template< class Client, typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
313 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > t2n_exec \
314 ( \
315 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
316 ) \
317 { \
318 return T2nSingletonWrapper<Client>::exec(f); \
319 } // eo exec
320
321 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
322
323#undef _GEN_EXEC
324#undef _GEN_PLACEHOLDER
9a5d7790 325/// @endcond
0ea6d528 326
45508d07
GE
327}
328#endif