[Account] - Resolving problems in the JS API module
authorAndrzej Popowski <a.popowski@samsung.com>
Wed, 11 Feb 2015 13:52:49 +0000 (14:52 +0100)
committerPawel Andruszkiewicz <p.andruszkie@samsung.com>
Thu, 12 Feb 2015 12:34:50 +0000 (21:34 +0900)
Change-Id: Ic35b8aa53f1b8cf71598c51d56174ad9cf6101fa
Signed-off-by: Andrzej Popowski <a.popowski@samsung.com>
src/account/account_api.js

index 01061e0..5b0f492 100644 (file)
 
 var validator_ = xwalk.utils.validator;
 var types_ = validator_.Types;
+var T_ = xwalk.utils.type;
+var native_ = new xwalk.utils.NativeManager(extension);
 
-var callbackId = 0;
-var callbacks = {};
 
-var lastAccountChangeListenerId = -1;
-var accountChangeListener = {};
-
-function invokeListener(result) {
-  if (result.listener === 'accountChange') {
-    for (var listenerId in accountChangeListener) {
-      console.log("[Account][invokeListener] AccountChangeListenerId: " + listenerId);
-      var listener = callbacks[accountChangeListener[listenerId]];
-      listener(result);
+function InternalValues_(data) {
+    if (!(this instanceof InternalValues_)) {
+        return new InternalValues_(data);
+    }
+    for(var key in data) {
+        if (data.hasOwnProperty(key)) {
+            this[key] = data[key];
+        }
     }
-  }
 }
 
-extension.setMessageListener(function(json) {
-  var result = JSON.parse(json);
-
-  if (result.hasOwnProperty('listener')) {
-    console.log("[Account][setMessageListener] Call listner");
-    invokeListener(result);
-  } else {
-    console.log("[Account][setMessageListener] Call callback");
-    var callback = callbacks[result.callbackId];
-    callback(result);
-  }
-});
-
-function nextCallbackId() {
-  return callbackId++;
+
+function AccountProvider(data) {
+    var internal_ = [];
+    if (data) {
+        internal_ = data.capabilities;
+    }
+
+    Object.defineProperties(this, {
+        applicationId:              { enumerable: true, writable: false, value: data.applicationId },
+        displayName:                { enumerable: true, writable: false, value: data.displayName },
+        iconUri:                    { enumerable: true, writable: false, value: data.iconUri },
+        smallIconUri:               { enumerable: true, writable: false, value: data.smallIconUri },
+        capabilities:               { enumerable: true, 
+                                      set: function() {},
+                                      get: function() { return internal_.slice(); }
+                                    },
+        isMultipleAccountSupported: { enumerable: true, writable: false, value: data.isMultipleAccountSupported },
+    });
 }
 
-function nextAccountChangeListenerId() {
-  return ++lastAccountChangeListenerId;
+
+function Account() {
+    validator_.isConstructorCall(this, tizen.Account);
+    var args = validator_.validateArgs(arguments, [
+        { name: 'provider', type: types_.PLATFORM_OBJECT, values: AccountProvider },
+        { name: 'accountInitDict', type: types_.DICTIONARY, optional: true, nullable: true }
+    ]);
+
+    var _internal = { id: null };
+
+    Object.defineProperties(this, {
+        id:         { enumerable: true,
+                      set: function (value) { if (value instanceof InternalValues_) _internal.id = value.id; },
+                      get: function () { return _internal.id; }
+        },
+        userName:   { enumerable: true, writable: true,
+                      value: (args.accountInitDict ? args.accountInitDict.userName : null) },
+        iconUri:    { enumerable: true, writable: true,
+                      value: (args.accountInitDict ? args.accountInitDict.iconUri : null) },
+        provider:   { enumerable: true, writable: false, value: args.provider }
+    });
 }
 
-function callNative(cmd, args) {
-  var json = {'cmd': cmd, 'args': args};
-  var argjson = JSON.stringify(json);
-  var resultString = extension.internal.sendSyncMessage(argjson);
-  var result = JSON.parse(resultString);
 
-  if (typeof result !== 'object') {
-    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
-  }
+Account.prototype.setExtendedData = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'key', type: types_.STRING },
+        { name: 'value', type: types_.STRING }
+    ]);
 
-  if (result.status === 'success') {
-    if (result.result) {
-      return result.result;
-    }
-    return true;
-  } else if (result.status === 'error') {
-    var err = result.error;
-    if (err) {
-      throw new tizen.WebAPIException(err.name, err.message);
+    var result = native_.callSync('Account_setExtendedData',
+                                  {
+                                      accountId: this.id,
+                                      key: args.key,
+                                      value: args.value
+                                  }
+    );
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
     }
-    return false;
-  }
-}
+};
 
 
-function callNativeWithCallback(cmd, args, callback) {
-  if (callback) {
-    var id = nextCallbackId();
-    args.callbackId = id;
-    callbacks[id] = callback;
-  }
+Account.prototype.getExtendedData = function() {
+    if (T_.isFunction(arguments[0])) {
+        var args = validator_.validateArgs(arguments, [
+            {
+                name : 'successCallback',
+                type : types_.FUNCTION,
+                optional : false,
+                nullable : false
+            },
+            {
+                name : 'errorCallback',
+                type : types_.FUNCTION,
+                optional : true,
+                nullable : true
+            }
+        ]);
+
+        // TODO handling exceptions
+
+        native_.call( 'Account_getExtendedData', { accountId: this.id },
+            function(result) {
+                if (native_.isFailure(result)) {
+                    if(!T_.isNullOrUndefined(args.errorCallback)) {
+                        args.errorCallback(native_.getErrorObject(result));
+                    }
+                } else {
+                    args.successCallback(native_.getResultObject(result));
+                }
+            }
+        );
+    } else {
+        var args = validator_.validateArgs(arguments, [
+            { name: 'key', type: types_.STRING }
+        ]);
+
+        var result = native_.callSync('Account_getExtendedData',
+                                      { 
+                                           accountId: this.id,
+                                           key: args.key
+                                      }
+        );
+        if (native_.isFailure(result)) {
+            throw native_.getErrorObject(result);
+        }
+        return native_.getResultObject(result);
+    }
+};
 
-  return callNative(cmd, args);
-}
 
