libt2n: (gerd) basic structure of wrappers done, ignore handler missing, unit tests...
[libt2n] / src / client_wrapper.hxx
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>
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
32 #ifndef T2N_SINGLETON_WRAPPER_MAX_ARGS
33 #define T2N_SINGLETON_WRAPPER_MAX_ARGS 9
34 #endif
35
36 namespace libt2n
37 {
38
39 class ConnectionWrapper
40 {
41     public:
42
43         virtual client_connection* get_connection()=0;
44
45         virtual long long get_command_timeout_usec(void)
46         {
47             return command_client::command_timeout_usec_default;
48         }
49
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)
56         {
57             f();
58         }
59
60         virtual ~ConnectionWrapper()
61             { }
62 };
63
64 // contains the internal stuff needed for T2nWrapper
65 namespace 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
115 class T2nSingletonWrapperMessages
116 {
117     protected:
118         static const char* NotInitializedMessage;
119 };
120
121 template< class Client >
122 class T2nSingletonWrapper : public T2nSingletonWrapperMessages
123 {
124     private:
125         std::auto_ptr<Client> Stub;
126
127         static std::auto_ptr<T2nSingletonWrapper> SingletonObject;
128         static std::auto_ptr<ConnectionWrapper> WrappedConnection;
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
147         BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ )
148
149 #undef _GEN_PREP
150 #undef _GEN_ARG
151
152         T2nSingletonWrapper(std::auto_ptr<Client> stub)
153         {
154             Stub=stub;
155         }
156
157         static void init()
158         {
159             if (WrappedConnection.get() == NULL)
160                 throw std::logic_error(NotInitializedMessage);
161
162             std::auto_ptr<Client> stub(new Client(*(WrappedConnection->get_connection()),
163                 WrappedConnection->get_command_timeout_usec(),
164                 WrappedConnection->get_hello_timeout_usec()));
165
166             SingletonObject=std::auto_ptr<T2nSingletonWrapper>(new T2nSingletonWrapper(stub));
167         }
168
169         template< typename R >
170         static
171         typename detail::TypeWrap<R>::type real_exec( boost::function< R(Client*) > f)
172         {
173             ensure_singleton_there();
174
175             typename detail::TypeWrap<R>::type result;
176             detail::Call<R> call( boost::bind( f, SingletonObject->Stub.get()), result );
177             WrappedConnection->handle(SingletonObject->Stub.get(),call);
178             return result;
179         }
180
181     public:
182
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(); }
193
194         static void ensure_singleton_there(void)
195         {
196             if (SingletonObject.get() == NULL)
197                 init();
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)) \
211                 = &T2nSingletonWrapper::template prep<R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg) >; \
212             return boost::bind \
213             ( \
214                 T2nSingletonWrapper::template real_exec<R>, \
215                 boost::bind( p, f BOOST_PP_COMMA_IF(n) \
216                 BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \
217             ); \
218         } // eo exec
219
220         BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
221
222 #undef _GEN_EXEC
223 #undef _GEN_PLACEHOLDER
224
225 };
226
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
243 }
244 #endif