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 <ResourceObject.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[]{ "ResourceObject" };
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(ResourceObject& 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 ResourceAttributes getAttributesFromOCRequest(std::shared_ptr< OC::OCResourceRequest > request)
80 return ResourceAttributesConverter::fromOCRepresentation(
81 request->getResourceRepresentation());
84 template< typename HANDLER, typename RESPONSE = typename std::decay<HANDLER>::type::result_type >
85 RESPONSE invokeHandler(ResourceAttributes& attrs,
86 std::shared_ptr< OC::OCResourceRequest > ocRequest, HANDLER&& handler)
90 return handler(RCSRequest{ ocRequest->getResourceUri() }, attrs);
93 return RESPONSE::defaultAction();
96 typedef void (ResourceObject::* AutoNotifyFunc)(bool, ResourceObject::AutoNotifyPolicy) const;
98 std::function <void ()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
99 const ResourceObject& resourceObject, const ResourceAttributes& resourceAttributes,
100 ResourceObject::AutoNotifyPolicy autoNotifyPolicy)
102 if(autoNotifyPolicy == ResourceObject::AutoNotifyPolicy::UPDATED)
104 auto&& compareAttributesFunc =
105 std::bind(std::not_equal_to<ResourceAttributes>(),
107 std::cref(resourceAttributes));
108 return std::bind(autoNotifyFunc,
109 &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
111 else if(autoNotifyPolicy == ResourceObject::AutoNotifyPolicy::ALWAYS)
113 return std::bind(autoNotifyFunc,
114 &resourceObject, true, autoNotifyPolicy);
118 } // unnamed namespace
126 ResourceObject::Builder::Builder(const std::string& uri, const std::string& type,
127 const std::string& interface) :
130 m_interface{ interface },
131 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
132 m_resourceAttributes{ }
136 ResourceObject::Builder& ResourceObject::Builder::setDiscoverable(
139 m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
143 ResourceObject::Builder& ResourceObject::Builder::setObservable(
146 m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
150 ResourceObject::Builder& ResourceObject::Builder::setAttributes(
151 const ResourceAttributes& attrs)
153 m_resourceAttributes = attrs;
157 ResourceObject::Builder& ResourceObject::Builder::setAttributes(
158 ResourceAttributes&& attrs)
160 m_resourceAttributes = std::move(attrs);
164 ResourceObject::Ptr ResourceObject::Builder::build()
166 OCResourceHandle handle{ nullptr };
168 ResourceObject::Ptr server {
169 new ResourceObject{ m_properties, std::move(m_resourceAttributes) } };
171 OC::EntityHandler entityHandler{ std::bind(&ResourceObject::entityHandler,
172 server.get(), std::placeholders::_1) };
176 typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
177 const std::string&, const std::string&, OC::EntityHandler, uint8_t);
179 invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
180 handle, m_uri, m_type, m_interface, entityHandler, m_properties);
182 catch (OC::OCException& e)
184 throw PlatformException(e.code());
187 server->m_resourceHandle = handle;
193 ResourceObject::ResourceObject(uint8_t properties, ResourceAttributes&& attrs) :
194 m_properties { properties },
196 m_resourceAttributes{ std::move(attrs) },
197 m_getRequestHandler{ },
198 m_setRequestHandler{ },
199 m_autoNotifyPolicy { AutoNotifyPolicy::UPDATED },
200 m_setRequestHandlerPolicy { SetRequestHandlerPolicy::NEVER },
201 m_keyAttributesUpdatedListeners{ },
204 m_mutexKeyAttributeUpdate{ }
208 ResourceObject::~ResourceObject()
210 if (m_resourceHandle)
214 OC::OCPlatform::unregisterResource(m_resourceHandle);
218 OC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
223 void ResourceObject::setAttribute(const std::string& key,
224 const ResourceAttributes::Value& value)
226 WeakGuard lock(*this);
230 autoNotifyIfNeeded(key, value);
233 m_resourceAttributes[key] = value;
236 void ResourceObject::setAttribute(const std::string& key, ResourceAttributes::Value&& value)
238 WeakGuard lock(*this);
242 autoNotifyIfNeeded(key, value);
245 m_resourceAttributes[key] = std::move(value);
248 void ResourceObject::setAttribute(std::string&& key, const ResourceAttributes::Value& value)
250 WeakGuard lock(*this);
254 autoNotifyIfNeeded(key, value);
257 m_resourceAttributes[std::move(key)] = value;
260 void ResourceObject::setAttribute(std::string&& key, ResourceAttributes::Value&& value)
262 WeakGuard lock(*this);
266 autoNotifyIfNeeded(key, value);
269 m_resourceAttributes[std::move(key)] = std::move(value);
272 ResourceAttributes::Value ResourceObject::getAttributeValue(const std::string& key) const
274 WeakGuard lock(*this);
275 return m_resourceAttributes.at(key);
278 bool ResourceObject::removeAttribute(const std::string& key)
280 WeakGuard lock(*this);
281 if (m_resourceAttributes.erase(key))
283 autoNotify(true, getAutoNotifyPolicy());
289 bool ResourceObject::containsAttribute(const std::string& key) const
291 WeakGuard lock(*this);
292 return m_resourceAttributes.contains(key);
295 ResourceAttributes& ResourceObject::getAttributes()
298 return m_resourceAttributes;
301 const ResourceAttributes& ResourceObject::getAttributes() const
304 return m_resourceAttributes;
307 void ResourceObject::expectOwnLock() const
309 if (m_lockOwner != std::this_thread::get_id())
311 throw NoLockException{ "Must acquire the lock first using LockGuard." };
315 bool ResourceObject::isObservable() const
317 return ::hasProperty(m_properties, OC_OBSERVABLE);
320 bool ResourceObject::isDiscoverable() const
322 return ::hasProperty(m_properties, OC_DISCOVERABLE);
325 void ResourceObject::setGetRequestHandler(GetRequestHandler h)
327 m_getRequestHandler = std::move(h);
330 void ResourceObject::setSetRequestHandler(SetRequestHandler h)
332 m_setRequestHandler = std::move(h);
335 void ResourceObject::notify() const
337 typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
339 invokeOCFuncWithResultExpect(
340 { OC_STACK_OK, OC_STACK_NO_OBSERVERS },
341 static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
345 void ResourceObject::addAttributeUpdatedListener(const std::string& key,
346 AttributeUpdatedListener h)
348 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
349 m_keyAttributesUpdatedListeners[key] = std::move(h);
352 void ResourceObject::addAttributeUpdatedListener(std::string&& key,
353 AttributeUpdatedListener h)
355 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
356 m_keyAttributesUpdatedListeners[std::move(key)] = std::move(h);
359 bool ResourceObject::removeAttributeUpdatedListener(const std::string& key)
361 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
362 return (bool) m_keyAttributesUpdatedListeners.erase(key);
365 void ResourceObject::autoNotifyIfNeeded(const std::string& key,
366 const ResourceAttributes::Value& value)
368 autoNotify( m_resourceAttributes.contains(key) == false
369 || m_resourceAttributes.at(key) != value
370 , m_autoNotifyPolicy);
373 void ResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
375 m_autoNotifyPolicy = policy;
378 ResourceObject::AutoNotifyPolicy ResourceObject::getAutoNotifyPolicy() const
380 return m_autoNotifyPolicy;
383 void ResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
385 m_setRequestHandlerPolicy = policy;
388 ResourceObject::SetRequestHandlerPolicy ResourceObject::getSetRequestHandlerPolicy() const
390 return m_setRequestHandlerPolicy;
393 void ResourceObject::autoNotify(
394 bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
396 if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
397 if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED && isAttributesChanged == false) return;
401 OCEntityHandlerResult ResourceObject::entityHandler(
402 std::shared_ptr< OC::OCResourceRequest > request)
411 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
413 return handleRequest(request);
416 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
418 return handleObserve(request);
421 catch (const std::exception& e)
423 OC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
428 OC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
435 OCEntityHandlerResult ResourceObject::handleRequest(
436 std::shared_ptr< OC::OCResourceRequest > request)
438 assert(request != nullptr);
440 if (request->getRequestType() == "GET")
442 return handleRequestGet(request);
445 if (request->getRequestType() == "PUT")
447 return handleRequestSet(request);
453 OCEntityHandlerResult ResourceObject::handleRequestGet(
454 std::shared_ptr< OC::OCResourceRequest > request)
456 assert(request != nullptr);
458 auto attrs = getAttributesFromOCRequest(request);
460 return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler));
463 OCEntityHandlerResult ResourceObject::handleRequestSet(
464 std::shared_ptr< OC::OCResourceRequest > request)
466 assert(request != nullptr);
468 auto attrs = getAttributesFromOCRequest(request);
469 auto response = invokeHandler(attrs, request, m_setRequestHandler);
470 auto requestHandler = response.getHandler();
472 assert(requestHandler != nullptr);
474 AttrKeyValuePairs replaced = requestHandler->applyAcceptanceMethod(
475 response.getAcceptanceMethod(), *this, attrs);
477 for (const auto& it : replaced)
479 std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate);
481 auto keyAttribute = m_keyAttributesUpdatedListeners.find(it.first);
482 if(keyAttribute != m_keyAttributesUpdatedListeners.end())
484 keyAttribute-> second(it.second, attrs[it.first]);
488 autoNotify(!replaced.empty(), m_autoNotifyPolicy);
489 return sendResponse(*this, request, response);
492 OCEntityHandlerResult ResourceObject::handleObserve(
493 std::shared_ptr< OC::OCResourceRequest > request)
495 assert(request != nullptr);
505 ResourceObject::LockGuard::LockGuard(const ResourceObject::Ptr ptr) :
506 m_resourceObject(*ptr),
507 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
508 m_isOwningLock{ false }
513 ResourceObject::LockGuard::LockGuard(
514 const ResourceObject& serverResource) :
515 m_resourceObject(serverResource),
516 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
517 m_isOwningLock{ false }
522 ResourceObject::LockGuard::LockGuard(
523 const ResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
524 m_resourceObject(*ptr),
525 m_autoNotifyPolicy { autoNotifyPolicy },
526 m_isOwningLock{ false }
531 ResourceObject::LockGuard::LockGuard(
532 const ResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
533 m_resourceObject(resourceObject),
534 m_autoNotifyPolicy { autoNotifyPolicy },
535 m_isOwningLock{ false }
540 ResourceObject::LockGuard::~LockGuard()
542 if (m_autoNotifyFunc) m_autoNotifyFunc();
546 m_resourceObject.m_lockOwner = std::thread::id{ };
547 m_resourceObject.m_mutex.unlock();
551 void ResourceObject::LockGuard::init()
553 if (m_resourceObject.m_lockOwner != std::this_thread::get_id())
555 m_resourceObject.m_mutex.lock();
556 m_resourceObject.m_lockOwner = std::this_thread::get_id();
557 m_isOwningLock = true;
559 m_autoNotifyFunc = ::createAutoNotifyInvoker(&ResourceObject::autoNotify,
560 m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
563 ResourceObject::WeakGuard::WeakGuard(
564 const ResourceObject& resourceObject) :
565 m_isOwningLock{ false },
566 m_resourceObject(resourceObject)
568 if (resourceObject.m_lockOwner != std::this_thread::get_id())
570 m_resourceObject.m_mutex.lock();
571 m_isOwningLock = true;
575 ResourceObject::WeakGuard::~WeakGuard()
579 m_resourceObject.m_mutex.unlock();
583 bool ResourceObject::WeakGuard::hasLocked() const
585 return m_isOwningLock;