Added bind apis to 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         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(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{ ocRequest->getResourceUri() }, 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                     server.get(), 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
262             server->m_resourceHandle = handle;
263             server->m_interfaces = m_interfaces;
264             server->m_types = m_types;
265
266             return server;
267         }
268
269
270         RCSResourceObject::RCSResourceObject(const std::string& uri,
271                 uint8_t properties, RCSResourceAttributes&& attrs) :
272                 m_properties{ properties },
273                 m_uri{ uri },
274                 m_interfaces{ },
275                 m_types{ },
276                 m_resourceHandle{ },
277                 m_resourceAttributes{ std::move(attrs) },
278                 m_getRequestHandler{ },
279                 m_setRequestHandler{ },
280                 m_autoNotifyPolicy{ AutoNotifyPolicy::UPDATED },
281                 m_setRequestHandlerPolicy{ SetRequestHandlerPolicy::NEVER },
282                 m_attributeUpdatedListeners{ },
283                 m_lockOwner{ },
284                 m_mutex{ },
285                 m_mutexAttributeUpdatedListeners{ }
286         {
287             m_lockOwner.reset(new AtomicThreadId);
288         }
289
290         RCSResourceObject::~RCSResourceObject()
291         {
292             if (m_resourceHandle)
293             {
294                 try
295                 {
296                     OC::OCPlatform::unregisterResource(m_resourceHandle);
297                 }
298                 catch (...)
299                 {
300                     OIC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
301                 }
302             }
303         }
304
305         template< typename K, typename V >
306         void RCSResourceObject::setAttributeInternal(K&& key, V&& value)
307         {
308             bool needToNotify = false;
309             bool valueUpdated = false;
310
311             {
312                 WeakGuard lock(*this);
313
314                 if (lock.hasLocked())
315                 {
316                     needToNotify = true;
317                     valueUpdated = testValueUpdated(key, value);
318                 }
319
320                 m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value);
321             }
322
323             if (needToNotify) autoNotify(valueUpdated);
324         }
325         void RCSResourceObject::setAttribute(const std::string& key,
326                 const RCSResourceAttributes::Value& value)
327         {
328             setAttributeInternal(key, value);
329         }
330
331         void RCSResourceObject::setAttribute(const std::string& key,
332                 RCSResourceAttributes::Value&& value)
333         {
334             setAttributeInternal(key, std::move(value));
335         }
336
337         void RCSResourceObject::setAttribute(std::string&& key,
338                 const RCSResourceAttributes::Value& value)
339         {
340             setAttributeInternal(std::move(key), value);
341         }
342
343         void RCSResourceObject::setAttribute(std::string&& key,
344                 RCSResourceAttributes::Value&& value)
345         {
346             setAttributeInternal(std::move(key), std::move(value));
347         }
348
349         RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
350                 const std::string& key) const
351         {
352             WeakGuard lock(*this);
353             return m_resourceAttributes.at(key);
354         }
355
356         bool RCSResourceObject::removeAttribute(const std::string& key)
357         {
358             bool needToNotify = false;
359             bool erased = false;
360             {
361                 WeakGuard lock(*this);
362
363                 if (m_resourceAttributes.erase(key))
364                 {
365                     erased = true;
366                     needToNotify = lock.hasLocked();
367                 }
368             }
369
370             if (needToNotify) autoNotify(true);
371
372             return erased;
373         }
374
375         bool RCSResourceObject::containsAttribute(const std::string& key) const
376         {
377             WeakGuard lock(*this);
378             return m_resourceAttributes.contains(key);
379         }
380
381         RCSResourceAttributes& RCSResourceObject::getAttributes()
382         {
383             expectOwnLock();
384             return m_resourceAttributes;
385         }
386
387         const RCSResourceAttributes& RCSResourceObject::getAttributes() const
388         {
389             expectOwnLock();
390             return m_resourceAttributes;
391         }
392
393         void RCSResourceObject::expectOwnLock() const
394         {
395             if (getLockOwner() != std::this_thread::get_id())
396             {
397                 throw NoLockException{ "Must acquire the lock first using LockGuard." };
398             }
399         }
400
401         std::thread::id RCSResourceObject::getLockOwner() const noexcept
402         {
403             return *m_lockOwner;
404         }
405
406         void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept
407         {
408             m_lockOwner->store(std::move(id));
409         }
410
411         bool RCSResourceObject::isObservable() const
412         {
413             return ::hasProperty(m_properties, OC_OBSERVABLE);
414         }
415
416         bool RCSResourceObject::isDiscoverable() const
417         {
418             return ::hasProperty(m_properties, OC_DISCOVERABLE);
419         }
420
421         void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
422         {
423             m_getRequestHandler = std::make_shared< GetRequestHandler >(std::move(h));
424         }
425
426         void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
427         {
428             m_setRequestHandler = std::make_shared< SetRequestHandler >(std::move(h));
429         }
430
431         void RCSResourceObject::notify() const
432         {
433             typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
434
435             invokeOCFuncWithResultExpect({ OC_STACK_OK, OC_STACK_NO_OBSERVERS },
436                     static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
437                     m_resourceHandle);
438         }
439
440         void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
441                 AttributeUpdatedListener h)
442         {
443             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
444
445             m_attributeUpdatedListeners[key] =
446                     std::make_shared< AttributeUpdatedListener >(std::move(h));
447         }
448
449         void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
450                 AttributeUpdatedListener h)
451         {
452             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
453
454             m_attributeUpdatedListeners[std::move(key)] =
455                     std::make_shared< AttributeUpdatedListener >(std::move(h));
456         }
457
458         bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
459         {
460             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
461
462             return m_attributeUpdatedListeners.erase(key) != 0;
463         }
464
465         bool RCSResourceObject::testValueUpdated(const std::string& key,
466                 const RCSResourceAttributes::Value& value) const
467         {
468             return m_resourceAttributes.contains(key) == false
469                     || m_resourceAttributes.at(key) != value;
470         }
471
472         void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
473         {
474             m_autoNotifyPolicy = policy;
475         }
476
477         RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
478         {
479             return m_autoNotifyPolicy;
480         }
481
482         void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
483         {
484             m_setRequestHandlerPolicy = policy;
485         }
486
487         auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
488         {
489             return m_setRequestHandlerPolicy;
490         }
491
492         void RCSResourceObject::bindResource(const RCSResourceObject::Ptr& resource)
493         {
494             if (!resource || resource.get() == this)
495             {
496                 throw RCSInvalidParameterException("The resource is invalid!");
497             }
498
499             invokeOCFunc(OC::OCPlatform::bindResource,
500                     m_resourceHandle, resource->m_resourceHandle);
501
502             std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
503             m_boundResources.push_back(resource);
504         }
505
506         void RCSResourceObject::unbindResource(const RCSResourceObject::Ptr& resource)
507         {
508             if (!resource || resource.get() == this)
509             {
510                 throw RCSInvalidParameterException("The resource is invalid!");
511             }
512
513             invokeOCFunc(OC::OCPlatform::unbindResource,
514                     m_resourceHandle, resource->m_resourceHandle);
515
516             std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
517             m_boundResources.erase(std::find(m_boundResources.begin(), m_boundResources.end(),
518                     resource));
519         }
520
521         std::vector< RCSResourceObject::Ptr > RCSResourceObject::getBoundResources() const
522         {
523             std::lock_guard< std:: mutex > lock{ m_mutexForBoundResources };
524             return m_boundResources;
525         }
526
527         std::vector< std::string > RCSResourceObject::getInterfaces() const
528         {
529             return m_interfaces;
530         }
531
532         std::vector< std::string > RCSResourceObject::getTypes() const
533         {
534             return m_types;
535         }
536
537         RCSRepresentation RCSResourceObject::toRepresentation() const
538         {
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::shared_ptr< OC::OCResourceRequest >& request)
559         {
560             OIC_LOG(WARNING, LOG_TAG, "entityHandler");
561             if (!request)
562             {
563                 return OC_EH_ERROR;
564             }
565
566             try
567             {
568                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
569                 {
570                     return handleRequest(request);
571                 }
572
573                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
574                 {
575                     return handleObserve(request);
576                 }
577             }
578             catch (const std::exception& e)
579             {
580                 OIC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
581                 throw;
582             }
583             catch (...)
584             {
585                 OIC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
586                 throw;
587             }
588
589             return OC_EH_ERROR;
590         }
591
592         OCEntityHandlerResult RCSResourceObject::handleRequest(
593                 const std::shared_ptr< OC::OCResourceRequest >& request)
594         {
595             assert(request != nullptr);
596
597             if (request->getRequestType() == "GET")
598             {
599                 return handleRequestGet(request);
600             }
601
602             if (request->getRequestType() == "POST")
603             {
604                 return handleRequestSet(request);
605             }
606
607             return OC_EH_ERROR;
608         }
609
610         OCEntityHandlerResult RCSResourceObject::handleRequestGet(
611                 const std::shared_ptr< OC::OCResourceRequest >& request)
612         {
613             assert(request != nullptr);
614
615             if (requestContainsInterface(request, OC::BATCH_INTERFACE))
616             {
617                 return handleBatchInterfaceGetRequest(request, this);
618             }
619
620             auto attrs = getAttributesFromOCRequest(request);
621
622             return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler));
623         }
624
625         bool RCSResourceObject::applyAcceptanceMethod(const RCSSetResponse& response,
626                 const RCSResourceAttributes& requstAttrs)
627         {
628             auto requestHandler = response.getHandler();
629
630             assert(requestHandler != nullptr);
631
632             auto replaced = requestHandler->applyAcceptanceMethod(response.getAcceptanceMethod(),
633                     *this, requstAttrs);
634
635             OIC_LOG_V(WARNING, LOG_TAG, "replaced num %zu", replaced.size());
636             for (const auto& attrKeyValPair : replaced)
637             {
638                 std::shared_ptr< AttributeUpdatedListener > foundListener;
639                 {
640                     std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
641
642                     auto it = m_attributeUpdatedListeners.find(attrKeyValPair.first);
643                     if (it != m_attributeUpdatedListeners.end())
644                     {
645                         foundListener = it->second;
646                     }
647                 }
648
649                 if (foundListener)
650                 {
651                     (*foundListener)(attrKeyValPair.second, requstAttrs.at(attrKeyValPair.first));
652                 }
653             }
654
655             return !replaced.empty();
656         }
657
658         OCEntityHandlerResult RCSResourceObject::handleRequestSet(
659                 const std::shared_ptr< OC::OCResourceRequest >& request)
660         {
661             assert(request != nullptr);
662
663             auto attrs = getAttributesFromOCRequest(request);
664             auto response = invokeHandler(attrs, request, m_setRequestHandler);
665
666             auto attrsChanged = applyAcceptanceMethod(response, attrs);
667
668             try
669             {
670                 autoNotify(attrsChanged, m_autoNotifyPolicy);
671                 return sendResponse(*this, request, response);
672             } catch (const RCSPlatformException& e) {
673                 OIC_LOG_V(ERROR, LOG_TAG, "Error : %s ", e.what());
674                 return OC_EH_ERROR;
675             }
676         }
677
678         OCEntityHandlerResult RCSResourceObject::handleObserve(
679                 const std::shared_ptr< OC::OCResourceRequest >&)
680         {
681             if (!isObservable())
682             {
683                 return OC_EH_ERROR;
684             }
685
686             return OC_EH_OK;
687         }
688
689         RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
690                 m_resourceObject(*ptr),
691                 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
692                 m_isOwningLock{ false }
693         {
694             init();
695         }
696
697         RCSResourceObject::LockGuard::LockGuard(
698                 const RCSResourceObject& serverResource) :
699                 m_resourceObject(serverResource),
700                 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
701                 m_isOwningLock{ false }
702         {
703             init();
704         }
705
706         RCSResourceObject::LockGuard::LockGuard(
707                 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
708                 m_resourceObject(*ptr),
709                 m_autoNotifyPolicy { autoNotifyPolicy },
710                 m_isOwningLock{ false }
711         {
712             init();
713         }
714
715         RCSResourceObject::LockGuard::LockGuard(
716                 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
717                 m_resourceObject(resourceObject),
718                 m_autoNotifyPolicy { autoNotifyPolicy },
719                 m_isOwningLock{ false }
720         {
721             init();
722         }
723
724         RCSResourceObject::LockGuard::~LockGuard() noexcept(false)
725         {
726             if (!std::uncaught_exception() && m_autoNotifyFunc) m_autoNotifyFunc();
727
728             if (m_isOwningLock)
729             {
730                 m_resourceObject.setLockOwner(std::thread::id{ });
731                 m_resourceObject.m_mutex.unlock();
732             }
733         }
734
735         void RCSResourceObject::LockGuard::init()
736         {
737             if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
738             {
739                 m_resourceObject.m_mutex.lock();
740                 m_resourceObject.setLockOwner(std::this_thread::get_id());
741                 m_isOwningLock = true;
742             }
743             m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
744                     m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
745         }
746
747         RCSResourceObject::WeakGuard::WeakGuard(
748                 const RCSResourceObject& resourceObject) :
749                 m_isOwningLock{ false },
750                 m_resourceObject(resourceObject)
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         }
759
760         RCSResourceObject::WeakGuard::~WeakGuard()
761         {
762             if (m_isOwningLock)
763             {
764                 m_resourceObject.setLockOwner(std::thread::id{ });
765                 m_resourceObject.m_mutex.unlock();
766             }
767         }
768
769         bool RCSResourceObject::WeakGuard::hasLocked() const
770         {
771             return m_isOwningLock;
772         }
773
774     }
775 }