b71b3e6c4ce3227b5eff25a51399b6cc5ac9e57d
[platform/framework/web/crosswalk-tizen.git] / src / extension / widget / widget.cc
1 // Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #include "extension/widget/widget.h"
5
6 #include <list>
7 #include <memory>
8 #include <map>
9 #include <vector>
10
11 #include "extension/xwalk/XW_Extension.h"
12 #include "extension/xwalk/XW_Extension_EntryPoints.h"
13 #include "extension/xwalk/XW_Extension_Permissions.h"
14 #include "extension/xwalk/XW_Extension_Runtime.h"
15 #include "extension/xwalk/XW_Extension_SyncMessage.h"
16
17 #include "extension/widget/picojson.h"
18 #include "common/logger.h"
19 #include "common/app_db.h"
20 #include "common/application_data.h"
21 #include "common/locale_manager.h"
22 #include "common/string_utils.h"
23
24 XW_Extension g_xw_extension = 0;
25 std::string g_appid;
26 std::unique_ptr<wrt::ApplicationData> g_appdata;
27 const XW_CoreInterface* g_core = NULL;
28 const XW_MessagingInterface* g_messaging = NULL;
29 const XW_Internal_SyncMessagingInterface* g_sync_messaging = NULL;
30 const XW_Internal_EntryPointsInterface* g_entry_points = NULL;
31 const XW_Internal_RuntimeInterface* g_runtime = NULL;
32 extern const char kSource_widget_api[];
33
34 typedef void (*CmdHandler)(const picojson::value& args, picojson::object* out);
35
36 static void InitHandler(const picojson::value& args, picojson::object* out);
37 static void KeyHandler(const picojson::value& args, picojson::object* out);
38 static void GetItemHandler(const picojson::value& args,
39                            picojson::object* out);
40 static void LengthHandler(const picojson::value& args,
41                            picojson::object* out);
42 static void ClearHandler(const picojson::value& args,
43                            picojson::object* out);
44 static void SetItemHandler(const picojson::value& args,
45                            picojson::object* out);
46 static void RemoveHandler(const picojson::value& args,
47                            picojson::object* out);
48
49 std::map<std::string, CmdHandler> g_handler = {
50   {"init", InitHandler},
51   {"key", KeyHandler},
52   {"length", LengthHandler},
53   {"clear", ClearHandler},
54   {"getItem", GetItemHandler},
55   {"setItem", SetItemHandler},
56   {"removeItem", RemoveHandler},
57 };
58
59
60 static void HandleMessage(XW_Instance instance,
61                           const char* message,
62                           bool sync);
63
64 extern "C" int32_t XW_Initialize(XW_Extension extension,
65                                  XW_GetInterface get_interface) {
66   g_xw_extension = extension;
67   g_core = reinterpret_cast<const XW_CoreInterface*>(
68       get_interface(XW_CORE_INTERFACE));
69   if (!g_core) {
70     LOGGER(ERROR)
71         << "Can't initialize extension: error getting Core interface.";
72     return XW_ERROR;
73   }
74
75   g_messaging = reinterpret_cast<const XW_MessagingInterface*>(
76       get_interface(XW_MESSAGING_INTERFACE));
77   if (!g_messaging) {
78     LOGGER(ERROR)
79         << "Can't initialize extension: error getting Messaging interface.";
80     return XW_ERROR;
81   }
82
83   g_sync_messaging =
84       reinterpret_cast<const XW_Internal_SyncMessagingInterface*>(
85           get_interface(XW_INTERNAL_SYNC_MESSAGING_INTERFACE));
86   if (!g_sync_messaging) {
87     LOGGER(ERROR)
88         << "Can't initialize extension: "
89         << "error getting SyncMessaging interface.";
90     return XW_ERROR;
91   }
92
93   g_entry_points = reinterpret_cast<const XW_Internal_EntryPointsInterface*>(
94       get_interface(XW_INTERNAL_ENTRY_POINTS_INTERFACE));
95   if (!g_entry_points) {
96     LOGGER(ERROR)
97         << "NOTE: Entry points interface not available in this version "
98         << "of Crosswalk, ignoring entry point data for extensions.\n";
99     return XW_ERROR;
100   }
101
102   g_runtime = reinterpret_cast<const XW_Internal_RuntimeInterface*>(
103       get_interface(XW_INTERNAL_RUNTIME_INTERFACE));
104   if (!g_runtime) {
105     LOGGER(ERROR)
106         << "NOTE: runtime interface not available in this version "
107         << "of Crosswalk, ignoring runtime variables for extensions.\n";
108     return XW_ERROR;
109   }
110
111   std::vector<char> res(256, 0);
112   g_runtime->GetRuntimeVariableString(extension, "app_id", &res[0], 256);
113   g_appid = std::string(res.begin(), res.end());
114   if (g_appid.at(0) == '"') {
115     g_appid = g_appid.substr(1, g_appid.size()-2);
116   }
117
118   g_core->RegisterInstanceCallbacks(
119       g_xw_extension,
120       [](XW_Instance /*instance*/){
121         if (g_appdata.get() == NULL) {
122           g_appdata.reset(new wrt::ApplicationData(g_appid));
123         }
124         wrt::Widget::GetInstance()->Initialize(g_appdata.get());
125       },
126       NULL);
127
128   g_messaging->Register(g_xw_extension, [](XW_Instance instance,
129                                            const char* message) {
130     HandleMessage(instance, message, false);
131   });
132   g_sync_messaging->Register(g_xw_extension, [](XW_Instance instance,
133                                                 const char* message) {
134     HandleMessage(instance, message, true);
135   });
136
137   g_core->SetExtensionName(g_xw_extension, "Widget");
138   const char* entry_points[] = {"widget", NULL};
139   g_entry_points->SetExtraJSEntryPoints(g_xw_extension, entry_points);
140   g_core->SetJavaScriptAPI(g_xw_extension, kSource_widget_api);
141
142   return XW_OK;
143 }
144
145 static void InitHandler(const picojson::value& /*args*/,
146                         picojson::object* out) {
147   picojson::value result = picojson::value(picojson::object());
148   picojson::object& obj = result.get<picojson::object>();
149
150   auto widget_info = g_appdata->widget_info();
151   if (widget_info.get() == NULL) {
152     out->insert(std::make_pair("status", picojson::value("error")));
153     return;
154   }
155   out->insert(std::make_pair("status", picojson::value("success")));
156
157   wrt::LocaleManager locale_manager;
158   if (!widget_info->default_locale().empty()) {
159     locale_manager.SetDefaultLocale(widget_info->default_locale());
160   }
161
162   // TODO(sngn.lee): should be returned localized string
163   obj["author"] = picojson::value(widget_info->author());
164   obj["description"] = picojson::value(
165       locale_manager.GetLocalizedString(widget_info->description_set()));
166   obj["name"] = picojson::value(
167       locale_manager.GetLocalizedString(widget_info->name_set()));
168   obj["shortName"] = picojson::value(
169       locale_manager.GetLocalizedString(widget_info->short_name_set()));
170   obj["version"] = picojson::value(widget_info->version());
171   obj["id"] = picojson::value(widget_info->id());
172   obj["authorEmail"] = picojson::value(widget_info->author_email());
173   obj["authorHref"] = picojson::value(widget_info->author_href());
174   obj["height"] = picojson::value(static_cast<double>(widget_info->height()));
175   obj["width"] = picojson::value(static_cast<double>(widget_info->width()));
176
177   out->insert(std::make_pair("result", result));
178 }
179
180 static void KeyHandler(const picojson::value& args, picojson::object* out) {
181   int idx = static_cast<int>(args.get("idx").get<double>());
182   std::string key;
183   if (!wrt::Widget::GetInstance()->Key(idx, &key)) {
184     out->insert(std::make_pair("status", picojson::value("error")));
185     return;
186   }
187   out->insert(std::make_pair("status", picojson::value("success")));
188   out->insert(std::make_pair("result", picojson::value(key)));
189 }
190
191 static void GetItemHandler(const picojson::value& args,
192                            picojson::object* out) {
193   const std::string& key = args.get("key").get<std::string>();
194   std::string value;
195   if (!wrt::Widget::GetInstance()->GetItem(key, &value)) {
196     out->insert(std::make_pair("status", picojson::value("error")));
197     return;
198   }
199   out->insert(std::make_pair("status", picojson::value("success")));
200   out->insert(std::make_pair("result", picojson::value(value)));
201 }
202
203 static void LengthHandler(const picojson::value& /*args*/,
204                            picojson::object* out) {
205   int length = wrt::Widget::GetInstance()->Length();
206   out->insert(std::make_pair("status", picojson::value("success")));
207   out->insert(
208       std::make_pair("result", picojson::value(static_cast<double>(length))));
209 }
210
211 static void ClearHandler(const picojson::value& /*args*/,
212                            picojson::object* out) {
213   wrt::Widget::GetInstance()->Clear();
214   out->insert(std::make_pair("status", picojson::value("success")));
215 }
216
217 static void SetItemHandler(const picojson::value& args,
218                            picojson::object* out) {
219   const std::string& key = args.get("key").get<std::string>();
220   const std::string& value = args.get("value").get<std::string>();
221   std::string oldvalue;
222   if (wrt::Widget::GetInstance()->GetItem(key, &oldvalue)) {
223     out->insert(std::make_pair("result", picojson::value(oldvalue)));
224   } else {
225     out->insert(std::make_pair("result", picojson::value()));
226   }
227   wrt::Widget::GetInstance()->SetItem(key, value);
228   out->insert(std::make_pair("status", picojson::value("success")));
229 }
230
231 static void RemoveHandler(const picojson::value& args,
232                            picojson::object* out) {
233   const std::string& key = args.get("key").get<std::string>();
234   std::string oldvalue;
235   if (wrt::Widget::GetInstance()->GetItem(key, &oldvalue)) {
236     out->insert(std::make_pair("result", picojson::value(oldvalue)));
237   } else {
238     out->insert(std::make_pair("result", picojson::value()));
239   }
240   wrt::Widget::GetInstance()->RemoveItem(key);
241   out->insert(std::make_pair("status", picojson::value("success")));
242 }
243
244
245 static void HandleMessage(XW_Instance instance,
246                           const char* message,
247                           bool sync) {
248   picojson::value value;
249   std::string err;
250   picojson::parse(value, message, message + strlen(message), &err);
251   if (!err.empty()) {
252     LOGGER(ERROR) << "Ignoring message. " << err;
253     return;
254   }
255
256   if (!value.is<picojson::object>()) {
257     LOGGER(ERROR) << "Ignoring message. It is not an object.";
258     return;
259   }
260
261   std::string cmd = value.get("cmd").to_str();
262   // check for args in JSON message
263   const picojson::value& args = value.get("args");
264   picojson::value result = picojson::value(picojson::object());
265
266   auto handler = g_handler.find(cmd);
267   if (handler != g_handler.end()) {
268     handler->second(args, &result.get<picojson::object>());
269   } else {
270     result.get<picojson::object>().insert(
271         std::make_pair("status", picojson::value("error")));
272   }
273
274   if (sync) {
275     g_sync_messaging->SetSyncReply(instance, result.serialize().c_str());
276   }
277 }
278
279 namespace wrt {
280
281 namespace {
282   const char* kDbInitedCheckKey = "__WRT_DB_INITED__";
283   const char* kDBPublicSection = "public";
284   const char* kDBPrivateSection = "private";
285 }  // namespace
286
287
288 Widget* Widget::GetInstance() {
289   static Widget instance;
290   return &instance;
291 }
292
293 Widget::Widget() {
294 }
295 Widget::~Widget() {
296 }
297
298 void Widget::Initialize(const ApplicationData* appdata) {
299   AppDB* db = AppDB::GetInstance();
300   if (db->HasKey(kDBPrivateSection, kDbInitedCheckKey))
301     return;
302   if (appdata->widget_info() == NULL)
303     return;
304
305   auto preferences = appdata->widget_info()->preferences();
306   auto it = preferences.begin();
307   for ( ; it != preferences.end(); ++it) {
308     db->Set(kDBPublicSection,
309             (*it)->Name(),
310             (*it)->Value());
311   }
312   db->Set(kDBPrivateSection, kDbInitedCheckKey, "true");
313 }
314
315 int Widget::Length() {
316   AppDB* db = AppDB::GetInstance();
317   std::list<std::string> list;
318   db->GetKeys(kDBPublicSection, &list);
319   return list.size();
320 }
321
322 bool Widget::Key(int idx, std::string* key) {
323   AppDB* db = AppDB::GetInstance();
324   std::list<std::string> list;
325   db->GetKeys(kDBPublicSection, &list);
326
327   auto it = list.begin();
328   for ( ; it != list.end() && idx >= 0; ++it) {
329     if (idx == 0) {
330       *key = *it;
331       return true;
332     }
333     idx--;
334   }
335   return false;
336 }
337
338 bool Widget::GetItem(const std::string& key, std::string* value) {
339   AppDB* db = AppDB::GetInstance();
340   if (!db->HasKey(kDBPublicSection, key))
341     return false;
342   *value = db->Get(kDBPublicSection, key);
343   return true;
344 }
345
346 bool Widget::SetItem(const std::string& key, const std::string& value) {
347   AppDB* db = AppDB::GetInstance();
348   db->Set(kDBPublicSection, key, value);
349   return true;
350 }
351
352 bool Widget::RemoveItem(const std::string& key) {
353   AppDB* db = AppDB::GetInstance();
354   if (!db->HasKey(kDBPublicSection, key))
355     return false;
356   db->Remove(kDBPublicSection, key);
357   return true;
358 }
359
360 void Widget::Clear() {
361   AppDB* db = AppDB::GetInstance();
362   std::list<std::string> list;
363   db->GetKeys(kDBPublicSection, &list);
364   auto it = list.begin();
365   for ( ; it != list.end(); ++it) {
366     db->Remove(kDBPublicSection, *it);
367   }
368 }
369
370 }  // namespace wrt