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 "nullptr.h"
34#include "message_types.h"
35#include "message.h"
36#include "message_router.h"
37#include "span.h"
38
39#include <stdint.h>
40
41namespace etl
42{
43 //***************************************************************************
45 //***************************************************************************
47 {
48 private:
49
50 //*******************************************
51 class subscription_node
52 {
53 friend class message_broker;
54
55 protected:
56
57 //*******************************
58 subscription_node()
59 : p_next(ETL_NULLPTR)
60 {
61 }
62
63 //*******************************
64 void set_next(subscription_node* sub)
65 {
66 p_next = sub;
67 }
68
69 //*******************************
70 subscription_node* get_next() const
71 {
72 return p_next;
73 }
74
75 //*******************************
76 void terminate()
77 {
78 set_next(ETL_NULLPTR);
79 }
80
81 //*******************************
82 void append(subscription_node* sub)
83 {
84 if (sub != ETL_NULLPTR)
85 {
86 sub->set_next(get_next());
87 }
88 set_next(sub);
89 }
90
91 subscription_node* p_next;
92 };
93
94 public:
95
97
98 //*******************************************
99 class subscription : public subscription_node
100 {
101 public:
102
103 friend class message_broker;
104
105 //*******************************
107 : p_router(&router_)
108 {
109 }
110
111 private:
112
113 //*******************************
114 virtual message_id_span_t message_id_list() const = 0;
115
116 //*******************************
117 etl::imessage_router* get_router() const
118 {
119 return p_router;
120 }
121
122 //*******************************
123 subscription* next_subscription() const
124 {
125 return static_cast<subscription*>(get_next());
126 }
127
128 etl::imessage_router* const p_router;
129 };
130
131 using etl::imessage_router::receive;
132
133 //*******************************************
135 //*******************************************
137 : imessage_router(etl::imessage_router::MESSAGE_BROKER)
138 , head()
139 {
140 }
141
142 //*******************************************
144 //*******************************************
150
151 //*******************************************
153 //*******************************************
154 message_broker(etl::message_router_id_t id_)
156 , head()
157 {
158 ETL_ASSERT((id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER) || (id_ == etl::imessage_router::MESSAGE_BROKER), ETL_ERROR(etl::message_router_illegal_id));
159 }
160
161 //*******************************************
163 //*******************************************
166 , head()
167 {
168 ETL_ASSERT((id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER) || (id_ == etl::imessage_router::MESSAGE_BROKER), ETL_ERROR(etl::message_router_illegal_id));
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,
198 const etl::imessage& msg) ETL_OVERRIDE
199 {
200 const etl::message_id_t id = msg.get_message_id();
201
202 if (!empty())
203 {
204 // Scan the subscription lists.
205 subscription* sub = static_cast<subscription*>(head.get_next());
206
207 while (sub != ETL_NULLPTR)
208 {
209 message_id_span_t message_ids = sub->message_id_list();
210
211 message_id_span_t::iterator itr = etl::find(message_ids.begin(), message_ids.end(), id);
212
213 if (itr != message_ids.end())
214 {
215 etl::imessage_router* router = sub->get_router();
216
217 if (destination_router_id == etl::imessage_router::ALL_MESSAGE_ROUTERS ||
218 destination_router_id == router->get_message_router_id())
219 {
220 router->receive(msg);
221 }
222 }
223
224 sub = sub->next_subscription();
225 }
226 }
227
228 // Always pass the message on to the successor.
229 if (has_successor())
230 {
231 get_successor().receive(destination_router_id, msg);
232 }
233 }
234
235 //*******************************************
236 virtual void receive(etl::message_router_id_t destination_router_id,
237 etl::shared_message shared_msg) ETL_OVERRIDE
238 {
239 const etl::message_id_t id = shared_msg.get_message().get_message_id();
240
241 if (!empty())
242 {
243 // Scan the subscription lists.
244 subscription* sub = static_cast<subscription*>(head.get_next());
245
246 while (sub != ETL_NULLPTR)
247 {
248 message_id_span_t message_ids = sub->message_id_list();
249
250 message_id_span_t::iterator itr = etl::find(message_ids.begin(), message_ids.end(), id);
251
252 if (itr != message_ids.end())
253 {
254 etl::imessage_router* router = sub->get_router();
255
256 if (destination_router_id == etl::imessage_router::ALL_MESSAGE_ROUTERS ||
257 destination_router_id == router->get_message_router_id())
258 {
259 router->receive(shared_msg);
260 }
261 }
262
263 sub = sub->next_subscription();
264 }
265 }
266
267 // Always pass the message on to a successor.
268 if (has_successor())
269 {
270 get_successor().receive(destination_router_id, shared_msg);
271 }
272 }
273
274 using imessage_router::accepts;
275
276 //*******************************************
279 //*******************************************
280 virtual bool accepts(etl::message_id_t id) const ETL_OVERRIDE
281 {
282 if (!empty())
283 {
284 // Scan the subscription lists.
285 subscription* sub = static_cast<subscription*>(head.get_next());
286
287 while (sub != ETL_NULLPTR)
288 {
289 message_id_span_t message_ids = sub->message_id_list();
290
291 message_id_span_t::iterator itr = etl::find(message_ids.begin(), message_ids.end(), id);
292
293 if (itr != message_ids.end())
294 {
295 etl::imessage_router* router = sub->get_router();
296
297 if (router->accepts(id))
298 {
299 return true;
300 }
301 }
302
303 sub = sub->next_subscription();
304 }
305 }
306
307 // Check any successor.
308 if (has_successor())
309 {
310 if (get_successor().accepts(id))
311 {
312 return true;
313 }
314 }
315
316 return false;
317
318 //return true;
319 }
320
321 //*******************************************
322 void clear()
323 {
324 head.terminate();
325 }
326
327 //********************************************
328 ETL_DEPRECATED virtual bool is_null_router() const ETL_OVERRIDE
329 {
330 return false;
331 }
332
333 //********************************************
334 virtual bool is_producer() const ETL_OVERRIDE
335 {
336 return true;
337 }
338
339 //********************************************
340 virtual bool is_consumer() const ETL_OVERRIDE
341 {
342 return true;
343 }
344
345 //********************************************
346 bool empty() const
347 {
348 return head.get_next() == ETL_NULLPTR;
349 }
350
351 private:
352
353 //*******************************************
354 void initialise_insertion_point(const etl::imessage_router* p_router, etl::message_broker::subscription* p_new_sub)
355 {
356 const etl::imessage_router* p_target_router = p_router;
357
358 subscription_node* p_sub = head.get_next();
359 subscription_node* p_sub_previous = &head;
360
361 while (p_sub != ETL_NULLPTR)
362 {
363 // Do we already have a subscription for the router?
364 if (static_cast<subscription*>(p_sub)->get_router() == p_target_router)
365 {
366 // Then unlink it.
367 p_sub_previous->set_next(p_sub->get_next()); // Jump over the subscription.
368 p_sub->terminate(); // Terminate the unlinked subscription.
369
370 // We're done now.
371 break;
372 }
373
374 // Move on up the list.
375 p_sub = p_sub->get_next();
376 p_sub_previous = p_sub_previous->get_next();
377 }
378
379 if (p_new_sub != ETL_NULLPTR)
380 {
381 // Link in the new subscription.
382 p_sub_previous->append(p_new_sub);
383 }
384 }
385
386 subscription_node head;
387 };
388}
389
390#endif
This is the base of all message routers.
Definition message_router_generator.h:123
Definition message.h:73
Definition message_broker.h:100
Message broker.
Definition message_broker.h:47
void subscribe(etl::message_broker::subscription &new_sub)
Subscribe to the broker.
Definition message_broker.h:174
message_broker()
Constructor.
Definition message_broker.h:136
message_broker(etl::message_router_id_t id_)
Constructor.
Definition message_broker.h:154
virtual bool accepts(etl::message_id_t id) const ETL_OVERRIDE
Definition message_broker.h:280
message_broker(etl::message_router_id_t id_, etl::imessage_router &successor_)
Constructor.
Definition message_broker.h:164
message_broker(etl::imessage_router &successor_)
Constructor.
Definition message_broker.h:145
Router id is out of the legal range.
Definition message_router_generator.h:103
Definition shared_message.h:49
bool has_successor() const
Does this have a successor?
Definition successor.h:184
successor_type & get_successor() const
Definition successor.h:174
#define ETL_ASSERT(b, e)
Definition error_handler.h:316
bitset_ext
Definition absolute.h:38
uint_least8_t message_id_t
Allow alternative type for message id.
Definition message_types.h:40
pair holds two objects of arbitrary type
Definition utility.h:164