8a6843cf2c71f8d1cbe8ffd3d87613f14746e536
[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 << ", Object: " << object);
241
242     JSWidgetPrivateObject* priv =
243         static_cast<JSWidgetPrivateObject*>(JSObjectGetPrivate(object));
244
245     if (!priv) {
246         LogDebug("creation private object");
247
248         Try {
249             using namespace WrtDeviceApis::Commons;
250
251             Widget::Api::IWidgetPtr widget =
252                 Api::WidgetFactory::createWidget();
253             int widgetId = WrtAccessSingleton::Instance().getWidgetId();
254             JSObjectRef preferences =
255                 createPreferencesObject(context,
256                                         object,
257                                         widgetId);
258             if (!preferences) {
259                 LogError("Failed to create preferences object");
260             }
261
262             WidgetPrivateObjectPtr widgetPriv(new WidgetPrivateObject);
263             widgetPriv->iwidget = widget;
264             widgetPriv->preferencesObject = preferences;
265
266             priv = new JSWidgetPrivateObject(context, widgetPriv);
267             JSObjectSetPrivate(object, priv);
268         }
269         Catch(Commons::InvalidArgumentException){
270             LogError("You should register widget id in ON_WIDGET_START");
271             return;
272         }
273         Catch(DPL::Exception) {
274             LogError("Failed to create private object for JSWidget");
275             return;
276         }
277     }
278 }
279
280 void JSWidget::finalize(JSObjectRef object)
281 {
282     LogDebug("entered");
283     LogDebug("Object: " << object);
284     JSWidgetPrivateObject* priv =
285         static_cast<JSWidgetPrivateObject*>(JSObjectGetPrivate(object));
286
287     if (priv) {
288         JSValueUnprotect(priv->getContext(),
289                          priv->getObject()->preferencesObject);
290
291         delete priv;
292         LogDebug("private object is released");
293     } else {
294         LogDebug("private object wasn't created");
295     }
296 }
297
298 void JSWidget::acquireGlobalContext(java_script_context_t global_context,
299                                     js_object_instance_t /*iframe*/,
300                                     js_object_instance_t /*object*/)
301 {
302     if (!m_globalContext) {
303         m_globalContext = static_cast<JSContextRef>(global_context);
304         LogInfo("Global context acquired.");
305     } else {
306         LogInfo("Global context already set.");
307     }
308 }
309
310 JSValueRef JSWidget::getAuthor(JSContextRef context,
311                                JSObjectRef object,
312                                JSStringRef /*propertyName*/,
313                                JSValueRef* exception)
314 {
315     LogDebug("entered");
316
317     Try {
318         Converter converter(context);
319         return converter.toJSValueRef(getIWidget(object)->getAuthor());
320     }
321     CATCH_EXCEPTION_CONVERSION
322     CATCH_EXCEPTION_NULL_PTR
323         CATCH_EXCEPTION_PLATFORM_ERROR
324 }
325
326 JSValueRef JSWidget::getAuthorEmail(JSContextRef context,
327                                     JSObjectRef object,
328                                     JSStringRef /*propertyName*/,
329                                     JSValueRef* exception)
330 {
331     Try {
332         Converter converter(context);
333         return converter.toJSValueRef(getIWidget(object)->getAuthorEmail());
334     }
335     CATCH_EXCEPTION_CONVERSION
336     CATCH_EXCEPTION_NULL_PTR
337         CATCH_EXCEPTION_PLATFORM_ERROR
338 }
339
340 JSValueRef JSWidget::getAuthorHref(JSContextRef context,
341                                    JSObjectRef object,
342                                    JSStringRef /*propertyName*/,
343                                    JSValueRef* exception)
344 {
345     Try {
346         Converter converter(context);
347         return converter.toJSValueRef(getIWidget(object)->getAuthorHref());
348     }
349     CATCH_EXCEPTION_CONVERSION
350     CATCH_EXCEPTION_NULL_PTR
351         CATCH_EXCEPTION_PLATFORM_ERROR
352 }
353
354 JSValueRef JSWidget::getDescription(JSContextRef context,
355                                     JSObjectRef object,
356                                     JSStringRef /*propertyName*/,
357                                     JSValueRef* exception)
358 {
359     Try {
360         Converter converter(context);
361         return converter.toJSValueRef(getIWidget(object)->getDescription());
362     }
363     CATCH_EXCEPTION_CONVERSION
364     CATCH_EXCEPTION_NULL_PTR
365         CATCH_EXCEPTION_PLATFORM_ERROR
366 }
367
368 JSValueRef JSWidget::getId(JSContextRef context,
369                            JSObjectRef object,
370                            JSStringRef /*propertyName*/,
371                            JSValueRef* exception)
372 {
373     Try {
374         Converter converter(context);
375         return converter.toJSValueRef(getIWidget(object)->getId());
376     }
377     CATCH_EXCEPTION_CONVERSION
378     CATCH_EXCEPTION_NULL_PTR
379         CATCH_EXCEPTION_PLATFORM_ERROR
380 }
381
382 JSValueRef JSWidget::getName(JSContextRef context,
383                              JSObjectRef object,
384                              JSStringRef /*propertyName*/,
385                              JSValueRef* exception)
386 {
387     Try {
388         Converter converter(context);
389         return converter.toJSValueRef(getIWidget(object)->getName());
390     }
391     CATCH_EXCEPTION_CONVERSION
392     CATCH_EXCEPTION_NULL_PTR
393         CATCH_EXCEPTION_PLATFORM_ERROR
394 }
395
396 JSValueRef JSWidget::getShortName(JSContextRef context,
397                                   JSObjectRef object,
398                                   JSStringRef /*propertyName*/,
399                                   JSValueRef* exception)
400 {
401     Try {
402         Converter converter(context);
403         return converter.toJSValueRef(getIWidget(object)->getShortName());
404     }
405     CATCH_EXCEPTION_CONVERSION
406     CATCH_EXCEPTION_NULL_PTR
407         CATCH_EXCEPTION_PLATFORM_ERROR
408 }
409
410 JSValueRef JSWidget::getVersion(JSContextRef context,
411                                 JSObjectRef object,
412                                 JSStringRef /*propertyName*/,
413                                 JSValueRef* exception)
414 {
415     Try {
416         Converter converter(context);
417         return converter.toJSValueRef(getIWidget(object)->getVersion());
418     }
419     CATCH_EXCEPTION_CONVERSION
420     CATCH_EXCEPTION_NULL_PTR
421         CATCH_EXCEPTION_PLATFORM_ERROR
422 }
423
424 JSValueRef JSWidget::getHeight(JSContextRef context,
425                                JSObjectRef object,
426                                JSStringRef /*propertyName*/,
427                                JSValueRef* exception)
428 {
429     Try {
430         Converter converter(context);
431         unsigned int height = getIWidget(object)->getHeight();
432         if (0 == height) {
433             height = 1;
434         }
435         return converter.toJSValueRef(height);
436     }
437     CATCH_EXCEPTION_CONVERSION
438     CATCH_EXCEPTION_NULL_PTR
439         CATCH_EXCEPTION_PLATFORM_ERROR
440 }
441
442 JSValueRef JSWidget::getWidth(JSContextRef context,
443                               JSObjectRef object,
444                               JSStringRef /*propertyName*/,
445                               JSValueRef* exception)
446 {
447     Try {
448         Converter converter(context);
449         unsigned int width = getIWidget(object)->getWidth();
450         if (0 == width) {
451             width = 1;
452         }
453         return converter.toJSValueRef(width);
454     }
455     CATCH_EXCEPTION_CONVERSION
456     CATCH_EXCEPTION_NULL_PTR
457         CATCH_EXCEPTION_PLATFORM_ERROR
458 }
459
460 bool JSWidget::hasProperty(JSContextRef context,
461                            JSObjectRef /*object*/,
462                            JSStringRef propertyName)
463 {
464     LogDebug("enter");
465
466     Try {
467         Converter converter(context);
468
469         std::string key = converter.toString(propertyName);
470         if (key == "preferences") {
471             return true;
472         }
473     }
474     Catch(Commons::InvalidArgumentException) {
475         LogDebug("Pair for given key doesnt exist");
476     }
477
478     Catch(Commons::ConversionException) {
479         LogError("Error on conversion");
480     }
481
482     Catch(Commons::NullPointerException) {
483         LogError("Error on pointer, null value");
484     }
485
486     Catch(Commons::PlatformException){
487         LogError("PlatformException occured");
488     }
489     return false;
490 }
491
492 JSValueRef JSWidget::getProperty(JSContextRef context,
493                                  JSObjectRef object,
494                                  JSStringRef propertyName,
495                                  JSValueRef* exception)
496 {
497     LogDebug("Object: " << object);
498
499     Try {
500         Converter converter(context);
501
502         std::string key = converter.toString(propertyName);
503
504         if (key == "preferences") {
505             Converter converter(context);
506             JSObjectRef pref = getPreferences(object);
507             if (!pref) {
508                 LogError("Preferences object is NULL");
509                 return JSValueMakeUndefined(context);
510             }
511             return pref;
512         }
513         LogError("Property NOT supported: " << propertyName);
514         return JSValueMakeUndefined(context);
515     }
516
517     CATCH_EXCEPTION_CONVERSION
518     CATCH_EXCEPTION_NULL_PTR
519         CATCH_EXCEPTION_INVALID_ARG
520 }
521
522 bool JSWidget::setProperty(JSContextRef context,
523                            JSObjectRef /*object*/,
524                            JSStringRef propertyName,
525                            JSValueRef /*jvalue*/,
526                            JSValueRef* exception)
527 {
528     LogDebug("enter");
529
530     Try {
531         Converter converter(context);
532
533         std::string key = converter.toString(propertyName);
534         if (key == "preferences") {
535             LogError("Object is read only");
536             return true;
537         }
538     }
539     CATCH_EXCEPTION_INVALID_ARG
540     CATCH_EXCEPTION_CONVERSION
541         CATCH_EXCEPTION_NULL_PTR
542
543     return false;
544 }
545
546 JSObjectRef JSWidget::callAsConstructor(JSContextRef context,
547                                         JSObjectRef /*constructor*/,
548                                         size_t /*argumentCount*/,
549                                         const JSValueRef /*arguments*/[],
550                                         JSValueRef* /*exception*/)
551 {
552     LogDebug("widget constructor");
553     if (!m_globalContext) {
554         LogError("Global context not set. Creating 'widget' object with "
555                  "local context!");
556         return JSObjectMake(context, JSWidget::getClassRef(), NULL);
557     }
558     return JSObjectMake(m_globalContext, JSWidget::getClassRef(), NULL);
559 }
560
561 #undef CATCH_EXCEPTION_NO_MODIFABLE
562 #undef CATCH_EXCEPTION_CONVERSION
563 #undef CATCH_EXCEPTION_NULL_PTR
564 #undef CATCH_EXCEPTION_PLATFORM_ERROR
565 #undef CATCH_EXCEPTION_SECURITY
566 #undef CATCH_EXCEPTION_OUT_OF_RANGE
567 #undef CATCH_EXCEPTION_INVALID_ARG
568 }
569 }