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