libt2n: (gerd) basic structure of wrappers done, ignore handler missing, unit tests...
[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
GE
40{
41 public:
42
0ea6d528 43 virtual client_connection* get_connection()=0;
45508d07 44
0ea6d528
GE
45 virtual long long get_command_timeout_usec(void)
46 {
47 return command_client::command_timeout_usec_default;
48 }
45508d07 49
0ea6d528
GE
50 virtual long long get_hello_timeout_usec(void)
51 {
52 return command_client::hello_timeout_usec_default;
53 }
54
55 virtual void handle(command_client* stubBase, boost::function< void() > f)
45508d07
GE
56 {
57 f();
58 }
0ea6d528
GE
59
60 virtual ~ConnectionWrapper()
61 { }
45508d07
GE
62};
63
64// contains the internal stuff needed for T2nWrapper
65namespace detail
66{
67
68 template< typename T >
69 struct TypeWrap
70 {
71 typedef T type;
72 };
73
74 template< >
75 struct TypeWrap< void >
76 {
77 typedef int type;
78 };
79
80 template< typename R >
81 struct Call
82 {
83 typedef boost::function< R() > FuncType;
84
85 FuncType function;
86 R& result;
87
88 Call( FuncType f, R& res ) : function(f), result( res ) {}
89
90 void operator()()
91 {
92 result= function();
93 }
94 };
95
96 template< >
97 struct Call<void>
98 {
99 typedef boost::function< void() > FuncType;
100 typedef TypeWrap< void >::type ResultType;
101
102 FuncType function;
103 ResultType& result;
104
105 Call( FuncType f, ResultType& res ) : function(f), result( res ) {}
106
107 void operator()()
108 {
109 function();
110 result= ResultType();
111 }
112 };
113} // eo namespace detail
114
0ea6d528 115class T2nSingletonWrapperMessages
45508d07 116{
0ea6d528
GE
117 protected:
118 static const char* NotInitializedMessage;
119};
45508d07 120
0ea6d528
GE
121template< class Client >
122class T2nSingletonWrapper : public T2nSingletonWrapperMessages
123{
124 private:
125 std::auto_ptr<Client> Stub;
45508d07 126
0ea6d528
GE
127 static std::auto_ptr<T2nSingletonWrapper> SingletonObject;
128 static std::auto_ptr<ConnectionWrapper> WrappedConnection;
45508d07
GE
129
130 // create a prep-method for each possible number of parameters
131#define _GEN_ARG(z,n,d) Arg ## n arg ##n
132#define _GEN_PREP(z,n,d) \
133 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
134 static boost::function< R(Client*) > prep \
135 ( \
136 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
137 BOOST_PP_COMMA_IF(n) \
138 BOOST_PP_ENUM( n, _GEN_ARG, ~ ) \
139 ) \
140 { \
141 return boost::bind< R > \
142 ( \
143 f, _1 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,arg) \
144 ); \
145 } // eo prep
146
0ea6d528 147 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ )
45508d07
GE
148
149#undef _GEN_PREP
150#undef _GEN_ARG
151
a64066eb
GE
152 T2nSingletonWrapper(std::auto_ptr<Client> stub)
153 {
154 Stub=stub;
155 }
156
157 static void init()
45508d07 158 {
0ea6d528
GE
159 if (WrappedConnection.get() == NULL)
160 throw std::logic_error(NotInitializedMessage);
45508d07 161
a64066eb 162 std::auto_ptr<Client> stub(new Client(*(WrappedConnection->get_connection()),
0ea6d528
GE
163 WrappedConnection->get_command_timeout_usec(),
164 WrappedConnection->get_hello_timeout_usec()));
a64066eb
GE
165
166 SingletonObject=std::auto_ptr<T2nSingletonWrapper>(new T2nSingletonWrapper(stub));
45508d07
GE
167 }
168
169 template< typename R >
170 static
171 typename detail::TypeWrap<R>::type real_exec( boost::function< R(Client*) > f)
172 {
0ea6d528 173 ensure_singleton_there();
45508d07
GE
174
175 typename detail::TypeWrap<R>::type result;
0ea6d528
GE
176 detail::Call<R> call( boost::bind( f, SingletonObject->Stub.get()), result );
177 WrappedConnection->handle(SingletonObject->Stub.get(),call);
45508d07
GE
178 return result;
179 }
180
181 public:
182
0ea6d528
GE
183 static void set_connection(std::auto_ptr<ConnectionWrapper> wrappedConnection)
184 {
185 WrappedConnection=wrappedConnection;
186
187 // reset the singleton to NULL because the singleton must be constructed with current WrappedConnection
188 if (SingletonObject.get() != NULL)
189 SingletonObject.reset();
190 }
191 static ConnectionWrapper* get_connection(void)
192 { return WrappedConnection.get(); }
45508d07 193
0ea6d528 194 static void ensure_singleton_there(void)
45508d07 195 {
0ea6d528 196 if (SingletonObject.get() == NULL)
a64066eb 197 init();
45508d07
GE
198 }
199
200 // create an exec-method for each possible number of parameters
201#define _GEN_PLACEHOLDER(z,n,d) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
202#define _GEN_EXEC(z,n,d) \
203 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
204 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > exec \
205 ( \
206 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
207 ) \
208 { \
209 boost::function<R(Client*)>(*p)(R(Client::*)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
210 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg)) \
0ea6d528 211 = &T2nSingletonWrapper::template prep<R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg) >; \
45508d07
GE
212 return boost::bind \
213 ( \
0ea6d528 214 T2nSingletonWrapper::template real_exec<R>, \
45508d07
GE
215 boost::bind( p, f BOOST_PP_COMMA_IF(n) \
216 BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \
217 ); \
218 } // eo exec
219
0ea6d528 220 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
45508d07
GE
221
222#undef _GEN_EXEC
223#undef _GEN_PLACEHOLDER
224
225};
226
0ea6d528
GE
227// create an t2n_exec-method for each possible number of parameters
228#define _GEN_EXEC(z,n,d) \
229 template< class Client, typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
230 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > t2n_exec \
231 ( \
232 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
233 ) \
234 { \
235 return T2nSingletonWrapper<Client>::exec(f); \
236 } // eo exec
237
238 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
239
240#undef _GEN_EXEC
241#undef _GEN_PLACEHOLDER
242
45508d07
GE
243}
244#endif