08cd39706ffe7e1b196586543386e8ae3ca59c92
[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 T2NWRAPPER_MAX_ARGS
34 #define T2NWRAPPER_MAX_ARGS 9
35 #endif
36
37 namespace libt2n
38 {
39
40 class ConnectionInitData
41 {
42     public:
43
44         virtual std::auto_ptr<client_connection> createConnection()=0;
45
46         virtual ~ConnectionInitData()
47             { }
48 };
49
50 class TrivialHandler
51 {
52     public:
53         static void handle( boost::function< void() > f)
54         {
55             f();
56         }
57 };
58
59 // contains the internal stuff needed for T2nWrapper
60 namespace detail
61 {
62
63     template< typename T >
64     struct TypeWrap
65     {
66         typedef T type;
67     };
68
69     template< >
70     struct TypeWrap< void >
71     {
72         typedef int type;
73     };
74
75     template< typename R >
76     struct Call
77     {
78         typedef boost::function< R() > FuncType;
79
80         FuncType function;
81         R& result;
82
83         Call( FuncType f, R& res ) : function(f), result( res ) {}
84
85         void operator()()
86         {
87             result= function();
88         }
89     };
90
91     template< >
92     struct Call<void>
93     {
94         typedef boost::function< void() > FuncType;
95         typedef TypeWrap< void >::type ResultType;
96
97         FuncType function;
98         ResultType& result;
99
100         Call( FuncType f, ResultType& res ) : function(f), result( res ) {}
101
102         void operator()()
103         {
104             function();
105             result= ResultType();
106         }
107     };
108 } // eo namespace detail
109
110 template<
111     class Client,
112     class Handler = TrivialHandler
113 >
114 class T2nWrapper
115 {
116     private:
117
118         std::auto_ptr<client_connection> conndConn;
119         std::auto_ptr<Client> client;
120
121         static std::auto_ptr<T2nWrapper> singletonObject;
122         static std::auto_ptr<ConnectionInitData> initData;
123
124         // create a prep-method for each possible number of parameters
125 #define _GEN_ARG(z,n,d) Arg ## n arg ##n
126 #define _GEN_PREP(z,n,d) \
127         template< typename R  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
128         static boost::function< R(Client*) > prep \
129         ( \
130             R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
131             BOOST_PP_COMMA_IF(n) \
132             BOOST_PP_ENUM( n, _GEN_ARG, ~ ) \
133         ) \
134         { \
135             return boost::bind< R > \
136                 ( \
137                     f, _1  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,arg) \
138                 ); \
139         } // eo prep
140
141         BOOST_PP_REPEAT( BOOST_PP_ADD(T2NWRAPPER_MAX_ARGS,1) , _GEN_PREP, ~ )
142
143 #undef _GEN_PREP
144 #undef _GEN_ARG
145
146         static void ensureSingletonThere(void)
147         {
148             if (singletonObject.get() == NULL)
149             {
150                 // we need to initialize
151
152                 if (initData.get() == NULL)
153                     throw std::logic_error("T2nWrapper singleton used before setting initData");
154
155                 std::auto_ptr<client_connection> myConndConn=initData->createConnection();
156
157             }
158         }
159
160         template< typename R >
161         static
162         typename detail::TypeWrap<R>::type real_exec( boost::function< R(Client*) > f)
163         {
164             ensureSingletonThere();
165
166             typename detail::TypeWrap<R>::type result;
167             detail::Call<R> call( boost::bind( f, &(*(singletonObject->client))), result );
168             Handler::handle( call );
169             return result;
170         }
171
172     public:
173
174         static void setInitData(std::auto_ptr<ConnectionInitData> newInitData)
175             { initData=newInitData; }
176         static ConnectionInitData* getInitData(void)
177             { return initData.get(); }
178
179         T2nWrapper()
180         {
181             client=std::auto_ptr<Client>(new Client(*conndConn));
182         }
183
184         // create an exec-method for each possible number of parameters
185 #define _GEN_PLACEHOLDER(z,n,d) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
186 #define _GEN_EXEC(z,n,d) \
187         template< typename R  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,typename Arg) > \
188         static boost::function< R( BOOST_PP_ENUM_PARAMS(n,Arg) ) > exec \
189         ( \
190             R(Client::*f)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
191         ) \
192         { \
193             boost::function<R(Client*)>(*p)(R(Client::*)( BOOST_PP_ENUM_PARAMS(n,Arg) ) \
194                     BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg)) \
195                 = &T2nWrapper::template prep<R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,Arg) >; \
196             return boost::bind \
197             ( \
198                 T2nWrapper::template real_exec<R>, \
199                 boost::bind( p, f BOOST_PP_COMMA_IF(n) \
200                 BOOST_PP_ENUM(n, _GEN_PLACEHOLDER, ~ ) ) \
201             ); \
202         } // eo exec
203
204         BOOST_PP_REPEAT( BOOST_PP_ADD(T2NWRAPPER_MAX_ARGS,1), _GEN_EXEC, ~ )
205
206 #undef _GEN_EXEC
207 #undef _GEN_PLACEHOLDER
208
209 };
210
211 }
212 #endif