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