From: coderhyme Date: Fri, 29 Jan 2016 02:11:55 +0000 (-0800) Subject: Added bind apis to RCSResourceObject X-Git-Tag: 1.2.0+RC1~709 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7dd094244dce73a10d4a975e7077530236f45032;p=platform%2Fupstream%2Fiotivity.git Added bind apis to RCSResourceObject Bind apis are required for some specific use-cases. An auto-interface handler for BATCH, which builds the response conforming with the OIC-spec, is added. Change-Id: I9dd7c822bfb1ec06ed9176b20d3dcd06c8cb1f44 Signed-off-by: coderhyme Reviewed-on: https://gerrit.iotivity.org/gerrit/4879 Tested-by: jenkins-iotivity Reviewed-by: Uze Choi --- diff --git a/service/resource-encapsulation/include/RCSResourceObject.h b/service/resource-encapsulation/include/RCSResourceObject.h index 93eb4c7..146ca8f 100644 --- a/service/resource-encapsulation/include/RCSResourceObject.h +++ b/service/resource-encapsulation/include/RCSResourceObject.h @@ -44,6 +44,7 @@ namespace OIC { class RCSRequest; + class RCSRepresentation; /** * @brief Thrown when lock has not been acquired. @@ -141,6 +142,12 @@ namespace OIC Builder(const std::string& uri, const std::string& type, const std::string& interface); + Builder& addInterface(const std::string& interface); + Builder& addInterface(std::string&& interface); + + Builder& addType(const std::string& type); + Builder& addType(std::string&& type); + /** * Sets whether the resource is discoverable. * @@ -188,8 +195,8 @@ namespace OIC private: std::string m_uri; - std::string m_type; - std::string m_interface; + std::vector< std::string > m_types; + std::vector< std::string > m_interfaces; uint8_t m_properties; RCSResourceAttributes m_resourceAttributes; }; @@ -449,8 +456,19 @@ namespace OIC */ SetRequestHandlerPolicy getSetRequestHandlerPolicy() const; + void bindResource(const RCSResourceObject::Ptr&); + + void unbindResource(const RCSResourceObject::Ptr&); + + std::vector< RCSResourceObject::Ptr > getBoundResources() const; + + std::vector< std::string > getInterfaces() const; + std::vector< std::string > getTypes() const; + + RCSRepresentation toRepresentation() const; + private: - RCSResourceObject(uint8_t, RCSResourceAttributes&&); + RCSResourceObject(const std::string&, uint8_t, RCSResourceAttributes&&); OCEntityHandlerResult entityHandler(const std::shared_ptr< OC::OCResourceRequest >&); @@ -478,6 +496,10 @@ namespace OIC private: const uint8_t m_properties; + const std::string m_uri; + std::vector< std::string > m_interfaces; + std::vector< std::string > m_types; + OCResourceHandle m_resourceHandle; RCSResourceAttributes m_resourceAttributes; @@ -496,6 +518,10 @@ namespace OIC std::mutex m_mutexAttributeUpdatedListeners; + mutable std::mutex m_mutexForBoundResources; + + std::vector< RCSResourceObject::Ptr > m_boundResources; + }; /** diff --git a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp index 0566fb1..5a69cd0 100644 --- a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp +++ b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp @@ -30,6 +30,7 @@ #include "ResourceAttributesConverter.h" #include "ResourceAttributesUtils.h" #include "RCSRequest.h" +#include "RCSRepresentation.h" #include "logger.h" #include "OCPlatform.h" @@ -55,11 +56,15 @@ namespace return base & ~target; } - template - OCEntityHandlerResult sendResponse(RCSResourceObject& resource, - const std::shared_ptr< OC::OCResourceRequest >& ocRequest, RESPONSE&& response) + inline bool requestContainsInterface(const std::shared_ptr< OC::OCResourceRequest >& request, + const std::string& interface) + { + return request->getQueryParameters().find(interface) != request->getQueryParameters().end(); + } + + OCEntityHandlerResult sendResponse(const std::shared_ptr< OC::OCResourceRequest >& ocRequest, + const std::shared_ptr< OC::OCResourceResponse >& ocResponse) { - auto ocResponse = response.getHandler()->buildResponse(resource); ocResponse->setRequestHandle(ocRequest->getRequestHandle()); ocResponse->setResourceHandle(ocRequest->getResourceHandle()); @@ -78,6 +83,14 @@ namespace return OC_EH_ERROR; } + + template + OCEntityHandlerResult sendResponse(RCSResourceObject& resource, + const std::shared_ptr< OC::OCResourceRequest >& ocRequest, RESPONSE&& response) + { + return sendResponse(ocRequest, response.getHandler()->buildResponse(resource)); + } + RCSResourceAttributes getAttributesFromOCRequest( const std::shared_ptr< OC::OCResourceRequest >& request) { @@ -122,8 +135,29 @@ namespace } return {}; } -} // unnamed namespace + OCEntityHandlerResult handleBatchInterfaceGetRequest( + const std::shared_ptr< OC::OCResourceRequest >& request, + const RCSResourceObject* resourceObject) + { + auto rcsRep = resourceObject->toRepresentation(); + + for (const auto& bound : resourceObject->getBoundResources()) + { + rcsRep.addChild(bound->toRepresentation()); + } + + auto response = std::make_shared< OC::OCResourceResponse >(); + + response->setResponseResult(OC_EH_OK); + response->setErrorCode(200); + response->setResourceRepresentation( + RCSRepresentation::toOCRepresentation(std::move(rcsRep))); + + return sendResponse(request, response); + } + +} // unnamed namespace namespace OIC { @@ -133,13 +167,37 @@ namespace OIC RCSResourceObject::Builder::Builder(const std::string& uri, const std::string& type, const std::string& interface) : m_uri{ uri }, - m_type{ type }, - m_interface{ interface }, + m_types{ type }, + m_interfaces{ interface }, m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE }, m_resourceAttributes{ } { } + RCSResourceObject::Builder& RCSResourceObject::Builder::addInterface( + const std::string& interface) + { + return addInterface(std::string{ interface }); + } + + RCSResourceObject::Builder& RCSResourceObject::Builder::addInterface( + std::string&& interface) + { + m_interfaces.push_back(std::move(interface)); + return *this; + } + + RCSResourceObject::Builder& RCSResourceObject::Builder::addType(const std::string& type) + { + return addType(std::string{ type }); + } + + RCSResourceObject::Builder& RCSResourceObject::Builder::addType(std::string&& type) + { + m_types.push_back(std::move(type)); + return *this; + } + RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable( bool discoverable) { @@ -179,7 +237,7 @@ namespace OIC OCResourceHandle handle{ nullptr }; RCSResourceObject::Ptr server { - new RCSResourceObject{ m_properties, std::move(m_resourceAttributes) } }; + new RCSResourceObject{ m_uri, m_properties, std::move(m_resourceAttributes) } }; OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler, server.get(), std::placeholders::_1) }; @@ -188,22 +246,39 @@ namespace OIC const std::string&, const std::string&, OC::EntityHandler, uint8_t); invokeOCFunc(static_cast(OC::OCPlatform::registerResource), - handle, m_uri, m_type, m_interface, entityHandler, m_properties); + handle, m_uri, m_types[0], m_interfaces[0], entityHandler, m_properties); + + std::for_each(m_interfaces.begin() + 1, m_interfaces.end(), + [&handle](const std::string& interfaceName){ + invokeOCFunc(OC::OCPlatform::bindInterfaceToResource, handle, interfaceName); + }); + + std::for_each(m_types.begin() + 1, m_types.end(), + [&handle](const std::string& typeName){ + invokeOCFunc(OC::OCPlatform::bindTypeToResource, handle, typeName); + }); + server->m_resourceHandle = handle; + server->m_interfaces = m_interfaces; + server->m_types = m_types; return server; } - RCSResourceObject::RCSResourceObject(uint8_t properties, RCSResourceAttributes&& attrs) : - m_properties { properties }, + RCSResourceObject::RCSResourceObject(const std::string& uri, + uint8_t properties, RCSResourceAttributes&& attrs) : + m_properties{ properties }, + m_uri{ uri }, + m_interfaces{ }, + m_types{ }, m_resourceHandle{ }, m_resourceAttributes{ std::move(attrs) }, m_getRequestHandler{ }, m_setRequestHandler{ }, - m_autoNotifyPolicy { AutoNotifyPolicy::UPDATED }, - m_setRequestHandlerPolicy { SetRequestHandlerPolicy::NEVER }, + m_autoNotifyPolicy{ AutoNotifyPolicy::UPDATED }, + m_setRequestHandlerPolicy{ SetRequestHandlerPolicy::NEVER }, m_attributeUpdatedListeners{ }, m_lockOwner{ }, m_mutex{ }, @@ -414,6 +489,56 @@ namespace OIC return m_setRequestHandlerPolicy; } + void RCSResourceObject::bindResource(const RCSResourceObject::Ptr& resource) + { + if (!resource || resource.get() == this) + { + throw RCSInvalidParameterException("The resource is invalid!"); + } + + invokeOCFunc(OC::OCPlatform::bindResource, + m_resourceHandle, resource->m_resourceHandle); + + std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources }; + m_boundResources.push_back(resource); + } + + void RCSResourceObject::unbindResource(const RCSResourceObject::Ptr& resource) + { + if (!resource || resource.get() == this) + { + throw RCSInvalidParameterException("The resource is invalid!"); + } + + invokeOCFunc(OC::OCPlatform::unbindResource, + m_resourceHandle, resource->m_resourceHandle); + + std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources }; + m_boundResources.erase(std::find(m_boundResources.begin(), m_boundResources.end(), + resource)); + } + + std::vector< RCSResourceObject::Ptr > RCSResourceObject::getBoundResources() const + { + std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources }; + return m_boundResources; + } + + std::vector< std::string > RCSResourceObject::getInterfaces() const + { + return m_interfaces; + } + + std::vector< std::string > RCSResourceObject::getTypes() const + { + return m_types; + } + + RCSRepresentation RCSResourceObject::toRepresentation() const + { + return RCSRepresentation{ m_uri, m_interfaces, m_types, m_resourceAttributes }; + } + void RCSResourceObject::autoNotify(bool isAttributesChanged) const { autoNotify(isAttributesChanged, m_autoNotifyPolicy); @@ -487,6 +612,11 @@ namespace OIC { assert(request != nullptr); + if (requestContainsInterface(request, OC::BATCH_INTERFACE)) + { + return handleBatchInterfaceGetRequest(request, this); + } + auto attrs = getAttributesFromOCRequest(request); return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler)); diff --git a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp index 33431bb..a4ed8a3 100644 --- a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp +++ b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp @@ -86,6 +86,39 @@ TEST_F(ResourceObjectBuilderTest, ResourceServerHasAttrsSetByBuilder) EXPECT_EQ(attrs, serverResource->getAttributes()); } +TEST_F(ResourceObjectBuilderTest, TypesAddedInBuilderWillBeBound) +{ + int count = 0; + mocks.OnCallFunc(OCPlatform::bindTypeToResource).Do( + [&count](const OCResourceHandle&, const std::string&) + { + ++count; + return OC_STACK_OK; + } + ); + + auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, ""). + addType("1").addType("2").build(); + + EXPECT_EQ(2, count); +} + +TEST_F(ResourceObjectBuilderTest, InterfaceAddedInBuilderWillBeBound) +{ + int count = 0; + mocks.OnCallFunc(OCPlatform::bindInterfaceToResource).Do( + [&count](const OCResourceHandle&, const std::string&) + { + ++count; + return OC_STACK_OK; + } + ); + + auto serverResource = RCSResourceObject::Builder(RESOURCE_URI, RESOURCE_TYPE, ""). + addInterface("1").addInterface("2").build(); + + EXPECT_EQ(2, count); +} class ResourceObjectTest: public TestWithMock { @@ -164,7 +197,35 @@ TEST_F(ResourceObjectTest, SettingNestedVectorAttributesIsSameToGettingNestedVec server->setAttribute(KEY, arr31); - ASSERT_EQ(arr31, server->getAttribute>>>(KEY)); + ASSERT_EQ(arr31, server->getAttributeValue(KEY)); +} + +TEST_F(ResourceObjectTest, ThrowIfResourceToBindIsInvalid) +{ + ASSERT_THROW(server->bindResource(server), RCSInvalidParameterException); +} + +TEST_F(ResourceObjectTest, ThrowIfBindResourceFailed) +{ + mocks.OnCallFunc(OCBindResource).Return(OC_STACK_ERROR); + + ASSERT_THROW(server->bindResource( + RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build()), RCSPlatformException); +} + +TEST_F(ResourceObjectTest, ThrowIfResourceToUnbindIsInvalid) +{ + ASSERT_THROW(server->unbindResource(server), RCSInvalidParameterException); +} + +TEST_F(ResourceObjectTest, BoundResourceCanBeRetrieved) +{ + mocks.OnCallFunc(OCBindResource).Return(OC_STACK_OK); + + auto boundResource = RCSResourceObject::Builder("a/temp", RESOURCE_TYPE, "").build(); + server->bindResource(boundResource); + + ASSERT_EQ(boundResource, server->getBoundResources()[0]); } @@ -415,7 +476,7 @@ TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs) } ).Return(OC_STACK_OK); - ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_PUT))); + ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_POST))); } @@ -458,7 +519,7 @@ TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_DeniedIfKeyIsNew) { server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::NEVER); - handler(createRequest(OC_REST_PUT, createOCRepresentation())); + handler(createRequest(OC_REST_POST, createOCRepresentation())); RCSResourceObject::LockGuard guard{ server }; ASSERT_FALSE(server->getAttributes().contains(KEY)); @@ -468,7 +529,7 @@ TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_AcceptedEvenIfKeyIsNew) { server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE); - handler(createRequest(OC_REST_PUT, createOCRepresentation())); + handler(createRequest(OC_REST_POST, createOCRepresentation())); RCSResourceObject::LockGuard guard{ server }; ASSERT_TRUE(server->getAttributes().contains(KEY)); @@ -557,7 +618,7 @@ TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequ for (int i=0; i<10000; ++i) { if (i % 5 == 0) handler(createRequest(OC_REST_OBSERVE)); - handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_PUT)); + handler(createRequest((i & 1) ? OC_REST_GET : OC_REST_POST)); } } }); @@ -600,6 +661,8 @@ class AttributeUpdatedListener public: virtual void onUpdated(const OIC::Service::RCSResourceAttributes::Value&, const OIC::Service::RCSResourceAttributes::Value&)=0; + + virtual ~AttributeUpdatedListener() {} }; @@ -627,7 +690,7 @@ TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction) mocks.ExpectCall(listener, AttributeUpdatedListener::onUpdated); - handler(createRequest(OC_REST_PUT, createOCRepresentation())); + handler(createRequest(OC_REST_POST, createOCRepresentation())); } TEST_F(AttributeUpdatedListenerTest, ListenerWithSameKeyOverridesPreviousOne) @@ -643,7 +706,7 @@ TEST_F(AttributeUpdatedListenerTest, ListenerWithSameKeyOverridesPreviousOne) server->addAttributeUpdatedListener(KEY, std::bind(&AttributeUpdatedListener::onUpdated, second, _1, _2)); - handler(createRequest(OC_REST_PUT, createOCRepresentation())); + handler(createRequest(OC_REST_POST, createOCRepresentation())); } TEST_F(AttributeUpdatedListenerTest, RemovedListenerNotBeInvoked) @@ -656,5 +719,5 @@ TEST_F(AttributeUpdatedListenerTest, RemovedListenerNotBeInvoked) server->removeAttributeUpdatedListener(KEY); - handler(createRequest(OC_REST_PUT, createOCRepresentation())); + handler(createRequest(OC_REST_POST, createOCRepresentation())); }