-function SetReadOnlyProperty(obj, n, v){
-    if (v)
-        Object.defineProperty(obj, n, {value:v, writable: false, enumerable: true, configurable: true});
-    else
-        Object.defineProperty(obj, n, {writable: false, enumerable: true, configurable: true});
+function AccountFromResult(result) {
+    var provider = new AccountProvider(result.provider);
+    var account_init_dict = { userName: result.userName, iconUri: result.iconUri };
+    var account = new Account(provider, account_init_dict);
+    account.id = new InternalValues_({ id: result.id });
+    return account;
 }
 
-function AccountProvider(providerInfo) {
-  SetReadOnlyProperty(this, 'applicationId', providerInfo.applicationId); // read only property
-  SetReadOnlyProperty(this, 'displayName', providerInfo.displayName); // read only property
-  SetReadOnlyProperty(this, 'iconUri', providerInfo.iconUri); // read only property
-  SetReadOnlyProperty(this, 'smallIconUri', providerInfo.smallIconUri); // read only property
-  SetReadOnlyProperty(this, 'capabilities', providerInfo.capabilities); // read only property
-  SetReadOnlyProperty(this, 'isMultipleAccountSupported', providerInfo.isMultipleAccountSupported); // read only property
-}
 
-function SetAccountId(account, accountId) {
+function AccountManager() {}
 
-  Object.defineProperty(account, 'id', {writable: true});
-  account.id = accountId;
-  Object.defineProperty(account, 'id', {writable: false});
 
-  return account;
-}
+AccountManager.prototype.add = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'account', type: types_.PLATFORM_OBJECT, values: Account }
+    ]);
 
-function Account(provider, accountInitDict) {
-  console.log("[Constructor of Account] Enter");
+    var result = native_.callSync( 'AccountManager_add', { account: args.account });
 
-  var args = validator_.validateArgs(arguments, [
-    {'name' : 'provider', 'type' : types_.PLATFORM_OBJECT, 'values' : AccountProvider},
-    {'name' : 'accountInitDict',
-      'type' : types_.DICTIONARY,
-      'optional' : true,
-      'nullable' : true
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
     }
-  ]);
-
-  SetReadOnlyProperty(this, 'id', null); // read only property
-  SetReadOnlyProperty(this, 'provider', provider); // read only property
-  if(arguments.length > 1) {
-      this.userName = accountInitDict.userName;
-      this.iconUri = accountInitDict.iconUri;
-  } else {
-      this.userName = null;
-      this.iconUri = null;
-  }
 }
 
