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.
83 class RCSResourceObject
87 typedef AtomicWrapper< std::thread::id > AtomicThreadId;
93 WeakGuard(const RCSResourceObject&);
96 WeakGuard(const WeakGuard&) = delete;
97 WeakGuard(WeakGuard&&) = delete;
99 WeakGuard& operator=(const WeakGuard&) = delete;
100 WeakGuard& operator=(WeakGuard&&) = delete;
102 bool hasLocked() const;
106 const RCSResourceObject& m_resourceObject;
113 * Represents the policy of auto-notify function.
114 * In accord with this policy, observers are notified of attributes
115 * when the attributes are set.
117 * @note Attributes are set according to the execution of some functions which
118 * modify attributes or receipt of set requests.
120 * @see RCSResourceObject::setAttribute
121 * @see RCSResourceObject::removeAttribute
122 * @see RCSResourceObject::getAttributes
123 * @see RCSResourceObject::LockGuard
125 enum class AutoNotifyPolicy
128 ALWAYS, /**< Always*/
129 UPDATED /**< Only when attributes are changed*/
133 * Represents the policy of set-request handler.
134 * In accord with this, the RCSResourceObject decides whether a set-request is
137 enum class SetRequestHandlerPolicy
139 NEVER, /**< Requests will be ignored if attributes of the request contain
140 a new key or a value that has different type from the current
142 ACCEPTANCE /**< The attributes of the request will be applied unconditionally
143 even if there are new name or type conflicts. */
146 typedef std::shared_ptr< RCSResourceObject > Ptr;
147 typedef std::shared_ptr< const RCSResourceObject > ConstPtr;
150 * This is a builder to create resource with properties and attributes.
152 * The resource will be observable and discoverable by default, to make them disable
153 * set these properties explicitly with setDiscoverable and setObservable.
155 * "oic.if.baseline" is an interface that a resource always holds, by default,
156 * even it is not added manually.
162 * Constructs a Builder.
164 * @param uri Resource uri
165 * @param type Resource type
166 * @param interface Resource interface
169 Builder(std::string uri, std::string type, std::string interface);
172 * Add an interface for the resource.
174 * @param interface new interface.
176 Builder& addInterface(std::string interface);
179 * Add a type for the resource.
181 * @param type new type.
183 Builder& addType(std::string type);
186 * Sets the default interface.
187 * If it is not called, the interface passed to the constructor is the default.
189 * @param interface default interface name
192 Builder& setDefaultInterface(std::string interface);
195 * Sets whether the resource is discoverable.
197 * @param discoverable whether to be discoverable.
200 Builder& setDiscoverable(bool discoverable);
203 * Sets the observable property of the resource.
205 * @param observable whether to be observable.
208 Builder& setObservable(bool observable);
211 * Sets whether the resource should be secure or not.
213 * @param secureFlag whether to be secure or not.
216 Builder& setSecureFlag(bool secureFlag);
219 * Sets attributes for the resource.
221 * @param attributes attributes to set
224 Builder& setAttributes(const RCSResourceAttributes &attributes);
229 Builder& setAttributes(RCSResourceAttributes &&attributes);
232 * Register a resource and returns a RCSResourceObject.
234 * @throw RCSPlatformException if resource registration is failed.
237 RCSResourceObject::Ptr build();
241 std::vector< std::string > m_types;
242 std::vector< std::string > m_interfaces;
243 std::string m_defaultInterface;
244 uint8_t m_properties;
245 RCSResourceAttributes m_resourceAttributes;
251 * Callback definition for a handler to be invoked when a get request is received.
253 * The handler will be called first when a get request is received, before the
254 * RCSResourceObject handles.
256 * @param request the request information
257 * @param attributes attributes of the request
259 * @return response to be sent and that indicates how the request to be handled by
260 * the RCSResourceObject.
262 * @see setGetRequestHandler
264 typedef std::function < RCSGetResponse(const RCSRequest& request,
265 RCSResourceAttributes& attributes) > GetRequestHandler;
268 * Callback definition for a handler to be invoked when a set request is received.
270 * The handler will be called first when a get request is received, before the
271 * RCSResourceObject handles. If the attributes are modified in the callback,
272 * the modified attributes will be set in the RCSResourceObject if the request is
275 * @param request the request information
276 * @param attributes attributes of the request
278 * @return response to be sent and that indicates how the request to be handled by
279 * the RCSResourceObject.
281 * @see setGetRequestHandler
283 typedef std::function < RCSSetResponse(const RCSRequest& request,
284 RCSResourceAttributes& attributes) > SetRequestHandler;
287 * Callback definition to be invoked when an attribute is updated.
289 * @param oldValue the value before being changed
290 * @param newValue changed value
292 typedef std::function < void(const RCSResourceAttributes::Value& oldValue,
293 const RCSResourceAttributes::Value& newValue) > AttributeUpdatedListener;
296 RCSResourceObject(RCSResourceObject&&) = delete;
297 RCSResourceObject(const RCSResourceObject&) = delete;
299 RCSResourceObject& operator=(RCSResourceObject&&) = delete;
300 RCSResourceObject& operator=(const RCSResourceObject&) = delete;
302 virtual ~RCSResourceObject();
305 * Sets a particular attribute value.
307 * @param key key of attribute
308 * @param value value to be mapped against the key
310 * @note Thread-safety is guaranteed for the attributes.
312 void setAttribute(const std::string& key, const RCSResourceAttributes::Value& value);
317 void setAttribute(const std::string& key, RCSResourceAttributes::Value&& value);
322 void setAttribute(std::string&& key, const RCSResourceAttributes::Value& value);
327 void setAttribute(std::string&& key, RCSResourceAttributes::Value&& value);
330 * Returns an attribute value corresponding to a key.
332 * @param key key of the attribute
334 * @throws RCSInvalidKeyException If key is invalid.
336 * @note Thread-safety is guaranteed for the attributes.
338 RCSResourceAttributes::Value getAttributeValue(const std::string& key) const;
341 * Returns the attribute value as T.
343 * @param key key of the attribute
345 * @throws RCSBadGetException If type of the underlying value is not T.
346 * @throws RCSInvalidKeyException If @a key doesn't match the key of any value.
348 * @note Thread-safety is guaranteed for the attributes.
350 template< typename T >
351 T getAttribute(const std::string& key) const
353 RCSResourceObject::WeakGuard lock(*this);
354 return m_resourceAttributes.at(key).get< T >();
358 * Removes a particular attribute of the resource.
360 * @param key key of the attribute.
362 * @return True if the key exists and matched attribute is removed, otherwise false.
364 * @note Thread-safety is guaranteed for the attributes.
366 bool removeAttribute(const std::string& key);
369 * Checks whether a particular attribute exists or not.
371 * @param key key of the attribute
373 * @return True if the key exists, otherwise false.
375 * @note Thread-safety is guaranteed for the attributes.
377 bool containsAttribute(const std::string& key) const;
380 * Returns reference to the attributes of the RCSResourceObject.
382 * @pre The call must be guarded by LockGuard.
385 * @return Reference to the attributes
387 * @throws NoLockException If the call is not guarded by LockGuard.
389 * @note Here is the standard idiom for LockGuard:
392 RCSResourceObject::LockGuard lock(rcsResourceObject);
394 auto &attributes = server->getAttributes();
399 RCSResourceAttributes& getAttributes();
404 const RCSResourceAttributes& getAttributes() const;
407 * Checks whether the resource is observable or not.
409 virtual bool isObservable() const;
412 * Checks whether the resource is discoverable or not.
414 virtual bool isDiscoverable() const;
417 * Sets the get request handler.
418 * To remove handler, pass empty handler or nullptr.
420 * Default behavior is RCSGetResponse::defaultAction().
422 * @param handler a get request handler
424 * @see RCSGetResponse
427 virtual void setGetRequestHandler(GetRequestHandler handler);
430 * Sets the set request handler.
431 * To remove handler, pass empty handler or nullptr.
433 * Default behavior is RCSSetResponse::defaultAction().
435 * @param handler a set request handler
437 * @see RCSSetResponse
440 virtual void setSetRequestHandler(SetRequestHandler handler);
443 * Adds a listener for a particular attribute updated.
445 * @param key the interested attribute's key
446 * @param listener listener to be invoked
449 virtual void addAttributeUpdatedListener(const std::string& key,
450 AttributeUpdatedListener listener);
455 virtual void addAttributeUpdatedListener(std::string&& key,
456 AttributeUpdatedListener listener);
459 * Removes a listener for a particular attribute updated.
461 * @param key the key associated with the listener to be removed
463 * @return True if the listener added with same key exists and is removed.
466 virtual bool removeAttributeUpdatedListener(const std::string& key);
469 * Notifies all observers of the current attributes.
471 * @throws RCSPlatformException If the operation failed.
473 virtual void notify() const;
476 * Sets auto notify policy
478 * @param policy policy to be set
481 void setAutoNotifyPolicy(AutoNotifyPolicy policy);
484 * Returns the current policy
487 AutoNotifyPolicy getAutoNotifyPolicy() const;
490 * Sets the policy for handling a set request.
492 * @param policy policy to be set
495 void setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy);
498 * Returns the current policy.
501 SetRequestHandlerPolicy getSetRequestHandlerPolicy() const;
504 * Bind a resource to this resource.
505 * Binding another resource makes this resource work as a collection resource,
508 * @param resource a resource to be bound to this resource.
510 * @throws RCSInvalidParameterException If resource is nullptr or itself.
511 * @throws RCSPlatformException If the operation failed.
513 * @see unbindResource
515 void bindResource(const RCSResourceObject::Ptr& resource);
518 * Unbind a resource from this resource.
519 * If there is no bound resource left, the resource will run as a normal resource.
521 * @param resource a resource to be unbound from this resource.
523 * @throws RCSInvalidParameterException If resource is nullptr or itself.
524 * @throws RCSPlatformException If the operation failed.
528 void unbindResource(const RCSResourceObject::Ptr& resource);
531 * Returns all bound resources to this resource.
533 std::vector< RCSResourceObject::Ptr > getBoundResources() const;
536 * Returns the uri of the resource.
538 std::string getUri() const;
541 * Returns the default interface of the resource
543 * @see Builder::setDefaultInterface
545 std::string getDefaultInterface() const;
548 * Returns all interfaces added for the resource.
550 * @see Builder::addInterface
552 std::vector< std::string > getInterfaces() const;
555 * Returns all types added for the resource.
557 * @see Builder::addType
559 std::vector< std::string > getTypes() const;
562 RCSResourceObject(const std::string&, uint8_t, RCSResourceAttributes&&);
564 void init(OCResourceHandle, const std::vector< std::string >&,
565 const std::vector< std::string >&, const std::string&);
567 static OCEntityHandlerResult entityHandler(const std::weak_ptr< RCSResourceObject >&,
568 const std::shared_ptr< OC::OCResourceRequest >&);
570 OCEntityHandlerResult handleRequest(const RCSRequest&);
571 OCEntityHandlerResult handleRequestGet(const RCSRequest&);
572 OCEntityHandlerResult handleRequestSet(const RCSRequest&);
573 OCEntityHandlerResult handleObserve(const RCSRequest&);
575 template <typename RESPONSE, typename RESPONSE_BUILDER>
576 OCEntityHandlerResult sendResponse(const RCSRequest&,
577 const RESPONSE&, const RESPONSE_BUILDER&);
579 void expectOwnLock() const;
581 std::thread::id getLockOwner() const noexcept;
583 void setLockOwner(std::thread::id&&) const noexcept;
585 void autoNotify(bool, AutoNotifyPolicy) const;
586 void autoNotify(bool) const;
588 bool testValueUpdated(const std::string&, const RCSResourceAttributes::Value&) const;
590 template< typename K, typename V >
591 void setAttributeInternal(K&&, V&&);
593 bool applyAcceptanceMethod(const RCSSetResponse&, const RCSResourceAttributes&);
595 InterfaceHandler findInterfaceHandler(const std::string&) const;
597 RCSRepresentation getRepresentation(const RCSRequest&) const;
600 const uint8_t m_properties;
602 const std::string m_uri;
603 std::vector< std::string > m_interfaces;
604 std::vector< std::string > m_types;
605 std::string m_defaultInterface;
607 OCResourceHandle m_resourceHandle;
609 RCSResourceAttributes m_resourceAttributes;
611 std::shared_ptr< GetRequestHandler > m_getRequestHandler;
612 std::shared_ptr< SetRequestHandler > m_setRequestHandler;
614 AutoNotifyPolicy m_autoNotifyPolicy;
615 SetRequestHandlerPolicy m_setRequestHandlerPolicy;
617 std::unordered_map< std::string, std::shared_ptr< AttributeUpdatedListener > >
618 m_attributeUpdatedListeners;
620 mutable std::unique_ptr< AtomicThreadId > m_lockOwner;
621 mutable std::mutex m_mutex;
623 std::mutex m_mutexAttributeUpdatedListeners;
625 mutable std::mutex m_mutexForBoundResources;
627 std::vector< RCSResourceObject::Ptr > m_boundResources;
629 std::map< std::string, InterfaceHandler > m_interfaceHandlers;
631 friend class RCSSeparateResponse;
635 * The class provides a convenient RAII-style mechanism for the attributes of a
636 * RCSResourceObject. When a LockGuard is created, it attempts to lock the attributes of
637 * the RCSResourceObject it is given. When control leaves the scope in which the LockGuard
638 * object was created, the LockGuard is destructed and the attributes is unlocked.
640 * Additionally when it is destructed and only when destructed not by stack unwinding
641 * caused by an exception, it tries to notify depending on AutoNotifyPolicy.
643 * @note The destrcutor can throw an exception if auto notify failed.
645 class RCSResourceObject::LockGuard
648 LockGuard(const RCSResourceObject& rcsResourceObject);
650 LockGuard(const RCSResourceObject::Ptr);
653 * Constructs a LockGuard with auto notify policy.
655 * @param object an object to be locked
656 * @param autoNotifyPolicy the policy to indicate how auto notification is handled
657 * when the LockGuard is destructed.
660 LockGuard(const RCSResourceObject& object, AutoNotifyPolicy autoNotifyPolicy);
665 LockGuard(const RCSResourceObject::Ptr, AutoNotifyPolicy);
668 * @throws RCSPlatformException If auto notify operation failed.
670 * @note The exception will never be thrown while stack unwinding.
672 ~LockGuard() noexcept(false);
674 LockGuard(const LockGuard&) = delete;
675 LockGuard(LockGuard&&) = delete;
677 LockGuard& operator=(const LockGuard&) = delete;
678 LockGuard& operator=(LockGuard&&) = delete;
684 const RCSResourceObject& m_resourceObject;
686 AutoNotifyPolicy m_autoNotifyPolicy;
690 std::function<void()> m_autoNotifyFunc;
696 #endif // SERVER_RCSRESOURCEOBJECT_H