From 841e0abe41d699b0a4aa4376fac8e63ed70c271c Mon Sep 17 00:00:00 2001 From: Pawel Andruszkiewicz Date: Wed, 10 Feb 2016 10:59:19 +0100 Subject: [PATCH] [iotcon] Implementation of Resource.addChildResource()/removeChildResource(). Change-Id: I94f127970b3ea39da131e7f893c02da2e3c2cdbd Signed-off-by: Pawel Andruszkiewicz --- src/iotcon/iotcon_api.js | 31 +++++++------ src/iotcon/iotcon_instance.cc | 67 +++++++++++++++++++++++++---- src/iotcon/iotcon_instance.h | 6 +-- src/iotcon/iotcon_server_manager.cc | 45 +++++++++++++------ src/iotcon/iotcon_utils.cc | 21 +++------ src/iotcon/iotcon_utils.h | 11 +++-- 6 files changed, 125 insertions(+), 56 deletions(-) diff --git a/src/iotcon/iotcon_api.js b/src/iotcon/iotcon_api.js index 98e7ffc2..5a8a331a 100644 --- a/src/iotcon/iotcon_api.js +++ b/src/iotcon/iotcon_api.js @@ -381,40 +381,47 @@ Resource.prototype.addResourceInterfaces = function() { Resource.prototype.addChildResource = function() { var args = validator.validateMethod(arguments, [{ name: 'resource', - type: types_.PLATFORM_OBJECT, - values: Resource, - optional: false, - nullable: false + type: types.PLATFORM_OBJECT, + values: Resource }]); var callArgs = {}; callArgs.id = this[kIdKey]; - callArgs.resource = args.resource; + callArgs.childId = args.resource[kIdKey]; - var result = native.call('IotconResource_addChildResource', callArgs); + var result = native.callSync('IotconResource_addChildResource', callArgs); if (native.isFailure(result)) { throw native.getErrorObject(result); + } else { + var children = this.resources; + children.push(args.resource); + updateWithInternalData({ resources: children }, this); } }; Resource.prototype.removeChildResource = function() { var args = validator.validateMethod(arguments, [{ name: 'resource', - type: types_.PLATFORM_OBJECT, - values: Resource, - optional: false, - nullable: false + type: types.PLATFORM_OBJECT, + values: Resource }]); var callArgs = {}; callArgs.id = this[kIdKey]; - callArgs.resource = args.resource; + callArgs.childId = args.resource[kIdKey]; - var result = native.call('IotconResource_removeChildResource', callArgs); + var result = native.callSync('IotconResource_removeChildResource', callArgs); if (native.isFailure(result)) { throw native.getErrorObject(result); + } else { + var children = this.resources; + var position = children.indexOf(args.resource); + if (-1 !== position) { + children.splice(position, 1); + updateWithInternalData({ resources: children }, this); + } } }; diff --git a/src/iotcon/iotcon_instance.cc b/src/iotcon/iotcon_instance.cc index 73243eab..092ae134 100644 --- a/src/iotcon/iotcon_instance.cc +++ b/src/iotcon/iotcon_instance.cc @@ -58,6 +58,7 @@ const common::ListenerToken kResourceRequestListenerToken{"ResourceRequestListen const std::string kObserverIds = "observerIds"; const std::string kQos = "qos"; +const std::string kChildId = "childId"; } // namespace @@ -72,6 +73,8 @@ IotconInstance::IotconInstance() { REGISTER_SYNC("IotconResource_getObserverIds", ResourceGetObserverIds); REGISTER_SYNC("IotconResource_notify", ResourceNotify); + REGISTER_SYNC("IotconResource_addChildResource", ResourceAddChildResource); + REGISTER_SYNC("IotconResource_removeChildResource", ResourceRemoveChildResource); REGISTER_SYNC("IotconResource_setRequestListener", ResourceSetRequestListener); REGISTER_SYNC("IotconResource_unsetRequestListener", ResourceUnsetRequestListener); REGISTER_SYNC("IotconResponse_send", ResponseSend); @@ -96,8 +99,6 @@ IotconInstance::IotconInstance() { REGISTER_ASYNC("IotconResource_addResourceTypes", ResourceAddResourceTypes); REGISTER_ASYNC("IotconResource_addResourceInterfaces", ResourceAddResourceInterfaces); - REGISTER_ASYNC("IotconResource_addChildResource", ResourceAddChildResource); - REGISTER_ASYNC("IotconResource_removeChildResource", ResourceRemoveChildResource); REGISTER_ASYNC("IotconRemoteResource_methodGet", RemoteResourceMethodGet); REGISTER_ASYNC("IotconRemoteResource_methodPut", RemoteResourceMethodPut); REGISTER_ASYNC("IotconRemoteResource_methodPost", RemoteResourceMethodPost); @@ -246,16 +247,66 @@ common::TizenResult IotconInstance::ResourceAddResourceInterfaces(const picojson return common::UnknownError("Not implemented"); } -common::TizenResult IotconInstance::ResourceAddChildResource(const picojson::object& args, - const common::AsyncToken& token) { +common::TizenResult IotconInstance::ResourceAddChildResource(const picojson::object& args) { ScopeLogger(); - return common::UnknownError("Not implemented"); + + CHECK_EXIST(args, kId); + CHECK_EXIST(args, kChildId); + + ResourceInfoPtr parent; + auto result = IotconServerManager::GetInstance().GetResourceById(GetId(args), &parent); + if (!result) { + LogAndReturnTizenError(result, ("GetResourceById() parent failed")); + } + + long long child_id = static_cast(GetArg(args, kChildId).get()); + ResourceInfoPtr child; + + result = IotconServerManager::GetInstance().GetResourceById(child_id, &child); + if (!result) { + LogAndReturnTizenError(result, ("GetResourceById() failed")); + } + + result = IotconUtils::ConvertIotconError(iotcon_resource_bind_child_resource(parent->handle, child->handle)); + if (!result) { + LogAndReturnTizenError(result, ("iotcon_resource_bind_child_resource() failed")); + } + + parent->children.insert(child); + child->parents.insert(parent); + + return common::TizenSuccess(); } -common::TizenResult IotconInstance::ResourceRemoveChildResource(const picojson::object& args, - const common::AsyncToken& token) { +common::TizenResult IotconInstance::ResourceRemoveChildResource(const picojson::object& args) { ScopeLogger(); - return common::UnknownError("Not implemented"); + + CHECK_EXIST(args, kId); + CHECK_EXIST(args, kChildId); + + ResourceInfoPtr parent; + auto result = IotconServerManager::GetInstance().GetResourceById(GetId(args), &parent); + if (!result) { + LogAndReturnTizenError(result, ("GetResourceById() parent failed")); + } + + long long child_id = static_cast(GetArg(args, kChildId).get()); + ResourceInfoPtr child; + + result = IotconServerManager::GetInstance().GetResourceById(child_id, &child); + if (!result) { + LogAndReturnTizenError(result, ("GetResourceById() failed")); + } + + result = IotconUtils::ConvertIotconError(iotcon_resource_unbind_child_resource(parent->handle, child->handle)); + if (!result) { + LogAndReturnTizenError(result, ("iotcon_resource_unbind_child_resource() failed")); + } + + parent->children.erase(child); + child->parents.erase(parent); + + return common::TizenSuccess(); } common::TizenResult IotconInstance::ResourceSetRequestListener(const picojson::object& args) { diff --git a/src/iotcon/iotcon_instance.h b/src/iotcon/iotcon_instance.h index 57b9c194..960ba497 100644 --- a/src/iotcon/iotcon_instance.h +++ b/src/iotcon/iotcon_instance.h @@ -37,10 +37,8 @@ class IotconInstance : public common::TizenInstance { const common::AsyncToken& token); common::TizenResult ResourceAddResourceInterfaces(const picojson::object& args, const common::AsyncToken& token); - common::TizenResult ResourceAddChildResource(const picojson::object& args, - const common::AsyncToken& token); - common::TizenResult ResourceRemoveChildResource(const picojson::object& args, - const common::AsyncToken& token); + common::TizenResult ResourceAddChildResource(const picojson::object& args); + common::TizenResult ResourceRemoveChildResource(const picojson::object& args); common::TizenResult ResourceSetRequestListener(const picojson::object& args); common::TizenResult ResourceUnsetRequestListener(const picojson::object& args); common::TizenResult ResponseSend(const picojson::object& args); diff --git a/src/iotcon/iotcon_server_manager.cc b/src/iotcon/iotcon_server_manager.cc index 19ae602c..9a1144eb 100644 --- a/src/iotcon/iotcon_server_manager.cc +++ b/src/iotcon/iotcon_server_manager.cc @@ -43,14 +43,15 @@ IotconServerManager& IotconServerManager::GetInstance() { TizenResult IotconServerManager::RestoreHandles() { ScopeLogger(); - 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; + for (const auto& it : resource_map_) { + 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; + auto res = IotconUtils::ExtractFromResource(resource, &uri_path, &res_types, &ifaces, &properties); if (!res){ @@ -76,9 +77,16 @@ TizenResult IotconServerManager::RestoreHandles() { iotcon_resource_destroy(old_handle); } } - // TODO - // bind children (consider if it is necessary? - // Maybe holding children in resource_map is enough) + + // rebind children + for (const auto& it : resource_map_) { + for (const auto& child : it.second->children) { + auto result = IotconUtils::ConvertIotconError(iotcon_resource_bind_child_resource(it.second->handle, child->handle)); + if (!result) { + LogAndReturnTizenError(result, ("iotcon_resource_bind_child_resource() failed")); + } + } + } return TizenSuccess(); } @@ -206,8 +214,7 @@ TizenResult IotconServerManager::GetResourceById(long long id, auto it = resource_map_.find(id); if (it == resource_map_.end()) { - LoggerE("Not found such resource"); - return LogAndCreateTizenError(NotFoundError, "Not found such resource"); + return LogAndCreateTizenError(NotFoundError, "Resource with specified ID does not exist"); } LoggerE("Resource found"); *res_pointer = it->second; @@ -218,11 +225,25 @@ TizenResult IotconServerManager::GetResourceById(long long id, common::TizenResult IotconServerManager::DestroyResource(long long id) { ScopeLogger(); - if (resource_map_.erase(id)) { - return TizenSuccess(); - } else { - return LogAndCreateTizenError(NotFoundError, "Resource with specified ID does not exist"); + ResourceInfoPtr resource; + auto result = GetResourceById(id, &resource); + if (!result) { + LogAndReturnTizenError(result, ("GetResourceById() failed")); } + + // do not allow to destroy a resource which has a parent resource + if (resource->parents.size() > 0) { + return LogAndCreateTizenError(InvalidStateError, "Cannot destroy child resource, remove it from parent first"); + } + + // notify children they've lost a parent :( + for (const auto& child : resource->children) { + child->parents.erase(resource); + } + + resource_map_.erase(id); + + return TizenSuccess(); } common::TizenResult IotconServerManager::GetResourceByHandle( diff --git a/src/iotcon/iotcon_utils.cc b/src/iotcon/iotcon_utils.cc index b91060e5..7b19dc89 100644 --- a/src/iotcon/iotcon_utils.cc +++ b/src/iotcon/iotcon_utils.cc @@ -260,26 +260,15 @@ TizenResult IotconUtils::ResourceToJson(ResourceInfoPtr pointer, res->insert(std::make_pair(kIsExplicitDiscoverable, picojson::value(value))); 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 = IotconServerManager::GetInstance().GetResourceById((*iter), &resource); + for (const auto& child_resource : pointer->children) { + picojson::value child = picojson::value(picojson::object()); + ret = IotconUtils::ResourceToJson(child_resource, &(child.get())); 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, &(child.get())); - if (ret.IsSuccess()) { - children.push_back(child); - } - } else { - LoggerD("Not found such resource"); + children.push_back(child); } } res->insert(std::make_pair(kResourceChildren, picojson::value(children))); + // observerIds would be done on demand from JS return TizenSuccess(); diff --git a/src/iotcon/iotcon_utils.h b/src/iotcon/iotcon_utils.h index efe13f23..bfcfd747 100644 --- a/src/iotcon/iotcon_utils.h +++ b/src/iotcon/iotcon_utils.h @@ -48,13 +48,19 @@ extern const std::string kId; extern const std::string kHostAddress; extern const std::string kConnectivityType; +class ResourceInfo; +typedef std::shared_ptr ResourceInfoPtr; +typedef std::map ResourceInfoMap; + struct ResourceInfo { long long id; - std::vector children_ids; iotcon_resource_h handle; std::set observers; common::PostCallback request_listener; std::unordered_map unhandled_responses; + std::set children; + std::set parents; + ResourceInfo() : id(0), handle(nullptr) {} ~ResourceInfo() { @@ -65,9 +71,6 @@ struct ResourceInfo { } }; -typedef std::shared_ptr ResourceInfoPtr; -typedef std::map ResourceInfoMap; - class IotconUtils { public: static common::TizenResult ArrayToInterfaces(const picojson::array& interfaces, int* res); -- 2.34.1