Embedded Template Library 1.0
Loading...
Searching...
No Matches
message_broker.h
1/******************************************************************************
2The MIT License(MIT)
3
4Embedded Template Library.
5https://github.com/ETLCPP/etl
6https://www.etlcpp.com
7
8Copyright(c) 2017 John Wellbelove
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files(the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions :
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27******************************************************************************/
28
29#ifndef ETL_MESSAGE_BROKER_INCLUDED
30#define ETL_MESSAGE_BROKER_INCLUDED
31
32#include "platform.h"
33#include "message.h"
34#include "message_router.h"
35#include "message_types.h"
36#include "nullptr.h"
37#include "span.h"
38
39namespace etl
40{
41 //***************************************************************************
43 //***************************************************************************
45 {
46 private:
47
48 //*******************************************
49 class subscription_node
50 {
51 friend class message_broker;
52
53 protected:
54
55 //*******************************
56 subscription_node()
57 : p_next(ETL_NULLPTR)
58 {
59 }
60
61 //*******************************
62 void set_next(subscription_node* sub)
63 {
64 p_next = sub;
65 }
66
67 //*******************************
68 subscription_node* get_next() const
69 {
70 return p_next;
71 }
72
73 //*******************************
74 void terminate()
75 {
76 set_next(ETL_NULLPTR);
77 }
78
79 //*******************************
80 void append(subscription_node* sub)
81 {
82 if (sub != ETL_NULLPTR)
83 {
84 sub->set_next(get_next());
85 }
86 set_next(sub);
87 }
88
89 subscription_node* p_next;
90 };
91
92 public:
93
94 typedef etl::span<const etl::message_id_t> message_id_span_t;
95
96 //*******************************************
97 class subscription : public subscription_node
98 {
99 public:
100
101 friend class message_broker;
102
103 //*******************************
104 subscription(etl::imessage_router& router_)
105 : p_router(&router_)
106 {
107 }
108
109 private:
110
111 //*******************************
112 virtual message_id_span_t message_id_list() const = 0;
113
114 //*******************************
115 etl::imessage_router* get_router() const
116 {
117 return p_router;
118 }
119
120 //*******************************
121 subscription* next_subscription() const
122 {
123 return static_cast<subscription*>(get_next());
124 }
125
126 etl::imessage_router* const p_router;
127 };
128
129 using etl::imessage_router::receive;
130
131 //*******************************************
133 //*******************************************
135 : imessage_router(etl::imessage_router::MESSAGE_BROKER)
136 , head()
137 {
138 }
139
140 //*******************************************
142 //*******************************************
144 : imessage_router(etl::imessage_router::MESSAGE_BROKER, successor_)
145 , head()
146 {
147 }
148
149 //*******************************************
151 //*******************************************
152 message_broker(etl::message_router_id_t id_)
153 : imessage_router(id_)
154 , head()
155 {
156 ETL_ASSERT((id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER) || (id_ == etl::imessage_router::MESSAGE_BROKER),
158 }
159
160 //*******************************************
162 //*******************************************
163 message_broker(etl::message_router_id_t id_, etl::imessage_router& successor_)
164 : imessage_router(id_, successor_)
165 , head()
166 {
167 ETL_ASSERT((id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER) || (id_ == etl::imessage_router::MESSAGE_BROKER),
169 }
170
171 //*******************************************
173 //*******************************************
175 {
176 initialise_insertion_point(new_sub.get_router(), &new_sub);
177 }
178
179 //*******************************************
180 void unsubscribe(etl::imessage_router& router)
181 {
182 initialise_insertion_point(&router, ETL_NULLPTR);
183 }
184
185 //*******************************************
186 virtual void receive(const etl::imessage& msg) ETL_OVERRIDE
187 {
188 receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, msg);
189 }
190
191 virtual void receive(etl::shared_message shared_msg) ETL_OVERRIDE
192 {
193 receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, shared_msg);
194 }
195
196 //*******************************************
197 virtual void receive(etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE
198 {
199 const etl::message_id_t id = msg.get_message_id();
200
201 if (!empty())
202 {
203 // Scan the subscription lists.
204 subscription* sub = static_cast<subscription*>(head.get_next());
205
206 while (sub != ETL_NULLPTR)
207 {
208 message_id_span_t message_ids = sub->message_id_list();
209
210 message_id_span_t::iterator itr = etl::find(message_ids.begin(), message_ids.end(), id);
211
212 if (itr != message_ids.end())
213 {
214 etl::imessage_router* router = sub->get_router();
215
216 if (destination_router_id == etl::imessage_router::ALL_MESSAGE_ROUTERS || destination_router_id == router->get_message_router_id())
217 {
218 router->receive(msg);
219 }
220 }
221
222 sub = sub->next_subscription();
223 }
224 }
225
226 // Always pass the message on to the successor.
227 if (has_successor())
228 {
229 get_successor().receive(destination_router_id, msg);
230 }
231 }
232
233 //*******************************************
234 virtual void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) ETL_OVERRIDE
235 {
236 const etl::message_id_t id = shared_msg.get_message().get_message_id();
237
238 if (!empty())
239 {
240 // Scan the subscription lists.
241 subscription* sub = static_cast<subscription*>(head.get_next());
242
243 while (sub != ETL_NULLPTR)
244 {
245 message_id_span_t message_ids = sub->message_id_list();
246
247 message_id_span_t::iterator itr = etl::find(message_ids.begin(), message_ids.end(), id);
248
249 if (itr != message_ids.end())
250 {
251 etl::imessage_router* router = sub->get_router();
252
253 if (destination_router_id == etl::imessage_router::ALL_MESSAGE_ROUTERS || destination_router_id == router->get_message_router_id())
254 {
255 router->receive(shared_msg);
256 }
257 }
258
259 sub = sub->next_subscription();
260 }
261 }
262
263 // Always pass the message on to a successor.
264 if (has_successor())
265 {
266 get_successor().receive(destination_router_id, shared_msg);
267 }
268 }
269
270 using imessage_router::accepts;
271
272 //*******************************************
275 //*******************************************
276 virtual bool accepts(etl::message_id_t id) const ETL_OVERRIDE
277 {
278 if (!empty())
279 {
280 // Scan the subscription lists.
281 subscription* sub = static_cast<subscription*>(head.get_next());
282
283 while (sub != ETL_NULLPTR)
284 {
285 message_id_span_t message_ids = sub->message_id_list();
286
287 message_id_span_t::iterator itr = etl::find(message_ids.begin(), message_ids.end(), id);
288
289 if (itr != message_ids.end())
290 {
291 etl::imessage_router* router = sub->get_router();
292
293 if (router->accepts(id))
294 {
295 return true;
296 }
297 }
298
299 sub = sub->next_subscription();
300 }
301 }
302
303 // Check any successor.
304 if (has_successor())
305 {
306 if (get_successor().accepts(id))
307 {
308 return true;
309 }
310 }
311
312 return false;
313
314 // return true;
315 }
316
317 //*******************************************
318 void clear()
319 {
320 head.terminate();
321 }
322
323 //********************************************
324 ETL_DEPRECATED
325 virtual bool is_null_router() const ETL_OVERRIDE
326 {
327 return false;
328 }
329
330 //********************************************
331 virtual bool is_producer() const ETL_OVERRIDE
332 {
333 return true;
334 }
335
336 //********************************************
337 virtual bool is_consumer() const ETL_OVERRIDE
338 {
339 return true;
340 }
341
342 //********************************************
343 bool empty() const
344 {
345 return head.get_next() == ETL_NULLPTR;
346 }
347
348 private:
349
350 //*******************************************
351 void initialise_insertion_point(const etl::imessage_router* p_router, etl::message_broker::subscription* p_new_sub)
352 {
353 const etl::imessage_router* p_target_router = p_router;
354
355 subscription_node* p_sub = head.get_next();
356 subscription_node* p_sub_previous = &head;
357
358 while (p_sub != ETL_NULLPTR)
359 {
360 // Do we already have a subscription for the router?
361 if (static_cast<subscription*>(p_sub)->get_router() == p_target_router)
362 {
363 // Then unlink it.
364 p_sub_previous->set_next(p_sub->get_next()); // Jump over the subscription.
365 p_sub->terminate(); // Terminate the unlinked subscription.
366
367 // We're done now.
368 break;
369 }
370
371 // Move on up the list.
372 p_sub = p_sub->get_next();
373 p_sub_previous = p_sub_previous->get_next();
374 }
375
376 if (p_new_sub != ETL_NULLPTR)
377 {
378 // Link in the new subscription.
379 p_sub_previous->append(p_new_sub);
380 }
381 }
382
383 subscription_node head;
384 };
385} // namespace etl
386
387#endif
This is the base of all message routers.
Definition message_router.h:141
Definition message.h:73
Definition message_broker.h:98
void subscribe(etl::message_broker::subscription &new_sub)
Subscribe to the broker.
Definition message_broker.h:174
message_broker()
Constructor.
Definition message_broker.h:134
message_broker(etl::message_router_id_t id_)
Constructor.
Definition message_broker.h:152
virtual bool accepts(etl::message_id_t id) const ETL_OVERRIDE
Definition message_broker.h:276
message_broker(etl::message_router_id_t id_, etl::imessage_router &successor_)
Constructor.
Definition message_broker.h:163
message_broker(etl::imessage_router &successor_)
Constructor.
Definition message_broker.h:143
Router id is out of the legal range.
Definition message_router.h:67
Span - Fixed Extent.
Definition span.h:208
ETL_NODISCARD ETL_CONSTEXPR iterator begin() const ETL_NOEXCEPT
Returns an iterator to the beginning of the span.
Definition span.h:484
ETL_NODISCARD ETL_CONSTEXPR iterator end() const ETL_NOEXCEPT
Returns an iterator to the end of the span.
Definition span.h:508
bool has_successor() const
Definition successor.h:184
successor_type & get_successor() const
Definition successor.h:174
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition absolute.h:40
uint_least8_t message_id_t
Allow alternative type for message id.
Definition message_types.h:40