From: Lukasz Bardeli Date: Fri, 11 Aug 2017 11:45:05 +0000 (+0200) Subject: [DataControl] Add addChangeListener and removeChangeListener implementation X-Git-Tag: submit/tizen/20170816.103516~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d509778f92e78d6fd615458174d532b258d41bee;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [DataControl] Add addChangeListener and removeChangeListener implementation [Verification] Code compiles without error Change-Id: Ifd05e4a4746e64500d4336e1c5598159194c5a6e Signed-off-by: Lukasz Bardeli --- diff --git a/src/datacontrol/datacontrol_api.js b/src/datacontrol/datacontrol_api.js index cb7158e8..5d609965 100755 --- a/src/datacontrol/datacontrol_api.js +++ b/src/datacontrol/datacontrol_api.js @@ -18,18 +18,201 @@ tizen.debug = extension; var JSON_ = xwalk.JSON; var validator_ = xwalk.utils.validator; +var converter_ = xwalk.utils.converter; var types_ = validator_.Types; +var type_ = xwalk.utils.type; +var native_ = new xwalk.utils.NativeManager(extension); var callbackId = 0; var callbacks = {}; +var listeners_ = {}; +var DATA_CONTROL_MANAGER_LISTENER_ID = 'DataControlManagerChangeCallback'; + +var DataType = { + 'MAP': 'MAP', + 'SQL': 'SQL' +}; + +var EventType = { + 'SQL_UPDATE': 'SQL_UPDATE', + 'SQL_INSERT': 'SQL_INSERT', + 'SQL_DELETE': 'SQL_DELETE', + 'MAP_SET': 'MAP_SET', + 'MAP_ADD': 'MAP_ADD', + 'MAP_REMOVE': 'MAP_REMOVE' +}; + + +var DataControlListenersManager = (function() { + + function changeEvent(event) { + var successCallback; + + if (DataType.SQL === event.eventType) { + if (type_.isEmptyObject(this._SQLDataControlCallbackMap)) { + return; + } + for (var listenerId in this._SQLDataControlCallbackMap) { + if (this._SQLDataControlCallbackMap.hasOwnProperty(listenerId)) { + if (this._SQLDataControlCallbackMap[listenerId].providerId === event.providerId && + this._SQLDataControlCallbackMap[listenerId].dataId === event.dataId) { + successCallback = this._SQLDataControlCallbackMap[listenerId].changeCallback; + if (type_.isFunction(successCallback)) { + successCallback(event.type, {columns: event.columns, values: event.values}); + } + } + } + } + } else { + if (type_.isEmptyObject(this._MAPDataControlCallbackMap)) { + return; + } + for (var listenerId in this._MAPDataControlCallbackMap) { + if (this._MAPDataControlCallbackMap.hasOwnProperty(listenerId)) { + if (this._MAPDataControlCallbackMap[listenerId].providerId === event.providerId && + this._MAPDataControlCallbackMap[listenerId].dataId === event.dataId) { + successCallback = this._MAPDataControlCallbackMap[listenerId].changeCallback; + if (type_.isFunction(successCallback)) { + successCallback(event.type, {columns: event.columns, values: event.values}); + } + } + } + } + } + } + + function _DataControlListenerManager() { + this._SQLDataControlCallbackMap = {}; + this._MAPDataControlCallbackMap = {}; + this.lastListenerId = 0; + this.changeEvent = changeEvent.bind(this); + } + + _DataControlListenerManager.prototype.addChangeListener = function(type, providerId, dataId, changeCallback, errorCallback) { + var _realWatchId = 0; + if (DataType.SQL === type) { + for (var i in this._SQLDataControlCallbackMap) { + if (this._SQLDataControlCallbackMap.hasOwnProperty(i) && + this._SQLDataControlCallbackMap[i].providerId === providerId && + this._SQLDataControlCallbackMap[i].dataId === dataId) { + _realWatchId = this._SQLDataControlCallbackMap[i].realWatchId; + } + } + } else { + for (var i in this._MAPDataControlCallbackMap) { + if (this._MAPDataControlCallbackMap.hasOwnProperty(i) && + this._MAPDataControlCallbackMap[i].providerId === providerId && + this._MAPDataControlCallbackMap[i].dataId === dataId) { + _realWatchId = this._MAPDataControlCallbackMap[i].realWatchId; + } + } + } + + if (!_realWatchId) { + var callback = function(result) { + if (native_.isFailure(result)) { + native_.callIfPossible(errorCallback, native_.getErrorObject(result)); + return; + } + } + var result = + callNativeWithCallback('DataControlConsumerObject_addChangeListener', { + providerId: providerId, + dataId: dataId, + type: type + }, callback); + + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } else { + _realWatchId = converter_.toLong(result.watchId, true); + } + if (type_.isEmptyObject(this._SQLDataControlCallbackMap) && + type_.isEmptyObject(this._MAPDataControlCallbackMap)) { + AddListener(DATA_CONTROL_MANAGER_LISTENER_ID, this.changeEvent); + } + } + + if (DataType.SQL === type) { + this._SQLDataControlCallbackMap[++this.lastListenerId] = {'providerId': providerId, + 'dataId': dataId, + 'changeCallback': changeCallback, + 'realWatchId': _realWatchId}; + } else { + this._MAPDataControlCallbackMap[++this.lastListenerId] = {'providerId': providerId, + 'dataId': dataId, + 'changeCallback': changeCallback, + 'realWatchId': _realWatchId}; + } + + return this.lastListenerId; + }; + + _DataControlListenerManager.prototype.removeChangeListener = function(type, providerId, dataId, listenerId) { + var _realWatchId = 0; + if (DataType.SQL === type && !type_.isUndefined(this._SQLDataControlCallbackMap[listenerId])) { + _realWatchId = this._SQLDataControlCallbackMap[listenerId].realWatchId; + delete this._SQLDataControlCallbackMap[listenerId]; + for (var i in this._SQLDataControlCallbackMap) { + if (this._SQLDataControlCallbackMap.hasOwnProperty(i) && + this._SQLDataControlCallbackMap[i].realWatchId === _realWatchId) { + return; + } + } + } else if (DataType.MAP === type && !type_.isUndefined(this._MAPDataControlCallbackMap[listenerId])) { + _realWatchId = this._MAPDataControlCallbackMap[listenerId].realWatchId; + delete this._MAPDataControlCallbackMap[listenerId]; + for (var i in this._MAPDataControlCallbackMap) { + if (this._MAPDataControlCallbackMap.hasOwnProperty(i) && + this._MAPDataControlCallbackMap[i].realWatchId === _realWatchId) { + return; + } + } + } else { + console.log("Type invalid or listener was not added") + return; + } + + if (0 != _realWatchId) { + callNative('DataControlConsumerObject_removeChangeListener',{ + providerId: providerId, + dataId: dataId, + watchId: _realWatchId, + type: type + }) + + if (type_.isEmptyObject(this._SQLDataControlCallbackMap) && + type_.isEmptyObject(this._MAPDataControlCallbackMap)) { + RemoveListener(DATA_CONTROL_MANAGER_LISTENER_ID); + } + } + }; + + return _DataControlListenerManager; + +})(); + +var listenersManager = new DataControlListenersManager(); + +// TODO refactor setMessageListener to start using common functionality extension.setMessageListener(function(json) { var result = JSON_.parse(json); - var callback = callbacks[result['callbackId']]; - setTimeout(function() { - callback(result); - delete callbacks[result['callbackId']]; - }, 0); + if (result.hasOwnProperty("callbackId")) { + var callback = callbacks[result['callbackId']]; + setTimeout(function() { + callback(result); + delete callbacks[result['callbackId']]; + }, 0); + } + if (result.hasOwnProperty("listenerId")) { + var id = result['listenerId']; + delete result['listenerId']; + var f = listeners_[id]; + setTimeout(function() { + f(result); + }, 0); + } }); function nextCallbackId() { @@ -71,15 +254,24 @@ function callNativeWithCallback(cmd, args, callback) { return callNative(cmd, args); } +function AddListener(name, callback) { + if (!type_.isString(name) || !name.length) { + throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR); + } + + listeners_[name] = callback; +}; + +function RemoveListener(name) { + if (listeners_.hasOwnProperty(name)) { + delete listeners_[name]; + } +}; + function SetReadOnlyProperty(obj, n, v) { Object.defineProperty(obj, n, {value: v, writable: false}); } -var DataType = { - 'MAP': 'MAP', - 'SQL': 'SQL' -}; - function DataControlManager() { // constructor of DataControlManager } @@ -91,15 +283,16 @@ var getDataControlConsumer = function(providerId, dataId, type) { var args = validator_.validateArgs(arguments, [ {'name': 'providerId', 'type': types_.STRING}, {'name': 'dataId', 'type': types_.STRING}, - {'name': 'type', 'type': types_.ENUM, 'values': ['MAP', 'SQL']} + {'name': 'type', 'type': types_.ENUM, 'values': [DataType.SQL, DataType.MAP]} ]); var returnObject = null; - if (type === 'SQL') { + if (DataType.SQL === type) { returnObject = new SQLDataControlConsumer(); - } else if (type === 'MAP') { + } else if (DataType.MAP == type) { returnObject = new MappedDataControlConsumer(); } + SetReadOnlyProperty(returnObject, 'type', args.type); // read only property SetReadOnlyProperty(returnObject, 'providerId', args.providerId); // read only property SetReadOnlyProperty(returnObject, 'dataId', args.dataId); // read only property @@ -116,7 +309,34 @@ function DataControlConsumerObject() { // constructor of DataControlConsumerObject } +DataControlConsumerObject.prototype.addChangeListener = function() { + var args = validator_.validateArgs(arguments, [ + {'name': 'dataChangeCallback', 'type': types_.FUNCTION, optional: false, nullable: false}, + {'name': 'errorCallback', 'type': types_.FUNCTION, optional: true, nullable: true} + ]); + + var type = DataType.SQL; + if (this instanceof MappedDataControlConsumer) { + type = DataType.MAP; + } + + return listenersManager.addChangeListener(type, this.providerId, this.dataId, + args.dataChangeCallback, args.errorCallback); +} + +DataControlConsumerObject.prototype.removeChangeListener = function() { + + var args = validator_.validateArgs(arguments, [ + {'name': 'watchId', 'type': types_.LONG} + ]); + var type = DataType.SQL; + if (this instanceof MappedDataControlConsumer) { + type = DataType.MAP; + } + + listenersManager.removeChangeListener(type, this.providerId, this.dataId, args.watchId); +} function SQLDataControlConsumer() { // constructor of SQLDataControlConsumer diff --git a/src/datacontrol/datacontrol_instance.cc b/src/datacontrol/datacontrol_instance.cc index a55ab14c..60adcee9 100755 --- a/src/datacontrol/datacontrol_instance.cc +++ b/src/datacontrol/datacontrol_instance.cc @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -38,7 +37,10 @@ namespace datacontrol { namespace { // The privileges that required in Datacontrol API const std::string kPrivilegeDatacontrol = "http://tizen.org/privilege/datacontrol.consumer"; - +const std::string kPrivilegeDatasharing = "http://tizen.org/privilege/datasharing"; +const std::string kPrivilegeAppmanagerLaunch = "http://tizen.org/privilege/appmanager.launch"; +const std::string SQL = "SQL"; +const std::string MAP = "MAP"; } // namespace using common::InvalidValuesException; @@ -47,10 +49,13 @@ using common::IOException; using common::SecurityException; using common::UnknownException; using common::NotFoundException; +using common::AbortException; using common::ScopeExit; using common::operator+; +using namespace common; + struct DatacontrolInformation { int callbackId; int requestId; @@ -79,7 +84,14 @@ DatacontrolInstance::DatacontrolInstance() { REGISTER_SYNC("SQLDataControlConsumer_insert", SQLDataControlConsumerInsert); REGISTER_SYNC("MappedDataControlConsumer_getValue", MappedDataControlConsumerGetvalue); + REGISTER_SYNC("DataControlConsumerObject_removeChangeListener", + RemoveChangeListener); #undef REGISTER_SYNC + #define REGISTER_ASYNC(c, x) \ + RegisterSyncHandler(c, std::bind(&DatacontrolInstance::x, this, _1, _2)); + REGISTER_ASYNC("DataControlConsumerObject_addChangeListener", + AddChangeListener); + #undef REGISTER_ASYNC } DatacontrolInstance::~DatacontrolInstance() { @@ -976,6 +988,309 @@ void DatacontrolInstance::MappedDataControlConsumerUpdatevalue( } } +int DatacontrolInstance::CreateMAPHandle(const std::string& providerId, + const std::string& dataId, + data_control_h *handle) { + LoggerD("Enter"); + int result = DATA_CONTROL_ERROR_NONE; + + result = ::data_control_map_create(handle); + RETURN_IF_FAIL(result, + "Creating map data control handle is failed with error"); + + result = ::data_control_map_set_provider_id(*handle, providerId.c_str()); + RETURN_IF_FAIL(result, + "Setting provider id is failed with error"); + + result = ::data_control_map_set_data_id(*handle, dataId.c_str()); + RETURN_IF_FAIL(result, + "Setting data id is failed the error"); + + return result; +} + +int DatacontrolInstance::CreateSQLHandle(const std::string& providerId, + const std::string& dataId, + data_control_h *handle) { + LoggerD("Enter"); + int result = DATA_CONTROL_ERROR_NONE; + + result = ::data_control_sql_create(handle); + RETURN_IF_FAIL(result, + "Creating sql data control handle is failed with error"); + + result = ::data_control_sql_set_provider_id(*handle, providerId.c_str()); + RETURN_IF_FAIL(result, "Setting provider id is failed with error"); + + result = ::data_control_sql_set_data_id(*handle, dataId.c_str()); + RETURN_IF_FAIL(result, "Setting data id is failed the error"); + + return result; +} + +PlatformResult DatacontrolInstance::ChangeTypeToString(data_control_data_change_type_e type_e, std::string *type) +{ + LoggerD("Enter"); + + switch(type_e) { + case DATA_CONTROL_DATA_CHANGE_SQL_UPDATE: + *type = "SQL_UPDATE"; + break; + case DATA_CONTROL_DATA_CHANGE_SQL_INSERT: + *type = "SQL_INSERT"; + break; + case DATA_CONTROL_DATA_CHANGE_SQL_DELETE: + *type = "SQL_DELETE"; + break; + case DATA_CONTROL_DATA_CHANGE_MAP_SET: + *type = "MAP_SET"; + break; + case DATA_CONTROL_DATA_CHANGE_MAP_ADD: + *type = "MAP_ADD"; + break; + case DATA_CONTROL_DATA_CHANGE_MAP_REMOVE: + *type = "MAP_REMOVE"; + break; + default: + return LogAndCreateResult(ErrorCode::ABORT_ERR, + "Undefined data change type"); + break; + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +void DatacontrolInstance::callback(data_control_h provider, data_control_data_change_type_e type, bundle *bundle_data, void *user_data) +{ + LoggerD("Enter"); + + auto data = static_cast(user_data); + + char *provider_id = nullptr; + char *data_id = nullptr; + int result = DATA_CONTROL_ERROR_NONE; + + if (DATA_CONTROL_DATA_CHANGE_SQL_UPDATE == type || + DATA_CONTROL_DATA_CHANGE_SQL_INSERT == type || + DATA_CONTROL_DATA_CHANGE_SQL_DELETE == type) { + + if (MAP == data->event_type) { + LoggerI("Callback registered for different type"); + return; + } + + result = data_control_sql_get_provider_id(provider, &provider_id); + + if (DATA_CONTROL_ERROR_NONE == result) { + result = data_control_sql_get_data_id(provider, &data_id); + } + } else { + + if (SQL == data->event_type) { + LoggerI("Callback registered for different type"); + return; + } + + result = data_control_map_get_provider_id(provider, &provider_id); + + if (DATA_CONTROL_ERROR_NONE == result) { + result = data_control_map_get_data_id(provider, &data_id); + } + } + + picojson::value event = picojson::value(picojson::object()); + picojson::object& obj = event.get(); + + if (DATA_CONTROL_ERROR_NONE != result) { + obj.insert(std::make_pair("callbackId", picojson::value(std::to_string(data->callbackId)))); + // According to native documentation only IOError can be returned to webapi, other errors are handled earlier + LogAndReportError(PlatformResult(ErrorCode::IO_ERR, "Get callback data failed"), &obj); + Instance::PostMessage(data->_instance, event.serialize().c_str()); + return; + } + + std::string event_type = ""; + PlatformResult status = ChangeTypeToString(type, &event_type); + + if (status.IsError()) { + obj.insert(std::make_pair("callbackId", picojson::value(std::to_string(data->callbackId)))); + LogAndReportError(status, &obj); + Instance::PostMessage(data->_instance, event.serialize().c_str()); + return; + } + + obj.insert(std::make_pair("type", picojson::value(event_type))); + + obj.insert(std::make_pair("providerId", picojson::value(std::string(provider_id)))); + obj.insert(std::make_pair("dataId", picojson::value(std::string(data_id)))); + + obj.insert(std::make_pair("columns", picojson::value(picojson::array()))); + obj.insert(std::make_pair("values", picojson::value(picojson::array()))); + + bundle_foreach(bundle_data, [](const char *key, const int type, const bundle_keyval_t *kv, void *user_data){ + LoggerD("Enter"); + + picojson::object &row_data = *(static_cast(user_data)); + + void *basic_val = NULL; + size_t basic_size = 0; + + LoggerD("Key:%s, Type:%d\n", key, type); + bundle_keyval_get_basic_val(const_cast(kv), &basic_val, &basic_size); + + row_data["columns"].get().push_back(picojson::value(std::string(key))); + row_data["values"].get().push_back(picojson::value(std::string(static_cast(basic_val)))); + }, &obj); + + obj.insert(std::make_pair("listenerId", picojson::value("DataControlManagerChangeCallback"))); + + Instance::PostMessage(data->_instance, event.serialize().c_str()); +} + +// result_callback method is used only for pass information to errorCallback if any error +// occur while adding listener +void DatacontrolInstance::result_callback(data_control_h provider, data_control_error_e result, int callback_id, void *user_data) { + LoggerD("Enter"); + if (DATA_CONTROL_ERROR_NONE != result) { + auto data = static_cast(user_data); + picojson::value event = picojson::value(picojson::object()); + picojson::object& obj = event.get(); + obj.insert(std::make_pair("callbackId", picojson::value(std::to_string(data->callbackId)))); + // According to native documentation only IOError can be returned to webapi, other errors are handled earlier + LogAndReportError(IOException("AddChangeListener failed"), obj); + Instance::PostMessage(data->_instance, event.serialize().c_str()); + if (0 != callback_id) { + data->_instance->EraseMap(callback_id); + } + } +} + + +void DatacontrolInstance::AddChangeListener(const picojson::value& args, picojson::object& out) { + LoggerD("Enter"); + + CHECK_PRIVILEGE_ACCESS(kPrivilegeDatasharing, &out); + CHECK_PRIVILEGE_ACCESS(kPrivilegeAppmanagerLaunch, &out); + + CHECK_EXIST(args, "providerId", out) + CHECK_EXIST(args, "dataId", out) + CHECK_EXIST(args, "type", out) + CHECK_EXIST(args, "callbackId", out) + + const std::string& providerId = args.get("providerId").get(); + const std::string& dataId = args.get("dataId").get(); + const std::string& type = args.get("type").get(); + int callbackId = static_cast(args.get("callbackId").get()); + int result = DATA_CONTROL_ERROR_NONE; + data_control_h handle = nullptr; + std::function del; + + if (SQL == type) { + result = CreateSQLHandle(providerId, dataId, &handle); + del = data_control_sql_destroy; + } else { + result = CreateMAPHandle(providerId, dataId, &handle); + del = data_control_map_destroy; + } + + auto deleter = [&del](data_control_h handle) { + if (handle && DATA_CONTROL_ERROR_NONE != del(handle)) { + LoggerE("Destroy handle failed"); + } + }; + + std::unique_ptr::type, decltype(deleter)> handle_ptr( + handle, deleter); + + std::shared_ptr user_data(new ReplyCallbackData()); + user_data->_instance = this; + user_data->callbackId = callbackId; + user_data->event_type = type; + + + if (DATA_CONTROL_ERROR_NONE != result) { + // According to native documentation only IOError can be returned to webapi, other errors are handled earlier + result_callback(handle, DATA_CONTROL_ERROR_IO_ERROR, 0, user_data.get()); + return; + } + + + int watch_id = 0; + result = ::data_control_add_data_change_cb(handle, callback, user_data.get(), result_callback, user_data.get(), &watch_id); + + if (DATA_CONTROL_ERROR_NONE != result) { + // According to native documentation only IOError can be returned to webapi, other errors are handled earlier + result_callback(handle, DATA_CONTROL_ERROR_IO_ERROR, 0, user_data.get()); + return; + } + + reply_map.insert(std::pair(watch_id, user_data)); + + picojson::value return_value = picojson::value(picojson::object()); + picojson::object& return_value_obj = return_value.get(); + + return_value_obj.insert(std::make_pair("watchId", picojson::value(std::to_string(watch_id)))); + ReportSuccess(return_value, out); +} + +void DatacontrolInstance::RemoveChangeListener( + const picojson::value& args, picojson::object& out) { + LoggerD("Enter"); + + CHECK_PRIVILEGE_ACCESS(kPrivilegeDatasharing, &out); + CHECK_PRIVILEGE_ACCESS(kPrivilegeAppmanagerLaunch, &out); + + CHECK_EXIST(args, "providerId", out) + CHECK_EXIST(args, "dataId", out) + CHECK_EXIST(args, "watchId", out) + CHECK_EXIST(args, "type", out) + + const std::string& providerId = args.get("providerId").get(); + const std::string& dataId = args.get("dataId").get(); + const std::string& type = args.get("type").get(); + int watch_id = static_cast(args.get("watchId").get()); + data_control_h handle = nullptr; + std::function del; + int result = DATA_CONTROL_ERROR_NONE; + + if (SQL == type) { + result = CreateSQLHandle(providerId, dataId, &handle); + del = data_control_sql_destroy; + } else { + result = CreateMAPHandle(providerId, dataId, &handle); + del = data_control_map_destroy; + } + + if (DATA_CONTROL_ERROR_NONE != result) { + // According to native documentation only IOError can be returned to webapi, other errors are handled earlier + LogAndReportError(IOException("RemoveChangeListener failed"), out, + ("RemoveChangeListener failed: %d (%s)", result, + get_error_message(result))); + return; + } + + auto deleter = [&del](data_control_h handle){ + if (handle && DATA_CONTROL_ERROR_NONE != del(handle)) { + LoggerE("Destroy handle failed"); + } + }; + + std::unique_ptr::type, decltype(deleter)> handle_ptr( + handle, deleter); + + result = ::data_control_remove_data_change_cb(handle, watch_id); + + if (DATA_CONTROL_ERROR_NONE != result) { + // According to native documentation only IOError can be returned to webapi, other errors are handled earlier + LogAndReportError(IOException("RemoveChangeListener failed"), out, + ("RemoveChangeListener failed: %d (%s)", result, + get_error_message(result))); + return; + } + + reply_map.erase(watch_id); + + ReportSuccess(out); +} #undef CHECK_EXIST diff --git a/src/datacontrol/datacontrol_instance.h b/src/datacontrol/datacontrol_instance.h index e2f2ee35..5b1c3416 100755 --- a/src/datacontrol/datacontrol_instance.h +++ b/src/datacontrol/datacontrol_instance.h @@ -19,12 +19,25 @@ #include #include +#include +#include #include "common/extension.h" namespace extension { namespace datacontrol { +class DatacontrolInstance; + +struct ReplyCallbackData { + DatacontrolInstance* _instance; + int callbackId; + std::string event_type; +}; + +typedef std::shared_ptr ReplyCallbackDataPtr; +typedef std::map ReplyCallbackDataMap; + class DatacontrolInstance : public common::ParsedInstance { public: DatacontrolInstance(); @@ -41,6 +54,25 @@ class DatacontrolInstance : public common::ParsedInstance { int callbackId, int userRequestId, DataControlJob job); + int CreateMAPHandle(const std::string& providerId, + const std::string& dataId, + data_control_h *handle); + + int CreateSQLHandle(const std::string& providerId, + const std::string& dataId, + data_control_h *handle); + + void EraseMap(int watch_id) {reply_map.erase(watch_id);}; + + static void callback(data_control_h provider, + data_control_data_change_type_e type, + bundle *bundle_data, void *user_data); + static void result_callback(data_control_h provider, + data_control_error_e result, + int callback_id, void *user_data); + static common::PlatformResult ChangeTypeToString(data_control_data_change_type_e type_e, + std::string *type); + private: void DataControlManagerGetdatacontrolconsumer(const picojson::value& args, picojson::object& out); @@ -60,6 +92,12 @@ class DatacontrolInstance : public common::ParsedInstance { picojson::object& out); void MappedDataControlConsumerUpdatevalue(const picojson::value& args, picojson::object& out); + void AddChangeListener(const picojson::value& args, + picojson::object& out); + void RemoveChangeListener(const picojson::value& args, + picojson::object& out); + + ReplyCallbackDataMap reply_map; }; } // namespace datacontrol