Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_wearable / 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 class ObjectProxy;
40
41 /**
42  * Represents a remote method.
43  */
44 template<typename Result, typename ... Args>
45 class MethodProxy
46 {
47   public:
48     ~MethodProxy()
49     {
50         g_object_unref(m_connection);
51     }
52
53     /**
54      * Invokes remote method.
55      *
56      * @param args Input arguments for remote method.
57      * @return Value returned by remote method.
58      * @throw DBus::InvalidArgumentException If invalid argument(s) supplied.
59      * @throw DBus::ConnectionClosedException If connection is closed.
60      * @throw DBus::Exception If some other error occurs.
61      */
62     Result operator()(const Args& ... args)
63     {
64         return invoke(args ...);
65     }
66
67   private:
68     friend class ObjectProxy;
69
70     MethodProxy(GDBusConnection* connection,
71                 const std::string& serviceName,
72                 const std::string& objectPath,
73                 const std::string& interfaceName,
74                 const std::string& methodName) :
75         m_connection(connection),
76         m_serviceName(serviceName),
77         m_objectPath(objectPath),
78         m_interfaceName(interfaceName),
79         m_methodName(methodName)
80     {
81         Assert(m_connection && "Connection is not set.");
82
83         g_object_ref(m_connection);
84     }
85
86     /**
87      * @remarks Making it a template with parameter set by default to class
88      *          template parameter to overload on return type by utilizing
89      *          the SFINAE concept.
90      */
91     template<typename R = Result>
92     typename std::enable_if<!std::is_void<R>::value, R>::type
93     invoke(const Args& ... args)
94     {
95         GVariant* parameters = serialize(args ...);
96
97         GVariant* invokeResult = invokeSync(parameters);
98
99         R result;
100
101         ServerDeserialization::deserialize(invokeResult, &result);
102
103         g_variant_unref(invokeResult);
104
105         return result;
106     }
107
108     /**
109      * @remarks Void return type overload.
110      */
111     template<typename R = Result>
112     typename std::enable_if<std::is_void<R>::value>::type
113     invoke(const Args& ... args)
114     {
115         GVariant* parameters = serialize(args ...);
116
117         GVariant* invokeResult = invokeSync(parameters);
118
119         g_variant_unref(invokeResult);
120     }
121
122     /**
123      * @remarks ArgsM... are the same as Args...; it has been made a template
124      *          to make overloading/specialization possible.
125      */
126     template<typename ... ArgsM>
127     GVariant* serialize(ArgsM && ... args)
128     {
129         return ServerSerialization::serialize(std::forward<ArgsM>(args) ...);
130     }
131
132     /**
133      * @remarks Specialization for zero-argument functions.
134      */
135     GVariant* serialize()
136     {
137         return NULL;
138     }
139
140     /**
141      * Calls remote method over DBus.
142      *
143      * @param parameters Input parameters for the remote method.
144      * @return Result returned by the remote method.
145      * @throw DBus::InvalidArgumentException If invalid argument(s) supplied.
146      * @throw DBus::ConnectionClosedException If connection is closed.
147      * @throw DBus::Exception If some other error occurs.
148      */
149     GVariant* invokeSync(GVariant* parameters)
150     {
151         GError* error = NULL;
152
153         LogPedantic(
154             "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             std::ostringstream oss;
168             oss << "Error while invoking: "
169                 << m_interfaceName << "." << m_methodName
170                 << " <" << error->message << ">";
171             std::string message = oss.str();
172
173             gint code = error->code;
174
175             g_error_free(error);
176
177             switch (code) {
178             case G_IO_ERROR_INVALID_ARGUMENT:
179                 ThrowMsg(DBus::InvalidArgumentException, message);
180             case G_IO_ERROR_CLOSED:
181                 ThrowMsg(DBus::ConnectionClosedException, message);
182             default:
183                 ThrowMsg(DBus::Exception, message);
184             }
185         }
186
187         return result;
188     }
189
190     /**
191      * Default timeout for synchronous method call.
192      *
193      * @see GIO::GDBusConnection::g_dbus_connection_call_sync() for details.
194      */
195     static const gint DBUS_SYNC_CALL_TIMEOUT = -1;
196
197     GDBusConnection* m_connection;
198     std::string m_serviceName;
199     std::string m_objectPath;
200     std::string m_interfaceName;
201     std::string m_methodName;
202 };
203
204 /**
205  * Smart pointer for MethodProxy objects.
206  */
207 template<typename Result, typename ... Args>
208 class MethodProxyPtr
209 {
210   public:
211     explicit MethodProxyPtr(MethodProxy<Result, Args ...>* method = NULL) :
212         m_method(method)
213     {}
214
215     Result operator()(const Args& ... args) const
216     {
217         Assert(NULL != m_method.get() && "Method not set.");
218
219         return (*m_method)(args ...);
220     }
221
222   private:
223     std::shared_ptr<MethodProxy<Result, Args ...> > m_method;
224 };
225 }
226 }
227
228 #endif