{
class RCSRequest;
+ class RCSRepresentation;
/**
* @brief Thrown when lock has not been acquired.
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.
*
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;
};
*/
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 >&);
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;
std::mutex m_mutexAttributeUpdatedListeners;
+ mutable std::mutex m_mutexForBoundResources;
+
+ std::vector< RCSResourceObject::Ptr > m_boundResources;
+
};
/**
#include "ResourceAttributesConverter.h"
#include "ResourceAttributesUtils.h"
#include "RCSRequest.h"
+#include "RCSRepresentation.h"
#include "logger.h"
#include "OCPlatform.h"
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());
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)
{
}
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
{
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)
{
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) };
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{ },
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);
{
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));
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
{
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]);
}
}
).Return(OC_STACK_OK);
- ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_PUT)));
+ ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_POST)));
}
{
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));
{
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));
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));
}
}
});
public:
virtual void onUpdated(const OIC::Service::RCSResourceAttributes::Value&,
const OIC::Service::RCSResourceAttributes::Value&)=0;
+
+ virtual ~AttributeUpdatedListener() {}
};
mocks.ExpectCall(listener, AttributeUpdatedListener::onUpdated);
- handler(createRequest(OC_REST_PUT, createOCRepresentation()));
+ handler(createRequest(OC_REST_POST, createOCRepresentation()));
}
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)
server->removeAttributeUpdatedListener(KEY);
- handler(createRequest(OC_REST_PUT, createOCRepresentation()));
+ handler(createRequest(OC_REST_POST, createOCRepresentation()));
}