RTI Routing Service Version 7.7.0
StreamReaderForwarder.hpp
1/*
2 * (c) Copyright, Real-Time Innovations, 2017.
3 * All rights reserved.
4 *
5 * No duplications, whole or partial, manual or electronic, may be made
6 * without express written permission. Any such copies, or
7 * revisions thereof, must display this notice unaltered.
8 * This code contains trade secrets of Real-Time Innovations, Inc.
9 */
10
11#ifndef RTI_ROUTING_ADAPTER_DETAIL_STREAM_READER_FORWARDER_HPP_
12#define RTI_ROUTING_ADAPTER_DETAIL_STREAM_READER_FORWARDER_HPP_
13
14#include <assert.h>
15#include <list>
16#include <rti/core/Exception.hpp>
17
18#include <rti/apputils/ServiceException.hpp>
19
20#include <rti/routing/adapter/StreamReader.hpp>
21#include <rti/routing/StreamInfo.hpp>
22#include <rti/routing/detail/UpdatableEntityForwarder.hpp>
23#include <rti/routing/detail/ForwarderUtils.hpp>
24#include <rti/routing/adapter/detail/DiscoveryStreamReaderForwarder.hpp>
25
26
27namespace rti { namespace routing { namespace adapter { namespace detail {
28
29template <bool ReadOrTake, bool HasSelector> struct read_or_take;
30
31
32template<>
33struct read_or_take<false, false> {
34
35 static void read(
37 std::vector<StreamReader::SamplePtr>& sample_seq,
38 std::vector<StreamReader::InfoPtr>& info_seq,
39 const struct RTI_RoutingServiceSelectorState *)
40 {
41 stream_reader.take(sample_seq, info_seq);
42 }
43};
44
45template<>
46struct read_or_take<true, false> {
47
48 static void read(
50 std::vector<StreamReader::SamplePtr>& sample_seq,
51 std::vector<StreamReader::InfoPtr>& info_seq,
52 const struct RTI_RoutingServiceSelectorState *)
53 {
54 stream_reader.read(sample_seq, info_seq);
55 }
56};
57
58template<>
59struct read_or_take<false, true> {
60
61 static void read(
63 std::vector<StreamReader::SamplePtr>& sample_seq,
64 std::vector<StreamReader::InfoPtr>& info_seq,
65 const struct RTI_RoutingServiceSelectorState *native_selector)
66 {
67 stream_reader.take(
68 sample_seq,
69 info_seq,
70 SelectorState(*native_selector));
71 }
72};
73
74
75template<>
76struct read_or_take<true, true> {
77
78 static void read(
80 std::vector<StreamReader::SamplePtr>& sample_seq,
81 std::vector<StreamReader::InfoPtr>& info_seq,
82 const struct RTI_RoutingServiceSelectorState *native_selector)
83 {
84 stream_reader.read(
85 sample_seq,
86 info_seq,
87 SelectorState(*native_selector));
88 }
89};
90
91
92struct SamplesHolder {
93public:
94
95 SamplesHolder()
96 {
97 }
98
99 std::vector<StreamReader::SamplePtr> sample_seq_;
100 std::vector<StreamReader::InfoPtr> info_seq_;
101};
102
103class StreamReaderForwarder {
104public:
105 static RTI_RoutingServiceStreamReaderExt* create_native(
106 Connection *connection,
107 Session *session,
108 const struct RTI_RoutingServiceStreamInfo *native_stream_info,
109 const struct RTI_RoutingServiceProperties *native_properties,
110 const struct RTI_RoutingServiceStreamReaderListenerExt *native_listener,
111 RTI_RoutingServiceEnvironment *environment)
112 {
113
114 try {
115 using rti::routing::detail::ScopedForwarder;
116
117 StreamInfo stream_info(*native_stream_info);
118
119 std::map<std::string, std::string> properties;
120 rti::routing::PropertyAdapter::add_properties_from_native(
121 properties,
122 native_properties);
123
124 StreamReaderForwarder *forwarder = new StreamReaderForwarder(
125 native_listener);
126 ScopedForwarder<Connection, StreamReaderForwarder> scoped(
127 connection,
128 forwarder,
129 environment);
130 forwarder->stream_reader_ = connection->create_stream_reader(
131 session,
132 stream_info,
133 properties,
134 &forwarder->listener_);
135 RTI_ROUTING_THROW_ON_NULL(forwarder->stream_reader_);
136
137 scoped.release();
138
139 // TRUST-134: the forwarder is not leaked here. It might be leaked
140 // if delete_native() were not to be called, but Routing Service
141 // will make sure that is not the case
142
143 /* coverity[leaked_storage : FALSE] */
144 return forwarder->native();
145 } catch(const rti::apputils::FatalServiceException& ex) {
146 RTI_RoutingServiceEnvironment_fatal_error(
147 environment,
148 ex.what());
149 return NULL;
150 } catch(const std::exception& ex) {
151 RTI_RoutingServiceEnvironment_set_error(
152 environment,
153 ex.what());
154 return NULL;
155 } catch (...) {
156 RTI_RoutingServiceEnvironment_set_error(
157 environment,
158 "unexpected exception");
159 return NULL;
160 }
161
162
163 }
164
165 static void delete_native(
166 Connection *connection,
167 RTI_RoutingServiceStreamReaderExt *native_stream_reader,
168 RTI_RoutingServiceEnvironment *environment)
169 {
170 StreamReaderForwarder *stream_reader_forwarder =
171 from_native(native_stream_reader);
172 try {
173 if (stream_reader_forwarder->stream_reader_ != NULL) {
174 connection->delete_stream_reader(
175 stream_reader_forwarder->stream_reader_);
176 stream_reader_forwarder->stream_reader_ = NULL;
177 }
178 } catch(const rti::apputils::FatalServiceException& ex) {
179 RTI_RoutingServiceEnvironment_fatal_error(
180 environment,
181 ex.what());
182 } catch(const std::exception& ex) {
183 RTI_RoutingServiceEnvironment_set_error(
184 environment,
185 ex.what());
186 } catch (...) {
187 RTI_RoutingServiceEnvironment_set_error(
188 environment,
189 "unexpected exception");
190 }
191
192 delete stream_reader_forwarder;
193 }
194
195
196 RTI_RoutingServiceStreamReaderExt* native()
197 {
198 return &this->native_;
199 }
200
201
202private:
203
204 StreamReaderForwarder(
205 const RTI_RoutingServiceStreamReaderListenerExt *native_listener) :
206 stream_reader_(NULL),
207 listener_(native_listener)
208 {
209 RTIOsapiMemory_zero(&native_, sizeof(native_));
210 native_.stream_reader_data =
211 static_cast<void *>(this);
212 native_.take =
213 StreamReaderForwarder::take;
214 native_.read =
215 StreamReaderForwarder::read;
216 native_.take_w_selector =
217 StreamReaderForwarder::take_with_selector;
218 native_.read_w_selector =
219 StreamReaderForwarder::read_with_selector;
220 native_.return_loan =
221 StreamReaderForwarder::return_loan;
222 native_.create_content_query =
223 StreamReaderForwarder::create_content_query;
224 native_.delete_content_query =
225 StreamReaderForwarder::delete_content_query;
226 native_.update =
227 StreamReaderForwarder::update;
228 }
229
230 ~StreamReaderForwarder()
231 {
232 // delete holders
233 for (std::list<SamplesHolder*>::iterator it = holder_pool_.begin();
234 it != holder_pool_.end();
235 ++it) {
236 delete (*it);
237 }
238 }
239
240
241 static void take(
242 void *native_stream_reader_data,
243 RTI_RoutingServiceSample **sample_array,
244 RTI_RoutingServiceSampleInfo **sample_info_array,
245 int *array_length,
246 RTI_RoutingServiceEnvironment *environment)
247 {
248 proxy_read<false, false>(
249 native_stream_reader_data,
250 sample_array,
251 sample_info_array,
252 array_length,
253 NULL,
254 environment);
255 }
256
257 static void read(
258 void *native_stream_reader_data,
259 RTI_RoutingServiceSample **sample_array,
260 RTI_RoutingServiceSampleInfo **sample_info_array,
261 int *array_length,
262 RTI_RoutingServiceEnvironment *environment)
263 {
264 proxy_read<true, false>(
265 native_stream_reader_data,
266 sample_array,
267 sample_info_array,
268 array_length,
269 NULL,
270 environment);
271 }
272
273 static void take_with_selector(
274 void *native_stream_reader_data,
275 RTI_RoutingServiceSample **sample_array,
276 RTI_RoutingServiceSampleInfo **sample_info_array,
277 int *array_length,
278 const struct RTI_RoutingServiceSelectorState *native_selector,
279 RTI_RoutingServiceEnvironment *environment)
280 {
281 proxy_read<false, true>(
282 native_stream_reader_data,
283 sample_array,
284 sample_info_array,
285 array_length,
286 native_selector,
287 environment);
288 }
289
290 static void read_with_selector(
291 void *native_stream_reader_data,
292 RTI_RoutingServiceSample **sample_array,
293 RTI_RoutingServiceSampleInfo **sample_info_array,
294 int *array_length,
295 const struct RTI_RoutingServiceSelectorState *native_selector,
296 RTI_RoutingServiceEnvironment *environment)
297 {
298 proxy_read<true, true>(
299 native_stream_reader_data,
300 sample_array,
301 sample_info_array,
302 array_length,
303 native_selector,
304 environment);
305 }
306
307 static void return_loan(
308 void *native_stream_reader_data,
309 RTI_RoutingServiceSample *native_samples,
310 RTI_RoutingServiceSampleInfo *,
311 int count,
312 RTI_RoutingServiceEnvironment *environment)
313 {
314 StreamReaderForwarder *forwarder =
315 static_cast<StreamReaderForwarder*>(native_stream_reader_data);
316 assert(forwarder != NULL);
317
318 SamplesHolder *holder = static_cast<SamplesHolder*>(
319 native_samples[count]);
320 assert(holder != NULL);
321
322
323 try {
324 forwarder->stream_reader_->return_loan(
325 holder->sample_seq_,
326 holder->info_seq_);
327 } catch (const rti::apputils::FatalServiceException& ex) {
328 RTI_RoutingServiceEnvironment_fatal_error(
329 environment,
330 ex.what());
331 } catch (const std::exception& ex) {
332 RTI_RoutingServiceEnvironment_set_error(
333 environment,
334 ex.what());
335 } catch (...) {
336 RTI_RoutingServiceEnvironment_set_error(
337 environment,
338 "unexpected exception");
339 }
340
341 forwarder->return_holder(holder);
342 }
343
344 static void update(
345 void *native_stream_reader_data,
346 const struct RTI_RoutingServiceProperties * native_properties,
347 RTI_RoutingServiceEnvironment * environment)
348 {
349
350 StreamReaderForwarder *stream_reader_forwarder =
351 static_cast<StreamReaderForwarder*>(native_stream_reader_data);
352
353 rti::routing::detail::UpdatableEntityForwarder::update(
354 stream_reader_forwarder->stream_reader_,
355 native_properties,
356 environment);
357 }
358
359 static void* create_content_query(
360 void *native_stream_reader_data,
361 RTI_RoutingServiceSelectorStateQueryData old_query_data,
362 const struct RTI_RoutingServiceSelectorContent *content,
363 RTI_RoutingServiceEnvironment *environment)
364 {
365 StreamReaderForwarder *forwarder =
366 static_cast<StreamReaderForwarder*>(native_stream_reader_data);
367
368 void *query_data = NULL;
369 try {
370 dds::topic::Filter filter(
371 content->expression == NULL ? "" : content->expression,
372 rti::core::native_conversions::from_native<std::string>(
373 content->expression_parameters));
374 query_data = forwarder->stream_reader_->create_content_query(
375 old_query_data,
376 filter);
377 } catch (const rti::apputils::FatalServiceException& ex) {
378 RTI_RoutingServiceEnvironment_fatal_error(
379 environment,
380 ex.what());
381 } catch (const std::exception& ex) {
382 RTI_RoutingServiceEnvironment_set_error(
383 environment,
384 ex.what());
385 } catch (...) {
386 RTI_RoutingServiceEnvironment_set_error(
387 environment,
388 "unexpected exception");
389 }
390
391 return query_data;
392 }
393
394 static void delete_content_query(
395 void *native_stream_reader_data,
396 RTI_RoutingServiceSelectorStateQueryData query_data,
397 RTI_RoutingServiceEnvironment *environment)
398 {
399 StreamReaderForwarder *forwarder =
400 static_cast<StreamReaderForwarder*>(native_stream_reader_data);
401 try {
402 forwarder->stream_reader_->delete_content_query(query_data);
403 } catch (const std::exception& ex) {
404 RTI_RoutingServiceEnvironment_set_error(
405 environment,
406 "%s",
407 ex.what());
408 } catch (...) {
409 RTI_RoutingServiceEnvironment_set_error(
410 environment,
411 "unexpected exception");
412 }
413 }
414
415 static StreamReaderForwarder* from_native(
416 RTI_RoutingServiceStreamReaderExt *native)
417 {
418 return static_cast<StreamReaderForwarder*>(native->stream_reader_data);
419 }
420
421 template <bool ReadOrTake, bool HasSelector>
422 static void proxy_read(
423 void *native_stream_reader_data,
424 RTI_RoutingServiceSample **sample_array,
425 RTI_RoutingServiceSampleInfo **sample_info_array,
426 int *array_length,
427 const struct RTI_RoutingServiceSelectorState *native_selector,
428 RTI_RoutingServiceEnvironment *environment)
429 {
430 StreamReaderForwarder *forwarder =
431 static_cast<StreamReaderForwarder*>(native_stream_reader_data);
432 assert(forwarder != NULL);
433
434 SamplesHolder *holder = forwarder->get_holder();
435
436 *array_length = 0;
437 try {
438 read_or_take<ReadOrTake, HasSelector>::read(
439 *forwarder->stream_reader_,
440 holder->sample_seq_,
441 holder->info_seq_,
442 native_selector);
443 if (!holder->info_seq_.empty()
444 && (holder->info_seq_.size() != holder->sample_seq_.size())) {
445 throw dds::core::PreconditionNotMetError(
446 "sample and info sequences length mismatch");
447 }
448 /*
449 * We reserve a hidden slot in the sample_seq to keep the original
450 * loaned returned from the native StreamReader. This allows us
451 * to quickly access it on return_loan(), instead of having to search
452 * in a list.
453 *
454 * TRUST-1466: reserving just 1 more memory spot can be inefficient,
455 * and we're doing this for every read/take operation called in C++.
456 */
457 if (holder->sample_seq_.size() + 1
458 >= holder->sample_seq_.capacity()) {
459 holder->sample_seq_.reserve(
460 holder->sample_seq_.capacity() == 0
461 ? 1
462 : 2 * holder->sample_seq_.capacity());
463 }
464 *(holder->sample_seq_.data() + holder->sample_seq_.size()) = holder;
465 } catch (const rti::apputils::FatalServiceException& ex) {
466 RTI_RoutingServiceEnvironment_fatal_error(
467 environment,
468 ex.what());
469 forwarder->return_holder(holder);
470 return;
471 } catch (const std::exception& ex) {
472 RTI_RoutingServiceEnvironment_set_error(
473 environment,
474 ex.what());
475 forwarder->return_holder(holder);
476 return;
477 } catch (...) {
478 RTI_RoutingServiceEnvironment_set_error(
479 environment,
480 "unexpected exception");
481 forwarder->return_holder(holder);
482 return;
483 }
484
485 // direct mapping
486 *array_length = static_cast<int>(holder->sample_seq_.size());
487 *sample_array = holder->sample_seq_.data();
488 if (holder->info_seq_.empty()) {
489 *sample_info_array = NULL;
490 } else {
491 *sample_info_array = &holder->info_seq_[0];
492 }
493 }
494
495 SamplesHolder* get_holder()
496 {
497 if (holder_pool_.size() == 0) {
498 return new SamplesHolder();
499 }
500
501 SamplesHolder *holder = holder_pool_.front();
502 holder_pool_.pop_front();
503
504 return holder;
505 }
506
507 void return_holder(SamplesHolder *holder)
508 {
509 holder->sample_seq_.clear();
510 holder->info_seq_.clear();
511 holder_pool_.push_front(holder);
512 }
513
514private:
515
516 RTI_RoutingServiceStreamReaderExt native_;
517 StreamReader *stream_reader_;
518 StreamReaderListener listener_;
519 std::list<SamplesHolder*> holder_pool_;
520};
521
522}}}}
523
524#endif // RTI_ROUTING_ADAPTER_DETAIL_STREAM_READER_FORWARDER_HPP_
Listener representation used by StreamReader to notify RTI Routing Service when new data is available...
Provides a way to read samples of a specific type from a data domain. In the XML configuration file,...
Definition: StreamReader.hpp:45
virtual void take(std::vector< SamplePtr > &sample_seq, std::vector< InfoPtr > &info_seq)=0
Takes a collection of all data samples and info samples available from an input stream.
virtual void read(std::vector< SamplePtr > &sample_seq, std::vector< InfoPtr > &info_seq)=0
Variation of StreamReader::take where the returned samples will remain in the StreamReader's cache,...