1 /*
2  * SObjectizer-5
3  */
4 
5 /*!
6  * \file
7  * \since
8  * v.5.5.23
9  *
10  * \brief Stuff related to enveloped messages.
11  */
12 
13 #pragma once
14 
15 #include <so_5/message.hpp>
16 
17 #include <so_5/optional.hpp>
18 
19 namespace so_5 {
20 
21 namespace enveloped_msg {
22 
23 //
24 // payload_info_t
25 //
26 /*!
27  * \brief An information about payload inside envelope.
28  *
29  * This class is necessary for incapsulation of information related
30  * to payload inside an envelope. In v.5.5.23 this class contains only
31  * reference to the payload message. But additional info can be added
32  * in some future versions.
33  *
34  * \since
35  * v.5.5.23
36  */
37 class payload_info_t
38 	{
39 		//! Actual enveloped message.
40 		/*!
41 		 * This member is mutable because we need to return non-const
42 		 * reference to message_ref_t from const method message().
43 		 *
44 		 * \note
45 		 * This pointer can be null if the enveloped message is a signal.
46 		 */
47 		mutable message_ref_t m_message;
48 
49 	public:
50 		//! Initializing constructor.
payload_info_t(message_ref_t message)51 		payload_info_t(
52 			message_ref_t message )
53 			:	m_message{ std::move(message) }
54 			{}
55 
56 		/*!
57 		 * \name Getters
58 		 * \{
59 		 */
60 		[[nodiscard]]
61 		message_ref_t &
message() const62 		message() const noexcept { return m_message; }
63 		/*!
64 		 * \}
65 		 */
66 	};
67 
68 //
69 // handler_invoker_t
70 //
71 /*!
72  * \brief An extended version of handling_context which can be used
73  * for calling event handler.
74  *
75  * \note
76  * This class has non-virtual and protected destructor because
77  * creation on instances derived classes in dynamic memory
78  * is not intended.
79  *
80  * \since
81  * v.5.5.23
82  */
83 class SO_5_TYPE handler_invoker_t
84 	{
85 	protected:
86 		// clang requires this.
87 		handler_invoker_t() = default;
88 		handler_invoker_t( const handler_invoker_t & ) = default;
89 		handler_invoker_t & operator=( const handler_invoker_t & ) = default;
90 
91 		handler_invoker_t( handler_invoker_t && ) = default;
92 		handler_invoker_t & operator=( handler_invoker_t && ) = default;
93 
94 		~handler_invoker_t() = default;
95 
96 	public:
97 		//! Call an actual handler for the enveloped message/signal.
98 		virtual void
99 		invoke( const payload_info_t & payload ) noexcept = 0;
100 	};
101 
102 //
103 // access_context_t
104 //
105 /*!
106  * \brief Information about context on that enveloped message is handled.
107  *
108  * \since
109  * v.5.5.23
110  */
111 enum class access_context_t
112 	{
113 		//! Enveloped message is delivered to a receiver and the payload
114 		//! is necessary for calling event handler.
115 		handler_found,
116 		//! The content of enveloped message should be transformed to
117 		//! another representation.
118 		//! For example it can be necessary for limit_then_transform
119 		//! overload reaction.
120 		transformation,
121 		//! The content of enveloped message should be analyzed for
122 		//! the further delivery.
123 		//! For example it can be necessary for delivery filters.
124 		inspection
125 	};
126 
127 //
128 // envelope_t
129 //
130 /*!
131  * \brief An interface of envelope with some message/signal inside.
132  *
133  * SObjectizer v.5.5.23 introduced a new thing: enveloped messages.
134  * It means that actual message/signal is placed into a special
135  * container called 'envelope'. This envelope is delivered to all
136  * receivers of the original message/signal. But before the calling
137  * of event handler in a receiver the original message/signal (e.g. payload)
138  * are extracted from envelope and passed to the event handler.
139  *
140  * This interface describes 'envelope' for such containers. All envelopes
141  * should implement this interface.
142  *
143  * Method access_hook() is called by SObjectizer when the payload
144  * of enveloped message should be accessed. For example:
145  *
146  * - envelope is delivered to a receiver and receiver is ready to handle a
147  *   message from envelope;
148  * - envelope can't be delivered to a receiver in its current form and there is
149  *   a need to transform the message/signal from the envelope to another type
150  *   of message/signal. For example it can happen when limit_then_transform is
151  *   used for overload control. In that case the payload should be extracted
152  *   and passed to a transformation function;
153  * - envelope should be analyzed by a delivery filter for further delivery
154  *   of message.
155  *
156  * When access_hook() is called the envelope should check the
157  * availability of the payload and, if the payload is available for processing,
158  * should pass the payload info to handler_invoker_t::invoke() method.
159  *
160  * Please note that call of handler_invoker_t::invoke() is not guaranteed.
161  * Envelope can check some conditions (like payload expiration or revocation)
162  * and does call to invoke() only if these conditions are meet. But if some
163  * conditions are not fulfilled then access_hook() won't call
164  * handler_invoker_t::invoke() method.
165  *
166  * \since
167  * v.5.5.23
168  */
169 class SO_5_TYPE envelope_t : public message_t
170 	{
171 	public:
172 		// Introduce some names into the scope of this class to
173 		// be easily used in derived classes outside so_5 namespace.
174 		using payload_info_t = ::so_5::enveloped_msg::payload_info_t;
175 		using handler_invoker_t = ::so_5::enveloped_msg::handler_invoker_t;
176 		using access_context_t = ::so_5::enveloped_msg::access_context_t;
177 
178 		// clang requires this.
179 		envelope_t() = default;
180 		envelope_t( const envelope_t & ) = default;
181 		envelope_t & operator=( const envelope_t & ) = default;
182 
183 		envelope_t( envelope_t && ) = default;
184 		envelope_t & operator=( envelope_t && ) = default;
185 
186 		virtual ~envelope_t() override = default;
187 
188 		virtual void
189 		access_hook(
190 			//! Why this hook is called.
191 			access_context_t context,
192 			//! Proxy object which can call an actual event handler.
193 			handler_invoker_t & invoker ) noexcept = 0;
194 
195 	private :
196 		kind_t
so5_message_kind() const197 		so5_message_kind() const noexcept override
198 			{
199 				return kind_t::enveloped_msg;
200 			}
201 	};
202 
203 //
204 // extract_payload_for_message_transformation
205 //
206 /*!
207  * \brief Helper function for extraction of a payload
208  * from enveloped message.
209  *
210  * Extraction of a payload from an envelope is not an easy task.
211  * It is necessary to create an implementation of handler_invoker_t
212  * interface and pass it to envelope_t::transformation_hook() method.
213  * This implementation should check type of the payload: if it is
214  * another envelope then next call to transformation_hook() should
215  * be done and so on.
216  *
217  * Because of that extraction of the payload from an envelope is a boring
218  * task. This helper function preforms all described actions an returns
219  * optional with payload inside (if the payload available).
220  *
221  * \attention
222  * Argument \a envelope should not be nullptr.
223  *
224  * \since
225  * v.5.5.23
226  */
227 [[nodiscard]]
228 SO_5_FUNC
229 optional< payload_info_t >
230 extract_payload_for_message_transformation(
231 	//! Envelope with message inside.
232 	const message_ref_t & envelope );
233 
234 //
235 // message_to_be_inspected
236 //
237 /*!
238  * \brief Helper function for extraction of a payload from enveloped
239  * message.
240  *
241  * This function checks the kind of \a msg_or_envelope. If this is
242  * an enveloped message message_to_be_inspected() will try to extract
243  * the payload and return it. In that case an empty \a optional object
244  * can be returned.
245  *
246  * If \a msg_or_envelope is not an envelope then \a msg_or_envelope
247  * is returned as a result.
248  *
249  * \since
250  * v.5.5.23
251  */
252 [[nodiscard]]
253 SO_5_FUNC
254 optional< message_ref_t >
255 message_to_be_inspected(
256 	const message_ref_t & msg_or_envelope );
257 
258 } /* namespace enveloped_msg */
259 
260 } /* namespace so_5 */
261 
262