Intra2net AG

client_wrapper.hxx

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2006 by Intra2net AG - Gerd v. Egidy
00003 
00004 The software in this package is distributed under the GNU General
00005 Public License version 2 (with a special exception described below).
00006 
00007 A copy of GNU General Public License (GPL) is included in this distribution,
00008 in the file COPYING.GPL.
00009 
00010 As a special exception, if other files instantiate templates or use macros
00011 or inline functions from this file, or you compile this file and link it
00012 with other works to produce a work based on this file, this file
00013 does not by itself cause the resulting work to be covered
00014 by the GNU General Public License.
00015 
00016 However the source code for this file must still be made available
00017 in accordance with section (3) of the GNU General Public License.
00018 
00019 This exception does not invalidate any other reasons why a work based
00020 on this file might be covered by the GNU General Public License.
00021 */
00022 #ifndef __LIBT2N_CLIENT_WRAPPER
00023 #define __LIBT2N_CLIENT_WRAPPER
00024 
00025 #include <functional>
00026 
00027 #include <boost/config.hpp>
00028 #include <boost/bind.hpp>
00029 #include <boost/function.hpp>
00030 #include <boost/preprocessor.hpp>
00031 
00032 #include <client.hxx>
00033 #include <command_client.hxx>
00034 
00035 #ifndef T2N_SINGLETON_WRAPPER_MAX_ARGS
00036 #define T2N_SINGLETON_WRAPPER_MAX_ARGS 9
00037 #endif
00038 
00039 namespace libt2n
00040 {
00041 
00048 class ConnectionWrapper
00049 {
00050     private:
00051         long long command_timeout_usec;
00052         long long hello_timeout_usec;
00053 
00054     protected:
00055         log_level_values log_level;
00056         std::ostream *logstream;
00057         void set_logging_on_connection(client_connection& c);
00058 
00059     public:
00060         ConnectionWrapper()
00061             : command_timeout_usec(command_client::command_timeout_usec_default),
00062               hello_timeout_usec(command_client::hello_timeout_usec_default),
00063               log_level(none),
00064               logstream(NULL)
00065             { }
00066 
00067         virtual ~ConnectionWrapper()
00068             { }
00069 
00077         virtual client_connection* get_connection()=0;
00078 
00090         virtual bool handle(command_client* stubBase, boost::function< void() > f)
00091         {
00092             f();
00093             return true;
00094         }
00095 
00096         long long get_command_timeout_usec(void)
00097             { return command_timeout_usec; }
00098 
00099         void set_command_timeout_usec(long long _command_timeout_usec)
00100             { command_timeout_usec=_command_timeout_usec; }
00101 
00102         long long get_hello_timeout_usec(void)
00103             { return hello_timeout_usec; }
00104 
00105         void set_hello_timeout_usec(long long _hello_timeout_usec)
00106             { hello_timeout_usec=_hello_timeout_usec; }
00107 
00108         virtual void set_logging(std::ostream *_logstream, log_level_values _log_level);
00109 
00110         std::ostream* get_logstream(log_level_values level);
00111 };
00112 
00113 // contains the internal stuff needed for T2nWrapper
00114 namespace detail
00115 {
00116 
00117     template< typename T >
00118     struct TypeWrap
00119     {
00120         typedef T type;
00121     };
00122 
00123     template< >
00124     struct TypeWrap< void >
00125     {
00126         typedef int type;
00127     };
00128 
00129     template< typename R >
00130     struct Call
00131     {
00132         typedef boost::function< R() > FuncType;
00133 
00134         FuncType function;
00135         R& result;
00136 
00137         Call( FuncType f, R& res ) : function(f), result( res ) {}
00138 
00139         void operator()()
00140         {
00141             result= function();
00142         }
00143     };
00144 
00145     template< >
00146     struct Call<void>
00147     {
00148         typedef boost::function< void() > FuncType;
00149         typedef TypeWrap< void >::type ResultType;
00150 
00151         FuncType function;
00152         ResultType& result;
00153 
00154         Call( FuncType f, ResultType& res ) : function(f), result( res ) {}
00155 
00156         void operator()()
00157         {
00158             function();
00159             result= ResultType();
00160         }
00161     };
00162 } // eo namespace detail
00163 
00164 class T2nSingletonWrapperMessages
00165 {
00166     protected:
00167         static const char* NotInitializedMessage;
00168 };
00169 
00184 template< class Client >
00185 class T2nSingletonWrapper : public T2nSingletonWrapperMessages
00186 {
00187     private:
00188         std::auto_ptr<Client> Stub;
00189 
00190         static std::auto_ptr<T2nSingletonWrapper> SingletonObject;
00191         static std::auto_ptr<ConnectionWrapper> WrappedConnection;
00192 
00194         // create a prep-method for each possible number of parameters
00195 #define _GEN_ARG(z,n,d) Arg ## n arg ##n
00196 #define _GEN_PREP(z,n,d) \
00197         template< typename R  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
00198         static boost::function< R(Client*) > prep \
00199         ( \
00200             R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
00201             BOOST_PP_COMMA_IF(n) \
00202             BOOST_PP_ENUM( n, _GEN_ARG, ~ ) \
00203         ) \
00204         { \
00205             return boost::bind< R > \
00206                 ( \
00207                     f, _1  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,arg) \
00208                 ); \
00209         } // eo prep
00210 
00211         BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ )
00212 
00213 #undef _GEN_PREP
00214 #undef _GEN_ARG
00216 
00217         T2nSingletonWrapper(std::auto_ptr<Client> stub)
00218         {
00219             Stub=stub;
00220         }
00221 
00222         static void init()
00223         {
00224             if (WrappedConnection.get() == NULL)
00225                 throw std::logic_error(NotInitializedMessage);
00226 
00227             std::auto_ptr<Client> stub(new Client(WrappedConnection->get_connection(),
00228                 WrappedConnection->get_command_timeout_usec(),
00229                 WrappedConnection->get_hello_timeout_usec()));
00230 
00231             SingletonObject=std::auto_ptr<T2nSingletonWrapper>(new T2nSingletonWrapper(stub));
00232         }
00233 
00234         template< typename R >
00235         static
00236         typename detail::TypeWrap<R>::type real_exec( boost::function< R(Client*) > f)
00237         {
00238             ensure_singleton_there();
00239 
00240             typename detail::TypeWrap<R>::type result;
00241 
00242             // bind our Client-object and the local result
00243             detail::Call<R> call( boost::bind( f, SingletonObject->Stub.get()), result );
00244 
00245             // let the wrapper-handler call the fully-bound function
00246             if (!WrappedConnection->handle(SingletonObject->Stub.get(),call))
00247             {
00248                 // create an result with default-constructor if the handler could not
00249                 // successfully do a call but no exception occured
00250                 result=typename detail::TypeWrap<R>::type();
00251             }
00252             return result;
00253         }
00254 
00255     public:
00256 
00260         static void set_connection(std::auto_ptr<ConnectionWrapper> wrappedConnection)
00261         {
00262             WrappedConnection=wrappedConnection;
00263 
00264             // reset the singleton to NULL because the singleton must be constructed with current WrappedConnection
00265             if (SingletonObject.get() != NULL)
00266                 SingletonObject.reset();
00267         }
00268 
00270         static ConnectionWrapper* get_connection_wrapper(void)
00271             { return WrappedConnection.get(); }
00272 
00274         static void ensure_singleton_there(void)
00275         {
00276             if (SingletonObject.get() == NULL)
00277                 init();
00278         }
00279 
00281         // create an exec-method for each possible number of parameters
00282 #define _GEN_PLACEHOLDER(z,n,d) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
00283 #define _GEN_EXEC(z,n,d) \
00284         template< typename R  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
00285         static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > exec \
00286         ( \
00287             R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
00288         ) \
00289         { \
00290             boost::function<R(Client*)>(*p)(R(Client::*)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
00291                     BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg)) \
00292                 = &T2nSingletonWrapper::template prep<R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg) >; \
00293             return boost::bind \
00294             ( \
00295                 T2nSingletonWrapper::template real_exec<R>, \
00296                 boost::bind( p, f BOOST_PP_COMMA_IF(n) \
00297                 BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \
00298             ); \
00299         } // eo exec
00300 
00301         BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
00302 
00303 #undef _GEN_EXEC
00304 #undef _GEN_PLACEHOLDER
00306 
00307 };
00308 
00310 // create an t2n_exec-method for each possible number of parameters
00311 #define _GEN_EXEC(z,n,d) \
00312         template< class Client, typename R  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
00313         static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > t2n_exec \
00314         ( \
00315             R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
00316         ) \
00317         { \
00318             return T2nSingletonWrapper<Client>::exec(f); \
00319         } // eo exec
00320 
00321         BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
00322 
00323 #undef _GEN_EXEC
00324 #undef _GEN_PLACEHOLDER
00326 
00327 }
00328 #endif

Generated on 13 May 2015 by  doxygen 1.6.1
© Intra2net AG 2024 | Legal | Contact