2f962f0f63aa741eba5623c7c97d61d1b713181e
[platform/framework/web/wrt-plugins-common.git] / src / standards / W3C / Widget / JSPreferences.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        JSPreferences.cpp
19  * @author      Grzegorz Krawczyk (g.krawczyk@samsung.com)
20  * @version     0.1
21  */
22
23 #include "JSPreferences.h"
24
25 #include <string>
26 #include <dpl/assert.h>
27 #include <dpl/log/log.h>
28 #include <dpl/optional.h>
29 #include <CommonsJavaScript/Converter.h>
30 #include <CommonsJavaScript/JSDOMExceptionFactory.h>
31 #include <StorageEvent/StorageEventMgr.h>
32 #include <StorageEvent/IStorageEvent.h>
33 #include <js-overlay/js_iframe_support.h>
34 #include <js-overlay/js_overlay_addEventListener.h>
35
36 using namespace std;
37 using namespace WrtDeviceApis;
38 using namespace WrtDeviceApis::Commons;
39 using namespace WrtDeviceApis::CommonsJavaScript;
40 using namespace WrtDeviceApis::LocalStorage::Api;
41 using namespace WrtDeviceApis::StorageEvent::Api;
42
43 #define PREFERENCES_PLUGIN_NAME       "preferences"
44 #define LOCAL_STORAGE_PROPERTY_LENGTH "length"
45
46 #define CATCH_EXCEPTION_NO_MODIFABLE \
47     Catch(Commons::LocalStorageValueNoModifableException) { \
48         LogError("The item is read only"); \
49         return JSDOMExceptionFactory:: \
50                    NoModificationAllowedException.make(context, exception); \
51     }
52
53 #define CATCH_EXCEPTION_CONVERSION \
54     Catch(Commons::ConversionException) { \
55         LogError("Error on conversion"); \
56         return JSDOMExceptionFactory:: \
57                    UnknownException.make(context, exception); \
58     }
59
60 #define CATCH_EXCEPTION_NULL_PTR \
61     Catch(Commons::NullPointerException) { \
62         LogError("Error on pointer, null value"); \
63         return JSDOMExceptionFactory:: \
64                    UnknownException.make(context, exception); \
65     }
66
67 #define CATCH_EXCEPTION_PLATFORM_ERROR \
68     Catch(Commons::PlatformException){ \
69         LogError("PlatformException occured"); \
70         return JSDOMExceptionFactory:: \
71                    UnknownException.make(context, exception); \
72     }
73
74 #define CATCH_EXCEPTION_SECURITY \
75     Catch(Commons::SecurityException){ \
76         LogError("Security exception occured"); \
77         return JSDOMExceptionFactory:: \
78                    SecurityException.make(context, exception); \
79     }
80
81 #define CATCH_EXCEPTION_OUT_OF_RANGE \
82     Catch(Commons::OutOfRangeException) { \
83         LogError("OutOfRangeException"); \
84         return JSDOMExceptionFactory:: \
85                    QuotaExceededException.make(context, exception); \
86     }
87
88 #define CATCH_EXCEPTION_INVALID_ARG \
89     Catch(Commons::InvalidArgumentException) { \
90         LogError("Pair for given key doesnt exist"); \
91         return JSValueMakeNull(context); \
92     }
93
94 namespace WrtPlugins {
95 namespace W3C {
96 ILocalStoragePtr getIStorage(JSObjectRef arg)
97 {
98     LogWarning("get localstorage object");
99
100     LocalStoragePrivateData* priv =
101         static_cast<LocalStoragePrivateData*>(JSObjectGetPrivate(arg));
102
103     if (!priv) {
104         LogError("Private object not initialized");
105         ThrowMsg(Commons::NullPointerException,
106                  "Private object not initialized");
107     }
108
109     return priv->istorage;
110 }
111
112 JSObjectRef getWidgetObject(JSObjectRef arg)
113 {
114     LogWarning("get widget object");
115
116     LocalStoragePrivateData* priv =
117         static_cast<LocalStoragePrivateData*>(JSObjectGetPrivate(arg));
118
119     if (!priv) {
120         LogError("Private object not initialized");
121         ThrowMsg(Commons::NullPointerException,
122                  "Private object not initialized");
123     }
124
125     return priv->widgetObject;
126 }
127
128 enum class ModificationType
129 {
130     RemoveItem,
131     SetItem
132 };
133
134 //this function may throw exceptions
135 IStorageEventPtr modifyItemAndCreateEvent(ModificationType type,
136                                           JSObjectRef thisObject,
137                                           const string& key,
138                                           const string& value = std::string())
139 {
140     DPL::Optional<std::string> oldValue =
141         getIStorage(thisObject)->getValue(key);
142
143     if (ModificationType::SetItem == type) {
144         getIStorage(thisObject)->setItem(key, value, false);
145     } else if (ModificationType::RemoveItem == type) {
146         getIStorage(thisObject)->removeItem(key);
147     } else {
148         Assert(0 && "Wrong Modification type");
149     }
150
151     DPL::Optional<std::string> newValue =
152         getIStorage(thisObject)->getValue(key);
153
154     //create event object
155     IStorageEventPtr storageEvent = getStorageEvent();
156
157     //key
158     storageEvent->setKey(key);
159     //oldvalue
160     if (!!oldValue) {
161         storageEvent->setOldValue(*oldValue);
162     }
163     //newValue
164     if (!!newValue) {
165         storageEvent->setNewValue(*newValue);
166     }
167
168     return storageEvent;
169 }
170
171 JSClassDefinition JSPreferences::m_classInfo = {
172     0,
173     kJSClassAttributeNone,
174     PREFERENCES_PLUGIN_NAME,
175     0,
176     m_property,
177     m_function,
178     initialize,
179     finalize,
180     hasProperty,
181     getProperty,
182     setProperty,
183     NULL, //DeleteProperty,
184     NULL, //GetPropertyNames,
185     NULL, //CallAsFunction,
186     NULL, //CallAsConstructor,
187     NULL, //HasInstance,
188     NULL, //ConvertToType,
189 };
190
191 JSStaticFunction JSPreferences::m_function[] = {
192     { "setItem", JSPreferences::setItem, kJSPropertyAttributeNone },
193     { "removeItem", JSPreferences::removeItem, kJSPropertyAttributeNone },
194     { "getItem", JSPreferences::getItem, kJSPropertyAttributeNone },
195     { "clear", JSPreferences::clear, kJSPropertyAttributeNone },
196     { "key", JSPreferences::key, kJSPropertyAttributeNone },
197     { 0, 0, 0 }
198 };
199
200 JSStaticValue JSPreferences::m_property[] = {
201     { LOCAL_STORAGE_PROPERTY_LENGTH,
202       JSPreferences::getLength,
203       NULL,
204       kJSPropertyAttributeReadOnly },
205     { 0, 0, 0, 0 }
206 };
207
208 JSClassRef JSPreferences::getClassRef()
209 {
210     if (!m_jsClassRef) {
211         m_jsClassRef = JSClassCreate(&m_classInfo);
212     }
213     return m_jsClassRef;
214 }
215
216 const JSClassDefinition* JSPreferences::getClassInfo()
217 {
218     return &m_classInfo;
219 }
220
221 JSClassRef JSPreferences::m_jsClassRef =
222     JSClassCreate(JSPreferences::getClassInfo());
223
224 void JSPreferences::initialize(JSContextRef context,
225                                JSObjectRef object)
226 {
227     LogDebug("entered. Context: " << context);
228
229     LocalStoragePrivateData* priv =
230         static_cast<LocalStoragePrivateData*>(JSObjectGetPrivate(object));
231
232     Assert(priv && "private object of preferences is NULL");
233 }
234
235 void JSPreferences::finalize(JSObjectRef object)
236 {
237     LogDebug("entered");
238     LocalStoragePrivateData* priv =
239         static_cast<LocalStoragePrivateData*>(JSObjectGetPrivate(object));
240
241     delete priv;
242     LogDebug("private object is realised");
243 }
244
245 JSValueRef JSPreferences::removeItem(JSContextRef context,
246                                      JSObjectRef /*object*/,
247                                      JSObjectRef thisObject,
248                                      size_t /*argumentCount*/,
249                                      const JSValueRef arguments[],
250                                      JSValueRef* exception)
251 {
252     LogDebug("entered");
253
254     Try {
255         Converter converter(context);
256
257         std::string key = converter.toString(arguments[0]);
258
259         auto event = modifyItemAndCreateEvent(ModificationType::RemoveItem,
260                                               thisObject,
261                                               key);
262
263         auto iframe = IFrameSupport::
264                 getIFrameObjectForWidget(getWidgetObject(thisObject));
265
266         Assert(iframe && "Iframe is NULL");
267
268         AddEventListenerSupport::
269             CallStorageListenersFromDifferentIFrames(iframe, event);
270
271         LogDebug("end");
272         return JSValueMakeNull(context);
273     }
274     CATCH_EXCEPTION_NO_MODIFABLE
275     CATCH_EXCEPTION_CONVERSION
276     CATCH_EXCEPTION_NULL_PTR
277     CATCH_EXCEPTION_PLATFORM_ERROR
278         CATCH_EXCEPTION_SECURITY
279 }
280
281 JSValueRef JSPreferences::setItem(JSContextRef context,
282                                   JSObjectRef object,
283                                   JSObjectRef thisObject,
284                                   size_t /*argumentCount*/,
285                                   const JSValueRef arguments[],
286                                   JSValueRef* exception)
287 {
288     LogDebug("entered");
289     LogDebug("This: " << thisObject);
290     LogDebug("Object: " << object);
291
292     Try {
293         Converter converter(context);
294
295         std::string key = converter.toString(arguments[0]);
296         std::string value = converter.tryString(arguments[1]);
297
298         auto event = modifyItemAndCreateEvent(ModificationType::SetItem,
299                                               thisObject,
300                                               key,
301                                               value);
302
303         auto iframe = IFrameSupport::
304                 getIFrameObjectForWidget(getWidgetObject(thisObject));
305         Assert(iframe && "Iframe is NULL");
306
307         AddEventListenerSupport::
308             CallStorageListenersFromDifferentIFrames(iframe, event);
309
310         LogDebug("end");
311
312         return JSValueMakeUndefined(context);
313     }
314     CATCH_EXCEPTION_NO_MODIFABLE
315     CATCH_EXCEPTION_CONVERSION
316     CATCH_EXCEPTION_NULL_PTR
317     CATCH_EXCEPTION_PLATFORM_ERROR
318     CATCH_EXCEPTION_SECURITY
319         CATCH_EXCEPTION_OUT_OF_RANGE
320 }
321
322 JSValueRef JSPreferences::clear(JSContextRef context,
323                                 JSObjectRef /*object*/,
324                                 JSObjectRef thisObject,
325                                 size_t /*argumentCount*/,
326                                 const JSValueRef /*arguments*/[],
327                                 JSValueRef* exception)
328 {
329     LogDebug("entered");
330
331     Try {
332         getIStorage(thisObject)->clear(false);
333
334         auto iframe = IFrameSupport::
335                 getIFrameObjectForWidget(getWidgetObject(thisObject));
336
337         Assert(iframe && "Iframe is NULL");
338
339         //create event object
340         IStorageEventPtr storageEvent = getStorageEvent();
341
342         AddEventListenerSupport::
343             CallStorageListenersFromDifferentIFrames(iframe, storageEvent);
344
345         LogDebug("end");
346
347         return JSValueMakeNull(context);
348     }
349     CATCH_EXCEPTION_NULL_PTR
350     CATCH_EXCEPTION_PLATFORM_ERROR
351         CATCH_EXCEPTION_SECURITY
352 }
353
354 JSValueRef JSPreferences::getItem(JSContextRef context,
355                                   JSObjectRef /*object*/,
356                                   JSObjectRef thisObject,
357                                   size_t /*argumentCount*/,
358                                   const JSValueRef arguments[],
359                                   JSValueRef* exception)
360 {
361     LogDebug("entered");
362
363     Try {
364         Converter converter(context);
365
366         std::string key = converter.tryString(arguments[0]);
367
368         LogDebug("Getting item for key " << key);
369
370         DPL::Optional<std::string> value =
371             getIStorage(thisObject)->getValue(key);
372
373         if (!value) {
374             return JSValueMakeNull(context);
375         } else {
376             return converter.toJSValueRef(*value);
377         }
378     }
379     CATCH_EXCEPTION_INVALID_ARG
380     CATCH_EXCEPTION_CONVERSION
381     CATCH_EXCEPTION_NULL_PTR
382     CATCH_EXCEPTION_PLATFORM_ERROR
383         CATCH_EXCEPTION_SECURITY
384 }
385
386 JSValueRef JSPreferences::key(JSContextRef context,
387                               JSObjectRef /*object*/,
388                               JSObjectRef thisObject,
389                               size_t argumentCount,
390                               const JSValueRef arguments[],
391                               JSValueRef* exception)
392 {
393     LogDebug("entered");
394
395     Try {
396         if (argumentCount < 1) {
397             LogError("No argument found");
398             Throw(Commons::InvalidArgumentException);
399         }
400
401         Converter converter(context);
402
403         size_t n = converter.toSizeT(arguments[0]);
404
405         std::string value = getIStorage(thisObject)->getKeyByIndex(n);
406
407         LogDebug("end");
408
409         return converter.toJSValueRef(value);
410     }
411     CATCH_EXCEPTION_CONVERSION
412     CATCH_EXCEPTION_NULL_PTR
413     CATCH_EXCEPTION_PLATFORM_ERROR
414     CATCH_EXCEPTION_SECURITY
415         CATCH_EXCEPTION_INVALID_ARG
416 }
417
418 JSValueRef JSPreferences::getLength(JSContextRef context,
419                                     JSObjectRef object,
420                                     JSStringRef /*propertyName*/,
421                                     JSValueRef* exception)
422 {
423     LogDebug("enter");
424
425     Try
426     {
427         Converter converter(context);
428
429         size_t value = getIStorage(object)->getStorageSize();
430         return converter.toJSValueRef(value);
431     }
432     CATCH_EXCEPTION_CONVERSION
433     CATCH_EXCEPTION_NULL_PTR
434     CATCH_EXCEPTION_PLATFORM_ERROR
435     CATCH_EXCEPTION_SECURITY
436         CATCH_EXCEPTION_INVALID_ARG
437 }
438
439 bool JSPreferences::hasProperty(JSContextRef context,
440                                 JSObjectRef object,
441                                 JSStringRef propertyName)
442 {
443     LogDebug("enter");
444
445     Try {
446         Converter converter(context);
447
448         std::string key = converter.toString(propertyName);
449
450         if (!getIStorage(object)->getValue(key)) {
451             return false;
452         } else {
453             return true;
454         }
455     }
456
457     Catch(Commons::InvalidArgumentException) {
458         LogDebug("Pair for given key doesnt exist");
459     }
460
461     Catch(Commons::ConversionException) {
462         LogError("Error on conversion");
463     }
464
465     Catch(Commons::NullPointerException) {
466         LogError("Error on pointer, null value");
467     }
468
469     Catch(Commons::PlatformException){
470         LogError("PlatformException occured");
471     }
472     return false;
473 }
474
475 JSValueRef JSPreferences::getProperty(JSContextRef context,
476                                       JSObjectRef object,
477                                       JSStringRef propertyName,
478                                       JSValueRef* exception)
479 {
480     LogDebug("enter");
481
482     Try {
483         Converter converter(context);
484
485         std::string key = converter.toString(propertyName);
486
487         DPL::Optional<std::string> value =
488             getIStorage(object)->getValue(key);
489
490         LogDebug("end");
491
492         if (!value) {
493             return JSValueMakeNull(context);
494         } else {
495             return converter.toJSValueRef(*value);
496         }
497     }
498
499     CATCH_EXCEPTION_CONVERSION
500     CATCH_EXCEPTION_NULL_PTR
501     CATCH_EXCEPTION_PLATFORM_ERROR
502         CATCH_EXCEPTION_INVALID_ARG
503 }
504
505 bool JSPreferences::setProperty(JSContextRef context,
506                                 JSObjectRef object,
507                                 JSStringRef propertyName,
508                                 JSValueRef jvalue,
509                                 JSValueRef* exception)
510 {
511     LogDebug("enter");
512
513     Try {
514         Converter converter(context);
515
516         std::string key = converter.toString(propertyName);
517         std::string value = converter.toString(jvalue);
518
519         auto event = modifyItemAndCreateEvent(ModificationType::SetItem,
520                                               object,
521                                               key,
522                                               value);
523
524         auto iframe = IFrameSupport::
525                 getIFrameObjectForWidget(getWidgetObject(object));
526         Assert(iframe && "Iframe is NULL");
527
528         AddEventListenerSupport::
529             CallStorageListenersFromDifferentIFrames(iframe, event);
530
531         LogDebug("end");
532
533         return true;
534     }
535     CATCH_EXCEPTION_NO_MODIFABLE
536     CATCH_EXCEPTION_OUT_OF_RANGE
537     CATCH_EXCEPTION_INVALID_ARG
538     CATCH_EXCEPTION_CONVERSION
539     CATCH_EXCEPTION_NULL_PTR
540     CATCH_EXCEPTION_PLATFORM_ERROR
541         CATCH_EXCEPTION_SECURITY
542
543     return false;
544 }
545
546 #undef CATCH_EXCEPTION_NO_MODIFABLE
547 #undef CATCH_EXCEPTION_CONVERSION
548 #undef CATCH_EXCEPTION_NULL_PTR
549 #undef CATCH_EXCEPTION_PLATFORM_ERROR
550 #undef CATCH_EXCEPTION_SECURITY
551 #undef CATCH_EXCEPTION_OUT_OF_RANGE
552 #undef CATCH_EXCEPTION_INVALID_ARG
553 }
554 }