3d553cf56d6441c0590818c134e112c7b605deb1
[platform/framework/web/wrt-commons.git] / modules / dbus / include / dpl / dbus / method_proxy.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file    method_proxy.h
18  * @author  Zbigniew Kostrzewa (z.kostrzewa@samsung.com)
19  * @version 1.0
20  * @brief
21  */
22
23 #ifndef DPL_DBUS_METHOD_PROXY_H
24 #define DPL_DBUS_METHOD_PROXY_H
25
26 #include <type_traits>
27 #include <utility>
28 #include <memory>
29 #include <string>
30 #include <gio/gio.h>
31 #include <dpl/log/log.h>
32 #include <dpl/assert.h>
33 #include <dpl/dbus/exception.h>
34 #include <dpl/dbus/dbus_server_serialization.h>
35 #include <dpl/dbus/dbus_server_deserialization.h>
36
37 namespace DPL {
38 namespace DBus {
39
40 class ObjectProxy;
41
42 /**
43  * Represents a remote method.
44  */
45 template<typename Result, typename ...Args>
46 class MethodProxy
47 {
48 public:
49     ~MethodProxy()
50     {
51         g_object_unref(m_connection);
52     }
53
54     /**
55      * Invokes remote method.
56      *
57      * @param args Input arguments for remote method.
58      * @return Value returned by remote method.
59      * @throw DBus::InvalidArgumentException If invalid argument(s) supplied.
60      * @throw DBus::ConnectionClosedException If connection is closed.
61      * @throw DBus::Exception If some other error occurs.
62      */
63     Result operator()(const Args&... args)
64     {
65         return invoke(args...);
66     }
67
68 private:
69     friend class ObjectProxy;
70
71     MethodProxy(GDBusConnection* connection,
72                 const std::string& serviceName,
73                 const std::string& objectPath,
74                 const std::string& interfaceName,
75                 const std::string& methodName)
76         : m_connection(connection),
77           m_serviceName(serviceName),
78           m_objectPath(objectPath),
79           m_interfaceName(interfaceName),
80           m_methodName(methodName)
81     {
82         Assert(m_connection && "Connection is not set.");
83
84         g_object_ref(m_connection);
85     }
86
87     /**
88      * @remarks Making it a template with parameter set by default to class
89      *          template parameter to overload on return type by utilizing
90      *          the SFINAE concept.
91      */
92     template<typename R = Result>
93     typename std::enable_if<!std::is_void<R>::value, R>::type
94     invoke(const Args&... args)
95     {
96         GVariant* parameters = serialize(args...);
97
98         GVariant* invokeResult = invokeSync(parameters);
99
100         R result;
101
102         ServerDeserialization::deserialize(invokeResult, &result);
103
104         g_variant_unref(invokeResult);
105
106         return result;
107     }
108
109     /**
110      * @remarks Void return type overload.
111      */
112     template<typename R = Result>
113     typename std::enable_if<std::is_void<R>::value>::type
114     invoke(const Args&... args)
115     {
116         GVariant* parameters = serialize(args...);
117
118         GVariant* invokeResult = invokeSync(parameters);
119
120         g_variant_unref(invokeResult);
121     }
122
123     /**
124      * @remarks ArgsM... are the same as Args...; it has been made a template
125      *          to make overloading/specialization possible.
126      */
127     template<typename ...ArgsM>
128     GVariant* serialize(ArgsM&&... args)
129     {
130         return ServerSerialization::serialize(std::forward<ArgsM>(args)...);
131     }
132
133     /**
134      * @remarks Specialization for zero-argument functions.
135      */
136     GVariant* serialize()
137     {
138         return NULL;
139     }
140
141     /**
142      * Calls remote method over DBus.
143      *
144      * @param parameters Input parameters for the remote method.
145      * @return Result returned by the remote method.
146      * @throw DBus::InvalidArgumentException If invalid argument(s) supplied.
147      * @throw DBus::ConnectionClosedException If connection is closed.
148      * @throw DBus::Exception If some other error occurs.
149      */
150     GVariant* invokeSync(GVariant* parameters)
151     {
152         GError* error = NULL;
153
154         LogPedantic("Invoking method: " << m_interfaceName << "." << m_methodName);
155         GVariant* result = g_dbus_connection_call_sync(m_connection,
156                                                        m_serviceName.c_str(),
157                                                        m_objectPath.c_str(),
158                                                        m_interfaceName.c_str(),
159                                                        m_methodName.c_str(),
160                                                        parameters,
161                                                        G_VARIANT_TYPE_TUPLE,
162                                                        G_DBUS_CALL_FLAGS_NONE,
163                                                        DBUS_SYNC_CALL_TIMEOUT,
164                                                        NULL,
165                                                        &error);
166         if (NULL == result)
167         {
168             std::ostringstream oss;
169             oss << "Error while invoking: "
170                 << m_interfaceName << "." << m_methodName
171                 << " <" << error->message << ">";
172             std::string message = oss.str();
173
174             gint code = error->code;
175
176             g_error_free(error);
177
178             switch (code)
179             {
180             case G_IO_ERROR_INVALID_ARGUMENT:
181                 ThrowMsg(DBus::InvalidArgumentException, message);
182             case G_IO_ERROR_CLOSED:
183                 ThrowMsg(DBus::ConnectionClosedException, message);
184             default:
185                 ThrowMsg(DBus::Exception, message);
186             }
187         }
188
189         return result;
190     }
191
192     /**
193      * Default timeout for synchronous method call.
194      *
195      * @see GIO::GDBusConnection::g_dbus_connection_call_sync() for details.
196      */
197     static const gint DBUS_SYNC_CALL_TIMEOUT = -1;
198
199     GDBusConnection* m_connection;
200     std::string m_serviceName;
201     std::string m_objectPath;
202     std::string m_interfaceName;
203     std::string m_methodName;
204 };
205
206 /**
207  * Smart pointer for MethodProxy objects.
208  */
209 template<typename Result, typename ...Args>
210 class MethodProxyPtr
211 {
212 public:
213     explicit MethodProxyPtr(MethodProxy<Result, Args...>* method = NULL)
214         : m_method(method)
215     {
216     }
217
218     Result operator()(const Args&... args) const
219     {
220         Assert(NULL != m_method.get() && "Method not set.");
221
222         return (*m_method)(args...);
223     }
224
225 private:
226     std::shared_ptr<MethodProxy<Result, Args...> > m_method;
227 };
228
229 }
230 }
231
232 #endif