-function MakeAccountObject(obj) {
-  console.log("[Account][MakeAccountObject] Enter");
-  var account = new Account(new AccountProvider(obj.provider), obj.accountInitDict);
-  return SetAccountId(account, obj.id);
-}
 
-Account.prototype.setExtendedData = function(key, value) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'key', 'type': types_.STRING},
-    {'name': 'value', 'type': types_.STRING}
-  ]);
+AccountManager.prototype.remove = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'accountId', type: types_.UNSIGNED_LONG}
+    ]);
 
-  var nativeParam = {
-    'key': args.key,
-    'value': args.value
-  };
+    var result = native_.callSync('AccountManager_remove', { accountId: args.accountId });
 
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+}
 
-  try {
-    var syncResult = callNative('Account_setExtendedData', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
 
-};
+AccountManager.prototype.update = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'account', type: types_.PLATFORM_OBJECT, values: Account }
+    ]);
 
-Account.prototype.getExtendedData = function(key) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'key', 'type': types_.STRING}
-  ]);
+    var result = native_.callSync( 'AccountManager_update',
+                                    {
+                                        accountId:  args.account.id,
+                                        userName:   args.account.userName,
+                                        iconUri:    args.account.iconUri
+                                    }
+    );
 
-  var nativeParam = {
-    'key': args.key
-  };
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+}
 
 
-  try {
-    var syncResult = callNative('Account_getExtendedData', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
+AccountManager.prototype.getAccount = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'accountId', type: types_.UNSIGNED_LONG }
+    ]);
 
-};
+    var result = native_.callSync(
+                        'AccountManager_getAccount',
+                        { accountId: args.accountId }
+    );
 
-Account.prototype.getExtendedData = function(successCallback, errorCallback) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'successCallback', 'type': types_.LISTENER, 'values': ['onsuccess']},
-    {'name': 'errorCallback', 'type': types_.FUNCTION}
-  ]);
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
 
-  var nativeParam = {
-  };
+    var account_result = native_.getResultObject(result);
 
+    if (!T_.isNull(account_result)) {
+        return AccountFromResult(account_result);
+    } else {
+        return null;
+    }
+}
 
-  try {
-    var syncResult = callNative('Account_getExtendedData', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
 
-};
+AccountManager.prototype.getAccounts = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'successCallback', type: types_.FUNCTION, optional: false, nullable: false },
+        { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+        { name: 'applicationId', type: types_.STRING, optional: true, nullable: true }
+    ]);
+
+    // TODO handling exceptions
+
+    native_.call('AccountManager_getAccounts',
+        { 
+            applicationId: args.applicationId
+        },
+        function(result) {
+            if (native_.isFailure(result)) {
+                if(!T_.isNullOrUndefined(args.errorCallback)) {
+                    args.errorCallback(native_.getErrorObject(result));
+                }
+            } else {
+                var accounts_result = native_.getResultObject(result);
+                var accounts_table = [];
+                for (var i = 0; i < accounts_result.length; i++) {
+                    accounts_table[i] = AccountFromResult(accounts_result[i]);
+                }
+                args.successCallback(accounts_table);
+            }
+        }
+    );
+}
 
 
+AccountManager.prototype.getProvider = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'applicationId', type: types_.STRING }
+    ]);
 
-function AccountManager() {
-  // constructor of AccountManager
+    var result = native_.callSync(
+                        'AccountManager_getProvider',
+                        { applicationId: args.applicationId }
+    );
 
-}
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
 
+    var provider_result = native_.getResultObject(result);
 
-AccountManager.prototype.add = function(account) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'account', 'type': types_.PLATFORM_OBJECT, 'values': Account}
-  ]);
+    if (!T_.isNull(provider_result)) {
+        return new AccountProvider(provider_result);
+    } else {
+        return null;
+    }
+};
 
-  var nativeParam = {
-  };
 
