1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
24 * This file contains the declaration of classes and its members related to RCSResourceObject
26 #ifndef SERVER_RCSRESOURCEOBJECT_H
27 #define SERVER_RCSRESOURCEOBJECT_H
34 #include "RCSResourceAttributes.h"
35 #include "RCSResponse.h"
39 class OCResourceRequest;
48 class RCSRepresentation;
49 class InterfaceHandler;
52 * @brief Thrown when lock has not been acquired.
54 * @see RCSResourceObject::LockGuard
55 * @see RCSResourceObject::getAttributes
57 class NoLockException: public RCSException
60 NoLockException(std::string what) : RCSException { std::move(what) } {}
64 template < typename T >
69 * This class represents a resource and handles any requests from clients
70 * automatically with attributes.
72 * It also provides an auto notification mechanism that notifies to the observers.
74 * Requests are handled automatically by defaultAction of RCSGetResponse and
75 * RCSSetResponse. You can override them and send your own response.
77 * For simple resources, they are simply required to notify whenever attributes are changed
78 * by a set request. In this case, add an AttributeUpdatedListener with a key interested
79 * in instead of overriding SetRequestHandler.
82 class RCSResourceObject
87 typedef AtomicWrapper< std::thread::id > AtomicThreadId;
91 * Represents the policy of auto-notify function.
92 * In accord with this policy, observers are notified of attributes
93 * when the attributes are set.
95 * @note Attributes are set according to the execution of some functions which
96 * modify attributes or receipt of set requests.
98 * @see RCSResourceObject::setAttribute
99 * @see RCSResourceObject::removeAttribute
100 * @see RCSResourceObject::getAttributes
101 * @see RCSResourceObject::LockGuard
103 enum class AutoNotifyPolicy
106 ALWAYS, /**< Always*/
107 UPDATED /**< Only when attributes are changed*/
111 * Represents the policy of set-request handler.
112 * In accord with this, the RCSResourceObject decides whether a set-request is
115 enum class SetRequestHandlerPolicy
117 NEVER, /**< Requests will be ignored if attributes of the request contain
118 a new key or a value that has different type from the current
120 ACCEPTANCE /**< The attributes of the request will be applied unconditionally
121 even if there are new name or type conflicts. */
124 typedef std::shared_ptr< RCSResourceObject > Ptr;
125 typedef std::shared_ptr< const RCSResourceObject > ConstPtr;
128 * This is a builder to create resource with properties and attributes.
130 * The resource will be observable and discoverable by default, to make them disable
131 * set these properties explicitly with setDiscoverable and setObservable.
133 * "oic.if.baseline" is an interface that a resource always holds, by default,
134 * even it is not added manually.
140 * Constructs a Builder.
142 * @param uri Resource uri
143 * @param type Resource type
144 * @param interface Resource interface
147 Builder(std::string uri, std::string type, std::string interface);
150 * Add an interface for the resource.
152 * @param interface new interface.
154 Builder& addInterface(std::string interface);
157 * Add a type for the resource.
159 * @param type new type.
161 Builder& addType(std::string type);
164 * Sets the default interface.
165 * If it is not called, the interface passed to the constructor is the default.
167 * @param interface default interface name
170 Builder& setDefaultInterface(std::string interface);
173 * Sets whether the resource is discoverable.
175 * @param discoverable whether to be discoverable.
178 Builder& setDiscoverable(bool discoverable);
181 * Sets the observable property of the resource.
183 * @param observable whether to be observable.
186 Builder& setObservable(bool observable);
189 * Sets whether the resource should be secure or not.
191 * @param secureFlag whether to be secure or not.
194 Builder& setSecureFlag(bool secureFlag);
197 * Sets attributes for the resource.
199 * @param attributes attributes to set
202 Builder& setAttributes(const RCSResourceAttributes &attributes);
207 Builder& setAttributes(RCSResourceAttributes &&attributes);
210 * Register a resource and returns a RCSResourceObject.
212 * @throw RCSPlatformException if resource registration is failed.
215 RCSResourceObject::Ptr build();
219 std::vector< std::string > m_types;
220 std::vector< std::string > m_interfaces;
221 std::string m_defaultInterface;
222 uint8_t m_properties;
223 RCSResourceAttributes m_resourceAttributes;
229 * Callback definition for a handler to be invoked when a get request is received.
231 * The handler will be called first when a get request is received, before the
232 * RCSResourceObject handles.
234 * @param request the request information
235 * @param attributes attributes of the request
237 * @return response to be sent and that indicates how the request to be handled by
238 * the RCSResourceObject.
240 * @see setGetRequestHandler
242 typedef std::function < RCSGetResponse(const RCSRequest& request,
243 RCSResourceAttributes& attributes) > GetRequestHandler;
246 * Callback definition for a handler to be invoked when a set request is received.
248 * The handler will be called first when a get request is received, before the
249 * RCSResourceObject handles. If the attributes are modified in the callback,
250 * the modified attributes will be set in the RCSResourceObject if the request is
253 * @param request the request information
254 * @param attributes attributes of the request
256 * @return response to be sent and that indicates how the request to be handled by
257 * the RCSResourceObject.
259 * @see setGetRequestHandler
261 typedef std::function < RCSSetResponse(const RCSRequest& request,
262 RCSResourceAttributes& attributes) > SetRequestHandler;
265 * Callback definition to be invoked when an attribute is updated.
267 * @param oldValue the value before being changed
268 * @param newValue changed value
270 typedef std::function < void(const RCSResourceAttributes::Value& oldValue,
271 const RCSResourceAttributes::Value& newValue) > AttributeUpdatedListener;
274 RCSResourceObject(RCSResourceObject&&) = delete;
275 RCSResourceObject(const RCSResourceObject&) = delete;
277 RCSResourceObject& operator=(RCSResourceObject&&) = delete;
278 RCSResourceObject& operator=(const RCSResourceObject&) = delete;
280 virtual ~RCSResourceObject();
283 * Sets a particular attribute value.
285 * @param key key of attribute
286 * @param value value to be mapped against the key
288 * @note Thread-safety is guaranteed for the attributes.
290 void setAttribute(const std::string& key, const RCSResourceAttributes::Value& value);
295 void setAttribute(const std::string& key, RCSResourceAttributes::Value&& value);
300 void setAttribute(std::string&& key, const RCSResourceAttributes::Value& value);
305 void setAttribute(std::string&& key, RCSResourceAttributes::Value&& value);
308 * Returns an attribute value corresponding to a key.
310 * @param key key of the attribute
312 * @throws RCSInvalidKeyException If key is invalid.
314 * @note Thread-safety is guaranteed for the attributes.
316 RCSResourceAttributes::Value getAttributeValue(const std::string& key) const;
319 * Returns the attribute value as T.
321 * @param key key of the attribute
323 * @throws RCSBadGetException If type of the underlying value is not T.
324 * @throws RCSInvalidKeyException If @a key doesn't match the key of any value.
326 * @note Thread-safety is guaranteed for the attributes.
328 template< typename T >
329 T getAttribute(const std::string& key) const
331 WeakGuard lock(*this);
332 return m_resourceAttributes.at(key).get< T >();
336 * Removes a particular attribute of the resource.
338 * @param key key of the attribute.
340 * @return True if the key exists and matched attribute is removed, otherwise false.
342 * @note Thread-safety is guaranteed for the attributes.
344 bool removeAttribute(const std::string& key);
347 * Checks whether a particular attribute exists or not.
349 * @param key key of the attribute
351 * @return True if the key exists, otherwise false.
353 * @note Thread-safety is guaranteed for the attributes.
355 bool containsAttribute(const std::string& key) const;
358 * Returns reference to the attributes of the RCSResourceObject.
360 * @pre The call must be guarded by LockGuard.
363 * @return Reference to the attributes
365 * @throws NoLockException If the call is not guarded by LockGuard.
367 * @note Here is the standard idiom for LockGuard:
370 RCSResourceObject::LockGuard lock(rcsResourceObject);
372 auto &attributes = server->getAttributes();
377 RCSResourceAttributes& getAttributes();
382 const RCSResourceAttributes& getAttributes() const;
385 * Checks whether the resource is observable or not.
387 virtual bool isObservable() const;
390 * Checks whether the resource is discoverable or not.
392 virtual bool isDiscoverable() const;
395 * Sets the get request handler.
396 * To remove handler, pass empty handler or nullptr.
398 * Default behavior is RCSGetResponse::defaultAction().
400 * @param handler a get request handler
402 * @see RCSGetResponse
405 virtual void setGetRequestHandler(GetRequestHandler handler);
408 * Sets the set request handler.
409 * To remove handler, pass empty handler or nullptr.
411 * Default behavior is RCSSetResponse::defaultAction().
413 * @param handler a set request handler
415 * @see RCSSetResponse
418 virtual void setSetRequestHandler(SetRequestHandler handler);
421 * Adds a listener for a particular attribute updated.
423 * @param key the interested attribute's key
424 * @param listener listener to be invoked
427 virtual void addAttributeUpdatedListener(const std::string& key,
428 AttributeUpdatedListener listener);
433 virtual void addAttributeUpdatedListener(std::string&& key,
434 AttributeUpdatedListener listener);
437 * Removes a listener for a particular attribute updated.
439 * @param key the key associated with the listener to be removed
441 * @return True if the listener added with same key exists and is removed.
444 virtual bool removeAttributeUpdatedListener(const std::string& key);
447 * Notifies all observers of the current attributes.
449 * @throws RCSPlatformException If the operation failed.
451 virtual void notify() const;
454 * Sets auto notify policy
456 * @param policy policy to be set
459 void setAutoNotifyPolicy(AutoNotifyPolicy policy);
462 * Returns the current policy
465 AutoNotifyPolicy getAutoNotifyPolicy() const;
468 * Sets the policy for handling a set request.
470 * @param policy policy to be set
473 void setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy);
476 * Returns the current policy.
479 SetRequestHandlerPolicy getSetRequestHandlerPolicy() const;
482 * Bind a resource to this resource.
483 * Binding another resource makes this resource work as a collection resource,
486 * @param resource a resource to be bound to this resource.
488 * @throws RCSInvalidParameterException If resource is nullptr or itself.
489 * @throws RCSPlatformException If the operation failed.
491 * @see unbindResource
493 void bindResource(const RCSResourceObject::Ptr& resource);
496 * Unbind a resource from this resource.
497 * If there is no bound resource left, the resource will run as a normal resource.
499 * @param resource a resource to be unbound from this resource.
501 * @throws RCSInvalidParameterException If resource is nullptr or itself.
502 * @throws RCSPlatformException If the operation failed.
506 void unbindResource(const RCSResourceObject::Ptr& resource);
509 * Returns all bound resources to this resource.
511 std::vector< RCSResourceObject::Ptr > getBoundResources() const;
514 * Returns the uri of the resource.
516 std::string getUri() const;
519 * Returns the default interface of the resource
521 * @see Builder::setDefaultInterface
523 std::string getDefaultInterface() const;
526 * Returns all interfaces added for the resource.
528 * @see Builder::addInterface
530 std::vector< std::string > getInterfaces() const;
533 * Returns all types added for the resource.
535 * @see Builder::addType
537 std::vector< std::string > getTypes() const;
540 RCSResourceObject(const std::string&, uint8_t, RCSResourceAttributes&&);
542 void init(OCResourceHandle, const std::vector< std::string >&,
543 const std::vector< std::string >&, const std::string&);
545 static OCEntityHandlerResult entityHandler(const std::weak_ptr< RCSResourceObject >&,
546 const std::shared_ptr< OC::OCResourceRequest >&);
548 OCEntityHandlerResult handleRequest(const RCSRequest&);
549 OCEntityHandlerResult handleRequestGet(const RCSRequest&);
550 OCEntityHandlerResult handleRequestSet(const RCSRequest&);
551 OCEntityHandlerResult handleObserve(const RCSRequest&);
553 template <typename RESPONSE, typename RESPONSE_BUILDER>
554 OCEntityHandlerResult sendResponse(const RCSRequest&,
555 const RESPONSE&, const RESPONSE_BUILDER&);
557 void expectOwnLock() const;
559 std::thread::id getLockOwner() const noexcept;
561 void setLockOwner(std::thread::id&&) const noexcept;
563 void autoNotify(bool, AutoNotifyPolicy) const;
564 void autoNotify(bool) const;
566 bool testValueUpdated(const std::string&, const RCSResourceAttributes::Value&) const;
568 template< typename K, typename V >
569 void setAttributeInternal(K&&, V&&);
571 bool applyAcceptanceMethod(const RCSSetResponse&, const RCSResourceAttributes&);
573 InterfaceHandler findInterfaceHandler(const std::string&) const;
575 RCSRepresentation getRepresentation(const RCSRequest&) const;
578 const uint8_t m_properties;
580 const std::string m_uri;
581 std::vector< std::string > m_interfaces;
582 std::vector< std::string > m_types;
583 std::string m_defaultInterface;
585 OCResourceHandle m_resourceHandle;
587 RCSResourceAttributes m_resourceAttributes;
589 std::shared_ptr< GetRequestHandler > m_getRequestHandler;
590 std::shared_ptr< SetRequestHandler > m_setRequestHandler;
592 AutoNotifyPolicy m_autoNotifyPolicy;
593 SetRequestHandlerPolicy m_setRequestHandlerPolicy;
595 std::unordered_map< std::string, std::shared_ptr< AttributeUpdatedListener > >
596 m_attributeUpdatedListeners;
598 mutable std::unique_ptr< AtomicThreadId > m_lockOwner;
599 mutable std::mutex m_mutex;
601 std::mutex m_mutexAttributeUpdatedListeners;
603 mutable std::mutex m_mutexForBoundResources;
605 std::vector< RCSResourceObject::Ptr > m_boundResources;
607 std::map< std::string, InterfaceHandler > m_interfaceHandlers;
609 friend class RCSSeparateResponse;
613 * The class provides a convenient RAII-style mechanism for the attributes of a
614 * RCSResourceObject. When a LockGuard is created, it attempts to lock the attributes of
615 * the RCSResourceObject it is given. When control leaves the scope in which the LockGuard
616 * object was created, the LockGuard is destructed and the attributes is unlocked.
618 * Additionally when it is destructed and only when destructed not by stack unwinding
619 * caused by an exception, it tries to notify depending on AutoNotifyPolicy.
621 * @note The destrcutor can throw an exception if auto notify failed.
623 class RCSResourceObject::LockGuard
626 LockGuard(const RCSResourceObject& rcsResourceObject);
628 LockGuard(const RCSResourceObject::Ptr);
631 * Constructs a LockGuard with auto notify policy.
633 * @param object an object to be locked
634 * @param autoNotifyPolicy the policy to indicate how auto notification is handled
635 * when the LockGuard is destructed.
638 LockGuard(const RCSResourceObject& object, AutoNotifyPolicy autoNotifyPolicy);
643 LockGuard(const RCSResourceObject::Ptr, AutoNotifyPolicy);
646 * @throws RCSPlatformException If auto notify operation failed.
648 * @note The exception will never be thrown while stack unwinding.
650 ~LockGuard() noexcept(false);
652 LockGuard(const LockGuard&) = delete;
653 LockGuard(LockGuard&&) = delete;
655 LockGuard& operator=(const LockGuard&) = delete;
656 LockGuard& operator=(LockGuard&&) = delete;
662 const RCSResourceObject& m_resourceObject;
664 AutoNotifyPolicy m_autoNotifyPolicy;
668 std::function<void()> m_autoNotifyFunc;
672 class RCSResourceObject::WeakGuard
675 WeakGuard(const RCSResourceObject&);
678 WeakGuard(const WeakGuard&) = delete;
679 WeakGuard(WeakGuard&&) = delete;
681 WeakGuard& operator=(const WeakGuard&) = delete;
682 WeakGuard& operator=(WeakGuard&&) = delete;
684 bool hasLocked() const;
688 const RCSResourceObject& m_resourceObject;
694 #endif // SERVER_RCSRESOURCEOBJECT_H