libt2n: (gerd) fix client-connection-logic, finish wrappers, all tests are working...
[libt2n] / src / client_wrapper.hxx
CommitLineData
45508d07
GE
1/***************************************************************************
2 * Copyright (C) 2008 by Gerd v. Egidy and Reinhard Pfau *
3 * gve@intra2net.com *
4 * *
5 * This library is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Lesser General Public License version *
7 * 2.1 as published by the Free Software Foundation. *
8 * *
9 * This library is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19#ifndef __LIBT2N_CLIENT_WRAPPER
20#define __LIBT2N_CLIENT_WRAPPER
21
22#include <functional>
23
24#include <boost/config.hpp>
45508d07
GE
25#include <boost/bind.hpp>
26#include <boost/function.hpp>
27#include <boost/preprocessor.hpp>
28
29#include <client.hxx>
30#include <command_client.hxx>
31
0ea6d528
GE
32#ifndef T2N_SINGLETON_WRAPPER_MAX_ARGS
33#define T2N_SINGLETON_WRAPPER_MAX_ARGS 9
45508d07
GE
34#endif
35
36namespace libt2n
37{
38
0ea6d528 39class ConnectionWrapper
45508d07 40{
e1614a6d
GE
41 private:
42 long long command_timeout_usec;
43 long long hello_timeout_usec;
45508d07 44
e1614a6d
GE
45 protected:
46 log_level_values log_level;
47 std::ostream *logstream;
48 void set_logging_on_connection(client_connection& c);
45508d07 49
e1614a6d
GE
50 public:
51 ConnectionWrapper()
52 : log_level(none), logstream(NULL),
53 command_timeout_usec(command_client::command_timeout_usec_default),
54 hello_timeout_usec(command_client::hello_timeout_usec_default)
55 { }
45508d07 56
e1614a6d
GE
57 virtual ~ConnectionWrapper()
58 { }
59
60 virtual client_connection* get_connection()=0;
0ea6d528 61
fb3345ad 62 virtual bool handle(command_client* stubBase, boost::function< void() > f)
45508d07
GE
63 {
64 f();
fb3345ad 65 return true;
45508d07 66 }
0ea6d528 67
e1614a6d
GE
68 long long get_command_timeout_usec(void)
69 { return command_timeout_usec; }
70
71 void set_command_timeout_usec(long long _command_timeout_usec)
72 { command_timeout_usec=_command_timeout_usec; }
73
74 long long get_hello_timeout_usec(void)
75 { return hello_timeout_usec; }
76
77 void set_hello_timeout_usec(long long _hello_timeout_usec)
78 { hello_timeout_usec=_hello_timeout_usec; }
79
80 void set_logging(std::ostream *_logstream, log_level_values _log_level);
81
82 std::ostream* get_logstream(log_level_values level);
45508d07
GE
83};
84
85// contains the internal stuff needed for T2nWrapper
86namespace detail
87{
88
89 template< typename T >
90 struct TypeWrap
91 {
92 typedef T type;
93 };
94
95 template< >
96 struct TypeWrap< void >
97 {
98 typedef int type;
99 };
100
101 template< typename R >
102 struct Call
103 {
104 typedef boost::function< R() > FuncType;
105
106 FuncType function;
107 R& result;
108
109 Call( FuncType f, R& res ) : function(f), result( res ) {}
110
111 void operator()()
112 {
113 result= function();
114 }
115 };
116
117 template< >
118 struct Call<void>
119 {
120 typedef boost::function< void() > FuncType;
121 typedef TypeWrap< void >::type ResultType;
122
123 FuncType function;
124 ResultType& result;
125
126 Call( FuncType f, ResultType& res ) : function(f), result( res ) {}
127
128 void operator()()
129 {
130 function();
131 result= ResultType();
132 }
133 };
134} // eo namespace detail
135
0ea6d528 136class T2nSingletonWrapperMessages
45508d07 137{
0ea6d528
GE
138 protected:
139 static const char* NotInitializedMessage;
140};
45508d07 141
0ea6d528
GE
142template< class Client >
143class T2nSingletonWrapper : public T2nSingletonWrapperMessages
144{
145 private:
146 std::auto_ptr<Client> Stub;
45508d07 147
0ea6d528
GE
148 static std::auto_ptr<T2nSingletonWrapper> SingletonObject;
149 static std::auto_ptr<ConnectionWrapper> WrappedConnection;
45508d07
GE
150
151 // create a prep-method for each possible number of parameters
152#define _GEN_ARG(z,n,d) Arg ## n arg ##n
153#define _GEN_PREP(z,n,d) \
154 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
155 static boost::function< R(Client*) > prep \
156 ( \
157 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
158 BOOST_PP_COMMA_IF(n) \
159 BOOST_PP_ENUM( n, _GEN_ARG, ~ ) \
160 ) \
161 { \
162 return boost::bind< R > \
163 ( \
164 f, _1 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,arg) \
165 ); \
166 } // eo prep
167
0ea6d528 168 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ )
45508d07
GE
169
170#undef _GEN_PREP
171#undef _GEN_ARG
172
a64066eb
GE
173 T2nSingletonWrapper(std::auto_ptr<Client> stub)
174 {
175 Stub=stub;
176 }
177
178 static void init()
45508d07 179 {
0ea6d528
GE
180 if (WrappedConnection.get() == NULL)
181 throw std::logic_error(NotInitializedMessage);
45508d07 182
fb3345ad 183 std::auto_ptr<Client> stub(new Client(WrappedConnection->get_connection(),
0ea6d528
GE
184 WrappedConnection->get_command_timeout_usec(),
185 WrappedConnection->get_hello_timeout_usec()));
a64066eb
GE
186
187 SingletonObject=std::auto_ptr<T2nSingletonWrapper>(new T2nSingletonWrapper(stub));
45508d07
GE
188 }
189
190 template< typename R >
191 static
192 typename detail::TypeWrap<R>::type real_exec( boost::function< R(Client*) > f)
193 {
0ea6d528 194 ensure_singleton_there();
45508d07
GE
195
196 typename detail::TypeWrap<R>::type result;
fb3345ad
GE
197
198 // bind our Client-object and the local result
0ea6d528 199 detail::Call<R> call( boost::bind( f, SingletonObject->Stub.get()), result );
fb3345ad
GE
200
201 // let the wrapper-handler call the fully-bound function
202 if (!WrappedConnection->handle(SingletonObject->Stub.get(),call))
203 {
204 // create an result with default-constructor if the handler could not
205 // successfully do a call but no exception occured
206 result=typename detail::TypeWrap<R>::type();
207 }
45508d07
GE
208 return result;
209 }
210
211 public:
212
0ea6d528
GE
213 static void set_connection(std::auto_ptr<ConnectionWrapper> wrappedConnection)
214 {
215 WrappedConnection=wrappedConnection;
216
217 // reset the singleton to NULL because the singleton must be constructed with current WrappedConnection
218 if (SingletonObject.get() != NULL)
219 SingletonObject.reset();
220 }
e1614a6d 221 static ConnectionWrapper* get_connection_wrapper(void)
0ea6d528 222 { return WrappedConnection.get(); }
45508d07 223
0ea6d528 224 static void ensure_singleton_there(void)
45508d07 225 {
0ea6d528 226 if (SingletonObject.get() == NULL)
a64066eb 227 init();
45508d07
GE
228 }
229
230 // create an exec-method for each possible number of parameters
231#define _GEN_PLACEHOLDER(z,n,d) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
232#define _GEN_EXEC(z,n,d) \
233 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
234 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > exec \
235 ( \
236 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
237 ) \
238 { \
239 boost::function<R(Client*)>(*p)(R(Client::*)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
240 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg)) \
0ea6d528 241 = &T2nSingletonWrapper::template prep<R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg) >; \
45508d07
GE
242 return boost::bind \
243 ( \
0ea6d528 244 T2nSingletonWrapper::template real_exec<R>, \
45508d07
GE
245 boost::bind( p, f BOOST_PP_COMMA_IF(n) \
246 BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \
247 ); \
248 } // eo exec
249
0ea6d528 250 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
45508d07
GE
251
252#undef _GEN_EXEC
253#undef _GEN_PLACEHOLDER
254
255};
256
0ea6d528
GE
257// create an t2n_exec-method for each possible number of parameters
258#define _GEN_EXEC(z,n,d) \
259 template< class Client, typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
260 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > t2n_exec \
261 ( \
262 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
263 ) \
264 { \
265 return T2nSingletonWrapper<Client>::exec(f); \
266 } // eo exec
267
268 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
269
270#undef _GEN_EXEC
271#undef _GEN_PLACEHOLDER
272
45508d07
GE
273}
274#endif