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