tizen 2.4 release
[framework/context/context-common.git] / src / request_handler.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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 #include <new>
18 #include <glib.h>
19 #include <map>
20 #include <string>
21
22 #include <types_internal.h>
23 #include <scope_mutex.h>
24 #include <request_handler.h>
25 #include "response_handler.h"
26 #include "dbus_client.h"
27
28 typedef std::map<std::string, ctx::request_handler::subject_response_cb> response_cb_map_t;
29
30 static ctx::dbus_client *dbus_handle = NULL;
31 static response_cb_map_t *response_cb_map = NULL;
32
33 namespace {
34         class exit_handler {
35                 public:
36                         exit_handler() {}
37                         ~exit_handler() { delete dbus_handle; }
38         };
39 }       /* namespace ctx */
40
41 static exit_handler _exit_handler;
42
43 static int generate_req_id()
44 {
45         static GMutex rid_mutex;
46         static int req_id = 0;
47
48         ctx::scope_mutex sm(&rid_mutex);
49
50         // Overflow handling
51         if (++req_id < 0) {
52                 req_id = 1;
53         }
54
55         return req_id;
56 }
57
58 static bool initialize()
59 {
60         static GMutex init_mutex;
61         ctx::scope_mutex sm(&init_mutex);
62
63         if (dbus_handle) {
64                 return true;
65         }
66
67         response_cb_map = new(std::nothrow) response_cb_map_t;
68         IF_FAIL_CATCH_TAG(response_cb_map, _E, "Memory allocation failed");
69
70         dbus_handle = new(std::nothrow) ctx::dbus_client();
71         IF_FAIL_CATCH_TAG(dbus_handle, _E, "Memory allocation failed");
72         IF_FAIL_CATCH_TAG(dbus_handle->init(), _E, "Dbus initialization failed");
73
74         return true;
75
76 CATCH:
77         delete dbus_handle;
78         delete response_cb_map;
79         dbus_handle = NULL;
80         response_cb_map = NULL;
81         return false;
82 }
83
84 int ctx::request_handler::subscribe(const char* subject, ctx::json* option, int* req_id, ctx::json* request_result)
85 {
86         ASSERT_NOT_NULL(subject);
87         ASSERT_NOT_NULL(req_id);
88         IF_FAIL_RETURN_TAG(initialize(), ERR_OPERATION_FAILED, _E, "Connection failed");
89
90         *req_id = generate_req_id();
91
92         char *opt_str = NULL;
93         if (option) {
94                 opt_str = option->dup_cstr();
95                 IF_FAIL_RETURN_TAG(opt_str, ERR_OPERATION_FAILED, _E, "Json string creation failed");
96         }
97
98         _I("[Subscribe] ReqId: %d, Subject: %s", *req_id, subject);
99
100         std::string result_str;
101         int error = dbus_handle->request(REQ_SUBSCRIBE, *req_id, subject, opt_str, &result_str, NULL);
102         g_free(opt_str);
103
104         if (request_result) {
105                 *request_result = result_str;
106         }
107
108         _D("Error: %#x", error);
109         _SD("Result: %s", result_str.c_str());
110
111         return error;
112 }
113
114 int ctx::request_handler::unsubscribe(const char* subject, int req_id)
115 {
116         ASSERT_NOT_NULL(subject);
117         IF_FAIL_RETURN_TAG(initialize(), false, _E, "Connection failed");
118         _I("[Unsubscribe] ReqId: %d, Subject: %s", req_id, subject);
119         return dbus_handle->request(REQ_UNSUBSCRIBE, req_id, subject, NULL, NULL, NULL);
120 }
121
122 int ctx::request_handler::read(const char* subject, ctx::json* option, int* req_id, ctx::json* request_result)
123 {
124         ASSERT_NOT_NULL(subject);
125         ASSERT_NOT_NULL(req_id);
126         IF_FAIL_RETURN_TAG(initialize(), false, _E, "Connection failed");
127
128         *req_id = generate_req_id();
129
130         char *opt_str = NULL;
131         if (option) {
132                 opt_str = option->dup_cstr();
133                 IF_FAIL_RETURN_TAG(opt_str, ERR_OPERATION_FAILED, _E, "Json string creation failed");
134         }
135
136         _I("[Read] ReqId: %d, Subject: %s", *req_id, subject);
137
138         std::string result_str;
139         int error = dbus_handle->request(REQ_READ, *req_id, subject, opt_str, &result_str, NULL);
140         g_free(opt_str);
141
142         if (request_result) {
143                 *request_result = result_str;
144         }
145
146         _D("Error: %#x", error);
147         _SD("Result: %s", result_str.c_str());
148
149         return error;
150 }
151
152 int ctx::request_handler::read_sync(const char* subject, ctx::json* option, int* req_id, ctx::json* data_read)
153 {
154         ASSERT_NOT_NULL(subject);
155         ASSERT_NOT_NULL(req_id);
156         ASSERT_NOT_NULL(data_read);
157         IF_FAIL_RETURN_TAG(initialize(), false, _E, "Connection failed");
158
159         *req_id = generate_req_id();
160
161         char *opt_str = NULL;
162         if (option) {
163                 opt_str = option->dup_cstr();
164                 IF_FAIL_RETURN_TAG(opt_str, ERR_OPERATION_FAILED, _E, "Json string creation failed");
165         }
166
167         _I("[ReadSync] ReqId: %d, Subject: %s", *req_id, subject);
168
169         std::string data_str;
170         int error = dbus_handle->request(REQ_READ_SYNC, *req_id, subject, opt_str, NULL, &data_str);
171         g_free(opt_str);
172
173         *data_read = data_str;
174
175         _D("Error: %#x", error);
176         _SD("Data: %s", data_str.c_str());
177
178         return error;
179 }
180
181 int ctx::request_handler::write(const char* subject, ctx::json* data)
182 {
183         ASSERT_NOT_NULL(subject);
184         ASSERT_NOT_NULL(data);
185         IF_FAIL_RETURN_TAG(initialize(), false, _E, "Connection failed");
186
187         int req_id = generate_req_id();
188         char *data_str = data->dup_cstr();
189         IF_FAIL_RETURN_TAG(data_str, ERR_OPERATION_FAILED, _E, "Json string creation failed");
190
191         _I("[Write] ReqId: %d, Subject: %s", req_id, subject);
192         _SD("Data: %s", data_str);
193
194         int error = dbus_handle->request_with_no_reply(REQ_WRITE, req_id, subject, data_str);
195         g_free(data_str);
196
197         _D("Error: %#x", error);
198
199         return error;
200 }
201
202 int ctx::request_handler::write_with_reply(const char* subject, ctx::json* data, ctx::json* request_result)
203 {
204         ASSERT_NOT_NULL(subject);
205         ASSERT_NOT_NULL(data);
206         IF_FAIL_RETURN_TAG(initialize(), false, _E, "Connection failed");
207
208         int req_id = generate_req_id();
209         char *data_str = data->dup_cstr();
210         IF_FAIL_RETURN_TAG(data_str, ERR_OPERATION_FAILED, _E, "Json string creation failed");
211
212         _I("[Write with reply] ReqId: %d, Subject: %s", req_id, subject);
213         _SD("Data: %s", data_str);
214
215         std::string result_str;
216         int error = dbus_handle->request(REQ_WRITE, req_id, subject, data_str, &result_str, NULL);
217         g_free(data_str);
218
219         if (request_result) {
220                 *request_result = result_str;
221         }
222
223         _D("Error: %#x", error);
224         _SD("Result: %s", result_str.c_str());
225
226         return error;
227 }
228
229 int ctx::request_handler::is_supported(const char* subject)
230 {
231         ASSERT_NOT_NULL(subject);
232         IF_FAIL_RETURN_TAG(initialize(), false, _E, "Connection failed");
233         return dbus_handle->request(REQ_SUPPORT, generate_req_id(), subject, NULL, NULL, NULL);
234 }
235
236 bool ctx::request_handler::register_callback(const char* subject, subject_response_cb callback)
237 {
238         IF_FAIL_RETURN_TAG(subject && callback, false, _E, "Invalid parameter");
239         IF_FAIL_RETURN_TAG(initialize(), false, _E, "Connection failed");
240
241         _D("Registering callback for subject '%s'", subject);
242
243         static GMutex cb_list_mutex;
244         ctx::scope_mutex sm(&cb_list_mutex);
245
246         (*response_cb_map)[subject] = callback;
247
248         return true;
249 }
250
251 void ctx::response_handler::deliver(const char* subject, int req_id, int error, const char* data)
252 {
253         response_cb_map_t::iterator it = response_cb_map->find(subject);
254         IF_FAIL_VOID_TAG(it != response_cb_map->end(), _E, "Unknown subject '%s'", subject);
255
256         it->second(subject, req_id, error, data);
257 }