1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 #include "RCSResourceObject.h"
27 #include "RequestHandler.h"
28 #include "AssertUtils.h"
29 #include "AtomicHelper.h"
30 #include "ResourceAttributesConverter.h"
31 #include "ResourceAttributesUtils.h"
32 #include "RCSRequest.h"
35 #include "OCPlatform.h"
37 #define LOG_TAG "RCSResourceObject"
41 using namespace OIC::Service;
43 inline bool hasProperty(uint8_t base, uint8_t target)
45 return (base & target) == target;
48 inline uint8_t makePropertyFlags(uint8_t base, uint8_t target, bool add)
55 return base & ~target;
58 template <typename RESPONSE>
59 OCEntityHandlerResult sendResponse(RCSResourceObject& resource,
60 const std::shared_ptr< OC::OCResourceRequest >& ocRequest, RESPONSE&& response)
62 auto ocResponse = response.getHandler()->buildResponse(resource);
63 ocResponse->setRequestHandle(ocRequest->getRequestHandle());
64 ocResponse->setResourceHandle(ocRequest->getResourceHandle());
68 if (OC::OCPlatform::sendResponse(ocResponse) == OC_STACK_OK)
73 catch (const OC::OCException& e)
75 OC_LOG_V(WARNING, LOG_TAG, "Error (%s)", e.what());
81 RCSResourceAttributes getAttributesFromOCRequest(
82 const std::shared_ptr< OC::OCResourceRequest >& request)
84 return ResourceAttributesConverter::fromOCRepresentation(
85 request->getResourceRepresentation());
88 template< typename HANDLER, typename RESPONSE =
89 typename std::decay<HANDLER>::type::result_type >
90 RESPONSE invokeHandler(RCSResourceAttributes& attrs,
91 const std::shared_ptr< OC::OCResourceRequest >& ocRequest,
92 std::shared_ptr< HANDLER > handler)
96 return (*handler)(RCSRequest{ ocRequest->getResourceUri() }, attrs);
99 return RESPONSE::defaultAction();
102 typedef void (RCSResourceObject::* AutoNotifyFunc)
103 (bool, RCSResourceObject::AutoNotifyPolicy) const;
105 std::function<void()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
106 const RCSResourceObject& resourceObject, const RCSResourceAttributes& resourceAttributes,
107 RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
109 if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::UPDATED)
111 auto&& compareAttributesFunc =
112 std::bind(std::not_equal_to<RCSResourceAttributes>(),
114 std::cref(resourceAttributes));
115 return std::bind(autoNotifyFunc,
116 &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
118 else if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::ALWAYS)
120 return std::bind(autoNotifyFunc,
121 &resourceObject, true, autoNotifyPolicy);
125 } // unnamed namespace
133 RCSResourceObject::Builder::Builder(const std::string& uri, const std::string& type,
134 const std::string& interface) :
137 m_interface{ interface },
138 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
139 m_resourceAttributes{ }
143 RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable(
146 m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
150 RCSResourceObject::Builder& RCSResourceObject::Builder::setObservable(
153 m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
157 RCSResourceObject::Builder& RCSResourceObject::Builder::setSecureFlag(
160 m_properties = ::makePropertyFlags(m_properties, OC_SECURE, secureFlag);
163 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
164 const RCSResourceAttributes& attrs)
166 m_resourceAttributes = attrs;
170 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
171 RCSResourceAttributes&& attrs)
173 m_resourceAttributes = std::move(attrs);
177 RCSResourceObject::Ptr RCSResourceObject::Builder::build()
179 OCResourceHandle handle{ nullptr };
181 RCSResourceObject::Ptr server {
182 new RCSResourceObject{ m_properties, std::move(m_resourceAttributes) } };
184 OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler,
185 server.get(), std::placeholders::_1) };
187 typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
188 const std::string&, const std::string&, OC::EntityHandler, uint8_t);
190 invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
191 handle, m_uri, m_type, m_interface, entityHandler, m_properties);
193 server->m_resourceHandle = handle;
199 RCSResourceObject::RCSResourceObject(uint8_t properties, RCSResourceAttributes&& attrs) :
200 m_properties { properties },
202 m_resourceAttributes{ std::move(attrs) },
203 m_getRequestHandler{ },
204 m_setRequestHandler{ },
205 m_autoNotifyPolicy { AutoNotifyPolicy::UPDATED },
206 m_setRequestHandlerPolicy { SetRequestHandlerPolicy::NEVER },
207 m_attributeUpdatedListeners{ },
210 m_mutexAttributeUpdatedListeners{ }
212 m_lockOwner.reset(new AtomicThreadId);
215 RCSResourceObject::~RCSResourceObject()
217 if (m_resourceHandle)
221 OC::OCPlatform::unregisterResource(m_resourceHandle);
225 OC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
230 template< typename K, typename V >
231 void RCSResourceObject::setAttributeInternal(K&& key, V&& value)
233 bool needToNotify = false;
234 bool valueUpdated = false;
237 WeakGuard lock(*this);
239 if (lock.hasLocked())
242 valueUpdated = testValueUpdated(key, value);
245 m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value);
248 if (needToNotify) autoNotify(valueUpdated);
250 void RCSResourceObject::setAttribute(const std::string& key,
251 const RCSResourceAttributes::Value& value)
253 setAttributeInternal(key, value);
256 void RCSResourceObject::setAttribute(const std::string& key,
257 RCSResourceAttributes::Value&& value)
259 setAttributeInternal(key, std::move(value));
262 void RCSResourceObject::setAttribute(std::string&& key,
263 const RCSResourceAttributes::Value& value)
265 setAttributeInternal(std::move(key), value);
268 void RCSResourceObject::setAttribute(std::string&& key,
269 RCSResourceAttributes::Value&& value)
271 setAttributeInternal(std::move(key), std::move(value));
274 RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
275 const std::string& key) const
277 WeakGuard lock(*this);
278 return m_resourceAttributes.at(key);
281 bool RCSResourceObject::removeAttribute(const std::string& key)
283 bool needToNotify = false;
286 WeakGuard lock(*this);
288 if (m_resourceAttributes.erase(key))
291 needToNotify = lock.hasLocked();
295 if (needToNotify) autoNotify(true);
300 bool RCSResourceObject::containsAttribute(const std::string& key) const
302 WeakGuard lock(*this);
303 return m_resourceAttributes.contains(key);
306 RCSResourceAttributes& RCSResourceObject::getAttributes()
309 return m_resourceAttributes;
312 const RCSResourceAttributes& RCSResourceObject::getAttributes() const
315 return m_resourceAttributes;
318 void RCSResourceObject::expectOwnLock() const
320 if (getLockOwner() != std::this_thread::get_id())
322 throw NoLockException{ "Must acquire the lock first using LockGuard." };
326 std::thread::id RCSResourceObject::getLockOwner() const noexcept
331 void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept
333 m_lockOwner->store(std::move(id));
336 bool RCSResourceObject::isObservable() const
338 return ::hasProperty(m_properties, OC_OBSERVABLE);
341 bool RCSResourceObject::isDiscoverable() const
343 return ::hasProperty(m_properties, OC_DISCOVERABLE);
346 void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
348 m_getRequestHandler = std::make_shared< GetRequestHandler >(std::move(h));
351 void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
353 m_setRequestHandler = std::make_shared< SetRequestHandler >(std::move(h));
356 void RCSResourceObject::notify() const
358 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
360 invokeOCFuncWithResultExpect({ OC_STACK_OK, OC_STACK_NO_OBSERVERS },
361 static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
365 void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
366 AttributeUpdatedListener h)
368 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
370 m_attributeUpdatedListeners[key] =
371 std::make_shared< AttributeUpdatedListener >(std::move(h));
374 void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
375 AttributeUpdatedListener h)
377 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
379 m_attributeUpdatedListeners[std::move(key)] =
380 std::make_shared< AttributeUpdatedListener >(std::move(h));
383 bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
385 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
387 return m_attributeUpdatedListeners.erase(key) != 0;
390 bool RCSResourceObject::testValueUpdated(const std::string& key,
391 const RCSResourceAttributes::Value& value) const
393 return m_resourceAttributes.contains(key) == false
394 || m_resourceAttributes.at(key) != value;
397 void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
399 m_autoNotifyPolicy = policy;
402 RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
404 return m_autoNotifyPolicy;
407 void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
409 m_setRequestHandlerPolicy = policy;
412 auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
414 return m_setRequestHandlerPolicy;
417 void RCSResourceObject::autoNotify(bool isAttributesChanged) const
419 autoNotify(isAttributesChanged, m_autoNotifyPolicy);
422 void RCSResourceObject::autoNotify(
423 bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
425 if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
426 if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED &&
427 isAttributesChanged == false) return;
432 OCEntityHandlerResult RCSResourceObject::entityHandler(
433 const std::shared_ptr< OC::OCResourceRequest >& request)
435 OC_LOG(WARNING, LOG_TAG, "entityHandler");
443 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
445 return handleRequest(request);
448 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
450 return handleObserve(request);
453 catch (const std::exception& e)
455 OC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
460 OC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
467 OCEntityHandlerResult RCSResourceObject::handleRequest(
468 const std::shared_ptr< OC::OCResourceRequest >& request)
470 assert(request != nullptr);
472 if (request->getRequestType() == "GET")
474 return handleRequestGet(request);
477 if (request->getRequestType() == "POST")
479 return handleRequestSet(request);
485 OCEntityHandlerResult RCSResourceObject::handleRequestGet(
486 const std::shared_ptr< OC::OCResourceRequest >& request)
488 assert(request != nullptr);
490 auto attrs = getAttributesFromOCRequest(request);
492 return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler));
495 bool RCSResourceObject::applyAcceptanceMethod(const RCSSetResponse& response,
496 const RCSResourceAttributes& requstAttrs)
498 auto requestHandler = response.getHandler();
500 assert(requestHandler != nullptr);
502 auto replaced = requestHandler->applyAcceptanceMethod(response.getAcceptanceMethod(),
505 OC_LOG_V(WARNING, LOG_TAG, "replaced num %zu", replaced.size());
506 for (const auto& attrKeyValPair : replaced)
508 std::shared_ptr< AttributeUpdatedListener > foundListener;
510 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
512 auto it = m_attributeUpdatedListeners.find(attrKeyValPair.first);
513 if (it != m_attributeUpdatedListeners.end())
515 foundListener = it->second;
521 (*foundListener)(attrKeyValPair.second, requstAttrs.at(attrKeyValPair.first));
525 return !replaced.empty();
528 OCEntityHandlerResult RCSResourceObject::handleRequestSet(
529 const std::shared_ptr< OC::OCResourceRequest >& request)
531 assert(request != nullptr);
533 auto attrs = getAttributesFromOCRequest(request);
534 auto response = invokeHandler(attrs, request, m_setRequestHandler);
536 auto attrsChanged = applyAcceptanceMethod(response, attrs);
540 autoNotify(attrsChanged, m_autoNotifyPolicy);
541 return sendResponse(*this, request, response);
542 } catch (const RCSPlatformException& e) {
543 OC_LOG_V(ERROR, LOG_TAG, "Error : %s ", e.what());
548 OCEntityHandlerResult RCSResourceObject::handleObserve(
549 const std::shared_ptr< OC::OCResourceRequest >&)
559 RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
560 m_resourceObject(*ptr),
561 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
562 m_isOwningLock{ false }
567 RCSResourceObject::LockGuard::LockGuard(
568 const RCSResourceObject& serverResource) :
569 m_resourceObject(serverResource),
570 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
571 m_isOwningLock{ false }
576 RCSResourceObject::LockGuard::LockGuard(
577 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
578 m_resourceObject(*ptr),
579 m_autoNotifyPolicy { autoNotifyPolicy },
580 m_isOwningLock{ false }
585 RCSResourceObject::LockGuard::LockGuard(
586 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
587 m_resourceObject(resourceObject),
588 m_autoNotifyPolicy { autoNotifyPolicy },
589 m_isOwningLock{ false }
594 RCSResourceObject::LockGuard::~LockGuard() noexcept(false)
596 if (!std::uncaught_exception() && m_autoNotifyFunc) m_autoNotifyFunc();
600 m_resourceObject.setLockOwner(std::thread::id{ });
601 m_resourceObject.m_mutex.unlock();
605 void RCSResourceObject::LockGuard::init()
607 if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
609 m_resourceObject.m_mutex.lock();
610 m_resourceObject.setLockOwner(std::this_thread::get_id());
611 m_isOwningLock = true;
613 m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
614 m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
617 RCSResourceObject::WeakGuard::WeakGuard(
618 const RCSResourceObject& resourceObject) :
619 m_isOwningLock{ false },
620 m_resourceObject(resourceObject)
622 if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
624 m_resourceObject.m_mutex.lock();
625 m_resourceObject.setLockOwner(std::this_thread::get_id());
626 m_isOwningLock = true;
630 RCSResourceObject::WeakGuard::~WeakGuard()
634 m_resourceObject.setLockOwner(std::thread::id{ });
635 m_resourceObject.m_mutex.unlock();
639 bool RCSResourceObject::WeakGuard::hasLocked() const
641 return m_isOwningLock;