Merge branch 'master' into group-manager
[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 #include "RCSRequest.h"
33 #include "RCSRepresentation.h"
34
35 #include "logger.h"
36 #include "OCPlatform.h"
37
38 #define LOG_TAG "RCSResourceObject"
39
40 namespace
41 {
42     using namespace OIC::Service;
43
44     inline bool hasProperty(uint8_t base, uint8_t target)
45     {
46         return (base & target) == target;
47     }
48
49     inline uint8_t makePropertyFlags(uint8_t base, uint8_t target, bool add)
50     {
51         if (add)
52         {
53             return base | target;
54         }
55
56         return base & ~target;
57     }
58
59     inline bool requestContainsInterface(const std::shared_ptr< OC::OCResourceRequest >& request,
60             const std::string& interface)
61     {
62         return request->getQueryParameters().find(interface) != request->getQueryParameters().end();
63     }
64
65     OCEntityHandlerResult sendResponse(const std::shared_ptr< OC::OCResourceRequest >& ocRequest,
66             const std::shared_ptr< OC::OCResourceResponse >& ocResponse)
67     {
68         ocResponse->setRequestHandle(ocRequest->getRequestHandle());
69         ocResponse->setResourceHandle(ocRequest->getResourceHandle());
70
71         try
72         {
73             if (OC::OCPlatform::sendResponse(ocResponse) == OC_STACK_OK)
74             {
75                 return OC_EH_OK;
76             }
77         }
78         catch (const OC::OCException& e)
79         {
80             OIC_LOG_V(WARNING, LOG_TAG, "Error (%s)", e.what());
81         }
82
83         return OC_EH_ERROR;
84     }
85
86
87     template <typename RESPONSE>
88     OCEntityHandlerResult sendResponse(RCSResourceObject& resource,
89             const std::shared_ptr< OC::OCResourceRequest >& ocRequest, RESPONSE&& response)
90     {
91         return sendResponse(ocRequest, response.getHandler()->buildResponse(resource));
92     }
93
94     RCSResourceAttributes getAttributesFromOCRequest(
95             const std::shared_ptr< OC::OCResourceRequest >& request)
96     {
97         return ResourceAttributesConverter::fromOCRepresentation(
98                 request->getResourceRepresentation());
99     }
100
101     template< typename HANDLER, typename RESPONSE =
102             typename std::decay<HANDLER>::type::result_type >
103     RESPONSE invokeHandler(const RCSResourceObject::Ptr& resObj, RCSResourceAttributes& attrs,
104             const std::shared_ptr< OC::OCResourceRequest >& ocRequest,
105             std::shared_ptr< HANDLER > handler)
106     {
107         if (handler)
108         {
109             return (*handler)(RCSRequest{ resObj, ocRequest }, attrs);
110         }
111
112         return RESPONSE::defaultAction();
113     }
114
115     typedef void (RCSResourceObject::* AutoNotifyFunc)
116             (bool, RCSResourceObject::AutoNotifyPolicy) const;
117
118     std::function<void()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
119             const RCSResourceObject& resourceObject, const RCSResourceAttributes& resourceAttributes,
120             RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
121     {
122         if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::UPDATED)
123         {
124             auto&& compareAttributesFunc =
125                     std::bind(std::not_equal_to<RCSResourceAttributes>(),
126                                 resourceAttributes,
127                                 std::cref(resourceAttributes));
128             return std::bind(autoNotifyFunc,
129                     &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
130         }
131         else if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::ALWAYS)
132         {
133             return std::bind(autoNotifyFunc,
134                     &resourceObject, true, autoNotifyPolicy);
135         }
136         return {};
137     }
138
139     OCEntityHandlerResult handleBatchInterfaceGetRequest(
140             const std::shared_ptr< OC::OCResourceRequest >& request,
141             const RCSResourceObject* resourceObject)
142     {
143         auto rcsRep = resourceObject->toRepresentation();
144
145         for (const auto& bound : resourceObject->getBoundResources())
146         {
147             rcsRep.addChild(bound->toRepresentation());
148         }
149
150         auto response = std::make_shared< OC::OCResourceResponse >();
151
152         response->setResponseResult(OC_EH_OK);
153         response->setErrorCode(200);
154         response->setResourceRepresentation(
155                 RCSRepresentation::toOCRepresentation(std::move(rcsRep)));
156
157         return sendResponse(request, response);
158     }
159
160 } // unnamed namespace
161
162 namespace OIC
163 {
164     namespace Service
165     {
166
167         RCSResourceObject::Builder::Builder(const std::string& uri, const std::string& type,
168                 const std::string& interface) :
169                 m_uri{ uri },
170                 m_types{ type },
171                 m_interfaces{ interface },
172                 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
173                 m_resourceAttributes{ }
174         {
175         }
176
177         RCSResourceObject::Builder& RCSResourceObject::Builder::addInterface(
178                 const std::string& interface)
179         {
180             return addInterface(std::string{ interface });
181         }
182
183         RCSResourceObject::Builder& RCSResourceObject::Builder::addInterface(
184                 std::string&& interface)
185         {
186             m_interfaces.push_back(std::move(interface));
187             return *this;
188         }
189
190         RCSResourceObject::Builder& RCSResourceObject::Builder::addType(const std::string& type)
191         {
192             return addType(std::string{ type });
193         }
194
195         RCSResourceObject::Builder& RCSResourceObject::Builder::addType(std::string&& type)
196         {
197             m_types.push_back(std::move(type));
198             return *this;
199         }
200
201         RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable(
202                 bool discoverable)
203         {
204             m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
205             return *this;
206         }
207
208         RCSResourceObject::Builder& RCSResourceObject::Builder::setObservable(
209                 bool observable)
210         {
211             m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
212             return *this;
213         }
214
215         RCSResourceObject::Builder& RCSResourceObject::Builder::setSecureFlag(
216             bool secureFlag)
217         {
218             m_properties = ::makePropertyFlags(m_properties, OC_SECURE, secureFlag);
219             return *this;
220         }
221         RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
222                 const RCSResourceAttributes& attrs)
223         {
224             m_resourceAttributes = attrs;
225             return *this;
226         }
227
228         RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
229                 RCSResourceAttributes&& attrs)
230         {
231             m_resourceAttributes = std::move(attrs);
232             return *this;
233         }
234
235         RCSResourceObject::Ptr RCSResourceObject::Builder::build()
236         {
237             OCResourceHandle handle{ nullptr };
238
239             RCSResourceObject::Ptr server {
240                 new RCSResourceObject{ m_uri, m_properties, std::move(m_resourceAttributes) } };
241
242             OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler,
243                     std::weak_ptr< RCSResourceObject >{ server }, std::placeholders::_1) };
244
245             typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
246                     const std::string&, const std::string&, OC::EntityHandler, uint8_t);
247
248             invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
249                     handle, m_uri, m_types[0], m_interfaces[0], entityHandler, m_properties);
250
251             std::for_each(m_interfaces.begin() + 1, m_interfaces.end(),
252                     [&handle](const std::string& interfaceName){
253                 invokeOCFunc(OC::OCPlatform::bindInterfaceToResource, handle, interfaceName);
254             });
255
256             std::for_each(m_types.begin() + 1, m_types.end(),
257                     [&handle](const std::string& typeName){
258                 invokeOCFunc(OC::OCPlatform::bindTypeToResource, handle, typeName);
259             });
260
261             server->m_resourceHandle = handle;
262             server->m_interfaces = m_interfaces;
263             server->m_types = m_types;
264
265             return server;
266         }
267
268
269         RCSResourceObject::RCSResourceObject(const std::string& uri,
270                 uint8_t properties, RCSResourceAttributes&& attrs) :
271                 m_properties{ properties },
272                 m_uri{ uri },
273                 m_interfaces{ },
274                 m_types{ },
275                 m_resourceHandle{ },
276                 m_resourceAttributes{ std::move(attrs) },
277                 m_getRequestHandler{ },
278                 m_setRequestHandler{ },
279                 m_autoNotifyPolicy{ AutoNotifyPolicy::UPDATED },
280                 m_setRequestHandlerPolicy{ SetRequestHandlerPolicy::NEVER },
281                 m_attributeUpdatedListeners{ },
282                 m_lockOwner{ },
283                 m_mutex{ },
284                 m_mutexAttributeUpdatedListeners{ }
285         {
286             m_lockOwner.reset(new AtomicThreadId);
287         }
288
289         RCSResourceObject::~RCSResourceObject()
290         {
291             if (m_resourceHandle)
292             {
293                 try
294                 {
295                     OC::OCPlatform::unregisterResource(m_resourceHandle);
296                 }
297                 catch (...)
298                 {
299                     OIC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
300                 }
301             }
302         }
303
304         template< typename K, typename V >
305         void RCSResourceObject::setAttributeInternal(K&& key, V&& value)
306         {
307             bool needToNotify = false;
308             bool valueUpdated = false;
309
310             {
311                 WeakGuard lock(*this);
312
313                 if (lock.hasLocked())
314                 {
315                     needToNotify = true;
316                     valueUpdated = testValueUpdated(key, value);
317                 }
318
319                 m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value);
320             }
321
322             if (needToNotify) autoNotify(valueUpdated);
323         }
324         void RCSResourceObject::setAttribute(const std::string& key,
325                 const RCSResourceAttributes::Value& value)
326         {
327             setAttributeInternal(key, value);
328         }
329
330         void RCSResourceObject::setAttribute(const std::string& key,
331                 RCSResourceAttributes::Value&& value)
332         {
333             setAttributeInternal(key, std::move(value));
334         }
335
336         void RCSResourceObject::setAttribute(std::string&& key,
337                 const RCSResourceAttributes::Value& value)
338         {
339             setAttributeInternal(std::move(key), value);
340         }
341
342         void RCSResourceObject::setAttribute(std::string&& key,
343                 RCSResourceAttributes::Value&& value)
344         {
345             setAttributeInternal(std::move(key), std::move(value));
346         }
347
348         RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
349                 const std::string& key) const
350         {
351             WeakGuard lock(*this);
352             return m_resourceAttributes.at(key);
353         }
354
355         bool RCSResourceObject::removeAttribute(const std::string& key)
356         {
357             bool needToNotify = false;
358             bool erased = false;
359             {
360                 WeakGuard lock(*this);
361
362                 if (m_resourceAttributes.erase(key))
363                 {
364                     erased = true;
365                     needToNotify = lock.hasLocked();
366                 }
367             }
368
369             if (needToNotify) autoNotify(true);
370
371             return erased;
372         }
373
374         bool RCSResourceObject::containsAttribute(const std::string& key) const
375         {
376             WeakGuard lock(*this);
377             return m_resourceAttributes.contains(key);
378         }
379
380         RCSResourceAttributes& RCSResourceObject::getAttributes()
381         {
382             expectOwnLock();
383             return m_resourceAttributes;
384         }
385
386         const RCSResourceAttributes& RCSResourceObject::getAttributes() const
387         {
388             expectOwnLock();
389             return m_resourceAttributes;
390         }
391
392         void RCSResourceObject::expectOwnLock() const
393         {
394             if (getLockOwner() != std::this_thread::get_id())
395             {
396                 throw NoLockException{ "Must acquire the lock first using LockGuard." };
397             }
398         }
399
400         std::thread::id RCSResourceObject::getLockOwner() const noexcept
401         {
402             return *m_lockOwner;
403         }
404
405         void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept
406         {
407             m_lockOwner->store(std::move(id));
408         }
409
410         bool RCSResourceObject::isObservable() const
411         {
412             return ::hasProperty(m_properties, OC_OBSERVABLE);
413         }
414
415         bool RCSResourceObject::isDiscoverable() const
416         {
417             return ::hasProperty(m_properties, OC_DISCOVERABLE);
418         }
419
420         void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
421         {
422             m_getRequestHandler = std::make_shared< GetRequestHandler >(std::move(h));
423         }
424
425         void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
426         {
427             m_setRequestHandler = std::make_shared< SetRequestHandler >(std::move(h));
428         }
429
430         void RCSResourceObject::notify() const
431         {
432             typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
433
434             invokeOCFuncWithResultExpect({ OC_STACK_OK, OC_STACK_NO_OBSERVERS },
435                     static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
436                     m_resourceHandle);
437         }
438
439         void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
440                 AttributeUpdatedListener h)
441         {
442             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
443
444             m_attributeUpdatedListeners[key] =
445                     std::make_shared< AttributeUpdatedListener >(std::move(h));
446         }
447
448         void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
449                 AttributeUpdatedListener h)
450         {
451             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
452
453             m_attributeUpdatedListeners[std::move(key)] =
454                     std::make_shared< AttributeUpdatedListener >(std::move(h));
455         }
456
457         bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
458         {
459             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
460
461             return m_attributeUpdatedListeners.erase(key) != 0;
462         }
463
464         bool RCSResourceObject::testValueUpdated(const std::string& key,
465                 const RCSResourceAttributes::Value& value) const
466         {
467             return m_resourceAttributes.contains(key) == false
468                     || m_resourceAttributes.at(key) != value;
469         }
470
471         void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
472         {
473             m_autoNotifyPolicy = policy;
474         }
475
476         RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
477         {
478             return m_autoNotifyPolicy;
479         }
480
481         void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
482         {
483             m_setRequestHandlerPolicy = policy;
484         }
485
486         auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
487         {
488             return m_setRequestHandlerPolicy;
489         }
490
491         void RCSResourceObject::bindResource(const RCSResourceObject::Ptr& resource)
492         {
493             if (!resource || resource.get() == this)
494             {
495                 throw RCSInvalidParameterException("The resource is invalid!");
496             }
497
498             invokeOCFunc(OC::OCPlatform::bindResource,
499                     m_resourceHandle, resource->m_resourceHandle);
500
501             std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
502             m_boundResources.push_back(resource);
503         }
504
505         void RCSResourceObject::unbindResource(const RCSResourceObject::Ptr& resource)
506         {
507             if (!resource || resource.get() == this)
508             {
509                 throw RCSInvalidParameterException("The resource is invalid!");
510             }
511
512             invokeOCFunc(OC::OCPlatform::unbindResource,
513                     m_resourceHandle, resource->m_resourceHandle);
514
515             std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
516             m_boundResources.erase(std::find(m_boundResources.begin(), m_boundResources.end(),
517                     resource));
518         }
519
520         std::vector< RCSResourceObject::Ptr > RCSResourceObject::getBoundResources() const
521         {
522             std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
523             return m_boundResources;
524         }
525
526         std::vector< std::string > RCSResourceObject::getInterfaces() const
527         {
528             return m_interfaces;
529         }
530
531         std::vector< std::string > RCSResourceObject::getTypes() const
532         {
533             return m_types;
534         }
535
536         RCSRepresentation RCSResourceObject::toRepresentation() const
537         {
538             WeakGuard lock{*this};
539             return RCSRepresentation{ m_uri, m_interfaces, m_types, m_resourceAttributes };
540          }
541
542         void RCSResourceObject::autoNotify(bool isAttributesChanged) const
543         {
544             autoNotify(isAttributesChanged, m_autoNotifyPolicy);
545         }
546
547         void RCSResourceObject::autoNotify(
548                         bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
549         {
550             if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
551             if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED &&
552                     isAttributesChanged == false) return;
553
554             notify();
555         }
556
557         OCEntityHandlerResult RCSResourceObject::entityHandler(
558                 const std::weak_ptr< RCSResourceObject >& weakRes,
559                 const std::shared_ptr< OC::OCResourceRequest >& request)
560         {
561             auto resource = weakRes.lock();
562
563             if (!resource) return OC_EH_ERROR;
564
565             OIC_LOG(WARNING, LOG_TAG, "entityHandler");
566             if (!request)
567             {
568                 return OC_EH_ERROR;
569             }
570
571             try
572             {
573                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
574                 {
575                     return resource->handleRequest(request);
576                 }
577
578                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
579                 {
580                     return resource->handleObserve(request);
581                 }
582             }
583             catch (const std::exception& e)
584             {
585                 OIC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
586                 throw;
587             }
588             catch (...)
589             {
590                 OIC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
591                 throw;
592             }
593
594             return OC_EH_ERROR;
595         }
596
597         OCEntityHandlerResult RCSResourceObject::handleRequest(
598                 const std::shared_ptr< OC::OCResourceRequest >& request)
599         {
600             assert(request != nullptr);
601
602             if (request->getRequestType() == "GET")
603             {
604                 return handleRequestGet(request);
605             }
606
607             if (request->getRequestType() == "POST")
608             {
609                 return handleRequestSet(request);
610             }
611
612             return OC_EH_ERROR;
613         }
614
615         OCEntityHandlerResult RCSResourceObject::handleRequestGet(
616                 const std::shared_ptr< OC::OCResourceRequest >& request)
617         {
618             assert(request != nullptr);
619
620             if (requestContainsInterface(request, OC::BATCH_INTERFACE))
621             {
622                 return handleBatchInterfaceGetRequest(request, this);
623             }
624
625             auto attrs = getAttributesFromOCRequest(request);
626
627             auto response = invokeHandler(shared_from_this(), attrs, request, m_getRequestHandler);
628
629             if (response.isSeparate()) return OC_EH_SLOW;
630
631             return sendResponse(*this, request, response);
632         }
633
634         bool RCSResourceObject::applyAcceptanceMethod(const RCSSetResponse& response,
635                 const RCSResourceAttributes& requstAttrs)
636         {
637             auto requestHandler = response.getHandler();
638
639             assert(requestHandler != nullptr);
640
641             auto replaced = requestHandler->applyAcceptanceMethod(response.getAcceptanceMethod(),
642                     *this, requstAttrs);
643
644             OIC_LOG_V(WARNING, LOG_TAG, "replaced num %zu", replaced.size());
645             for (const auto& attrKeyValPair : replaced)
646             {
647                 std::shared_ptr< AttributeUpdatedListener > foundListener;
648                 {
649                     std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
650
651                     auto it = m_attributeUpdatedListeners.find(attrKeyValPair.first);
652                     if (it != m_attributeUpdatedListeners.end())
653                     {
654                         foundListener = it->second;
655                     }
656                 }
657
658                 if (foundListener)
659                 {
660                     (*foundListener)(attrKeyValPair.second, requstAttrs.at(attrKeyValPair.first));
661                 }
662             }
663
664             return !replaced.empty();
665         }
666
667         OCEntityHandlerResult RCSResourceObject::handleRequestSet(
668                 const std::shared_ptr< OC::OCResourceRequest >& request)
669         {
670             assert(request != nullptr);
671
672             auto attrs = getAttributesFromOCRequest(request);
673             auto response = invokeHandler(shared_from_this(), attrs, request, m_setRequestHandler);
674
675             if (response.isSeparate()) return OC_EH_SLOW;
676
677             auto attrsChanged = applyAcceptanceMethod(response, attrs);
678
679             try
680             {
681                 autoNotify(attrsChanged, m_autoNotifyPolicy);
682                 return sendResponse(*this, request, response);
683             } catch (const RCSPlatformException& e) {
684                 OIC_LOG_V(ERROR, LOG_TAG, "Error : %s ", e.what());
685                 return OC_EH_ERROR;
686             }
687         }
688
689         OCEntityHandlerResult RCSResourceObject::handleObserve(
690                 const std::shared_ptr< OC::OCResourceRequest >&)
691         {
692             if (!isObservable())
693             {
694                 return OC_EH_ERROR;
695             }
696
697             return OC_EH_OK;
698         }
699
700         RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
701                 m_resourceObject(*ptr),
702                 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
703                 m_isOwningLock{ false }
704         {
705             init();
706         }
707
708         RCSResourceObject::LockGuard::LockGuard(
709                 const RCSResourceObject& serverResource) :
710                 m_resourceObject(serverResource),
711                 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
712                 m_isOwningLock{ false }
713         {
714             init();
715         }
716
717         RCSResourceObject::LockGuard::LockGuard(
718                 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
719                 m_resourceObject(*ptr),
720                 m_autoNotifyPolicy { autoNotifyPolicy },
721                 m_isOwningLock{ false }
722         {
723             init();
724         }
725
726         RCSResourceObject::LockGuard::LockGuard(
727                 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
728                 m_resourceObject(resourceObject),
729                 m_autoNotifyPolicy { autoNotifyPolicy },
730                 m_isOwningLock{ false }
731         {
732             init();
733         }
734
735         RCSResourceObject::LockGuard::~LockGuard() noexcept(false)
736         {
737             if (!std::uncaught_exception() && m_autoNotifyFunc) m_autoNotifyFunc();
738
739             if (m_isOwningLock)
740             {
741                 m_resourceObject.setLockOwner(std::thread::id{ });
742                 m_resourceObject.m_mutex.unlock();
743             }
744         }
745
746         void RCSResourceObject::LockGuard::init()
747         {
748             if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
749             {
750                 m_resourceObject.m_mutex.lock();
751                 m_resourceObject.setLockOwner(std::this_thread::get_id());
752                 m_isOwningLock = true;
753             }
754             m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
755                     m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
756         }
757
758         RCSResourceObject::WeakGuard::WeakGuard(
759                 const RCSResourceObject& resourceObject) :
760                 m_isOwningLock{ false },
761                 m_resourceObject(resourceObject)
762         {
763             if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
764             {
765                 m_resourceObject.m_mutex.lock();
766                 m_resourceObject.setLockOwner(std::this_thread::get_id());
767                 m_isOwningLock = true;
768             }
769         }
770
771         RCSResourceObject::WeakGuard::~WeakGuard()
772         {
773             if (m_isOwningLock)
774             {
775                 m_resourceObject.setLockOwner(std::thread::id{ });
776                 m_resourceObject.m_mutex.unlock();
777             }
778         }
779
780         bool RCSResourceObject::WeakGuard::hasLocked() const
781         {
782             return m_isOwningLock;
783         }
784
785     }
786 }