tizen 2.4 release
[framework/web/wrt-plugins-common.git] / src / xwalk-module / xwalk_extension_module.cpp
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2013 Intel Corporation. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include <dlog.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <plugins-ipc-message/ipc_message_support.h>
10
11 #include "xwalk_extension_module.h"
12 #include "xwalk_extension_client.h"
13 #include "JSLifeManager.h"
14 #include "xwalk_module_system.h"
15 #include "js_utils.h"
16
17 extern "C" JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx);
18
19 // The arraysize(arr) macro returns the # of elements in an array arr.
20 // The expression is a compile-time constant, and therefore can be
21 // used in defining new arrays, for example.  If you use arraysize on
22 // a pointer by mistake, you will get a compile-time error.
23 //
24 // One caveat is that arraysize() doesn't accept any array of an
25 // anonymous type or a type defined inside a function.  In these rare
26 // cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below.  This is
27 // due to a limitation in C++'s template system.  The limitation might
28 // eventually be removed, but it hasn't happened yet.
29
30 // This template function declaration is used in defining arraysize.
31 // Note that the function doesn't need an implementation, as we only
32 // use its type.
33 template <typename T, size_t N>
34 char (&ArraySizeHelper(T (&array)[N]))[N];
35
36 #define arraysize(array) (sizeof(ArraySizeHelper(array)))
37
38 namespace wrt {
39
40 namespace {
41
42 std::string CodeToEnsureNamespace(const std::string& extension_name) {
43     std::string result;
44     size_t pos = 0;
45     while (true) {
46         pos = extension_name.find('.', pos);
47         if (pos == std::string::npos) {
48             result += extension_name + ";";
49             break;
50         }
51         std::string ns = extension_name.substr(0, pos);
52         result += ns + " = " + ns + " || {}; ";
53         pos++;
54     }
55     return result;
56 }
57
58 // Templatized backend for StringPrintF/StringAppendF. This does not finalize
59 // the va_list, the caller is expected to do that.
60 template <class StringType>
61 static void StringAppendVT(StringType* dst,
62                            const typename StringType::value_type* format,
63                            va_list ap) {
64     // First try with a small fixed size buffer.
65     // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
66     // and StringUtilTest.StringPrintfBounds.
67     typename StringType::value_type stack_buf[1024];
68
69     va_list ap_copy;
70     va_copy(ap_copy, ap);
71
72     int result = vsnprintf(stack_buf, arraysize(stack_buf), format, ap_copy);
73     va_end(ap_copy);
74
75     if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
76         // It fit.
77         dst->append(stack_buf, result);
78         return;
79     }
80
81     // Repeatedly increase buffer size until it fits.
82     int mem_length = arraysize(stack_buf);
83     while (true) {
84         if (result < 0) {
85             if (errno != 0 && errno != EOVERFLOW)
86                 return;
87             // Try doubling the buffer size.
88             mem_length *= 2;
89         } else {
90             // We need exactly "result + 1" characters.
91             mem_length = result + 1;
92         }
93
94         if (mem_length > 32 * 1024 * 1024) {
95             // That should be plenty, don't try anything larger.  This protects
96             // against huge allocations when using vsnprintfT implementations that
97             // return -1 for reasons other than overflow without setting errno.
98             LOGE("Unable to printf the requested string due to size.");
99             return;
100         }
101
102         std::vector<typename StringType::value_type> mem_buf(mem_length);
103
104         // NOTE: You can only use a va_list once.  Since we're in a while loop, we
105         // need to make a new copy each time so we don't use up the original.
106         va_copy(ap_copy, ap);
107         result = vsnprintf(&mem_buf[0], mem_length, format, ap_copy);
108         va_end(ap_copy);
109
110         if ((result >= 0) && (result < mem_length)) {
111             // It fit.
112             dst->append(&mem_buf[0], result);
113             return;
114         }
115     }
116 }
117
118 std::string StringPrintf(const char* format, ...) {
119     va_list ap;
120     va_start(ap, format);
121     std::string result;
122     StringAppendVT(&result, format, ap);
123     va_end(ap);
124     return result;
125 }
126
127 // Wrap API code into a callable form that takes extension object as parameter.
128 std::string WrapAPICode(const std::string& extension_code,
129                         const std::string& extension_name) {
130     // We take care here to make sure that line numbering for api_code after
131     // wrapping doesn't change, so that syntax errors point to the correct line.
132
133     return StringPrintf(
134         "var %s; (function(extension, requireNative) { "
135         "extension.internal = {};"
136         "extension.internal.sendSyncMessage_ = extension.sendSyncMessage;"
137         "extension.internal.sendSyncMessage = function(){ return extension.internal.sendSyncMessage_.apply(extension, arguments); };"
138         "delete extension.sendSyncMessage;"
139         "var Object = requireNative('objecttools');"
140         "var exports = {}; (function() {'use strict'; %s\n})();"
141         "%s = %s || exports; });",
142         CodeToEnsureNamespace(extension_name).c_str(),
143         extension_code.c_str(),
144         extension_name.c_str(),
145         extension_name.c_str());
146 }
147
148 int GetNextChunkID() {
149     static int id = 0;
150     return ++id;
151 }
152
153 }  // namespace
154
155
156
157 JSClassDefinition XWalkExtensionModule::class_definition_ = {
158     0,
159     kJSClassAttributeNone,
160     "extensionModule",
161     NULL, //ParentClass
162     NULL, //StaticValues
163     XWalkExtensionModule::static_functions_,
164     NULL, //initialize,
165     NULL, //finalize,
166     NULL, //HasProperty,
167     NULL, //GetProperty,
168     NULL, //SetProperty,
169     NULL, //DeleteProperty,
170     NULL, //GetPropertyNames,
171     NULL, //CallAsFunction,
172     NULL, //CallAsConstructor,
173     NULL, //HasInstance,
174     NULL //ConvertToType
175 };
176
177
178 JSStaticFunction XWalkExtensionModule::static_functions_[] = {
179     { "postMessage", PostMessageCallback, kJSPropertyAttributeNone },
180     { "postData", PostDataCallback, kJSPropertyAttributeNone },
181     { "sendSyncMessage", SendSyncMessageCallback, kJSPropertyAttributeNone },
182     { "sendSyncData", SendSyncDataCallback, kJSPropertyAttributeNone },
183     { "sendRuntimeMessage", SendRuntimeMessageCallback, kJSPropertyAttributeNone },
184     { "sendRuntimeAsyncMessage", SendRuntimeAsyncMessageCallback, kJSPropertyAttributeNone },
185     { "sendRuntimeSyncMessage", SendRuntimeSyncMessageCallback, kJSPropertyAttributeNone },
186     { "setMessageListener", SetMessageListenerCallback, kJSPropertyAttributeNone },
187     { "setDataListener", SetDataListenerCallback, kJSPropertyAttributeNone },
188     { "receiveChunkData", ReceiveChunkDataCallback, kJSPropertyAttributeNone },
189     { 0, 0, 0 }
190 };
191
192 JSClassRef XWalkExtensionModule::class_ref_ = NULL;
193
194 XWalkExtensionModule::ChunkData::ChunkData()
195     : data_(nullptr), length_(0) {
196 }
197
198 XWalkExtensionModule::ChunkData::~ChunkData() {
199     if (data_) {
200        free(data_);
201     }
202 }
203
204 XWalkExtensionModule::XWalkExtensionModule(XWalkExtensionClient* client,
205                                            XWalkModuleSystem* module_system,
206                                            const std::string& extension_name,
207                                            std::function<std::string(void)> getter)
208     : js_object_(0),
209       extension_name_(extension_name),
210       client_(client),
211       module_system_(module_system),
212       instance_id_(0),
213       extension_code_getter_(getter) {
214 }
215
216 XWalkExtensionModule::~XWalkExtensionModule() {
217     JSContextRef ctx = module_system_->GetJSContext();
218
219     if( js_object_ != NULL ){
220         JSObjectSetPrivate(js_object_, NULL);
221         JSValueSafeUnprotect(ctx,js_object_);
222     }
223
224     if(message_listener_ != NULL){
225         JSValueSafeUnprotect(ctx,message_listener_);
226     }
227     if (instance_id_)
228         client_->DestroyInstance(instance_id_);
229 }
230
231 void XWalkExtensionModule::LoadExtensionCode(JSContextRef context, JSObjectRef native_require) {
232     LOGD("========== << LoadExtensionCode >> ENTER ==========");
233     //CHECK(!instance_id_);
234     instance_id_ = client_->CreateInstance(extension_name_, this);
235
236     LOGD("Extension Module Name : [%s]", extension_name_.c_str());
237
238     std::string exception;
239     std::string extension_code = extension_code_getter_();
240     std::string wrapped_api_code = WrapAPICode(extension_code, extension_name_);
241     JSValueRef result = JsUtils::RunString(context, wrapped_api_code, &exception);
242     JSObjectRef callable_api_code = JSValueToObject(context, result, NULL);
243
244     if (!JSValueIsObject(context, result) || !JSObjectIsFunction(context, callable_api_code)) {
245         LOGE("Couldn't load JS API code for %s: %s", extension_name_.c_str(), exception.c_str());
246         return;
247     }
248
249     const int argc = 2;
250     if( js_object_ == NULL ){
251         if( XWalkExtensionModule::class_ref_ == NULL ){
252             XWalkExtensionModule::class_ref_ = JSClassCreate(&XWalkExtensionModule::class_definition_);
253         }
254         js_object_ = JSObjectMake( context, XWalkExtensionModule::class_ref_, this);
255         JSValueSafeProtect(context,js_object_);
256     }
257     JSValueRef argv[argc] = {
258         js_object_,
259         native_require
260     };
261
262     JSValueRef except_value = NULL;
263     JSObjectCallAsFunction(context, callable_api_code, NULL, argc, argv, &except_value);
264     if( except_value != NULL ){
265         LOGE("Couldn't load JS API code for %s: %s", extension_name_.c_str(), JsUtils::ExceptionToString(context, except_value).c_str());
266     }
267
268 }
269
270 void XWalkExtensionModule::HandleMessageFromNative(const std::string& msg) {
271     if (message_listener_ == NULL)
272         return;
273
274     JSContextRef context = module_system_->GetJSContext();
275     JSValueRef args[] = { JsUtils::ToJSValueRef(context, msg) };
276
277     JSValueRef except_value = NULL;
278     JSObjectCallAsFunction(context, message_listener_, NULL, 1, args, &except_value);
279     if (except_value != NULL)
280         LOGE("Exception when running message listener: %s", JsUtils::ExceptionToString(context, except_value).c_str());
281 }
282
283 void XWalkExtensionModule::HandleMessageFromNative(const std::string& msg, unsigned char* buffer, std::size_t len) {
284     if (data_listener_ == NULL)
285         return;
286
287     JSContextRef context = module_system_->GetJSContext();
288     JSValueRef args[] = {
289       JsUtils::ToJSValueRef(context, msg),
290       JSValueMakeNull(context)
291     };
292     if (len > 0) {
293         int chunk_id = GetNextChunkID();
294         ChunkData& chunk_data = data_chunk_storage_[chunk_id];
295         chunk_data.set_data(buffer);
296         chunk_data.set_length(len);
297         args[1] = JSValueMakeNumber(context, chunk_id);
298     }
299
300     JSValueRef except_value = NULL;
301     JSObjectCallAsFunction(context, data_listener_, NULL, 2, args, &except_value);
302     if (except_value != NULL) {
303         LOGE("Exception when running message listener: %s", JsUtils::ExceptionToString(context, except_value).c_str());
304     }
305 }
306
307
308 // static
309 JSValueRef XWalkExtensionModule::PostMessageCallback(JSContextRef context,
310         JSObjectRef object,
311         JSObjectRef thisObject,
312         size_t argumentCount,
313         const JSValueRef arguments[],
314         JSValueRef* exception) {
315     XWalkExtensionModule* module = GetExtensionModule(thisObject);
316     if (!module || argumentCount != 1) {
317         return JSValueMakeBoolean(context, false);
318     }
319
320     //CHECK(module->instance_id_);
321     module->client_->PostMessageToNative(module->instance_id_, JsUtils::JSValueToString(context, arguments[0]));
322     return JSValueMakeBoolean(context, true);
323 }
324
325 JSValueRef XWalkExtensionModule::PostDataCallback(JSContextRef context,
326         JSObjectRef object,
327         JSObjectRef thisObject,
328         size_t argumentCount,
329         const JSValueRef arguments[],
330         JSValueRef* exception) {
331     XWalkExtensionModule* module = GetExtensionModule(thisObject);
332     if (!module || argumentCount < 1) {
333         return JSValueMakeBoolean(context, false);
334     }
335
336     std::vector<unsigned char> chunk;
337     size_t chunk_size = 0;
338     if (argumentCount > 1) {
339         if (JSValueIsObject(context, arguments[1])) {
340             JSObjectRef arrayobj = JSValueToObject(context, arguments[1], NULL);
341             if (arrayobj) {
342                 for (std::size_t i = 0; i < JSGetArrayLength(context, arrayobj); ++i) {
343                     JSValueRef element = JSGetArrayElement(context, arrayobj, i);
344                     unsigned char v = static_cast<unsigned char>(JSValueToNumber(context, element, NULL));
345                     chunk.push_back(v);
346                 }
347                 chunk_size = chunk.size();
348             }
349         } else if (JSValueIsString(context, arguments[1])) {
350             JSStringRef chunkStr = JSValueToStringCopy(context,
351                                                        arguments[1],
352                                                        exception);
353             size_t len = JSStringGetLength(chunkStr) + 1;
354             chunk.resize(len);
355             JSStringGetUTF8CString(chunkStr,
356                                    reinterpret_cast<char*>(chunk.data()),
357                                    len);
358             JSStringRelease(chunkStr);
359             chunk_size = len - 1;
360         }
361     }
362
363     module->client_->PostMessageToNative(module->instance_id_,
364                                          JsUtils::JSValueToString(context, arguments[0]),
365                                          chunk.data(),
366                                          chunk_size);
367     return JSValueMakeBoolean(context, true);
368 }
369
370
371 // static
372 JSValueRef XWalkExtensionModule::SendSyncMessageCallback(JSContextRef context,
373         JSObjectRef object,
374         JSObjectRef thisObject,
375         size_t argumentCount,
376         const JSValueRef arguments[],
377         JSValueRef* exception) {
378
379     XWalkExtensionModule* module = GetExtensionModule(thisObject);
380     if (!module || argumentCount != 1) {
381         return JSValueMakeBoolean(context, false);
382     }
383
384     //CHECK(module->instance_id_);
385     std::string reply =
386         module->client_->SendSyncMessageToNative(module->instance_id_, JsUtils::JSValueToString(context, arguments[0]));
387
388     // If we tried to send a message to an instance that became invalid,
389     // then reply will be NULL.
390     if (!reply.empty()) {
391         return JsUtils::ToJSValueRef(context, reply);
392     }
393     return JSValueMakeNull(context);
394 }
395
396 // static
397 JSValueRef XWalkExtensionModule::SendSyncDataCallback(JSContextRef context,
398         JSObjectRef object,
399         JSObjectRef thisObject,
400         size_t argumentCount,
401         const JSValueRef arguments[],
402         JSValueRef* exception) {
403
404     XWalkExtensionModule* module = GetExtensionModule(thisObject);
405     if (!module || argumentCount < 1) {
406         return JSValueMakeBoolean(context, false);
407     }
408
409     std::vector<unsigned char> chunk;
410     size_t chunk_size = 0;
411     if (argumentCount > 1) {
412         if (JSValueIsObject(context, arguments[1])) {
413           JSObjectRef arrayobj = JSValueToObject(context, arguments[1], NULL);
414           if (arrayobj) {
415             for (std::size_t i = 0; i < JSGetArrayLength(context, arrayobj); ++i) {
416                 JSValueRef element = JSGetArrayElement(context, arrayobj, i);
417                 unsigned char v = static_cast<unsigned char>(JSValueToNumber(context, element, NULL));
418                 chunk.push_back(v);
419             }
420             chunk_size = chunk.size();
421           }
422         } else if (JSValueIsString(context, arguments[1])) {
423             JSStringRef chunkStr = JSValueToStringCopy(context,
424                                                        arguments[1],
425                                                        exception);
426             size_t len = JSStringGetLength(chunkStr) + 1;
427             chunk.resize(len);
428             JSStringGetUTF8CString(chunkStr,
429                                    reinterpret_cast<char*>(chunk.data()),
430                                    len);
431             JSStringRelease(chunkStr);
432             chunk_size = len - 1;
433         }
434     }
435
436     unsigned char* received_buffer = NULL;
437     std::size_t received_size = 0;
438     //CHECK(module->instance_id_);
439     std::string reply =
440         module->client_->SendSyncMessageToNative(
441             module->instance_id_,
442             JsUtils::JSValueToString(context, arguments[0]),
443             chunk.data(),
444             chunk_size,
445             &received_buffer,
446             &received_size);
447
448     // If we tried to send a message to an instance that became invalid,
449     // then reply will be NULL.
450     if (!reply.empty()) {
451       JSObjectRef return_obj = JSObjectMake(context, NULL, NULL);
452       JsUtils::SetProperty(context,
453                            return_obj,
454                            "reply",
455                            JsUtils::ToJSValueRef(context, reply),
456                            NULL,
457                            NULL);
458       if (received_buffer || received_size > 0) {
459         int chunk_id = GetNextChunkID();
460         ChunkData& chunk_data = module->data_chunk_storage_[chunk_id];
461         chunk_data.set_data(received_buffer);
462         chunk_data.set_length(received_size);
463         JsUtils::SetProperty(context,
464                              return_obj,
465                              "chunk_id",
466                              JSValueMakeNumber(context, chunk_id),
467                              NULL,
468                              NULL);
469       }
470       return return_obj;
471     }
472     return JSValueMakeNull(context);
473 }
474
475 // static
476 JSValueRef XWalkExtensionModule::ReceiveChunkDataCallback(JSContextRef context,
477         JSObjectRef object,
478         JSObjectRef thisObject,
479         size_t argumentCount,
480         const JSValueRef arguments[],
481         JSValueRef* exception) {
482
483     XWalkExtensionModule* module = GetExtensionModule(thisObject);
484     if (!module || argumentCount < 1) {
485         return JSValueMakeBoolean(context, false);
486     }
487
488     int chunk_id = 0;
489     if (JSValueIsNumber(context, arguments[0])) {
490         chunk_id = JSValueToNumber(context, arguments[0], NULL);
491     }
492
493     std::string chunk_type("octet");
494     if (argumentCount > 1 && JSValueIsString(context, arguments[1])) {
495         chunk_type = JsUtils::JSValueToString(context, arguments[1]);
496     }
497
498     JSValueRef jschunk = JSValueMakeNull(context);
499
500     auto it = module->data_chunk_storage_.find(chunk_id);
501     if (it != module->data_chunk_storage_.end()) {
502         ChunkData& chunk_data = it->second;
503         if (chunk_type == "string") {
504             JSStringRef jsstr = JSStringCreateWithUTF8CString(reinterpret_cast<const char*>(chunk_data.data()));
505             jschunk = JSValueMakeString(context, jsstr);
506             JSStringRelease(jsstr);
507         } else {
508             std::unique_ptr<JSValueRef []> valueArray(new JSValueRef[chunk_data.length()]);
509             for (std::size_t i = 0; i < chunk_data.length(); ++i) {
510                 valueArray[i] = JSValueMakeNumber(context, chunk_data.data()[i]);
511             }
512             jschunk = JSObjectMakeArray(context,
513                                         chunk_data.length(),
514                                         valueArray.get(),
515                                         NULL);
516         }
517         module->data_chunk_storage_.erase(it);
518     }
519
520     return jschunk;
521 }
522
523 // static
524 JSValueRef XWalkExtensionModule::SendRuntimeMessageCallback(JSContextRef context,
525         JSObjectRef object,
526         JSObjectRef thisObject,
527         size_t argumentCount,
528         const JSValueRef arguments[],
529         JSValueRef* exception) {
530     LOGD("SendRuntimeMessageCallback");
531     XWalkExtensionModule* module = GetExtensionModule(thisObject);
532     if (!module || argumentCount < 1) {
533         return JSValueMakeBoolean(context, false);
534     }
535     std::string message = JsUtils::JSValueToString(context, arguments[0]);
536     std::string body;
537     if (argumentCount > 1) {
538       body = JsUtils::JSValueToString(context, arguments[1]);
539     }
540     IPCMessageSupport::sendMessageToUiProcess(message.c_str(), body.c_str());
541     return JSValueMakeBoolean(context, true);
542 }
543
544
545 namespace {
546 struct AsyncData{
547   JSContextRef context;
548   JSObjectRef callback;
549 };
550 }  // namespace
551
552 // static
553 JSValueRef XWalkExtensionModule::SendRuntimeAsyncMessageCallback(JSContextRef context,
554         JSObjectRef object,
555         JSObjectRef thisObject,
556         size_t argumentCount,
557         const JSValueRef arguments[],
558         JSValueRef* exception) {
559     LOGD("SendRuntimeAsyncMessageCallback");
560     XWalkExtensionModule* module = GetExtensionModule(thisObject);
561     if (!module || argumentCount < 1) {
562         return JSValueMakeBoolean(context, false);
563     }
564     std::string message = JsUtils::JSValueToString(context, arguments[0]);
565     std::string body;
566     if (argumentCount > 1) {
567         body = JsUtils::JSValueToString(context, arguments[1]);
568     }
569     JSObjectRef js_callback = NULL;
570     if (argumentCount > 2) {
571         js_callback = JSValueToObject(context, arguments[2], NULL);
572         if (js_callback != NULL) {
573             JSValueSafeProtect(context,js_callback);
574         }
575     }
576     AsyncData* user_data = new AsyncData;
577     user_data->callback = js_callback;
578     user_data->context = JSContextGetGlobalContext(context);
579
580     auto callback = [](unsigned int id, void* user_data, const char* result) -> void {
581         LOGD("SendRuntimeAsyncMessageCallback async result callback - start");
582         AsyncData* data = static_cast<AsyncData*>(user_data);
583         using namespace WrtDeviceApis::CommonsJavaScript;
584         if (data != NULL
585             && data->context != NULL
586             && JSLifeManager::GetInstance().IsAvailableContext(data->context)
587             && data->callback != NULL
588             && JSObjectIsFunction(data->context, data->callback)) {
589           JSValueRef args[1] = { JsUtils::ToJSValueRef(data->context, result) };
590           JSObjectCallAsFunction(data->context, data->callback, NULL, 1, args, NULL);
591           JSValueSafeUnprotect(data->context,data->callback);
592         }
593         if (data != NULL) {
594             delete data;
595         }
596     };
597
598     LOGD("SendRuntimeAsyncMessageCallback send async call");
599     IPCMessageSupport::sendAsyncMessageToUiProcess(
600             message.c_str(),
601             body.c_str(),
602             callback, user_data);
603     return JSValueMakeBoolean(context, true);
604 }
605
606 // static
607 JSValueRef XWalkExtensionModule::SendRuntimeSyncMessageCallback(JSContextRef context,
608         JSObjectRef object,
609         JSObjectRef thisObject,
610         size_t argumentCount,
611         const JSValueRef arguments[],
612         JSValueRef* exception) {
613     LOGD("SendRuntimeSyncMessageCallback");
614     XWalkExtensionModule* module = GetExtensionModule(thisObject);
615     if (!module || argumentCount < 1) {
616         return JSValueMakeUndefined(context);
617     }
618     std::string message = JsUtils::JSValueToString(context, arguments[0]);
619     std::string body;
620     if (argumentCount > 1) {
621         body = JsUtils::JSValueToString(context, arguments[1]);
622     }
623
624     std::string retval = IPCMessageSupport::sendSyncMessageToUiProcess(message.c_str(), body.c_str());
625     return JsUtils::ToJSValueRef(context, retval);
626 }
627
628
629
630 // static
631 JSValueRef XWalkExtensionModule::SetMessageListenerCallback(JSContextRef context,
632         JSObjectRef object,
633         JSObjectRef thisObject,
634         size_t argumentCount,
635         const JSValueRef arguments[],
636         JSValueRef* exception) {
637     XWalkExtensionModule* module = GetExtensionModule(thisObject);
638     if (!module || argumentCount != 1) {
639         return JSValueMakeBoolean(context, false);
640     }
641
642     JSObjectRef obj = JSValueToObject(context, arguments[0], NULL);
643     if ( !(obj != NULL && JSObjectIsFunction(context, obj)) && !JSValueIsUndefined(context, arguments[0])) {
644         LOGE("Trying to set message listener with invalid value.");
645         return JSValueMakeBoolean(context, false);
646     }
647
648     if( module->message_listener_ != NULL ){
649         JSValueSafeUnprotect(context,module->message_listener_);
650     }
651     module->message_listener_ = NULL;
652
653     if (!JSValueIsUndefined(context, arguments[0])){
654         module->message_listener_ = obj;
655         JSValueSafeProtect(context,module->message_listener_);
656     }
657
658     return JSValueMakeBoolean(context, true);
659 }
660
661 JSValueRef XWalkExtensionModule::SetDataListenerCallback(JSContextRef context,
662         JSObjectRef object,
663         JSObjectRef thisObject,
664         size_t argumentCount,
665         const JSValueRef arguments[],
666         JSValueRef* exception) {
667     XWalkExtensionModule* module = GetExtensionModule(thisObject);
668     if (!module || argumentCount != 1) {
669         return JSValueMakeBoolean(context, false);
670     }
671
672     JSObjectRef obj = JSValueToObject(context, arguments[0], NULL);
673     if ( !(obj != NULL && JSObjectIsFunction(context, obj)) && !JSValueIsUndefined(context, arguments[0])) {
674         LOGE("Trying to set message listener with invalid value.");
675         return JSValueMakeBoolean(context, false);
676     }
677
678     if( module->data_listener_ != NULL ){
679         JSValueSafeUnprotect(context,module->data_listener_);
680     }
681     module->data_listener_ = NULL;
682
683     if (!JSValueIsUndefined(context, arguments[0])){
684         module->data_listener_ = obj;
685         JSValueSafeProtect(context,module->data_listener_);
686     }
687
688     return JSValueMakeBoolean(context, true);
689 }
690
691
692 // static
693 XWalkExtensionModule* XWalkExtensionModule::GetExtensionModule(JSObjectRef thisObject) {
694     return static_cast<XWalkExtensionModule*>(JSObjectGetPrivate(thisObject));
695 }
696
697 }  // namespace wrt