From 61ff7411a690309b4832e1e639689f30b0e4b8e8 Mon Sep 17 00:00:00 2001 From: coderhyme Date: Thu, 4 Feb 2016 18:42:12 -0800 Subject: [PATCH] Added SeparateResponse class for the RCSResourceObject in RE. The class is to support the SLOW response concept of the base. For it, the RCSRequest now holds its owner resource object. - how to use RCSSeparateResponse separateResponse; ... server->setSetRequestHandler([](const RCSRequest& r, RCSResourceAttributes& attrs){ // make separate response to set result later separateResponse = RCSSeparateResponse(r); return RCSSetResponse::separate(); }); ... // the set method will throw an exception when the operation is failed. separateResponse.set(); Change-Id: I054ee3948d7742b5c45f821f3fec48216915f273 Signed-off-by: coderhyme Reviewed-on: https://gerrit.iotivity.org/gerrit/4947 Tested-by: jenkins-iotivity Reviewed-by: Madan Lanka Reviewed-by: JungYong KIM Reviewed-by: Uze Choi --- .../resource-encapsulation/include/RCSRequest.h | 44 +++++----- .../include/RCSResourceObject.h | 5 +- .../resource-encapsulation/include/RCSResponse.h | 9 +++ .../include/RCSSeparateResponse.h | 56 +++++++++++++ .../src/serverBuilder/src/RCSRequest.cpp | 13 ++- .../src/serverBuilder/src/RCSResourceObject.cpp | 26 ++++-- .../src/serverBuilder/src/RCSResponse.cpp | 30 +++++++ .../src/serverBuilder/src/RCSSeparateResponse.cpp | 93 ++++++++++++++++++++++ .../unittests/RCSResourceObjectTest.cpp | 50 ++++++++++++ .../serverBuilder/unittests/RCSResponseTest.cpp | 27 +++++-- 10 files changed, 317 insertions(+), 36 deletions(-) create mode 100755 service/resource-encapsulation/include/RCSSeparateResponse.h create mode 100755 service/resource-encapsulation/src/serverBuilder/src/RCSSeparateResponse.cpp diff --git a/service/resource-encapsulation/include/RCSRequest.h b/service/resource-encapsulation/include/RCSRequest.h index 0b45032..eb5a350 100644 --- a/service/resource-encapsulation/include/RCSRequest.h +++ b/service/resource-encapsulation/include/RCSRequest.h @@ -38,38 +38,44 @@ namespace OIC { namespace Service { + class RCSResourceObject; + /** * This class describes the request. * */ class RCSRequest { - public: - /** - * Constructor to set resource URI. - * - * @param resourceUri URI of the resource for which the request is generated. - */ - explicit RCSRequest(const std::string& resourceUri); + public: + RCSRequest() = default; + + /** + * Constructor to set resource URI. + * + * @param resourceUri URI of the resource for which the request is generated. + */ + explicit RCSRequest(const std::string& resourceUri); - explicit RCSRequest(const std::shared_ptr< OC::OCResourceRequest >&); + RCSRequest(const std::shared_ptr< RCSResourceObject >&, + const std::shared_ptr< OC::OCResourceRequest >&); - RCSRequest &operator=(RCSRequest &) = delete; + std::weak_ptr< RCSResourceObject > getResourceObject() const noexcept; - /** - * @return Returns the URI of the request. - * - */ - std::string getResourceUri() const; + /** + * @return Returns the URI of the request. + * + */ + std::string getResourceUri() const; - const std::shared_ptr< OC::OCResourceRequest >& getOCRequest() const; + const std::shared_ptr< OC::OCResourceRequest >& getOCRequest() const noexcept; - const std::map< std::string, std::string >& getQueryParams() const; + const std::map< std::string, std::string >& getQueryParams() const; - std::string getInterface() const; + std::string getInterface() const; - private: - const std::shared_ptr< OC::OCResourceRequest > m_ocRequest; + private: + std::weak_ptr< RCSResourceObject > m_resourceObject; + std::shared_ptr< OC::OCResourceRequest > m_ocRequest; }; } diff --git a/service/resource-encapsulation/include/RCSResourceObject.h b/service/resource-encapsulation/include/RCSResourceObject.h index 146ca8f..9eb4543 100644 --- a/service/resource-encapsulation/include/RCSResourceObject.h +++ b/service/resource-encapsulation/include/RCSResourceObject.h @@ -77,7 +77,7 @@ namespace OIC * in instead of overriding SetRequestHandler. *

*/ - class RCSResourceObject + class RCSResourceObject : public std::enable_shared_from_this< RCSResourceObject > { private: class WeakGuard; @@ -470,7 +470,8 @@ namespace OIC private: RCSResourceObject(const std::string&, uint8_t, RCSResourceAttributes&&); - OCEntityHandlerResult entityHandler(const std::shared_ptr< OC::OCResourceRequest >&); + static OCEntityHandlerResult entityHandler(const std::weak_ptr< RCSResourceObject >&, + const std::shared_ptr< OC::OCResourceRequest >&); OCEntityHandlerResult handleRequest(const std::shared_ptr< OC::OCResourceRequest >&); OCEntityHandlerResult handleRequestGet(const std::shared_ptr< OC::OCResourceRequest >&); diff --git a/service/resource-encapsulation/include/RCSResponse.h b/service/resource-encapsulation/include/RCSResponse.h index 13d94c2..041a187 100644 --- a/service/resource-encapsulation/include/RCSResponse.h +++ b/service/resource-encapsulation/include/RCSResponse.h @@ -127,11 +127,16 @@ namespace OIC */ static RCSGetResponse create(RCSResourceAttributes&& attrs, int errorCode); + static RCSGetResponse separate(); + + bool isSeparate() const; + //! @cond RequestHandler* getHandler() const; //! @endcond private: + RCSGetResponse(); RCSGetResponse(std::shared_ptr< RequestHandler >&&); private: @@ -289,6 +294,9 @@ namespace OIC */ static RCSSetResponse create(RCSResourceAttributes&& attrs, int errorCode); + static RCSSetResponse separate(); + + bool isSeparate() const; //! @cond SetRequestHandler* getHandler() const; @@ -313,6 +321,7 @@ namespace OIC RCSSetResponse& setAcceptanceMethod(AcceptanceMethod method); private: + RCSSetResponse(); RCSSetResponse(std::shared_ptr< SetRequestHandler >&&); RCSSetResponse(std::shared_ptr< SetRequestHandler >&&, AcceptanceMethod); diff --git a/service/resource-encapsulation/include/RCSSeparateResponse.h b/service/resource-encapsulation/include/RCSSeparateResponse.h new file mode 100755 index 0000000..b23cea5 --- /dev/null +++ b/service/resource-encapsulation/include/RCSSeparateResponse.h @@ -0,0 +1,56 @@ +//****************************************************************** +// +// Copyright 2015 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef SERVERBUILDER_RCSSEPARATERESPONSE_H +#define SERVERBUILDER_RCSSEPARATERESPONSE_H + +#include "RCSRequest.h" + +namespace OIC +{ + namespace Service + { + class RCSResourceAttributes; + class RCSRequest; + + class RCSSeparateResponse + { + public: + explicit RCSSeparateResponse(const RCSRequest&); + explicit RCSSeparateResponse(RCSRequest&&); + + RCSSeparateResponse(const RCSSeparateResponse&) = delete; + RCSSeparateResponse& operator=(const RCSSeparateResponse&) = delete; + + RCSSeparateResponse(RCSSeparateResponse&&) = default; + RCSSeparateResponse& operator=(RCSSeparateResponse&&) =default; + + void set(); + + private: + RCSRequest m_request; + + bool m_done; + }; + + } +} + +#endif // SERVERBUILDER_RCSSEPARATERESPONSE_H diff --git a/service/resource-encapsulation/src/serverBuilder/src/RCSRequest.cpp b/service/resource-encapsulation/src/serverBuilder/src/RCSRequest.cpp index b6d5dfc..88513af 100644 --- a/service/resource-encapsulation/src/serverBuilder/src/RCSRequest.cpp +++ b/service/resource-encapsulation/src/serverBuilder/src/RCSRequest.cpp @@ -27,7 +27,9 @@ namespace OIC namespace Service { - RCSRequest::RCSRequest(const std::shared_ptr< OC::OCResourceRequest >& ocRequest) : + RCSRequest::RCSRequest(const std::shared_ptr< RCSResourceObject >& resourceObject, + const std::shared_ptr< OC::OCResourceRequest >& ocRequest) : + m_resourceObject{ resourceObject }, m_ocRequest{ ocRequest } { } @@ -38,12 +40,18 @@ namespace OIC m_ocRequest->setResourceUri(resourceUri); } + + std::weak_ptr< RCSResourceObject > RCSRequest::getResourceObject() const noexcept + { + return m_resourceObject; + } + std::string RCSRequest::getResourceUri() const { return m_ocRequest->getResourceUri(); } - const std::shared_ptr< OC::OCResourceRequest >& RCSRequest::getOCRequest() const + const std::shared_ptr< OC::OCResourceRequest >& RCSRequest::getOCRequest() const noexcept { return m_ocRequest; } @@ -63,5 +71,6 @@ namespace OIC return it->second; } + } } diff --git a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp index 5b4c8b7..feb2068 100644 --- a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp +++ b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp @@ -100,13 +100,13 @@ namespace template< typename HANDLER, typename RESPONSE = typename std::decay::type::result_type > - RESPONSE invokeHandler(RCSResourceAttributes& attrs, + RESPONSE invokeHandler(const RCSResourceObject::Ptr& resObj, RCSResourceAttributes& attrs, const std::shared_ptr< OC::OCResourceRequest >& ocRequest, std::shared_ptr< HANDLER > handler) { if (handler) { - return (*handler)(RCSRequest{ ocRequest }, attrs); + return (*handler)(RCSRequest{ resObj, ocRequest }, attrs); } return RESPONSE::defaultAction(); @@ -240,7 +240,7 @@ namespace OIC new RCSResourceObject{ m_uri, m_properties, std::move(m_resourceAttributes) } }; OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler, - server.get(), std::placeholders::_1) }; + std::weak_ptr< RCSResourceObject >{ server }, std::placeholders::_1) }; typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&, const std::string&, const std::string&, OC::EntityHandler, uint8_t); @@ -535,6 +535,7 @@ namespace OIC RCSRepresentation RCSResourceObject::toRepresentation() const { + WeakGuard lock{*this}; return RCSRepresentation{ m_uri, m_interfaces, m_types, m_resourceAttributes }; } @@ -554,8 +555,13 @@ namespace OIC } OCEntityHandlerResult RCSResourceObject::entityHandler( + const std::weak_ptr< RCSResourceObject >& weakRes, const std::shared_ptr< OC::OCResourceRequest >& request) { + auto resource = weakRes.lock(); + + if (!resource) return OC_EH_ERROR; + OIC_LOG(WARNING, LOG_TAG, "entityHandler"); if (!request) { @@ -566,12 +572,12 @@ namespace OIC { if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag) { - return handleRequest(request); + return resource->handleRequest(request); } if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag) { - return handleObserve(request); + return resource->handleObserve(request); } } catch (const std::exception& e) @@ -618,7 +624,11 @@ namespace OIC auto attrs = getAttributesFromOCRequest(request); - return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler)); + auto response = invokeHandler(shared_from_this(), attrs, request, m_getRequestHandler); + + if (response.isSeparate()) return OC_EH_SLOW; + + return sendResponse(*this, request, response); } bool RCSResourceObject::applyAcceptanceMethod(const RCSSetResponse& response, @@ -660,7 +670,9 @@ namespace OIC assert(request != nullptr); auto attrs = getAttributesFromOCRequest(request); - auto response = invokeHandler(attrs, request, m_setRequestHandler); + auto response = invokeHandler(shared_from_this(), attrs, request, m_setRequestHandler); + + if (response.isSeparate()) return OC_EH_SLOW; auto attrsChanged = applyAcceptanceMethod(response, attrs); diff --git a/service/resource-encapsulation/src/serverBuilder/src/RCSResponse.cpp b/service/resource-encapsulation/src/serverBuilder/src/RCSResponse.cpp index 9a91c61..79d42c3 100644 --- a/service/resource-encapsulation/src/serverBuilder/src/RCSResponse.cpp +++ b/service/resource-encapsulation/src/serverBuilder/src/RCSResponse.cpp @@ -61,6 +61,20 @@ namespace OIC std::move(attrs), errorCode) }; } + RCSGetResponse RCSGetResponse::separate() + { + return RCSGetResponse(); + } + + bool RCSGetResponse::isSeparate() const + { + return !m_handler; + } + + RCSGetResponse::RCSGetResponse() + { + } + RCSGetResponse::RCSGetResponse(std::shared_ptr< RequestHandler >&& handler) : m_handler{ std::move(handler) } { @@ -123,6 +137,16 @@ namespace OIC return std::make_shared< SetRequestHandler >(std::move(attrs), errorCode); } + RCSSetResponse RCSSetResponse::separate() + { + return RCSSetResponse(); + } + + RCSSetResponse::RCSSetResponse() : + m_acceptanceMethod { AcceptanceMethod::DEFAULT } + { + } + RCSSetResponse::RCSSetResponse(std::shared_ptr< SetRequestHandler >&& handler) : m_acceptanceMethod { AcceptanceMethod::DEFAULT }, m_handler{ std::move(handler) } @@ -137,6 +161,12 @@ namespace OIC assert(m_handler); } + bool RCSSetResponse::isSeparate() const + { + return !m_handler; + } + + SetRequestHandler* RCSSetResponse::getHandler() const { return m_handler.get(); diff --git a/service/resource-encapsulation/src/serverBuilder/src/RCSSeparateResponse.cpp b/service/resource-encapsulation/src/serverBuilder/src/RCSSeparateResponse.cpp new file mode 100755 index 0000000..98001e8 --- /dev/null +++ b/service/resource-encapsulation/src/serverBuilder/src/RCSSeparateResponse.cpp @@ -0,0 +1,93 @@ +//****************************************************************** +// +// Copyright 2015 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#include "RCSSeparateResponse.h" + +#include "RCSRequest.h" +#include "RCSResourceObject.h" +#include "RCSRepresentation.h" +#include "AssertUtils.h" + +#include "OCPlatform.h" +#include "OCResourceResponse.h" +#include "OCResourceRequest.h" + +namespace OIC +{ + namespace Service + { + + namespace + { + void validateRequest(const RCSRequest& request) + { + if (!request.getOCRequest() || request.getResourceObject().expired()) + { + throw RCSInvalidParameterException{ + "The request is incomplete. The resource for the request might be destroyed." }; + } + } + } + + RCSSeparateResponse::RCSSeparateResponse(const RCSRequest& request) : + m_request{ request }, + m_done{ false } + { + validateRequest(m_request); + } + + RCSSeparateResponse::RCSSeparateResponse(RCSRequest&& request) : + m_request{ std::move(request) }, + m_done{ false } + { + validateRequest(m_request); + } + + void RCSSeparateResponse::set() + { + assert(m_request.getOCRequest()); + + auto resObj = m_request.getResourceObject().lock(); + if (!resObj) + { + throw RCSBadRequestException{ "ResourceObject is unspecified(or destroyed)!" }; + } + + if (m_done) throw RCSBadRequestException{ "The response is already set!" }; + + auto ocRequest = m_request.getOCRequest(); + auto response = std::make_shared< OC::OCResourceResponse >(); + + response->setRequestHandle(ocRequest->getRequestHandle()); + response->setResourceHandle(ocRequest->getResourceHandle()); + + response->setResponseResult(OC_EH_OK); + + // TODO the response should be different by the request interface. + response->setResourceRepresentation( + RCSRepresentation::toOCRepresentation(resObj->toRepresentation())); + + invokeOCFunc(OC::OCPlatform::sendResponse, response); + + m_done = true; + } + + } +} diff --git a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp index a4ed8a3..52ee306 100644 --- a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp +++ b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp @@ -21,6 +21,8 @@ #include "UnitTestHelper.h" #include "RCSResourceObject.h" +#include "RCSRequest.h" +#include "RCSSeparateResponse.h" #include "OCPlatform.h" @@ -479,6 +481,54 @@ TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs) ASSERT_EQ(OC_EH_OK, handler(createRequest(OC_REST_POST))); } +TEST_F(ResourceObjectHandlingRequestTest, SeparateResponseIsSlowResponse) +{ + server->setGetRequestHandler( + [](const RCSRequest&, RCSResourceAttributes&) -> RCSGetResponse + { + return RCSGetResponse::separate(); + } + ); + + ASSERT_EQ(OC_EH_SLOW, handler(createRequest())); +} + +TEST_F(ResourceObjectHandlingRequestTest, SetMethodOfSeparateResponseInvokesSendResponse) +{ + RCSRequest aRequest; + server->setGetRequestHandler( + [&aRequest](const RCSRequest& request, RCSResourceAttributes&) -> RCSGetResponse + { + aRequest = request; + return RCSGetResponse::separate(); + } + ); + handler(createRequest(OC_REST_GET)); + + mocks.ExpectCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK); + + RCSSeparateResponse(aRequest).set(); +} + + +TEST_F(ResourceObjectHandlingRequestTest, SetMethodOfSeparateResponseThrowsIfTheResourceIsDestroyed) +{ + RCSRequest aRequest; + server->setGetRequestHandler( + [&aRequest](const RCSRequest& request, RCSResourceAttributes&) -> RCSGetResponse + { + aRequest = request; + return RCSGetResponse::separate(); + } + ); + handler(createRequest(OC_REST_GET)); + + RCSSeparateResponse resp(aRequest); + + server.reset(); + + EXPECT_THROW(resp.set(), RCSBadRequestException); +} class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest diff --git a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResponseTest.cpp b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResponseTest.cpp index 2ba3817..d76184e 100644 --- a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResponseTest.cpp +++ b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResponseTest.cpp @@ -18,15 +18,17 @@ // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -#include +#include "UnitTestHelper.h" -#include -#include +#include "RCSRequest.h" +#include "RCSResponse.h" +#include "RCSSeparateResponse.h" +#include "RCSResourceObject.h" -#include -#include +#include "RequestHandler.h" +#include "ResourceAttributesConverter.h" -#include +#include "OCPlatform.h" using namespace std; @@ -185,3 +187,16 @@ TEST_F(RCSResponseTest, SetResponseHasMethodSetBySetter) EXPECT_EQ(method, response.getAcceptanceMethod()); } + +TEST_F(RCSResponseTest, SeparateResponseHasNoHandler) +{ + RCSGetResponse response = RCSGetResponse::separate(); + EXPECT_EQ(nullptr, response.getHandler()); +} + +TEST_F(RCSResponseTest, ThrowIfRequestIsInvalidWhenConstructingSeparateResponse) +{ + RCSRequest aRequest; + + EXPECT_THROW(RCSSeparateResponse resp(aRequest), RCSInvalidParameterException); +} -- 2.7.4