Added bind apis to RCSResourceObject
authorcoderhyme <jhyo.kim@samsung.com>
Fri, 29 Jan 2016 02:11:55 +0000 (18:11 -0800)
committerUze Choi <uzchoi@samsung.com>
Fri, 29 Jan 2016 10:16:11 +0000 (10:16 +0000)
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 <jhyo.kim@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/4879
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Uze Choi <uzchoi@samsung.com>
service/resource-encapsulation/include/RCSResourceObject.h
service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp
service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp

index 93eb4c7..146ca8f 100644 (file)
@@ -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;
+
         };
 
         /**
index 0566fb1..5a69cd0 100644 (file)
@@ -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 <typename RESPONSE>
-    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 <typename RESPONSE>
+    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<RegisterResource>(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));
index 33431bb..a4ed8a3 100644 (file)
@@ -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<vector<vector<vector<int>>>>(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()));
 }