1 /***************************************************************************
2 * Copyright (C) 2008 by Gerd v. Egidy and Reinhard Pfau *
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. *
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. *
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
24 #include <boost/config.hpp>
25 #include <boost/bind.hpp>
26 #include <boost/function.hpp>
27 #include <boost/preprocessor.hpp>
30 #include <command_client.hxx>
32 #ifndef T2N_SINGLETON_WRAPPER_MAX_ARGS
33 #define T2N_SINGLETON_WRAPPER_MAX_ARGS 9
39 /** @brief provide access to client_connection singletons and call-handling function
41 This is an abstact base class for use with T2nSingletonWrapper. It provides access
42 to the singleton-client_connection and offers a handle-method which is used for
43 every call to a method on a t2n-server.
45 class ConnectionWrapper
48 long long command_timeout_usec;
49 long long hello_timeout_usec;
52 log_level_values log_level;
53 std::ostream *logstream;
54 void set_logging_on_connection(client_connection& c);
58 : log_level(none), logstream(NULL),
59 command_timeout_usec(command_client::command_timeout_usec_default),
60 hello_timeout_usec(command_client::hello_timeout_usec_default)
63 virtual ~ConnectionWrapper()
66 /** @brief return active connection, create new one if not existing
68 Return a pointer to an active client_connection. Use detail-data
69 stored within the derived class to create a new connection if needed,
70 otherwise return an alredy active connection. The derived class has
71 to take care of destroying the connection when not needed anymore.
73 virtual client_connection* get_connection()=0;
75 /** @brief this function is called on every execution of a method on a server
77 @param stubBase pointer to the command_client executing the call
78 @param f boost::function object containing the method to call and all parameters
79 @retval true if the call was successful and the original return-value of the called function can be used
80 false if T2nSingletonWrapper has to create a return-value with the default-constructor
82 T2nSingletonWrapper will call this function on every execution of a server-side
83 method. This version will just call the function without any special treatment.
84 You can overload this function to implement different error handling strategies.
86 virtual bool handle(command_client* stubBase, boost::function< void() > f)
92 long long get_command_timeout_usec(void)
93 { return command_timeout_usec; }
95 void set_command_timeout_usec(long long _command_timeout_usec)
96 { command_timeout_usec=_command_timeout_usec; }
98 long long get_hello_timeout_usec(void)
99 { return hello_timeout_usec; }
101 void set_hello_timeout_usec(long long _hello_timeout_usec)
102 { hello_timeout_usec=_hello_timeout_usec; }
104 virtual void set_logging(std::ostream *_logstream, log_level_values _log_level);
106 std::ostream* get_logstream(log_level_values level);
109 // contains the internal stuff needed for T2nWrapper
113 template< typename T >
120 struct TypeWrap< void >
125 template< typename R >
128 typedef boost::function< R() > FuncType;
133 Call( FuncType f, R& res ) : function(f), result( res ) {}
144 typedef boost::function< void() > FuncType;
145 typedef TypeWrap< void >::type ResultType;
150 Call( FuncType f, ResultType& res ) : function(f), result( res ) {}
155 result= ResultType();
158 } // eo namespace detail
160 class T2nSingletonWrapperMessages
163 static const char* NotInitializedMessage;
166 /** @brief wrap calls to server-side-functions with different error-handling strategies
168 Template class to access a process-wide singleton server-connection and to wrap all
169 calls using this connection with an error-handling strategy (e.g. to reconnect when
170 the connection broke). The source looks very complicated due to heavy use of templates,
171 look at the 3rd codegen example to see how to use it.
173 template< class Client >
174 class T2nSingletonWrapper : public T2nSingletonWrapperMessages
177 std::auto_ptr<Client> Stub;
179 static std::auto_ptr<T2nSingletonWrapper> SingletonObject;
180 static std::auto_ptr<ConnectionWrapper> WrappedConnection;
182 // create a prep-method for each possible number of parameters
183 #define _GEN_ARG(z,n,d) Arg ## n arg ##n
184 #define _GEN_PREP(z,n,d) \
185 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
186 static boost::function< R(Client*) > prep \
188 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
189 BOOST_PP_COMMA_IF(n) \
190 BOOST_PP_ENUM( n, _GEN_ARG, ~ ) \
193 return boost::bind< R > \
195 f, _1 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,arg) \
199 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ )
204 T2nSingletonWrapper(std::auto_ptr<Client> stub)
211 if (WrappedConnection.get() == NULL)
212 throw std::logic_error(NotInitializedMessage);
214 std::auto_ptr<Client> stub(new Client(WrappedConnection->get_connection(),
215 WrappedConnection->get_command_timeout_usec(),
216 WrappedConnection->get_hello_timeout_usec()));
218 SingletonObject=std::auto_ptr<T2nSingletonWrapper>(new T2nSingletonWrapper(stub));
221 template< typename R >
223 typename detail::TypeWrap<R>::type real_exec( boost::function< R(Client*) > f)
225 ensure_singleton_there();
227 typename detail::TypeWrap<R>::type result;
229 // bind our Client-object and the local result
230 detail::Call<R> call( boost::bind( f, SingletonObject->Stub.get()), result );
232 // let the wrapper-handler call the fully-bound function
233 if (!WrappedConnection->handle(SingletonObject->Stub.get(),call))
235 // create an result with default-constructor if the handler could not
236 // successfully do a call but no exception occured
237 result=typename detail::TypeWrap<R>::type();
244 static void set_connection(std::auto_ptr<ConnectionWrapper> wrappedConnection)
246 WrappedConnection=wrappedConnection;
248 // reset the singleton to NULL because the singleton must be constructed with current WrappedConnection
249 if (SingletonObject.get() != NULL)
250 SingletonObject.reset();
252 static ConnectionWrapper* get_connection_wrapper(void)
253 { return WrappedConnection.get(); }
255 static void ensure_singleton_there(void)
257 if (SingletonObject.get() == NULL)
261 // create an exec-method for each possible number of parameters
262 #define _GEN_PLACEHOLDER(z,n,d) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
263 #define _GEN_EXEC(z,n,d) \
264 template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
265 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > exec \
267 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
270 boost::function<R(Client*)>(*p)(R(Client::*)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
271 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg)) \
272 = &T2nSingletonWrapper::template prep<R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg) >; \
275 T2nSingletonWrapper::template real_exec<R>, \
276 boost::bind( p, f BOOST_PP_COMMA_IF(n) \
277 BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \
281 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
284 #undef _GEN_PLACEHOLDER
288 // create an t2n_exec-method for each possible number of parameters
289 #define _GEN_EXEC(z,n,d) \
290 template< class Client, typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
291 static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > t2n_exec \
293 R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
296 return T2nSingletonWrapper<Client>::exec(f); \
299 BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
302 #undef _GEN_PLACEHOLDER