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 <ResourceAttributesConverter.h>
32 #include <OCPlatform.h>
36 using namespace OIC::Service;
38 constexpr char LOG_TAG[]{ "RCSResourceObject" };
40 inline bool hasProperty(uint8_t base, uint8_t target)
42 return (base & target) == target;
45 inline uint8_t makePropertyFlags(uint8_t base, uint8_t target, bool add)
52 return base & ~target;
55 template <typename RESPONSE>
56 OCEntityHandlerResult sendResponse(RCSResourceObject& resource,
57 std::shared_ptr< OC::OCResourceRequest > ocRequest, RESPONSE&& response)
59 auto ocResponse = response.getHandler()->buildResponse(resource);
60 ocResponse->setRequestHandle(ocRequest->getRequestHandle());
61 ocResponse->setResourceHandle(ocRequest->getResourceHandle());
65 if (OC::OCPlatform::sendResponse(ocResponse) == OC_STACK_OK)
70 catch (const OC::OCException& e)
72 OC_LOG(WARNING, LOG_TAG, e.what());
78 RCSResourceAttributes getAttributesFromOCRequest(
79 std::shared_ptr< OC::OCResourceRequest > request)
81 return ResourceAttributesConverter::fromOCRepresentation(
82 request->getResourceRepresentation());
85 template< typename HANDLER, typename RESPONSE =
86 typename std::decay<HANDLER>::type::result_type >
87 RESPONSE invokeHandler(RCSResourceAttributes& attrs,
88 std::shared_ptr< OC::OCResourceRequest > ocRequest, HANDLER&& handler)
92 return handler(RCSRequest{ ocRequest->getResourceUri() }, attrs);
95 return RESPONSE::defaultAction();
98 typedef void (RCSResourceObject::* AutoNotifyFunc)
99 (bool, RCSResourceObject::AutoNotifyPolicy) const;
101 std::function <void ()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
102 const RCSResourceObject& resourceObject, const RCSResourceAttributes& resourceAttributes,
103 RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
105 if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::UPDATED)
107 auto&& compareAttributesFunc =
108 std::bind(std::not_equal_to<RCSResourceAttributes>(),
110 std::cref(resourceAttributes));
111 return std::bind(autoNotifyFunc,
112 &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
114 else if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::ALWAYS)
116 return std::bind(autoNotifyFunc,
117 &resourceObject, true, autoNotifyPolicy);
121 } // unnamed namespace
129 RCSResourceObject::Builder::Builder(const std::string& uri, const std::string& type,
130 const std::string& interface) :
133 m_interface{ interface },
134 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
135 m_resourceAttributes{ }
139 RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable(
142 m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
146 RCSResourceObject::Builder& RCSResourceObject::Builder::setObservable(
149 m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
153 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
154 const RCSResourceAttributes& attrs)
156 m_resourceAttributes = attrs;
160 RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
161 RCSResourceAttributes&& attrs)
163 m_resourceAttributes = std::move(attrs);
167 RCSResourceObject::Ptr RCSResourceObject::Builder::build()
169 OCResourceHandle handle{ nullptr };
171 RCSResourceObject::Ptr server {
172 new RCSResourceObject{ m_properties, std::move(m_resourceAttributes) } };
174 OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler,
175 server.get(), std::placeholders::_1) };
179 typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
180 const std::string&, const std::string&, OC::EntityHandler, uint8_t);
182 invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
183 handle, m_uri, m_type, m_interface, entityHandler, m_properties);
185 catch (OC::OCException& e)
187 throw PlatformException(e.code());
190 server->m_resourceHandle = handle;
196 RCSResourceObject::RCSResourceObject(uint8_t properties, RCSResourceAttributes&& attrs) :
197 m_properties { properties },
199 m_resourceAttributes{ std::move(attrs) },
200 m_getRequestHandler{ },
201 m_setRequestHandler{ },
202 m_autoNotifyPolicy { AutoNotifyPolicy::UPDATED },
203 m_setRequestHandlerPolicy { SetRequestHandlerPolicy::NEVER },
204 m_keyAttributesUpdatedListeners{ },
207 m_mutexKeyAttributeUpdate{ }
211 RCSResourceObject::~RCSResourceObject()
213 if (m_resourceHandle)
217 OC::OCPlatform::unregisterResource(m_resourceHandle);
221 OC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
226 void RCSResourceObject::setAttribute(const std::string& key,
227 const RCSResourceAttributes::Value& value)
229 WeakGuard lock(*this);
233 autoNotifyIfNeeded(key, value);
236 m_resourceAttributes[key] = value;
239 void RCSResourceObject::setAttribute(const std::string& key,
240 RCSResourceAttributes::Value&& value)
242 WeakGuard lock(*this);
246 autoNotifyIfNeeded(key, value);
249 m_resourceAttributes[key] = std::move(value);
252 void RCSResourceObject::setAttribute(std::string&& key,
253 const RCSResourceAttributes::Value& value)
255 WeakGuard lock(*this);
259 autoNotifyIfNeeded(key, value);
262 m_resourceAttributes[std::move(key)] = value;
265 void RCSResourceObject::setAttribute(std::string&& key,
266 RCSResourceAttributes::Value&& value)
268 WeakGuard lock(*this);
272 autoNotifyIfNeeded(key, value);
275 m_resourceAttributes[std::move(key)] = std::move(value);
278 RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
279 const std::string& key) const
281 WeakGuard lock(*this);
282 return m_resourceAttributes.at(key);
285 bool RCSResourceObject::removeAttribute(const std::string& key)
287 WeakGuard lock(*this);
288 if (m_resourceAttributes.erase(key))
290 autoNotify(true, getAutoNotifyPolicy());
296 bool RCSResourceObject::containsAttribute(const std::string& key) const
298 WeakGuard lock(*this);
299 return m_resourceAttributes.contains(key);
302 RCSResourceAttributes& RCSResourceObject::getAttributes()
305 return m_resourceAttributes;
308 const RCSResourceAttributes& RCSResourceObject::getAttributes() const
311 return m_resourceAttributes;
314 void RCSResourceObject::expectOwnLock() const
316 if (m_lockOwner != std::this_thread::get_id())
318 throw NoLockException{ "Must acquire the lock first using LockGuard." };
322 bool RCSResourceObject::isObservable() const
324 return ::hasProperty(m_properties, OC_OBSERVABLE);
327 bool RCSResourceObject::isDiscoverable() const
329 return ::hasProperty(m_properties, OC_DISCOVERABLE);
332 void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
334 m_getRequestHandler = std::move(h);
337 void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
339 m_setRequestHandler = std::move(h);
342 void RCSResourceObject::notify() const
344 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
346 invokeOCFuncWithResultExpect(
347 { OC_STACK_OK, OC_STACK_NO_OBSERVERS },
348 static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
352 void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
353 AttributeUpdatedListener h)
355 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
356 m_keyAttributesUpdatedListeners[key] = std::move(h);
359 void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
360 AttributeUpdatedListener h)
362 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
363 m_keyAttributesUpdatedListeners[std::move(key)] = std::move(h);
366 bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
368 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
369 return (bool) m_keyAttributesUpdatedListeners.erase(key);
372 void RCSResourceObject::autoNotifyIfNeeded(const std::string& key,
373 const RCSResourceAttributes::Value& value)
375 autoNotify( m_resourceAttributes.contains(key) == false
376 || m_resourceAttributes.at(key) != value
377 , m_autoNotifyPolicy);
380 void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
382 m_autoNotifyPolicy = policy;
385 RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
387 return m_autoNotifyPolicy;
390 void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
392 m_setRequestHandlerPolicy = policy;
395 auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
397 return m_setRequestHandlerPolicy;
400 void RCSResourceObject::autoNotify(
401 bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
403 if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
404 if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED && isAttributesChanged == false) return;
408 OCEntityHandlerResult RCSResourceObject::entityHandler(
409 std::shared_ptr< OC::OCResourceRequest > request)
418 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
420 return handleRequest(request);
423 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
425 return handleObserve(request);
428 catch (const std::exception& e)
430 OC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
435 OC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
442 OCEntityHandlerResult RCSResourceObject::handleRequest(
443 std::shared_ptr< OC::OCResourceRequest > request)
445 assert(request != nullptr);
447 if (request->getRequestType() == "GET")
449 return handleRequestGet(request);
452 if (request->getRequestType() == "PUT")
454 return handleRequestSet(request);
460 OCEntityHandlerResult RCSResourceObject::handleRequestGet(
461 std::shared_ptr< OC::OCResourceRequest > request)
463 assert(request != nullptr);
465 auto attrs = getAttributesFromOCRequest(request);
467 return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler));
470 OCEntityHandlerResult RCSResourceObject::handleRequestSet(
471 std::shared_ptr< OC::OCResourceRequest > request)
473 assert(request != nullptr);
475 auto attrs = getAttributesFromOCRequest(request);
476 auto response = invokeHandler(attrs, request, m_setRequestHandler);
477 auto requestHandler = response.getHandler();
479 assert(requestHandler != nullptr);
481 AttrKeyValuePairs replaced = requestHandler->applyAcceptanceMethod(
482 response.getAcceptanceMethod(), *this, attrs);
484 for (const auto& it : replaced)
486 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
488 auto keyAttribute = m_keyAttributesUpdatedListeners.find(it.first);
489 if(keyAttribute != m_keyAttributesUpdatedListeners.end())
491 keyAttribute-> second(it.second, attrs[it.first]);
495 autoNotify(!replaced.empty(), m_autoNotifyPolicy);
496 return sendResponse(*this, request, response);
499 OCEntityHandlerResult RCSResourceObject::handleObserve(
500 std::shared_ptr< OC::OCResourceRequest > request)
502 assert(request != nullptr);
512 RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
513 m_resourceObject(*ptr),
514 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
515 m_isOwningLock{ false }
520 RCSResourceObject::LockGuard::LockGuard(
521 const RCSResourceObject& serverResource) :
522 m_resourceObject(serverResource),
523 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
524 m_isOwningLock{ false }
529 RCSResourceObject::LockGuard::LockGuard(
530 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
531 m_resourceObject(*ptr),
532 m_autoNotifyPolicy { autoNotifyPolicy },
533 m_isOwningLock{ false }
538 RCSResourceObject::LockGuard::LockGuard(
539 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
540 m_resourceObject(resourceObject),
541 m_autoNotifyPolicy { autoNotifyPolicy },
542 m_isOwningLock{ false }
547 RCSResourceObject::LockGuard::~LockGuard()
549 if (m_autoNotifyFunc) m_autoNotifyFunc();
553 m_resourceObject.m_lockOwner = std::thread::id{ };
554 m_resourceObject.m_mutex.unlock();
558 void RCSResourceObject::LockGuard::init()
560 if (m_resourceObject.m_lockOwner != std::this_thread::get_id())
562 m_resourceObject.m_mutex.lock();
563 m_resourceObject.m_lockOwner = std::this_thread::get_id();
564 m_isOwningLock = true;
566 m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
567 m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
570 RCSResourceObject::WeakGuard::WeakGuard(
571 const RCSResourceObject& resourceObject) :
572 m_isOwningLock{ false },
573 m_resourceObject(resourceObject)
575 if (resourceObject.m_lockOwner != std::this_thread::get_id())
577 m_resourceObject.m_mutex.lock();
578 m_isOwningLock = true;
582 RCSResourceObject::WeakGuard::~WeakGuard()
586 m_resourceObject.m_mutex.unlock();
590 bool RCSResourceObject::WeakGuard::hasLocked() const
592 return m_isOwningLock;