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