+AccountManager.prototype.getProviders = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'successCallback', type: types_.FUNCTION, optional: false, nullable: false },
+        { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+        { name: 'capability', type: types_.STRING, optional: true, nullable: true }
+    ]);
+
+    // TODO handling exceptions
+
+    native_.call( 'AccountManager_getProviders',
+        {
+            capability: args.capability
+        },
+        function(result) {
+            if (native_.isFailure(result)) {
+                if(!T_.isNullOrUndefined(args.errorCallback)) {
+                    args.errorCallback(native_.getErrorObject(result));
+                }
+            } else {
+                var providers_result = native_.getResultObject(result);
+                var providers_table = [];
+                for (var i = 0; i < providers_result.length; i++) {
+                    providers_table[i] = new AccountProvider(providers_result[i]);
+                }
+                args.successCallback(providers_table);
+            }
+        }
+    );
+}
 
-  try {
-    var syncResult = callNative('AccountManager_add', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
 
-};
+var ACCOUNT_LISTENER = 'ACCOUNT_CHANGED';
 
-AccountManager.prototype.remove = function(accountId) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'accountId', 'type': types_.LONG}
-  ]);
 
-  var nativeParam = {
-    'accountId': args.accountId
-  };
+function AccountListeners() {
+    var that = this;
+    this.appCallback = function (event) {
+        if (!T_.isEmptyObject(that.instances)) {
+            var param;
+            switch (event.action) {
+                case 'onadded':
+                    param = AccountFromResult(native_.getResultObject(event));
+                    break;
 
+                case 'onremoved':
+                    param = native_.getResultObject(event);
+                    break;
 
-  try {
-    var syncResult = callNative('AccountManager_remove', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
+                case 'onupdated':
+                    param = AccountFromResult(native_.getResultObject(event));
+                    break;
 
-};
+                default:
+                    console.log('Unknown event: ' + event.action);
+                    break;
+            }
 
-AccountManager.prototype.update = function(account) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'account', 'type': types_.PLATFORM_OBJECT, 'values': Account}
-  ]);
+            var callback;
+            for ( var i = 0; i < that.instances.length; i++) {
+                callback = that.instances[i];
+                if (T_.isFunction(callback[event.action])) {
+                    callback[event.action](param);
+                }
+            }
+        }
+    };
+}
 
-  var nativeParam = {
-  };
 
+AccountListeners.prototype.instances = {};
 
-  try {
-    var syncResult = callNative('AccountManager_update', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
 
+AccountListeners.prototype.addListener = function(accountListenerId, callback) {
+    if (T_.isEmptyObject(this.instances)) {
+        native_.addListener(ACCOUNT_LISTENER, this.appCallback);
+    }
+    this.instances[accountListenerId] = callback;
 };
 
-AccountManager.prototype.getAccount = function(accountId) {
-  console.log("[AccountManager][getAccount] Enter");
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'accountId', 'type': types_.UNSIGNED_LONG}
-  ]);
-
-  var nativeParam = {
-    'accountId': args.accountId
-  };
-
-  try {
-    var syncResult = callNative('AccountManager_getAccount', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
-
-  var returnObject = new Account();
-  return returnObject;
-};
 
-AccountManager.prototype.getAccounts = function(successCallback, errorCallback, applicationId) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'successCallback', 'type': types_.LISTENER, 'values': ['onsuccess']},
-    {'name': 'errorCallback', 'type': types_.FUNCTION},
-    {'name': 'applicationId', 'type': types_.STRING}
-  ]);
+AccountListeners.prototype.removeListener = function(accountListenerId) {
+    delete this.instances[accountListenerId];
+    if (T_.isEmptyObject(this.instances)) {
+        native_.removeListener(ACCOUNT_LISTENER, this.appCallback);
+    }
+};
 
-  var nativeParam = {
-  };
 
-  if (args.applicationId) {
-    nativeParam.applicationId = args.applicationId;
-  }
+var _accountListeners = new AccountListeners();
 
-  try {
-    var syncResult = callNative('AccountManager_getAccounts', nativeParam);
-    // if you need synchronous result from native function using 'syncResult'.
-  } catch (e) {
-    throw e;
-  }
 
-};
+AccountManager.prototype.addAccountListener = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'callback', type: types_.LISTENER, values: ['onadded', 'onremoved', 'onupdated'] }
+    ]);
 
