/*************************************************************************** * Copyright (C) 2008 by Gerd v. Egidy and Reinhard Pfau * * gve@intra2net.com * * * * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef __LIBT2N_CLIENT_WRAPPER #define __LIBT2N_CLIENT_WRAPPER #include #include #include #include #include #include #include #include #ifndef T2N_SINGLETON_WRAPPER_MAX_ARGS #define T2N_SINGLETON_WRAPPER_MAX_ARGS 9 #endif namespace libt2n { class ConnectionWrapper { public: virtual client_connection* get_connection()=0; virtual long long get_command_timeout_usec(void) { return command_client::command_timeout_usec_default; } virtual long long get_hello_timeout_usec(void) { return command_client::hello_timeout_usec_default; } virtual void handle(command_client* stubBase, boost::function< void() > f) { f(); } virtual ~ConnectionWrapper() { } }; // contains the internal stuff needed for T2nWrapper namespace detail { template< typename T > struct TypeWrap { typedef T type; }; template< > struct TypeWrap< void > { typedef int type; }; template< typename R > struct Call { typedef boost::function< R() > FuncType; FuncType function; R& result; Call( FuncType f, R& res ) : function(f), result( res ) {} void operator()() { result= function(); } }; template< > struct Call { typedef boost::function< void() > FuncType; typedef TypeWrap< void >::type ResultType; FuncType function; ResultType& result; Call( FuncType f, ResultType& res ) : function(f), result( res ) {} void operator()() { function(); result= ResultType(); } }; } // eo namespace detail class T2nSingletonWrapperMessages { protected: static const char* NotInitializedMessage; }; template< class Client > class T2nSingletonWrapper : public T2nSingletonWrapperMessages { private: std::auto_ptr Stub; static std::auto_ptr SingletonObject; static std::auto_ptr WrappedConnection; // create a prep-method for each possible number of parameters #define _GEN_ARG(z,n,d) Arg ## n arg ##n #define _GEN_PREP(z,n,d) \ template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \ static boost::function< R(Client*) > prep \ ( \ R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \ BOOST_PP_COMMA_IF(n) \ BOOST_PP_ENUM( n, _GEN_ARG, ~ ) \ ) \ { \ return boost::bind< R > \ ( \ f, _1 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,arg) \ ); \ } // eo prep BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ ) #undef _GEN_PREP #undef _GEN_ARG T2nSingletonWrapper(std::auto_ptr stub) { Stub=stub; } static void init() { if (WrappedConnection.get() == NULL) throw std::logic_error(NotInitializedMessage); std::auto_ptr stub(new Client(*(WrappedConnection->get_connection()), WrappedConnection->get_command_timeout_usec(), WrappedConnection->get_hello_timeout_usec())); SingletonObject=std::auto_ptr(new T2nSingletonWrapper(stub)); } template< typename R > static typename detail::TypeWrap::type real_exec( boost::function< R(Client*) > f) { ensure_singleton_there(); typename detail::TypeWrap::type result; detail::Call call( boost::bind( f, SingletonObject->Stub.get()), result ); WrappedConnection->handle(SingletonObject->Stub.get(),call); return result; } public: static void set_connection(std::auto_ptr wrappedConnection) { WrappedConnection=wrappedConnection; // reset the singleton to NULL because the singleton must be constructed with current WrappedConnection if (SingletonObject.get() != NULL) SingletonObject.reset(); } static ConnectionWrapper* get_connection(void) { return WrappedConnection.get(); } static void ensure_singleton_there(void) { if (SingletonObject.get() == NULL) init(); } // create an exec-method for each possible number of parameters #define _GEN_PLACEHOLDER(z,n,d) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1)) #define _GEN_EXEC(z,n,d) \ template< typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \ static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > exec \ ( \ R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \ ) \ { \ boost::function(*p)(R(Client::*)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \ BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg)) \ = &T2nSingletonWrapper::template prep; \ return boost::bind \ ( \ T2nSingletonWrapper::template real_exec, \ boost::bind( p, f BOOST_PP_COMMA_IF(n) \ BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \ ); \ } // eo exec BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ ) #undef _GEN_EXEC #undef _GEN_PLACEHOLDER }; // create an t2n_exec-method for each possible number of parameters #define _GEN_EXEC(z,n,d) \ template< class Client, typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \ static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > t2n_exec \ ( \ R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \ ) \ { \ return T2nSingletonWrapper::exec(f); \ } // eo exec BOOST_PP_REPEAT( BOOST_PP_ADD(T2N_SINGLETON_WRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ ) #undef _GEN_EXEC #undef _GEN_PLACEHOLDER } #endif