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>
33 #include <OCPlatform.h>
37 using namespace OIC::Service;
39 constexpr char LOG_TAG[]{ "RCSResourceObject" };
41 inline bool hasProperty(uint8_t base, uint8_t target)
43 return (base & target) == target;
46 inline uint8_t makePropertyFlags(uint8_t base, uint8_t target, bool add)
53 return base & ~target;
56 template <typename RESPONSE>
57 OCEntityHandlerResult sendResponse(RCSResourceObject& resource,
58 std::shared_ptr< OC::OCResourceRequest > ocRequest, RESPONSE&& response)
60 auto ocResponse = response.getHandler()->buildResponse(resource);
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 OC_LOG(WARNING, LOG_TAG, e.what());
79 RCSResourceAttributes getAttributesFromOCRequest(
80 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,
89 std::shared_ptr< OC::OCResourceRequest > ocRequest, HANDLER&& handler)
93 return handler(RCSRequest{ ocRequest->getResourceUri() }, 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, const RCSResourceAttributes& resourceAttributes,
104 RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
106 if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::UPDATED)
108 auto&& compareAttributesFunc =
109 std::bind(std::not_equal_to<RCSResourceAttributes>(),
111 std::cref(resourceAttributes));
112 return std::bind(autoNotifyFunc,
113 &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
115 else if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::ALWAYS)
117 return std::bind(autoNotifyFunc,
118 &resourceObject, true, autoNotifyPolicy);
122 } // unnamed namespace
130 RCSResourceObject::Builder::Builder(const std::string& uri, const std::string& type,
131 const std::string& interface) :
134 m_interface{ interface },
135 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
136 m_resourceAttributes{ }
140 RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable(
143 m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
147 RCSResourceObject::Builder& RCSResourceObject::Builder::setObservable(
150 m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
154 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
155 const RCSResourceAttributes& attrs)
157 m_resourceAttributes = attrs;
161 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
162 RCSResourceAttributes&& attrs)
164 m_resourceAttributes = std::move(attrs);
168 RCSResourceObject::Ptr RCSResourceObject::Builder::build()
170 OCResourceHandle handle{ nullptr };
172 RCSResourceObject::Ptr server {
173 new RCSResourceObject{ m_properties, std::move(m_resourceAttributes) } };
175 OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler,
176 server.get(), std::placeholders::_1) };
178 typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
179 const std::string&, const std::string&, OC::EntityHandler, uint8_t);
181 invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
182 handle, m_uri, m_type, m_interface, entityHandler, m_properties);
184 server->m_resourceHandle = handle;
190 RCSResourceObject::RCSResourceObject(uint8_t properties, RCSResourceAttributes&& attrs) :
191 m_properties { properties },
193 m_resourceAttributes{ std::move(attrs) },
194 m_getRequestHandler{ },
195 m_setRequestHandler{ },
196 m_autoNotifyPolicy { AutoNotifyPolicy::UPDATED },
197 m_setRequestHandlerPolicy { SetRequestHandlerPolicy::NEVER },
198 m_keyAttributesUpdatedListeners{ },
201 m_mutexKeyAttributeUpdate{ }
203 m_lockOwner.reset(new AtomicThreadId);
206 RCSResourceObject::~RCSResourceObject()
208 if (m_resourceHandle)
212 OC::OCPlatform::unregisterResource(m_resourceHandle);
216 OC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
221 template< typename K, typename V >
222 void RCSResourceObject::setAttributeInternal(K&& key, V&& value)
224 bool needToNotify = false;
225 bool valueUpdated = false;
228 WeakGuard lock(*this);
230 if (lock.hasLocked())
233 valueUpdated = testValueUpdated(key, value);
236 m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value);
239 if (needToNotify) autoNotify(valueUpdated);
241 void RCSResourceObject::setAttribute(const std::string& key,
242 const RCSResourceAttributes::Value& value)
244 setAttributeInternal(key, value);
247 void RCSResourceObject::setAttribute(const std::string& key,
248 RCSResourceAttributes::Value&& value)
250 setAttributeInternal(key, std::move(value));
253 void RCSResourceObject::setAttribute(std::string&& key,
254 const RCSResourceAttributes::Value& value)
256 setAttributeInternal(std::move(key), value);
259 void RCSResourceObject::setAttribute(std::string&& key,
260 RCSResourceAttributes::Value&& value)
262 setAttributeInternal(std::move(key), std::move(value));
265 RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
266 const std::string& key) const
268 WeakGuard lock(*this);
269 return m_resourceAttributes.at(key);
272 bool RCSResourceObject::removeAttribute(const std::string& key)
274 bool needToNotify = false;
277 WeakGuard lock(*this);
279 if (m_resourceAttributes.erase(key))
282 needToNotify = lock.hasLocked();
286 if (needToNotify) autoNotify(true);
291 bool RCSResourceObject::containsAttribute(const std::string& key) const
293 WeakGuard lock(*this);
294 return m_resourceAttributes.contains(key);
297 RCSResourceAttributes& RCSResourceObject::getAttributes()
300 return m_resourceAttributes;
303 const RCSResourceAttributes& RCSResourceObject::getAttributes() const
306 return m_resourceAttributes;
309 void RCSResourceObject::expectOwnLock() const
311 if (getLockOwner() != std::this_thread::get_id())
313 throw NoLockException{ "Must acquire the lock first using LockGuard." };
317 std::thread::id RCSResourceObject::getLockOwner() const noexcept
322 void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept
324 m_lockOwner->store(std::move(id));
327 bool RCSResourceObject::isObservable() const
329 return ::hasProperty(m_properties, OC_OBSERVABLE);
332 bool RCSResourceObject::isDiscoverable() const
334 return ::hasProperty(m_properties, OC_DISCOVERABLE);
337 void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
339 m_getRequestHandler = std::move(h);
342 void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
344 m_setRequestHandler = std::move(h);
347 void RCSResourceObject::notify() const
349 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
351 invokeOCFuncWithResultExpect({ OC_STACK_OK, OC_STACK_NO_OBSERVERS },
352 static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
356 void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
357 AttributeUpdatedListener h)
359 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
360 m_keyAttributesUpdatedListeners[key] = std::move(h);
363 void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
364 AttributeUpdatedListener h)
366 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
367 m_keyAttributesUpdatedListeners[std::move(key)] = std::move(h);
370 bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
372 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
374 return m_keyAttributesUpdatedListeners.erase(key) != 0;
377 bool RCSResourceObject::testValueUpdated(const std::string& key,
378 const RCSResourceAttributes::Value& value) const
380 return m_resourceAttributes.contains(key) == false
381 || m_resourceAttributes.at(key) != value;
384 void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
386 m_autoNotifyPolicy = policy;
389 RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
391 return m_autoNotifyPolicy;
394 void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
396 m_setRequestHandlerPolicy = policy;
399 auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
401 return m_setRequestHandlerPolicy;
404 void RCSResourceObject::autoNotify(bool isAttributesChanged) const
406 autoNotify(isAttributesChanged, m_autoNotifyPolicy);
409 void RCSResourceObject::autoNotify(
410 bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
412 if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
413 if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED &&
414 isAttributesChanged == false) return;
419 OCEntityHandlerResult RCSResourceObject::entityHandler(
420 std::shared_ptr< OC::OCResourceRequest > request)
429 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
431 return handleRequest(request);
434 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
436 return handleObserve(request);
439 catch (const std::exception& e)
441 OC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
446 OC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
453 OCEntityHandlerResult RCSResourceObject::handleRequest(
454 std::shared_ptr< OC::OCResourceRequest > request)
456 assert(request != nullptr);
458 if (request->getRequestType() == "GET")
460 return handleRequestGet(request);
463 if (request->getRequestType() == "PUT")
465 return handleRequestSet(request);
471 OCEntityHandlerResult RCSResourceObject::handleRequestGet(
472 std::shared_ptr< OC::OCResourceRequest > request)
474 assert(request != nullptr);
476 auto attrs = getAttributesFromOCRequest(request);
478 return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler));
481 OCEntityHandlerResult RCSResourceObject::handleRequestSet(
482 std::shared_ptr< OC::OCResourceRequest > request)
484 assert(request != nullptr);
486 auto attrs = getAttributesFromOCRequest(request);
487 auto response = invokeHandler(attrs, request, m_setRequestHandler);
488 auto requestHandler = response.getHandler();
490 assert(requestHandler != nullptr);
492 AttrKeyValuePairs replaced = requestHandler->applyAcceptanceMethod(
493 response.getAcceptanceMethod(), *this, attrs);
495 for (const auto& attrKeyValPair : replaced)
497 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
499 auto keyAttrListener = m_keyAttributesUpdatedListeners.find(attrKeyValPair.first);
500 if(keyAttrListener != m_keyAttributesUpdatedListeners.end())
502 keyAttrListener-> second(attrKeyValPair.second, attrs[attrKeyValPair.first]);
506 autoNotify(!replaced.empty(), m_autoNotifyPolicy);
507 return sendResponse(*this, request, response);
510 OCEntityHandlerResult RCSResourceObject::handleObserve(
511 std::shared_ptr< OC::OCResourceRequest >)
521 RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
522 m_resourceObject(*ptr),
523 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
524 m_isOwningLock{ false }
529 RCSResourceObject::LockGuard::LockGuard(
530 const RCSResourceObject& serverResource) :
531 m_resourceObject(serverResource),
532 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
533 m_isOwningLock{ false }
538 RCSResourceObject::LockGuard::LockGuard(
539 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
540 m_resourceObject(*ptr),
541 m_autoNotifyPolicy { autoNotifyPolicy },
542 m_isOwningLock{ false }
547 RCSResourceObject::LockGuard::LockGuard(
548 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
549 m_resourceObject(resourceObject),
550 m_autoNotifyPolicy { autoNotifyPolicy },
551 m_isOwningLock{ false }
556 RCSResourceObject::LockGuard::~LockGuard()
558 if (m_autoNotifyFunc) m_autoNotifyFunc();
562 m_resourceObject.setLockOwner(std::thread::id{ });
563 m_resourceObject.m_mutex.unlock();
567 void RCSResourceObject::LockGuard::init()
569 if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
571 m_resourceObject.m_mutex.lock();
572 m_resourceObject.setLockOwner(std::this_thread::get_id());
573 m_isOwningLock = true;
575 m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
576 m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
579 RCSResourceObject::WeakGuard::WeakGuard(
580 const RCSResourceObject& resourceObject) :
581 m_isOwningLock{ false },
582 m_resourceObject(resourceObject)
584 if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
586 m_resourceObject.m_mutex.lock();
587 m_resourceObject.setLockOwner(std::this_thread::get_id());
588 m_isOwningLock = true;
592 RCSResourceObject::WeakGuard::~WeakGuard()
596 m_resourceObject.setLockOwner(std::thread::id{ });
597 m_resourceObject.m_mutex.unlock();
601 bool RCSResourceObject::WeakGuard::hasLocked() const
603 return m_isOwningLock;