-AccountManager.prototype.getProvider = function(applicationId) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'applicationId', 'type': types_.STRING}
-  ]);
-
-  var nativeParam = {
-    'applicationId': args.applicationId
-  };
-
-  try {
-    var syncResult = callNative('AccountManager_getProvider', nativeParam);
-    return new AccountProvider(syncResult);
-  } catch (e) {
-    throw e;
-  }
-};
+    var result = native_.callSync('AccountManager_addAccountListener');
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
 
-AccountManager.prototype.getProviders = function(successCallback, errorCallback, capability) {
-  var args = validator_.validateArgs(arguments, [
-    {'name' : 'successCallback', 'type' : types_.FUNCTION},
-    {'name' : 'errorCallback', 'type' : types_.FUNCTION, 'optional' : true, 'nullable' : true},
-    {'name' : 'capability', 'type' : types_.STRING, 'optional' : true, 'nullable' : true}
-  ]);
-
-  var nativeParam = {
-  };
-
-  if (args.capability) {
-    nativeParam.capability = args.capability;
-  }
-
-  try {
-    var syncResult = callNativeWithCallback(
-        'AccountManager_getProviders',
-        nativeParam,
-        function(param) {
-          if (param.status == 'success') {
-            for (var i = 0; i < param.result.length; i++) {
-              param.result[i] = new AccountProvider(param.result[i]);
-            }
-            args.successCallback(param.result);
-          } else if (param.status == 'error') {
-            var err = param.error;
-            if (err) {
-              args.errorCallback(new tizen.WebAPIError(err.name, err.message));
-              return;
-            }
-          }
+    var accountListenerId = native_.getResultObject(result);
+    _accountListeners.addListener(accountListenerId, args.callback);
+    return accountListenerId;
+}
 
-          delete callbacks[param.callbackId];
-        });
-  } catch (e) {
-    throw e;
-  }
-};
 
-AccountManager.prototype.addAccountListener = function(callback) {
-  var args = validator_.validateArgs(
-      arguments,
-      [
-          {'name' : 'callback',
-            'type' : types_.LISTENER,
-            'values' : ['onadded', 'onremoved', 'onupdated']}
-      ]);
-
-  var nativeParam = {
-  };
-
-  try {
-    var syncResult = callNativeWithCallback(
-        'AccountManager_addAccountListener',
-        nativeParam,
-        function(param) {
-          if (param.status === 'added') {            
-            args.callback.onadded(MakeAccountObject(param.result));
-          } else if (param.status === 'removed') {
-            args.callback.onremoved(param.result);
-          } else if (param.status === 'updated') {
-            args.callback.onupdated(MakeAccountObject(param.result));
-          }
-        });
-
-    console.log("[Account][addAccountListener] callbackId: " + nativeParam.callbackId);
-    var listenerId = nextAccountChangeListenerId();
-    accountChangeListener[listenerId] = nativeParam.callbackId;
-    console.log("[Account][addAccountListener] listenerId: " + listenerId);
-    return listenerId;
-  } catch (e) {
-    throw e;
-  }
-};
+AccountManager.prototype.removeAccountListener = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'accountListenerId', type: types_.UNSIGNED_LONG }
+    ]);
 
-AccountManager.prototype.removeAccountListener = function(accountListenerId) {
-  var args = validator_.validateArgs(arguments, [
-    {'name': 'accountListenerId', 'type': types_.LONG}
-  ]);
+    _accountListeners.removeListener(args.accountListenerId);
 
-  var nativeParam = {
-  };
+    if (T_.isEmptyObject(_accountListeners.instances)) {
+        var result = native_.callSync('AccountManager_removeListener');
 
-  try {
-    if (args.accountListenerId in accountChangeListener) {
-      delete callbacks[accountChangeListener[args.accountListenerId]];
-      delete accountChangeListener[args.accountListenerId];
+        if (native_.isFailure(result)) {
+            throw native_.getErrorObject(result);
+        }
     }
 
-    if (Object.keys(accountChangeListener).length === 0) {
-      console.log("[Account][removeAccountListener] Unscribe native notification");
-      var syncResult = callNative('AccountManager_removeAccountListener', nativeParam);
-    }
-  } catch (e) {
-    throw e;
-  }
-};
+    return;
+}
 
 tizen.Account = Account;
 
 exports = new AccountManager();
-