Remove use of a global variable for JSContext on WidgetInterface plugin
[platform/framework/web/wrt-plugins-common.git] / src / standards / W3C / Widget / JSWidget.cpp
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  *
18  * @file        JSWidget.cpp
19  * @author      Grzegorz Krawczyk (g.krawczyk@samsung.com)
20  * @version     0.1
21  */
22
23 #include "JSWidget.h"
24 #include <memory>
25 #include <CommonsJavaScript/Converter.h>
26 #include <dpl/log/log.h>
27 #include <dpl/assert.h>
28 #include <Widget/WidgetFactory.h>
29 #include <CommonsJavaScript/JSDOMExceptionFactory.h>
30 #include "JSPreferences.h"
31 #include <Widget/IWidget.h>
32 #include <LocalStorage/LocalStorageMgr.h>
33 #include <Commons/WrtAccess/WrtAccess.h>
34
35 // temporary
36 extern "C" JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx);
37
38 #define CATCH_EXCEPTION_NO_MODIFABLE \
39     Catch(Commons::LocalStorageValueNoModifableException) { \
40         LogError("The item is read only"); \
41         return JSDOMExceptionFactory:: \
42                    NoModificationAllowedException.make(context, exception); \
43     }
44
45 #define CATCH_EXCEPTION_CONVERSION \
46     Catch(Commons::ConversionException) { \
47         LogError("Error on conversion"); \
48         return JSDOMExceptionFactory:: \
49                    UnknownException.make(context, exception); \
50     }
51
52 #define CATCH_EXCEPTION_NULL_PTR \
53     Catch(Commons::NullPointerException) { \
54         LogError("Error on pointer, null value"); \
55         return JSDOMExceptionFactory:: \
56                    UnknownException.make(context, exception); \
57     }
58
59 #define CATCH_EXCEPTION_PLATFORM_ERROR \
60     Catch(Commons::PlatformException){ \
61         LogError("PlatformException occured"); \
62         return JSDOMExceptionFactory:: \
63                    UnknownException.make(context, exception); \
64     }
65
66 #define CATCH_EXCEPTION_SECURITY \
67     Catch(Commons::SecurityException){ \
68         LogError("Security exception occured"); \
69         return JSDOMExceptionFactory:: \
70                    SecurityException.make(context, exception); \
71     }
72
73 #define CATCH_EXCEPTION_OUT_OF_RANGE \
74     Catch(Commons::OutOfRangeException) { \
75         LogError("OutOfRangeException"); \
76         return JSDOMExceptionFactory:: \
77                    QuotaExceededException.make(context, exception); \
78     }
79
80 #define CATCH_EXCEPTION_INVALID_ARG \
81     Catch(Commons::InvalidArgumentException) { \
82         LogError("Pair for given key doesnt exist"); \
83         return JSValueMakeNull(context); \
84     }
85
86 #define WIDGET_PLUGIN_NAME "Widget"
87
88 #define WRT_WIDGET_PROPERTY_AUTHOR       "author"
89 #define WRT_WIDGET_PROPERTY_AUTHOR_EMAIL "authorEmail"
90 #define WRT_WIDGET_PROPERTY_AUTHOR_HREF  "authorHref"
91 #define WRT_WIDGET_PROPERTY_DESCRIPTION  "description"
92 #define WRT_WIDGET_PROPERTY_ID           "id"
93 #define WRT_WIDGET_PROPERTY_NAME         "name"
94 #define WRT_WIDGET_PROPERTY_SHORT_NAME   "shortName"
95 #define WRT_WIDGET_PROPERTY_VERSION      "version"
96 #define WRT_WIDGET_PROPERTY_HEIGHT       "height"
97 #define WRT_WIDGET_PROPERTY_WIDTH        "width"
98
99 namespace WrtPlugins {
100 namespace W3C {
101 using namespace WrtDeviceApis;
102 using namespace WrtDeviceApis::Commons;
103 using namespace WrtDeviceApis::CommonsJavaScript;
104 using namespace WrtDeviceApis::Widget;
105
106 struct WidgetPrivateObject
107 {
108     Widget::Api::IWidgetPtr iwidget;
109     JSObjectRef preferencesObject;
110     //TEMP
111     //int widgetId      // TODO: check is it necessary (g.rynkowski)
112     JSObjectRef widgetObject;
113 };
114 typedef std::shared_ptr<WidgetPrivateObject> WidgetPrivateObjectPtr;
115
116 typedef WrtDeviceApis::CommonsJavaScript::PrivateObjectT
117 <WidgetPrivateObjectPtr>::Type JSWidgetPrivateObject;
118
119 WrtDeviceApis::Widget::Api::IWidgetPtr getIWidget(JSObjectRef arg)
120 {
121     JSWidgetPrivateObject* priv =
122         static_cast<JSWidgetPrivateObject*>(JSObjectGetPrivate(arg));
123
124     if (!priv) {
125         LogError("Private object not initialized");
126         ThrowMsg(Commons::NullPointerException,
127                  "Private object not initialized");
128     }
129
130     return priv->getObject()->iwidget;
131 }
132
133 LocalStorage::Api::ILocalStoragePtr getLocalStorage(int widgetId)
134 {
135     LocalStorage::Api::ILocalStoragePtr storage(
136         LocalStorage::Api::getLocalStorage(widgetId));
137
138     return storage;
139 }
140
141 JSObjectRef getPreferences(JSObjectRef arg)
142 {
143     JSWidgetPrivateObject* priv =
144         static_cast<JSWidgetPrivateObject*>(JSObjectGetPrivate(arg));
145
146     if (!priv) {
147         LogError("Private object not initialized");
148         return NULL;
149     }
150
151     return priv->getObject()->preferencesObject;
152 }
153
154 JSObjectRef createPreferencesObject(JSContextRef context,
155                                     JSObjectRef widgetObject,
156                                     int widgetId)
157 {
158     Assert(widgetObject && "Widget Object can'n be null");
159     //delete is invoked in JSPreferences::finalize
160     LocalStoragePrivateData* priv = new LocalStoragePrivateData;
161     Assert(priv && "Private data is null");
162     priv->istorage = getLocalStorage(widgetId);
163     priv->widgetObject = widgetObject;
164
165     JSObjectRef preferences = JSObjectMake(context,
166                                            JSPreferences::getClassRef(),
167                                            priv);
168
169     if (!preferences) {
170         LogError("Preferences object is null");
171         delete priv;
172     }
173     //Unprotect is called in JSWidget::finalize
174     JSValueProtect(context, preferences);
175
176     return preferences;
177 }
178
179 JSClassDefinition JSWidget::m_classInfo = {
180     0,
181     kJSClassAttributeNone,
182     WIDGET_PLUGIN_NAME,
183     0,
184     m_property,
185     NULL,
186     initialize,
187     finalize,
188     hasProperty,
189     getProperty,
190     setProperty,
191     NULL, //DeleteProperty,
192     NULL, //GetPropertyNames,
193     NULL, //CallAsFunction,
194     callAsConstructor,
195     NULL, //HasInstance,
196     NULL, //ConvertToType,
197 };
198
199 JSStaticValue JSWidget::m_property[] = {
200     { WRT_WIDGET_PROPERTY_AUTHOR, JSWidget::getAuthor,
201       0, kJSPropertyAttributeReadOnly },
202     { WRT_WIDGET_PROPERTY_AUTHOR_EMAIL, JSWidget::getAuthorEmail,
203       0, kJSPropertyAttributeReadOnly },
204     { WRT_WIDGET_PROPERTY_AUTHOR_HREF, JSWidget::getAuthorHref,
205       0, kJSPropertyAttributeReadOnly },
206     { WRT_WIDGET_PROPERTY_DESCRIPTION, JSWidget::getDescription,
207       0, kJSPropertyAttributeReadOnly },
208     { WRT_WIDGET_PROPERTY_ID, JSWidget::getId,
209       0, kJSPropertyAttributeReadOnly },
210     { WRT_WIDGET_PROPERTY_NAME, JSWidget::getName,
211       0, kJSPropertyAttributeReadOnly },
212     { WRT_WIDGET_PROPERTY_SHORT_NAME, JSWidget::getShortName,
213       0, kJSPropertyAttributeReadOnly },
214     { WRT_WIDGET_PROPERTY_VERSION, JSWidget::getVersion,
215       0, kJSPropertyAttributeReadOnly },
216     { WRT_WIDGET_PROPERTY_HEIGHT, JSWidget::getHeight,
217       0, kJSPropertyAttributeReadOnly },
218     { WRT_WIDGET_PROPERTY_WIDTH, JSWidget::getWidth,
219       0, kJSPropertyAttributeReadOnly },
220     { 0, 0, 0, 0 }
221 };
222
223 JSClassRef JSWidget::getClassRef()
224 {
225     if (!m_jsClassRef) {
226         m_jsClassRef = JSClassCreate(&m_classInfo);
227     }
228     return m_jsClassRef;
229 }
230
231 const JSClassDefinition* JSWidget::getClassInfo()
232 {
233     return &m_classInfo;
234 }
235
236 JSClassRef JSWidget::m_jsClassRef = JSClassCreate(JSWidget::getClassInfo());
237
238 void JSWidget::initialize(JSContextRef context,
239                           JSObjectRef object)
240 {
241     JSGlobalContextRef g_context = JSContextGetGlobalContext(context);
242
243     LogDebug("entered. Context : " << context << "(global:" << g_context << "), Object: " << object);
244
245     if (context != g_context)
246     {
247         context = g_context;
248     }
249
250     JSWidgetPrivateObject* priv =
251         static_cast<JSWidgetPrivateObject*>(JSObjectGetPrivate(object));
252
253     if (!priv) {
254         LogDebug("creation private object");
255
256         Try {
257             using namespace WrtDeviceApis::Commons;
258
259             Widget::Api::IWidgetPtr widget =
260                 Api::WidgetFactory::createWidget();
261             int widgetId = WrtAccessSingleton::Instance().getWidgetId();
262             JSObjectRef preferences =
263                 createPreferencesObject(context,
264                                         object,
265                                         widgetId);
266             if (!preferences) {
267                 LogError("Failed to create preferences object");
268             }
269
270             WidgetPrivateObjectPtr widgetPriv(new WidgetPrivateObject);
271             widgetPriv->iwidget = widget;
272             widgetPriv->preferencesObject = preferences;
273
274             priv = new JSWidgetPrivateObject(context, widgetPriv);
275             JSObjectSetPrivate(object, priv);
276         }
277         Catch(Commons::InvalidArgumentException){
278             LogError("You should register widget id in ON_WIDGET_START");
279             return;
280         }
281         Catch(DPL::Exception) {
282             LogError("Failed to create private object for JSWidget");
283             return;
284         }
285     }
286 }
287
288 void JSWidget::finalize(JSObjectRef object)
289 {
290     LogDebug("entered");
291     LogDebug("Object: " << object);
292     JSWidgetPrivateObject* priv =
293         static_cast<JSWidgetPrivateObject*>(JSObjectGetPrivate(object));
294
295     if (priv) {
296         JSValueUnprotect(priv->getContext(),
297                          priv->getObject()->preferencesObject);
298
299         delete priv;
300         LogDebug("private object is released");
301     } else {
302         LogDebug("private object wasn't created");
303     }
304 }
305
306 JSValueRef JSWidget::getAuthor(JSContextRef context,
307                                JSObjectRef object,
308                                JSStringRef /*propertyName*/,
309                                JSValueRef* exception)
310 {
311     LogDebug("entered");
312
313     Try {
314         Converter converter(context);
315         return converter.toJSValueRef(getIWidget(object)->getAuthor());
316     }
317     CATCH_EXCEPTION_CONVERSION
318     CATCH_EXCEPTION_NULL_PTR
319         CATCH_EXCEPTION_PLATFORM_ERROR
320 }
321
322 JSValueRef JSWidget::getAuthorEmail(JSContextRef context,
323                                     JSObjectRef object,
324                                     JSStringRef /*propertyName*/,
325                                     JSValueRef* exception)
326 {
327     Try {
328         Converter converter(context);
329         return converter.toJSValueRef(getIWidget(object)->getAuthorEmail());
330     }
331     CATCH_EXCEPTION_CONVERSION
332     CATCH_EXCEPTION_NULL_PTR
333         CATCH_EXCEPTION_PLATFORM_ERROR
334 }
335
336 JSValueRef JSWidget::getAuthorHref(JSContextRef context,
337                                    JSObjectRef object,
338                                    JSStringRef /*propertyName*/,
339                                    JSValueRef* exception)
340 {
341     Try {
342         Converter converter(context);
343         return converter.toJSValueRef(getIWidget(object)->getAuthorHref());
344     }
345     CATCH_EXCEPTION_CONVERSION
346     CATCH_EXCEPTION_NULL_PTR
347         CATCH_EXCEPTION_PLATFORM_ERROR
348 }
349
350 JSValueRef JSWidget::getDescription(JSContextRef context,
351                                     JSObjectRef object,
352                                     JSStringRef /*propertyName*/,
353                                     JSValueRef* exception)
354 {
355     Try {
356         Converter converter(context);
357         return converter.toJSValueRef(getIWidget(object)->getDescription());
358     }
359     CATCH_EXCEPTION_CONVERSION
360     CATCH_EXCEPTION_NULL_PTR
361         CATCH_EXCEPTION_PLATFORM_ERROR
362 }
363
364 JSValueRef JSWidget::getId(JSContextRef context,
365                            JSObjectRef object,
366                            JSStringRef /*propertyName*/,
367                            JSValueRef* exception)
368 {
369     Try {
370         Converter converter(context);
371         return converter.toJSValueRef(getIWidget(object)->getId());
372     }
373     CATCH_EXCEPTION_CONVERSION
374     CATCH_EXCEPTION_NULL_PTR
375         CATCH_EXCEPTION_PLATFORM_ERROR
376 }
377
378 JSValueRef JSWidget::getName(JSContextRef context,
379                              JSObjectRef object,
380                              JSStringRef /*propertyName*/,
381                              JSValueRef* exception)
382 {
383     Try {
384         Converter converter(context);
385         return converter.toJSValueRef(getIWidget(object)->getName());
386     }
387     CATCH_EXCEPTION_CONVERSION
388     CATCH_EXCEPTION_NULL_PTR
389         CATCH_EXCEPTION_PLATFORM_ERROR
390 }
391
392 JSValueRef JSWidget::getShortName(JSContextRef context,
393                                   JSObjectRef object,
394                                   JSStringRef /*propertyName*/,
395                                   JSValueRef* exception)
396 {
397     Try {
398         Converter converter(context);
399         return converter.toJSValueRef(getIWidget(object)->getShortName());
400     }
401     CATCH_EXCEPTION_CONVERSION
402     CATCH_EXCEPTION_NULL_PTR
403         CATCH_EXCEPTION_PLATFORM_ERROR
404 }
405
406 JSValueRef JSWidget::getVersion(JSContextRef context,
407                                 JSObjectRef object,
408                                 JSStringRef /*propertyName*/,
409                                 JSValueRef* exception)
410 {
411     Try {
412         Converter converter(context);
413         return converter.toJSValueRef(getIWidget(object)->getVersion());
414     }
415     CATCH_EXCEPTION_CONVERSION
416     CATCH_EXCEPTION_NULL_PTR
417         CATCH_EXCEPTION_PLATFORM_ERROR
418 }
419
420 JSValueRef JSWidget::getHeight(JSContextRef context,
421                                JSObjectRef object,
422                                JSStringRef /*propertyName*/,
423                                JSValueRef* exception)
424 {
425     Try {
426         Converter converter(context);
427         unsigned int height = getIWidget(object)->getHeight();
428         if (0 == height) {
429             height = 1;
430         }
431         return converter.toJSValueRef(height);
432     }
433     CATCH_EXCEPTION_CONVERSION
434     CATCH_EXCEPTION_NULL_PTR
435         CATCH_EXCEPTION_PLATFORM_ERROR
436 }
437
438 JSValueRef JSWidget::getWidth(JSContextRef context,
439                               JSObjectRef object,
440                               JSStringRef /*propertyName*/,
441                               JSValueRef* exception)
442 {
443     Try {
444         Converter converter(context);
445         unsigned int width = getIWidget(object)->getWidth();
446         if (0 == width) {
447             width = 1;
448         }
449         return converter.toJSValueRef(width);
450     }
451     CATCH_EXCEPTION_CONVERSION
452     CATCH_EXCEPTION_NULL_PTR
453         CATCH_EXCEPTION_PLATFORM_ERROR
454 }
455
456 bool JSWidget::hasProperty(JSContextRef context,
457                            JSObjectRef /*object*/,
458                            JSStringRef propertyName)
459 {
460     LogDebug("enter");
461
462     Try {
463         Converter converter(context);
464
465         std::string key = converter.toString(propertyName);
466         if (key == "preferences") {
467             return true;
468         }
469     }
470     Catch(Commons::InvalidArgumentException) {
471         LogDebug("Pair for given key doesnt exist");
472     }
473
474     Catch(Commons::ConversionException) {
475         LogError("Error on conversion");
476     }
477
478     Catch(Commons::NullPointerException) {
479         LogError("Error on pointer, null value");
480     }
481
482     Catch(Commons::PlatformException){
483         LogError("PlatformException occured");
484     }
485     return false;
486 }
487
488 JSValueRef JSWidget::getProperty(JSContextRef context,
489                                  JSObjectRef object,
490                                  JSStringRef propertyName,
491                                  JSValueRef* exception)
492 {
493     LogDebug("Object: " << object);
494
495     Try {
496         Converter converter(context);
497
498         std::string key = converter.toString(propertyName);
499
500         if (key == "preferences") {
501             Converter converter(context);
502             JSObjectRef pref = getPreferences(object);
503             if (!pref) {
504                 LogError("Preferences object is NULL");
505                 return JSValueMakeUndefined(context);
506             }
507             return pref;
508         }
509         LogError("Property NOT supported: " << propertyName);
510         return JSValueMakeUndefined(context);
511     }
512
513     CATCH_EXCEPTION_CONVERSION
514     CATCH_EXCEPTION_NULL_PTR
515         CATCH_EXCEPTION_INVALID_ARG
516 }
517
518 bool JSWidget::setProperty(JSContextRef context,
519                            JSObjectRef /*object*/,
520                            JSStringRef propertyName,
521                            JSValueRef /*jvalue*/,
522                            JSValueRef* exception)
523 {
524     LogDebug("enter");
525
526     Try {
527         Converter converter(context);
528
529         std::string key = converter.toString(propertyName);
530         if (key == "preferences") {
531             LogError("Object is read only");
532             return true;
533         }
534     }
535     CATCH_EXCEPTION_INVALID_ARG
536     CATCH_EXCEPTION_CONVERSION
537         CATCH_EXCEPTION_NULL_PTR
538
539     return false;
540 }
541
542 JSObjectRef JSWidget::callAsConstructor(JSContextRef context,
543                                         JSObjectRef /*constructor*/,
544                                         size_t /*argumentCount*/,
545                                         const JSValueRef /*arguments*/[],
546                                         JSValueRef* /*exception*/)
547 {
548     LogDebug("widget constructor");
549     return JSObjectMake(context, JSWidget::getClassRef(), NULL);
550 }
551
552 #undef CATCH_EXCEPTION_NO_MODIFABLE
553 #undef CATCH_EXCEPTION_CONVERSION
554 #undef CATCH_EXCEPTION_NULL_PTR
555 #undef CATCH_EXCEPTION_PLATFORM_ERROR
556 #undef CATCH_EXCEPTION_SECURITY
557 #undef CATCH_EXCEPTION_OUT_OF_RANGE
558 #undef CATCH_EXCEPTION_INVALID_ARG
559 }
560 }