Merge branch 'master' into simulator
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / serverBuilder / src / RCSResourceObject.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <RCSResourceObject.h>
22
23 #include <string>
24 #include <functional>
25 #include <vector>
26
27 #include <RequestHandler.h>
28 #include <AssertUtils.h>
29 #include <AtomicHelper.h>
30 #include <ResourceAttributesConverter.h>
31 #include <ResourceAttributesUtils.h>
32
33 #include <logger.h>
34 #include <OCPlatform.h>
35
36 #define LOG_TAG "RCSResourceObject"
37
38 namespace
39 {
40     using namespace OIC::Service;
41
42     inline bool hasProperty(uint8_t base, uint8_t target)
43     {
44         return (base & target) == target;
45     }
46
47     inline uint8_t makePropertyFlags(uint8_t base, uint8_t target, bool add)
48     {
49         if (add)
50         {
51             return base | target;
52         }
53
54         return base & ~target;
55     }
56
57     template <typename RESPONSE>
58     OCEntityHandlerResult sendResponse(RCSResourceObject& resource,
59             std::shared_ptr< OC::OCResourceRequest > ocRequest, RESPONSE&& response)
60     {
61         auto ocResponse = response.getHandler()->buildResponse(resource);
62         ocResponse->setRequestHandle(ocRequest->getRequestHandle());
63         ocResponse->setResourceHandle(ocRequest->getResourceHandle());
64
65         try
66         {
67             if (OC::OCPlatform::sendResponse(ocResponse) == OC_STACK_OK)
68             {
69                 return OC_EH_OK;
70             }
71         }
72         catch (const OC::OCException& e)
73         {
74             OC_LOG_V(WARNING, LOG_TAG, "Error (%s)", e.what());
75         }
76
77         return OC_EH_ERROR;
78     }
79
80     RCSResourceAttributes getAttributesFromOCRequest(
81             std::shared_ptr< OC::OCResourceRequest > request)
82     {
83         return ResourceAttributesConverter::fromOCRepresentation(
84                 request->getResourceRepresentation());
85     }
86
87     template< typename HANDLER, typename RESPONSE =
88             typename std::decay<HANDLER>::type::result_type >
89     RESPONSE invokeHandler(RCSResourceAttributes& attrs,
90             std::shared_ptr< OC::OCResourceRequest > ocRequest, HANDLER&& handler)
91     {
92         if (handler)
93         {
94             return handler(RCSRequest{ ocRequest->getResourceUri() }, attrs);
95         }
96
97         return RESPONSE::defaultAction();
98     }
99
100     typedef void (RCSResourceObject::* AutoNotifyFunc)
101             (bool, RCSResourceObject::AutoNotifyPolicy) const;
102
103     std::function <void ()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
104             const RCSResourceObject& resourceObject, const RCSResourceAttributes& resourceAttributes,
105             RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
106     {
107         if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::UPDATED)
108         {
109             auto&& compareAttributesFunc =
110                     std::bind(std::not_equal_to<RCSResourceAttributes>(),
111                                 resourceAttributes,
112                                 std::cref(resourceAttributes));
113             return std::bind(autoNotifyFunc,
114                     &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
115         }
116         else if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::ALWAYS)
117         {
118             return std::bind(autoNotifyFunc,
119                     &resourceObject, true, autoNotifyPolicy);
120         }
121         return {};
122     }
123 } // unnamed namespace
124
125
126 namespace OIC
127 {
128     namespace Service
129     {
130
131         RCSResourceObject::Builder::Builder(const std::string& uri, const std::string& type,
132                 const std::string& interface) :
133                 m_uri{ uri },
134                 m_type{ type },
135                 m_interface{ interface },
136                 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
137                 m_resourceAttributes{ }
138         {
139         }
140
141         RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable(
142                 bool discoverable)
143         {
144             m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
145             return *this;
146         }
147
148         RCSResourceObject::Builder& RCSResourceObject::Builder::setObservable(
149                 bool observable)
150         {
151             m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
152             return *this;
153         }
154
155         RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
156                 const RCSResourceAttributes& attrs)
157         {
158             m_resourceAttributes = attrs;
159             return *this;
160         }
161
162         RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
163                 RCSResourceAttributes&& attrs)
164         {
165             m_resourceAttributes = std::move(attrs);
166             return *this;
167         }
168
169         RCSResourceObject::Ptr RCSResourceObject::Builder::build()
170         {
171             OCResourceHandle handle{ nullptr };
172
173             RCSResourceObject::Ptr server {
174                 new RCSResourceObject{ m_properties, std::move(m_resourceAttributes) } };
175
176             OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler,
177                     server.get(), std::placeholders::_1) };
178
179             typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
180                     const std::string&, const std::string&, OC::EntityHandler, uint8_t);
181
182             invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
183                     handle, m_uri, m_type, m_interface, entityHandler, m_properties);
184
185             server->m_resourceHandle = handle;
186
187             return server;
188         }
189
190
191         RCSResourceObject::RCSResourceObject(uint8_t properties, RCSResourceAttributes&& attrs) :
192                 m_properties { properties },
193                 m_resourceHandle{ },
194                 m_resourceAttributes{ std::move(attrs) },
195                 m_getRequestHandler{ },
196                 m_setRequestHandler{ },
197                 m_autoNotifyPolicy { AutoNotifyPolicy::UPDATED },
198                 m_setRequestHandlerPolicy { SetRequestHandlerPolicy::NEVER },
199                 m_attributeUpdatedListeners{ },
200                 m_lockOwner{ },
201                 m_mutex{ },
202                 m_mutexAttributeUpdatedListeners{ }
203         {
204             m_lockOwner.reset(new AtomicThreadId);
205         }
206
207         RCSResourceObject::~RCSResourceObject()
208         {
209             if (m_resourceHandle)
210             {
211                 try
212                 {
213                     OC::OCPlatform::unregisterResource(m_resourceHandle);
214                 }
215                 catch (...)
216                 {
217                     OC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
218                 }
219             }
220         }
221
222         template< typename K, typename V >
223         void RCSResourceObject::setAttributeInternal(K&& key, V&& value)
224         {
225             bool needToNotify = false;
226             bool valueUpdated = false;
227
228             {
229                 WeakGuard lock(*this);
230
231                 if (lock.hasLocked())
232                 {
233                     needToNotify = true;
234                     valueUpdated = testValueUpdated(key, value);
235                 }
236
237                 m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value);
238             }
239
240             if (needToNotify) autoNotify(valueUpdated);
241         }
242         void RCSResourceObject::setAttribute(const std::string& key,
243                 const RCSResourceAttributes::Value& value)
244         {
245             setAttributeInternal(key, value);
246         }
247
248         void RCSResourceObject::setAttribute(const std::string& key,
249                 RCSResourceAttributes::Value&& value)
250         {
251             setAttributeInternal(key, std::move(value));
252         }
253
254         void RCSResourceObject::setAttribute(std::string&& key,
255                 const RCSResourceAttributes::Value& value)
256         {
257             setAttributeInternal(std::move(key), value);
258         }
259
260         void RCSResourceObject::setAttribute(std::string&& key,
261                 RCSResourceAttributes::Value&& value)
262         {
263             setAttributeInternal(std::move(key), std::move(value));
264         }
265
266         RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
267                 const std::string& key) const
268         {
269             WeakGuard lock(*this);
270             return m_resourceAttributes.at(key);
271         }
272
273         bool RCSResourceObject::removeAttribute(const std::string& key)
274         {
275             bool needToNotify = false;
276             bool erased = false;
277             {
278                 WeakGuard lock(*this);
279
280                 if (m_resourceAttributes.erase(key))
281                 {
282                     erased = true;
283                     needToNotify = lock.hasLocked();
284                 }
285             }
286
287             if (needToNotify) autoNotify(true);
288
289             return erased;
290         }
291
292         bool RCSResourceObject::containsAttribute(const std::string& key) const
293         {
294             WeakGuard lock(*this);
295             return m_resourceAttributes.contains(key);
296         }
297
298         RCSResourceAttributes& RCSResourceObject::getAttributes()
299         {
300             expectOwnLock();
301             return m_resourceAttributes;
302         }
303
304         const RCSResourceAttributes& RCSResourceObject::getAttributes() const
305         {
306             expectOwnLock();
307             return m_resourceAttributes;
308         }
309
310         void RCSResourceObject::expectOwnLock() const
311         {
312             if (getLockOwner() != std::this_thread::get_id())
313             {
314                 throw NoLockException{ "Must acquire the lock first using LockGuard." };
315             }
316         }
317
318         std::thread::id RCSResourceObject::getLockOwner() const noexcept
319         {
320             return *m_lockOwner;
321         }
322
323         void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept
324         {
325             m_lockOwner->store(std::move(id));
326         }
327
328         bool RCSResourceObject::isObservable() const
329         {
330             return ::hasProperty(m_properties, OC_OBSERVABLE);
331         }
332
333         bool RCSResourceObject::isDiscoverable() const
334         {
335             return ::hasProperty(m_properties, OC_DISCOVERABLE);
336         }
337
338         void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
339         {
340             m_getRequestHandler = std::move(h);
341         }
342
343         void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
344         {
345             m_setRequestHandler = std::move(h);
346         }
347
348         void RCSResourceObject::notify() const
349         {
350             typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
351
352             invokeOCFuncWithResultExpect({ OC_STACK_OK, OC_STACK_NO_OBSERVERS },
353                     static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
354                     m_resourceHandle);
355         }
356
357         void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
358                 AttributeUpdatedListener h)
359         {
360             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
361
362             m_attributeUpdatedListeners[key] =
363                     std::make_shared< AttributeUpdatedListener >(std::move(h));
364         }
365
366         void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
367                 AttributeUpdatedListener h)
368         {
369             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
370
371             m_attributeUpdatedListeners[std::move(key)] =
372                     std::make_shared< AttributeUpdatedListener >(std::move(h));
373         }
374
375         bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
376         {
377             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
378
379             return m_attributeUpdatedListeners.erase(key) != 0;
380         }
381
382         bool RCSResourceObject::testValueUpdated(const std::string& key,
383                 const RCSResourceAttributes::Value& value) const
384         {
385             return m_resourceAttributes.contains(key) == false
386                     || m_resourceAttributes.at(key) != value;
387         }
388
389         void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
390         {
391             m_autoNotifyPolicy = policy;
392         }
393
394         RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
395         {
396             return m_autoNotifyPolicy;
397         }
398
399         void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
400         {
401             m_setRequestHandlerPolicy = policy;
402         }
403
404         auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
405         {
406             return m_setRequestHandlerPolicy;
407         }
408
409         void RCSResourceObject::autoNotify(bool isAttributesChanged) const
410         {
411             autoNotify(isAttributesChanged, m_autoNotifyPolicy);
412         }
413
414         void RCSResourceObject::autoNotify(
415                         bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
416         {
417             if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
418             if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED &&
419                     isAttributesChanged == false) return;
420
421             notify();
422         }
423
424         OCEntityHandlerResult RCSResourceObject::entityHandler(
425                 std::shared_ptr< OC::OCResourceRequest > request)
426         {
427             OC_LOG(WARNING, LOG_TAG, "entityHandler");
428             if (!request)
429             {
430                 return OC_EH_ERROR;
431             }
432
433             try
434             {
435                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
436                 {
437                     return handleRequest(request);
438                 }
439
440                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
441                 {
442                     return handleObserve(request);
443                 }
444             }
445             catch (const std::exception& e)
446             {
447                 OC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
448                 throw;
449             }
450             catch (...)
451             {
452                 OC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
453                 throw;
454             }
455
456             return OC_EH_ERROR;
457         }
458
459         OCEntityHandlerResult RCSResourceObject::handleRequest(
460                 std::shared_ptr< OC::OCResourceRequest > request)
461         {
462             assert(request != nullptr);
463
464             if (request->getRequestType() == "GET")
465             {
466                 return handleRequestGet(request);
467             }
468
469             if (request->getRequestType() == "PUT")
470             {
471                 return handleRequestSet(request);
472             }
473
474             return OC_EH_ERROR;
475         }
476
477         OCEntityHandlerResult RCSResourceObject::handleRequestGet(
478                 std::shared_ptr< OC::OCResourceRequest > request)
479         {
480             assert(request != nullptr);
481
482             auto attrs = getAttributesFromOCRequest(request);
483
484             return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler));
485         }
486
487         bool RCSResourceObject::applyAcceptanceMethod(const RCSSetResponse& response,
488                 const RCSResourceAttributes& requstAttrs)
489         {
490             auto requestHandler = response.getHandler();
491
492             assert(requestHandler != nullptr);
493
494             auto replaced = requestHandler->applyAcceptanceMethod(response.getAcceptanceMethod(),
495                     *this, requstAttrs);
496
497             OC_LOG_V(WARNING, LOG_TAG, "replaced num %d", replaced.size());
498             for (const auto& attrKeyValPair : replaced)
499             {
500                 std::shared_ptr< AttributeUpdatedListener > foundListener;
501                 {
502                     std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
503
504                     auto it = m_attributeUpdatedListeners.find(attrKeyValPair.first);
505                     if (it != m_attributeUpdatedListeners.end())
506                     {
507                         foundListener = it->second;
508                     }
509                 }
510
511                 if (foundListener)
512                 {
513                     (*foundListener)(attrKeyValPair.second, requstAttrs.at(attrKeyValPair.first));
514                 }
515             }
516
517             return !replaced.empty();
518         }
519
520         OCEntityHandlerResult RCSResourceObject::handleRequestSet(
521                 std::shared_ptr< OC::OCResourceRequest > request)
522         {
523             assert(request != nullptr);
524
525             auto attrs = getAttributesFromOCRequest(request);
526             auto response = invokeHandler(attrs, request, m_setRequestHandler);
527
528             auto attrsChanged = applyAcceptanceMethod(response, attrs);
529
530             try
531             {
532                 autoNotify(attrsChanged, m_autoNotifyPolicy);
533                 return sendResponse(*this, request, response);
534             } catch (const RCSPlatformException& e) {
535                 OC_LOG_V(ERROR, LOG_TAG, "Error : %s ", e.what());
536                 return OC_EH_ERROR;
537             }
538         }
539
540         OCEntityHandlerResult RCSResourceObject::handleObserve(
541                 std::shared_ptr< OC::OCResourceRequest >)
542         {
543             if (!isObservable())
544             {
545                 return OC_EH_ERROR;
546             }
547
548             return OC_EH_OK;
549         }
550
551         RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
552                 m_resourceObject(*ptr),
553                 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
554                 m_isOwningLock{ false }
555         {
556             init();
557         }
558
559         RCSResourceObject::LockGuard::LockGuard(
560                 const RCSResourceObject& serverResource) :
561                 m_resourceObject(serverResource),
562                 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
563                 m_isOwningLock{ false }
564         {
565             init();
566         }
567
568         RCSResourceObject::LockGuard::LockGuard(
569                 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
570                 m_resourceObject(*ptr),
571                 m_autoNotifyPolicy { autoNotifyPolicy },
572                 m_isOwningLock{ false }
573         {
574             init();
575         }
576
577         RCSResourceObject::LockGuard::LockGuard(
578                 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
579                 m_resourceObject(resourceObject),
580                 m_autoNotifyPolicy { autoNotifyPolicy },
581                 m_isOwningLock{ false }
582         {
583             init();
584         }
585
586         RCSResourceObject::LockGuard::~LockGuard()
587         {
588             if (m_autoNotifyFunc) m_autoNotifyFunc();
589
590             if (m_isOwningLock)
591             {
592                 m_resourceObject.setLockOwner(std::thread::id{ });
593                 m_resourceObject.m_mutex.unlock();
594             }
595         }
596
597         void RCSResourceObject::LockGuard::init()
598         {
599             if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
600             {
601                 m_resourceObject.m_mutex.lock();
602                 m_resourceObject.setLockOwner(std::this_thread::get_id());
603                 m_isOwningLock = true;
604             }
605             m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
606                     m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
607         }
608
609         RCSResourceObject::WeakGuard::WeakGuard(
610                 const RCSResourceObject& resourceObject) :
611                 m_isOwningLock{ false },
612                 m_resourceObject(resourceObject)
613         {
614             if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
615             {
616                 m_resourceObject.m_mutex.lock();
617                 m_resourceObject.setLockOwner(std::this_thread::get_id());
618                 m_isOwningLock = true;
619             }
620         }
621
622         RCSResourceObject::WeakGuard::~WeakGuard()
623         {
624             if (m_isOwningLock)
625             {
626                 m_resourceObject.setLockOwner(std::thread::id{ });
627                 m_resourceObject.m_mutex.unlock();
628             }
629         }
630
631         bool RCSResourceObject::WeakGuard::hasLocked() const
632         {
633             return m_isOwningLock;
634         }
635
636     }
637 }