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