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"
25 #include "RequestHandler.h"
26 #include "AssertUtils.h"
27 #include "AtomicHelper.h"
28 #include "ResourceAttributesConverter.h"
29 #include "ResourceAttributesUtils.h"
30 #include "RCSRequest.h"
31 #include "RCSRepresentation.h"
32 #include "InterfaceHandler.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 OCEntityHandlerResult sendResponse(const std::shared_ptr< OC::OCResourceRequest >& ocRequest,
59 const std::shared_ptr< OC::OCResourceResponse >& ocResponse)
61 ocResponse->setRequestHandle(ocRequest->getRequestHandle());
62 ocResponse->setResourceHandle(ocRequest->getResourceHandle());
66 if (OC::OCPlatform::sendResponse(ocResponse) == OC_STACK_OK)
71 catch (const OC::OCException& e)
73 OIC_LOG_V(WARNING, LOG_TAG, "Error (%s)", e.what());
79 RCSResourceAttributes getAttributesFromOCRequest(
80 const std::shared_ptr< OC::OCResourceRequest >& request)
82 return ResourceAttributesConverter::fromOCRepresentation(
83 request->getResourceRepresentation());
86 template< typename HANDLER, typename RESPONSE =
87 typename std::decay<HANDLER>::type::result_type >
88 RESPONSE invokeHandler(RCSResourceAttributes& attrs, const RCSRequest& request,
89 std::shared_ptr< HANDLER > handler)
93 return (*handler)(request, attrs);
96 return RESPONSE::defaultAction();
99 typedef void (RCSResourceObject::* AutoNotifyFunc)
100 (bool, RCSResourceObject::AutoNotifyPolicy) const;
102 std::function<void()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
103 const RCSResourceObject& resourceObject,
104 const RCSResourceAttributes& resourceAttributes,
105 RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
107 if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::UPDATED)
109 auto&& compareAttributesFunc =
110 std::bind(std::not_equal_to<RCSResourceAttributes>(),
112 std::cref(resourceAttributes));
113 return std::bind(autoNotifyFunc,
114 &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
116 else if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::ALWAYS)
118 return std::bind(autoNotifyFunc,
119 &resourceObject, true, autoNotifyPolicy);
124 void insertValue(std::vector<std::string>& container, std::string value)
126 if (value.empty()) return;
128 if (std::find(container.begin(), container.end(), value) == container.end())
130 container.push_back(std::move(value));
134 } // unnamed namespace
141 RCSResourceObject::Builder::Builder(std::string &&uri, std::string &&type,
142 std::string &&interface) :
143 m_uri{ std::move(uri) },
144 m_types{ std::move(type) },
146 m_defaultInterface{ interface },
147 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
148 m_resourceAttributes{ }
150 addInterface(interface);
151 addInterface(BASELINE_INTERFACE);
153 if (m_defaultInterface.empty())
155 m_defaultInterface = BASELINE_INTERFACE;
159 RCSResourceObject::Builder::Builder(const std::string &uri, const std::string &type,
160 const std::string &interface) :
163 m_interfaces{ interface },
164 m_defaultInterface { BASELINE_INTERFACE },
165 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
166 m_resourceAttributes{ }
170 RCSResourceObject::Builder& RCSResourceObject::Builder::addInterface(std::string interface)
172 insertValue(m_interfaces, std::move(interface));
176 RCSResourceObject::Builder& RCSResourceObject::Builder::addType(std::string type)
178 insertValue(m_types, std::move(type));
182 RCSResourceObject::Builder& RCSResourceObject::Builder::setDefaultInterface(
183 std::string interface)
185 if (std::find(m_interfaces.begin(), m_interfaces.end(), interface) ==
188 throw RCSBadRequestException{"The interface should be added, first."};
191 m_defaultInterface = std::move(interface);
196 RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable(
199 m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
203 RCSResourceObject::Builder& RCSResourceObject::Builder::setObservable(
206 m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
210 RCSResourceObject::Builder& RCSResourceObject::Builder::setSecureFlag(
213 m_properties = ::makePropertyFlags(m_properties, OC_SECURE, secureFlag);
216 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
217 const RCSResourceAttributes& attrs)
219 m_resourceAttributes = attrs;
223 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
224 RCSResourceAttributes&& attrs)
226 m_resourceAttributes = std::move(attrs);
230 RCSResourceObject::Ptr RCSResourceObject::Builder::build()
232 OCResourceHandle handle{ nullptr };
234 RCSResourceObject::Ptr server {
235 new RCSResourceObject{ m_uri, m_properties, std::move(m_resourceAttributes) } };
237 OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler,
238 std::weak_ptr< RCSResourceObject >{ server }, std::placeholders::_1) };
240 typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
241 const std::string&, const std::string&, OC::EntityHandler, uint8_t);
243 invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
244 handle, m_uri, m_types[0], m_interfaces[0], entityHandler, m_properties);
246 std::for_each(m_interfaces.begin() + 1, m_interfaces.end(),
247 [&handle](const std::string& interfaceName){
248 invokeOCFunc(OC::OCPlatform::bindInterfaceToResource, handle, interfaceName);
251 std::for_each(m_types.begin() + 1, m_types.end(),
252 [&handle](const std::string& typeName){
253 invokeOCFunc(OC::OCPlatform::bindTypeToResource, handle, typeName);
256 server->init(handle, m_interfaces, m_types, m_defaultInterface);
262 RCSResourceObject::RCSResourceObject(const std::string& uri,
263 uint8_t properties, RCSResourceAttributes&& attrs) :
264 m_properties{ properties },
268 m_defaultInterface{ },
270 m_resourceAttributes{ std::move(attrs) },
271 m_getRequestHandler{ },
272 m_setRequestHandler{ },
273 m_autoNotifyPolicy{ AutoNotifyPolicy::UPDATED },
274 m_setRequestHandlerPolicy{ SetRequestHandlerPolicy::NEVER },
275 m_attributeUpdatedListeners{ },
278 m_mutexAttributeUpdatedListeners{ }
280 m_lockOwner.reset(new AtomicThreadId);
283 void RCSResourceObject::init(OCResourceHandle handle,
284 const std::vector< std::string >& interfaces,
285 const std::vector< std::string >& types,
286 const std::string& defaultInterface)
288 m_resourceHandle = handle;
289 m_interfaces = interfaces;
291 m_defaultInterface = defaultInterface;
293 for (const auto& itf : interfaces)
295 m_interfaceHandlers.insert({ itf, getDefaultInterfaceHandler(itf,
296 m_defaultInterface) });
300 RCSResourceObject::~RCSResourceObject()
302 if (m_resourceHandle)
306 invokeOCFunc(OC::OCPlatform::unregisterResource, m_resourceHandle);
310 OIC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
315 template< typename K, typename V >
316 void RCSResourceObject::setAttributeInternal(K&& key, V&& value)
318 bool needToNotify = false;
319 bool valueUpdated = false;
322 WeakGuard lock(*this);
324 if (lock.hasLocked())
327 valueUpdated = testValueUpdated(key, value);
330 m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value);
333 if (needToNotify) autoNotify(valueUpdated);
335 void RCSResourceObject::setAttribute(const std::string& key,
336 const RCSResourceAttributes::Value& value)
338 setAttributeInternal(key, value);
341 void RCSResourceObject::setAttribute(const std::string& key,
342 RCSResourceAttributes::Value&& value)
344 setAttributeInternal(key, std::move(value));
347 void RCSResourceObject::setAttribute(std::string&& key,
348 const RCSResourceAttributes::Value& value)
350 setAttributeInternal(std::move(key), value);
353 void RCSResourceObject::setAttribute(std::string&& key,
354 RCSResourceAttributes::Value&& value)
356 setAttributeInternal(std::move(key), std::move(value));
359 RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
360 const std::string& key) const
362 WeakGuard lock(*this);
363 return m_resourceAttributes.at(key);
366 bool RCSResourceObject::removeAttribute(const std::string& key)
368 bool needToNotify = false;
371 WeakGuard lock(*this);
373 if (m_resourceAttributes.erase(key))
376 needToNotify = lock.hasLocked();
380 if (needToNotify) autoNotify(true);
385 bool RCSResourceObject::containsAttribute(const std::string& key) const
387 WeakGuard lock(*this);
388 return m_resourceAttributes.contains(key);
391 RCSResourceAttributes& RCSResourceObject::getAttributes()
394 return m_resourceAttributes;
397 const RCSResourceAttributes& RCSResourceObject::getAttributes() const
400 return m_resourceAttributes;
403 void RCSResourceObject::expectOwnLock() const
405 if (getLockOwner() != std::this_thread::get_id())
407 throw NoLockException{ "Must acquire the lock first using LockGuard." };
411 std::thread::id RCSResourceObject::getLockOwner() const noexcept
416 void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept
418 m_lockOwner->store(std::move(id));
421 bool RCSResourceObject::isObservable() const
423 return ::hasProperty(m_properties, OC_OBSERVABLE);
426 bool RCSResourceObject::isDiscoverable() const
428 return ::hasProperty(m_properties, OC_DISCOVERABLE);
431 void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
433 m_getRequestHandler = std::make_shared< GetRequestHandler >(std::move(h));
436 void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
438 m_setRequestHandler = std::make_shared< SetRequestHandler >(std::move(h));
441 void RCSResourceObject::notify() const
443 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
445 invokeOCFuncWithResultExpect({ OC_STACK_OK, OC_STACK_NO_OBSERVERS },
446 static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
450 void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
451 AttributeUpdatedListener h)
453 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
455 m_attributeUpdatedListeners[key] =
456 std::make_shared< AttributeUpdatedListener >(std::move(h));
459 void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
460 AttributeUpdatedListener h)
462 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
464 m_attributeUpdatedListeners[std::move(key)] =
465 std::make_shared< AttributeUpdatedListener >(std::move(h));
468 bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
470 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
472 return m_attributeUpdatedListeners.erase(key) != 0;
475 bool RCSResourceObject::testValueUpdated(const std::string& key,
476 const RCSResourceAttributes::Value& value) const
478 return m_resourceAttributes.contains(key) == false
479 || m_resourceAttributes.at(key) != value;
482 void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
484 m_autoNotifyPolicy = policy;
487 RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
489 return m_autoNotifyPolicy;
492 void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
494 m_setRequestHandlerPolicy = policy;
497 auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
499 return m_setRequestHandlerPolicy;
502 void RCSResourceObject::bindResource(const RCSResourceObject::Ptr& resource)
504 if (!resource || resource.get() == this)
506 throw RCSInvalidParameterException("The resource is invalid!");
509 invokeOCFunc(OC::OCPlatform::bindResource,
510 m_resourceHandle, resource->m_resourceHandle);
512 std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
513 m_boundResources.push_back(resource);
516 void RCSResourceObject::unbindResource(const RCSResourceObject::Ptr& resource)
518 if (!resource || resource.get() == this)
520 throw RCSInvalidParameterException("The resource is invalid!");
523 invokeOCFunc(OC::OCPlatform::unbindResource,
524 m_resourceHandle, resource->m_resourceHandle);
526 std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
527 m_boundResources.erase(std::find(m_boundResources.begin(), m_boundResources.end(),
531 std::vector< RCSResourceObject::Ptr > RCSResourceObject::getBoundResources() const
533 std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
534 return m_boundResources;
537 std::string RCSResourceObject::getUri() const
542 std::string RCSResourceObject::getDefaultInterface() const
544 return m_defaultInterface;
547 std::vector< std::string > RCSResourceObject::getInterfaces() const
552 std::vector< std::string > RCSResourceObject::getTypes() const
557 RCSRepresentation RCSResourceObject::getRepresentation(const RCSRequest& request) const
559 if (request.getOCRequest()->getRequestType() == "GET")
561 return findInterfaceHandler(
562 request.getInterface()).getGetResponseBuilder()(request, *this);
565 if (request.getOCRequest()->getRequestType() == "POST")
567 return findInterfaceHandler(
568 request.getInterface()).getSetResponseBuilder()(request, *this);
571 throw RCSBadRequestException{ "Unsupported request type!" };
574 void RCSResourceObject::autoNotify(bool isAttributesChanged) const
576 autoNotify(isAttributesChanged, m_autoNotifyPolicy);
579 void RCSResourceObject::autoNotify(
580 bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
582 if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
583 if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED &&
584 isAttributesChanged == false) return;
589 OCEntityHandlerResult RCSResourceObject::entityHandler(
590 const std::weak_ptr< RCSResourceObject >& weakRes,
591 const std::shared_ptr< OC::OCResourceRequest >& request)
593 auto resource = weakRes.lock();
595 if (!resource) return OC_EH_ERROR;
597 OIC_LOG(WARNING, LOG_TAG, "entityHandler");
605 RCSRequest rcsRequest{ resource, request };
607 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
609 return resource->handleRequest(rcsRequest);
612 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
614 return resource->handleObserve(rcsRequest);
617 catch (const std::exception& e)
619 OIC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
624 OIC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
631 OCEntityHandlerResult RCSResourceObject::handleRequest(
632 const RCSRequest& request)
634 if (request.getInterface() != "" &&
635 m_interfaceHandlers.find(request.getInterface()) == m_interfaceHandlers.end())
640 if (request.getOCRequest()->getRequestType() == "GET")
642 return handleRequestGet(request);
645 if (request.getOCRequest()->getRequestType() == "POST")
647 return handleRequestSet(request);
653 OCEntityHandlerResult RCSResourceObject::handleRequestGet(const RCSRequest& request)
655 if (!findInterfaceHandler(request.getInterface()).isGetSupported())
660 auto attrs = getAttributesFromOCRequest(request.getOCRequest());
662 auto response = invokeHandler(attrs, request, m_getRequestHandler);
664 if (response.isSeparate()) return OC_EH_SLOW;
666 return sendResponse(request, response,
667 findInterfaceHandler(request.getInterface()).getGetResponseBuilder());
670 bool RCSResourceObject::applyAcceptanceMethod(
671 const RCSSetResponse& response, const RCSResourceAttributes& requestAttrs)
673 auto requestHandler = response.getHandler();
675 assert(requestHandler != nullptr);
677 RCSResourceAttributes result;
679 auto replaced = requestHandler->applyAcceptanceMethod(response.getAcceptanceMethod(),
680 *this, requestAttrs);
682 OIC_LOG_V(WARNING, LOG_TAG, "replaced num %zu", replaced.size());
683 for (const auto& attrKeyValPair : replaced)
685 std::shared_ptr< AttributeUpdatedListener > foundListener;
687 std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
689 auto it = m_attributeUpdatedListeners.find(attrKeyValPair.first);
690 if (it != m_attributeUpdatedListeners.end())
692 foundListener = it->second;
698 (*foundListener)(attrKeyValPair.second, requestAttrs.at(attrKeyValPair.first));
702 return !replaced.empty();
705 OCEntityHandlerResult RCSResourceObject::handleRequestSet(const RCSRequest& request)
707 if (!findInterfaceHandler(request.getInterface()).isSetSupported())
712 auto attrs = getAttributesFromOCRequest(request.getOCRequest());
714 auto response = invokeHandler(attrs, request, m_setRequestHandler);
716 if (response.isSeparate()) return OC_EH_SLOW;
718 autoNotify(applyAcceptanceMethod(response, attrs), m_autoNotifyPolicy);
720 return sendResponse(request, response,
721 findInterfaceHandler(request.getInterface()).getSetResponseBuilder());
724 OCEntityHandlerResult RCSResourceObject::handleObserve(const RCSRequest&)
734 InterfaceHandler RCSResourceObject::findInterfaceHandler(
735 const std::string& interfaceName) const
737 auto it = m_interfaceHandlers.find(interfaceName);
739 if (it != m_interfaceHandlers.end()) return it->second;
741 assert(m_interfaceHandlers.find(m_defaultInterface) != m_interfaceHandlers.end());
743 return m_interfaceHandlers.find(m_defaultInterface)->second;
746 template <typename RESPONSE, typename RESPONSE_BUILDER>
747 OCEntityHandlerResult RCSResourceObject::sendResponse(
748 const RCSRequest& request, const RESPONSE& response,
749 const RESPONSE_BUILDER& resBuilder)
751 auto reqHandler = response.getHandler();
752 auto ocResponse = std::make_shared< OC::OCResourceResponse >();
754 ocResponse->setResponseResult(OC_EH_OK);
755 ocResponse->setErrorCode(reqHandler->getErrorCode());
757 if (reqHandler->hasCustomRepresentation())
759 ocResponse->setResourceRepresentation(reqHandler->getRepresentation());
763 ocResponse->setResourceRepresentation(
764 RCSRepresentation::toOCRepresentation(resBuilder(request, *this)));
767 return ::sendResponse(request.getOCRequest(), ocResponse);
771 RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
772 m_resourceObject(*ptr),
773 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
774 m_isOwningLock{ false }
779 RCSResourceObject::LockGuard::LockGuard(
780 const RCSResourceObject& serverResource) :
781 m_resourceObject(serverResource),
782 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
783 m_isOwningLock{ false }
788 RCSResourceObject::LockGuard::LockGuard(
789 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
790 m_resourceObject(*ptr),
791 m_autoNotifyPolicy { autoNotifyPolicy },
792 m_isOwningLock{ false }
797 RCSResourceObject::LockGuard::LockGuard(
798 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
799 m_resourceObject(resourceObject),
800 m_autoNotifyPolicy { autoNotifyPolicy },
801 m_isOwningLock{ false }
806 RCSResourceObject::LockGuard::~LockGuard() noexcept(false)
808 if (!std::uncaught_exception() && m_autoNotifyFunc) m_autoNotifyFunc();
812 m_resourceObject.setLockOwner(std::thread::id{ });
813 m_resourceObject.m_mutex.unlock();
817 void RCSResourceObject::LockGuard::init()
819 if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
821 m_resourceObject.m_mutex.lock();
822 m_resourceObject.setLockOwner(std::this_thread::get_id());
823 m_isOwningLock = true;
825 m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
826 m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
829 RCSResourceObject::WeakGuard::WeakGuard(
830 const RCSResourceObject& resourceObject) :
831 m_isOwningLock{ false },
832 m_resourceObject(resourceObject)
834 if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
836 m_resourceObject.m_mutex.lock();
837 m_resourceObject.setLockOwner(std::this_thread::get_id());
838 m_isOwningLock = true;
842 RCSResourceObject::WeakGuard::~WeakGuard()
846 m_resourceObject.setLockOwner(std::thread::id{ });
847 m_resourceObject.m_mutex.unlock();
851 bool RCSResourceObject::WeakGuard::hasLocked() const
853 return m_isOwningLock;