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