From: Piotr Kosko Date: Fri, 22 Jan 2016 13:33:46 +0000 (+0100) Subject: [Iotcon] Added implementation of createResource feature X-Git-Tag: submit/tizen/20160212.103506^2~15 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4598e6aab92669f6e4d1a50ff894cb1e210cdac4;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Iotcon] Added implementation of createResource feature [Verification] Code compiles without errors Code below works: // create door var dict = { uriPath : "/a/door2", resourceTypes : ["core.door"], resourceInterfaces : ["DEFAULT", "LINK"], isObservable : true, isDiscoverable : true }; server.createResource(dict, function(v) {console.log("success " + JSON.stringify(v))}, function(e) {console.log("error " + JSON.stringify(e))} ); Change-Id: Icaac4ad8fb8cd325161bd408a3215eb4beffd782 Signed-off-by: Piotr Kosko --- diff --git a/src/iotcon/iotcon_instance.cc b/src/iotcon/iotcon_instance.cc index 0cd3e939..49f2f03a 100644 --- a/src/iotcon/iotcon_instance.cc +++ b/src/iotcon/iotcon_instance.cc @@ -34,12 +34,6 @@ namespace extension { namespace iotcon { namespace { -const std::string kCallbackId = "callbackId"; -const std::string kIsDiscoverable = "isDiscoverable"; -const std::string kIsObservable = "isObservable"; -const std::string kResourceTypes = "resourceTypes"; -const std::string kUriPath = "uriPath"; - #define CHECK_EXIST(args, name, out) \ if (!args.contains(name)) {\ std::string message = std::string(name) + " is required argument";\ @@ -127,31 +121,40 @@ IotconInstance::IotconInstance() : manager_(this) { if (IOTCON_ERROR_NONE != ret) { LoggerE("Could not connnect to iotcon service: %s", get_error_message(ret)); } else { - ret = iotcon_add_connection_changed_cb(ConnectionChangedCallback, nullptr); + LoggerD("Iotcon service connected"); + ret = iotcon_add_connection_changed_cb(ConnectionChangedCallback, this); if (IOTCON_ERROR_NONE != ret) { LoggerE("Could not add connection changed callback for iotcon service: %s", get_error_message(ret)); + } else { + LoggerD("Iotcon connection changed callback is registered"); } } } void IotconInstance::ConnectionChangedCallback(bool is_connected, void* user_data) { LoggerD("Enter"); - - // try to recover connection to iotcon service if (!is_connected) { - int ret = iotcon_connect(); - if (IOTCON_ERROR_NONE != ret) { - LoggerE("Could not connnect to iotcon service: %s", get_error_message(ret)); + LoggerD("Connection lost, need to wait for connection recovery"); + } else { + IotconInstance* instance = static_cast(user_data); + if (!instance) { + LoggerE("instance is NULL"); + return; + } + + LoggerD("Connection recovered, restoring handles"); + PlatformResult ret = instance->manager_.RestoreHandles(); + if (ret.IsError()) { + LoggerD("Connection recovered, but restoring handles failed"); } - // TODO consider re-adding connection changed listener with iotcon_add_connection_changed_cb() } } IotconInstance::~IotconInstance() { LoggerD("Enter"); - iotcon_remove_connection_changed_cb(ConnectionChangedCallback, nullptr); + iotcon_remove_connection_changed_cb(ConnectionChangedCallback, this); iotcon_disconnect(); } @@ -309,27 +312,37 @@ void IotconInstance::IotconServerCreateResource(const picojson::value& args, picojson::object& out) { LoggerD("Enter"); LoggerD("args: %s", args.serialize().c_str()); - //args: {"callbackId":2,"isDiscoverable":true, - //"isObservable":true,"resourceTypes":["t1","t2"],"uriPath":"uriPath"} - CHECK_EXIST(args, kCallbackId, out) CHECK_EXIST(args, kIsDiscoverable, out) CHECK_EXIST(args, kIsObservable, out) CHECK_EXIST(args, kResourceTypes, out) + CHECK_EXIST(args, kResourceInterfaces, out) CHECK_EXIST(args, kUriPath, out) const double callback_id = args.get(kCallbackId).get(); + // TODO consider support other properties const bool is_discoverable = args.get(kIsDiscoverable).get(); const bool is_observable = args.get(kIsObservable).get(); - const auto& resource_type = args.get(kResourceTypes).get(); + const auto& resource_types = args.get(kResourceTypes).get(); + const auto& resource_interfaces = args.get(kResourceInterfaces).get(); const std::string& uri_path = args.get(kUriPath).get(); - auto create = [this, callback_id, is_discoverable, is_observable, resource_type, uri_path] + auto create = [this, callback_id, is_discoverable, is_observable, + resource_types, uri_path, resource_interfaces] (const std::shared_ptr& response) -> void { LoggerD("Create resource"); + picojson::value result = picojson::value(picojson::object()); - // TODO implement CreateResource - PlatformResult ret = manager_.CreateResource(); + ResourceInfoPtr resource{new ResourceInfo()}; + PlatformResult ret = manager_.CreateResource(uri_path, resource_interfaces, resource_types, + is_discoverable, is_observable, resource); + if (ret.IsError()) { + LogAndReportError(ret,&(response->get())); + return; + } + LoggerD("RESOURCE\nid: %lld\nhandle: %p", resource->id, resource->handle); + + ret = IotconUtils::ResourceToJson(resource, manager_, &(result.get())); if (ret.IsError()) { LogAndReportError(ret,&(response->get())); return; @@ -353,25 +366,21 @@ void IotconInstance::IotconServerCreateResource(const picojson::value& args, void IotconInstance::IotconServerRemoveResource(const picojson::value& args, picojson::object& out) { LoggerD("Enter"); - } void IotconInstance::IotconServerUpdateResource(const picojson::value& args, picojson::object& out) { LoggerD("Enter"); - } void IotconInstance::IotconGetTimeout(const picojson::value& args, picojson::object& out) { LoggerD("Enter"); - } void IotconInstance::IotconSetTimeout(const picojson::value& args, picojson::object& out) { LoggerD("Enter"); - } } // namespace iotcon diff --git a/src/iotcon/iotcon_server_manager.cc b/src/iotcon/iotcon_server_manager.cc index 07663d4c..dfc59020 100644 --- a/src/iotcon/iotcon_server_manager.cc +++ b/src/iotcon/iotcon_server_manager.cc @@ -27,7 +27,8 @@ using common::PlatformResult; using common::ErrorCode; IotconServerManager::IotconServerManager(IotconInstance* instance) - : instance_(instance) { + : instance_(instance), + global_id_(0) { LoggerD("Entered"); } @@ -37,13 +38,110 @@ IotconServerManager::~IotconServerManager() { PlatformResult IotconServerManager::RestoreHandles() { LoggerD("Entered"); + + for (auto it = resource_map_.begin(); it != resource_map_.end(); ++it) { + LoggerD ("Restoring handle for resource with id: %lld", it->first); + ResourceInfoPtr resource = it->second; + + char* uri_path = nullptr; + iotcon_resource_types_h res_types = nullptr; + int ifaces = 0; + int properties = 0; + PlatformResult res = IotconUtils::ExtractFromResource(resource, &uri_path, + &res_types, &ifaces, &properties); + if (res.IsError()){ + return res; + } + + const iotcon_resource_h old_handle = resource->handle; + LoggerD("Create resource from backup data, uri: %s, res_types: %p, ifaces: %d, properties: %d", + uri_path, res_types, ifaces, properties); + + int ret = iotcon_resource_create(uri_path, res_types, ifaces, properties, + RequestHandler, // request_callback + nullptr, // user_data + &(resource->handle)); + if (IOTCON_ERROR_NONE != ret || nullptr == resource->handle) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.", + ("iotcon_resource_create failed: %d (%s)", + ret, get_error_message(ret))); + } + LoggerD("new handle: %p", (resource->handle)); + if (old_handle) { + LoggerD("destroy handle which is currently invalid: %p", old_handle); + iotcon_resource_destroy(old_handle); + } + } + // TODO + // bind children (consider if it is necessary? + // Maybe holding children in resource_map is enough) + + return PlatformResult(ErrorCode::NO_ERROR); +} + +void IotconServerManager::RequestHandler(iotcon_resource_h resource, + iotcon_request_h request, void *user_data) { + LoggerD("Entered"); + // TODO probably should be handled somehow later +} + +PlatformResult IotconServerManager::CreateResource(const std::string& uri_path, + const picojson::array& interfaces_array, + const picojson::array& types_array, + bool is_discoverable, + bool is_observable, + ResourceInfoPtr res_pointer) { + LoggerD("Entered"); + + int ret; + int interfaces = IOTCON_INTERFACE_NONE; + PlatformResult res = IotconUtils::ArrayToInterfaces(interfaces_array, &interfaces); + if (res.IsError()) { + return res; + } + + iotcon_resource_types_h resource_types = nullptr; + res = IotconUtils::ArrayToTypes(types_array, &resource_types); + if (res.IsError()) { + return res; + } + + // TODO consider support other properties + int properties = ((is_discoverable ? IOTCON_RESOURCE_DISCOVERABLE : IOTCON_RESOURCE_NO_PROPERTY) | + (is_observable ? IOTCON_RESOURCE_OBSERVABLE : IOTCON_RESOURCE_NO_PROPERTY) | + IOTCON_RESOURCE_ACTIVE); + + // Create resource + ret = iotcon_resource_create(uri_path.c_str(), + resource_types, + interfaces, + properties, + RequestHandler, // request_callback + nullptr, // user_data + &(res_pointer->handle)); + if (IOTCON_ERROR_NONE != ret || nullptr == res_pointer->handle) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.", + ("iotcon_resource_create failed: %d (%s)", + ret, get_error_message(ret))); + } + + // storing ResourceInfo into map + res_pointer->id = ++global_id_; + resource_map_.insert(std::make_pair(res_pointer->id, res_pointer)); return PlatformResult(ErrorCode::NO_ERROR); } -PlatformResult IotconServerManager::CreateResource() { +common::PlatformResult IotconServerManager::GetResourceById(long long id, + ResourceInfoPtr* res_pointer) const { LoggerD("Entered"); - // TODO implement - return PlatformResult(ErrorCode::NOT_SUPPORTED_ERR, "Not implemented yet"); + auto it = resource_map_.find(id); + if (it == resource_map_.end()) { + LoggerE("Not found such resource"); + return PlatformResult(ErrorCode::NOT_FOUND_ERR, "Not found such resource"); + } + LoggerE("Resource found"); + *res_pointer = it->second; + return PlatformResult(ErrorCode::NO_ERROR); } } // namespace iotcon diff --git a/src/iotcon/iotcon_server_manager.h b/src/iotcon/iotcon_server_manager.h index 8e3e45a6..239019ce 100644 --- a/src/iotcon/iotcon_server_manager.h +++ b/src/iotcon/iotcon_server_manager.h @@ -22,31 +22,14 @@ #include #include +#include "iotcon/iotcon_utils.h" + #include "common/picojson.h" #include "common/platform_result.h" namespace extension { namespace iotcon { -struct ResourceInfo { - const char *uri_path; - iotcon_resource_types_h res_types; - int ifaces; - int properties; - iotcon_resource_h handle; - ResourceInfo() : - uri_path(nullptr), res_types(nullptr), ifaces(0), - properties(0), handle(nullptr) {} - ~ResourceInfo() { - delete uri_path; - iotcon_resource_types_destroy(res_types); - iotcon_resource_destroy (handle); - } -}; - -typedef std::shared_ptr ResourceInfoPtr; -typedef std::map ResourceInfoMap; - class IotconInstance; class IotconServerManager { @@ -54,15 +37,19 @@ class IotconServerManager { IotconServerManager(IotconInstance* instance); ~IotconServerManager(); + static void RequestHandler(iotcon_resource_h resource, + iotcon_request_h request, void *user_data); common::PlatformResult RestoreHandles(); - - common::PlatformResult CreateResource(/*std::string uri_path, bool is_discoverable, - bool is_observable, picojson::array array, - iotcon_resource_h* res_handle*/); - + common::PlatformResult CreateResource(const std::string& uri_path, + const picojson::array& interfaces_array, + const picojson::array& types_array, bool is_discoverable, + bool is_observable, + ResourceInfoPtr res_pointer); + common::PlatformResult GetResourceById(long long id, ResourceInfoPtr* res_pointer) const; private: IotconInstance* instance_; ResourceInfoMap resource_map_; + long long global_id_; }; } // namespace iotcon } // namespace extension diff --git a/src/iotcon/iotcon_utils.cc b/src/iotcon/iotcon_utils.cc index 2abd7ea3..5d14b88c 100644 --- a/src/iotcon/iotcon_utils.cc +++ b/src/iotcon/iotcon_utils.cc @@ -22,17 +22,208 @@ #include "common/platform_exception.h" #include "common/scope_exit.h" +#include "iotcon/iotcon_server_manager.h" + namespace extension { namespace iotcon { +const std::string kCallbackId = "callbackId"; +const std::string kIsDiscoverable = "isDiscoverable"; +const std::string kIsObservable = "isObservable"; +const std::string kResourceTypes = "resourceTypes"; +const std::string kResourceInterfaces = "resourceInterfaces"; +const std::string kResourceChildren = "resources"; +const std::string kUriPath = "uriPath"; +const std::string kResourceId = "id"; + +const std::string kInterfaceDefault = "DEFAULT"; +const std::string kInterfaceLink = "LINK"; +const std::string kInterfaceBatch = "BATCH"; +const std::string kInterfaceGroup = "GROUP"; + using common::PlatformResult; using common::ErrorCode; -PlatformResult IotconUtils::ResourceToJson(iotcon_resource_h handle, picojson::value* res) { +PlatformResult IotconUtils::StringToInterface(const std::string& interface, iotcon_interface_e* res) { LoggerD("Entered"); + if (kInterfaceDefault == interface) { + *res = IOTCON_INTERFACE_DEFAULT; + } else if (kInterfaceLink == interface) { + *res = IOTCON_INTERFACE_LINK; + } else if (kInterfaceBatch == interface) { + *res = IOTCON_INTERFACE_BATCH; + } else if (kInterfaceGroup == interface) { + *res = IOTCON_INTERFACE_GROUP; + } else { + return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Not supported interface name"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult IotconUtils::ArrayToInterfaces(const picojson::array& interfaces, int* res) { + LoggerD("Entered"); + int result_value = IOTCON_INTERFACE_NONE; + + for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) { + if (!iter->is()) { + LoggerE("Array holds incorrect interface names"); + return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Array holds incorrect interface names"); + } else { + iotcon_interface_e interface = IOTCON_INTERFACE_NONE; + PlatformResult ret = StringToInterface(iter->get(), &interface); + if (ret.IsError()) { + return ret; + } + result_value |= interface; + } + } + *res = result_value; + return PlatformResult(ErrorCode::NO_ERROR); +} + +picojson::array IotconUtils::InterfacesToArray(int interfaces) { + LoggerD("Entered"); + picojson::array res; + if (interfaces & IOTCON_INTERFACE_DEFAULT) { + res.push_back(picojson::value(kInterfaceDefault)); + } + if (interfaces & IOTCON_INTERFACE_LINK) { + res.push_back(picojson::value(kInterfaceLink)); + } + if (interfaces & IOTCON_INTERFACE_BATCH) { + res.push_back(picojson::value(kInterfaceBatch)); + } + if (interfaces & IOTCON_INTERFACE_GROUP) { + res.push_back(picojson::value(kInterfaceGroup)); + } + return res; +} + +PlatformResult IotconUtils::ArrayToTypes(const picojson::array& types, iotcon_resource_types_h* res) { + LoggerD("Entered"); + + iotcon_resource_types_h resource_types = nullptr; + int ret = iotcon_resource_types_create(&resource_types); + if (IOTCON_ERROR_NONE != ret) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.", + ("iotcon_resource_types_create failed: %d (%s)", + ret, get_error_message(ret))); + } + + for (auto iter = types.begin(); iter != types.end(); ++iter) { + if (!iter->is()) { + LoggerE("Array holds incorrect types"); + return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Array holds incorrect types"); + } else { + ret = iotcon_resource_types_add(resource_types, iter->get().c_str()); + if (IOTCON_ERROR_NONE != ret) { + iotcon_resource_types_destroy(resource_types); + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.", + ("iotcon_resource_types_add failed: %d (%s)", + ret, get_error_message(ret))); + } + } + } + *res = resource_types; + return PlatformResult(ErrorCode::NO_ERROR); +} + +static bool ResourceTypeIterator(const char *type, void *user_data) { + LoggerD("Enter"); + + picojson::array* array_data = static_cast(user_data); + if (!array_data) { + LoggerE("user_data is NULL"); + return false; + } + + array_data->push_back(picojson::value(type)); + return true; +} + +PlatformResult IotconUtils::ExtractFromResource(const ResourceInfoPtr& pointer, + char** uri_path, + iotcon_resource_types_h* res_types, + int* ifaces, + int* properties) { + LoggerD("Entered"); + int ret = iotcon_resource_get_uri_path (pointer->handle, uri_path); + if (IOTCON_ERROR_NONE != ret) { + LoggerD("Error %s", get_error_message(ret)); + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource uri path failed"); + } + + ret = iotcon_resource_get_types (pointer->handle, res_types); + if (IOTCON_ERROR_NONE != ret) { + LoggerD("Error %s", get_error_message(ret)); + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource types failed"); + } + + ret = iotcon_resource_get_interfaces (pointer->handle, ifaces); + if (IOTCON_ERROR_NONE != ret) { + LoggerD("Error %s", get_error_message(ret)); + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource interfaces failed"); + } + + ret = iotcon_resource_get_properties (pointer->handle, properties); + if (IOTCON_ERROR_NONE != ret) { + LoggerD("Error %s", get_error_message(ret)); + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource properties failed"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult IotconUtils::ResourceToJson(ResourceInfoPtr pointer, + const IotconServerManager& manager, + picojson::object* res) { + LoggerD("Entered"); + + char* uri_path = nullptr; + iotcon_resource_types_h res_types = nullptr; + int ifaces = 0; + int properties = 0; + PlatformResult ret = ExtractFromResource(pointer, &uri_path, &res_types, &ifaces, &properties); + if (ret.IsError()){ + return ret; + } + res->insert(std::make_pair(kResourceId, picojson::value(static_cast(pointer->id)))); + res->insert(std::make_pair(kUriPath, picojson::value(uri_path))); + + picojson::array types; + iotcon_resource_types_foreach(res_types, ResourceTypeIterator, &types); + res->insert(std::make_pair(kResourceTypes, picojson::value(types))); + + res->insert(std::make_pair(kResourceInterfaces, + picojson::value(InterfacesToArray(ifaces)))); + bool observable = properties & IOTCON_RESOURCE_OBSERVABLE; + res->insert(std::make_pair(kIsObservable, picojson::value(observable))); + bool discoverable = properties & IOTCON_RESOURCE_DISCOVERABLE; + res->insert(std::make_pair(kIsDiscoverable, picojson::value(discoverable))); + + picojson::array children; + for (auto iter = pointer->children_ids.begin(); iter != pointer->children_ids.end(); ++iter) { + if (pointer->id == (*iter)) { + // prevent infinite recurrence + continue; + } + ResourceInfoPtr resource; + ret = manager.GetResourceById((*iter), &resource); + if (ret.IsSuccess()) { + LoggerD("Found children RESOURCE\nid: %lld\nhandle: %p", resource->id, resource->handle); + + picojson::value child = picojson::value(picojson::object()); + ret = IotconUtils::ResourceToJson(resource, manager, &(child.get())); + if (ret.IsSuccess()) { + children.push_back(child); + } + } else { + LoggerD("Not found such resource"); + } + } + res->insert(std::make_pair(kResourceChildren, picojson::value(children))); + // observerIds would be done on demand from JS - // TODO implement conversion - return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "Not implemented yet"); + return PlatformResult(ErrorCode::NO_ERROR); } } // namespace iotcon diff --git a/src/iotcon/iotcon_utils.h b/src/iotcon/iotcon_utils.h index e9c6328f..a9787f87 100644 --- a/src/iotcon/iotcon_utils.h +++ b/src/iotcon/iotcon_utils.h @@ -18,6 +18,10 @@ #define WEBAPI_PLUGINS_IOTCON_IOTCON_UTILS_H__ #include +#include +#include +#include +#include #include @@ -26,10 +30,45 @@ namespace extension { namespace iotcon { +extern const std::string kCallbackId; +extern const std::string kIsDiscoverable; +extern const std::string kIsObservable; +extern const std::string kResourceTypes; +extern const std::string kResourceInterfaces; +extern const std::string kResourceChildren; +extern const std::string kUriPath; +extern const std::string kResourceId; + +struct ResourceInfo { + long long id; + std::vector children_ids; + iotcon_resource_h handle; + ResourceInfo() : + id(0), handle(nullptr) {} + ~ResourceInfo() { + iotcon_resource_destroy (handle); + } +}; + +typedef std::shared_ptr ResourceInfoPtr; +typedef std::map ResourceInfoMap; + +class IotconServerManager; class IotconUtils { public: - static common::PlatformResult ResourceToJson(iotcon_resource_h handle, picojson::value* res); + static common::PlatformResult StringToInterface(const std::string& interface, iotcon_interface_e* res); + static common::PlatformResult ArrayToInterfaces(const picojson::array& interfaces, int* res); + static picojson::array InterfacesToArray(int interfaces); + static common::PlatformResult ArrayToTypes(const picojson::array& types, iotcon_resource_types_h* res); + static common::PlatformResult ExtractFromResource(const ResourceInfoPtr& pointer, + char** uri_path, + iotcon_resource_types_h* res_types, + int* ifaces, + int* properties); + static common::PlatformResult ResourceToJson(ResourceInfoPtr pointer, + const IotconServerManager& manager, + picojson::object* res); }; } // namespace iotcon