17.1.3. RPC Replier¶
A Replier is the RPC Entity used in the communication at the server side, processing the received Request samples and sending Reply samples back to the Requester when the result of the operation is ready.
Since each Replier is used in only one Request/Reply communication, represented by a Service, all of them are registered
in a Service instance when created.
The name of the service associated with a Replier can be accessed using Replier::get_service_name()
method.
Similarly to the rest of the RPC entities, Replier
instances can be enabled or disabled,
according to whether they contain DDS entities or not:
Each active Replier contains two DDS entities: a DataWriter, which is used to publish Reply samples, and a DataReader, which is used to receive Request samples.
Each disabled Replier does not contain any DDS entity and is ignored by the middleware. Therefore, it cannot take requests nor send replies.
For consistency, the states of each Replier instance and its associated Service must follow the compatibility rule below:
where replier_state
is the state of the Replier instance and service_state
is the state of the associated Service, and the order of the states is defined as \(disabled < enabled\).
17.1.3.1. Creating a Replier¶
A new Replier instance can be created in an enabled or disabled Service using
DomainParticipant::create_service_replier()
method.
When a new Replier instance is created, it is registered internally in the Service.
Each Service can contain multiple Replier instances.
Note
Following the state compatibility rule, calling DomainParticipant::create_service_replier()
using a
disabled Service
instance as input parameter creates a disabled Replier
.
Reciprocally, calling DomainParticipant::create_service_replier()
with an enabled Service
instance tries
to return an enabled Replier
.
If the process of enabling the Replier fails (i.e., the creation of the internal DDS entities),
DomainParticipant::create_service_replier()
returns nullptr
.
All Replier’s DDS entities Qos can be configured manually when
creating the Replier
instance using ReplierQos
.
Before creating the Replier, Service validates DataWriterQos
and DataReaderQos
provided
in the ReplierQos
instance:
if some field is not valid, Service will notify it to the user using a log message error and Replier is not created.
User must ensure that ReliabilityQosPolicyKind
of both DataWriter and DataReader are set to RELIABLE_RELIABILITY_QOS
.
This is configured automatically when a new ReplierQos
instance is created.
Note
Before creating a new Replier, user must create its associated Service
instance in the DomainParticipant.
If a null pointer or a Service associated with a different participant are provided,
Replier is not created and DomainParticipant::create_service_replier()
method returns a null pointer.
17.1.3.2. Enabling and disabling a Replier¶
Replier
instances can be enabled or disabled using
enable()
and close()
methods, respectively.
When a disabled Replier
instance is enabled, a new DataWriter on the Reply topic and
a new DataReader on Request topic are created using the Qos configured at creation through ReplierQos
.
User can access to the DataWriter and DataReader instances using Replier::get_replier_writer()
and
Replier::get_replier_reader()
methods, respectively.
Reciprocally, when an enabled Replier is disabled, its respective DataWriter and DataReader are destroyed, making the Replier not participate in the communication through the Service.
Warning
A disabled Replier does not contain DDS entities, so Replier::get_replier_writer()
and
Replier::get_replier_reader()
return a null pointer in this case.
The user must be responsible for checking that the Replier is enabled
using the is_enabled()
method before accessing the Replier’s internal DDS entities.
17.1.3.3. Deleting a Replier¶
A Replier
instance can be unregistered from a Service and deleted using
DomainParticipant::delete_service_replier()
method.
This method can be called on Repliers in any state: if enabled, it will try to disable the instance,
returning a ReturnCode_t
error if it was not possible to close the Replier.
Note
If there is no Service
with the provided service_name
or the Replier is associated with a different Service,
DomainParticipant::delete_service_replier()
method will return a ReturnCode_t
error.
17.1.3.4. Sending and receiving samples¶
Request samples are taken using the Replier::take_request()
method.
When this method is called, Replier takes received Request samples from the history of the internal DataReader
and fills the related_sample_identity
member of the provided RequestInfo
struct
with the related_sample_identity`
of the received Request sample.
The Replier public API provides two overloads for Replier::take_request()
,
depending on whether you want to take only the next sample or all samples from the DataReader history.
Note
In case of using the overload that takes all samples, the loan must be returned to avoid memory problems.
The user must therefore be responsible for calling the Replier::return_loan()
method after
finishing processing the samples.
After processing the Request, Replier sends a new Reply sample using the Replier::send_reply()
method
and passing the previously created RequestInfo
as an input parameter.
When Replier::send_reply()
method is called,
the created DataWriter sends a new Reply sample with the provided data and
the related_sample_identity
of the Request sample that originated the Reply,
to allow Request and Reply samples correlation at the Requester side.
Warning
If a Reply sample is sent before discovering the Requester Reply topic DataReader, the middleware will not be able to deliver the Reply sample and will discard it. The endpoint matching algorithm described in RPC over DDS Standard will be implemented in future releases.
17.1.3.5. Example¶
The following code snippet shows how to use a Replier instance:
ReturnCode_t ret;
// Get a valid service
Service* service = participant->find_service("Service");
if (!service)
{
// Error
return;
}
/* Create a new Replier instance */
ReplierQos replier_qos;
Replier* replier = participant->create_service_replier(service, replier_qos);
if (!replier)
{
// Error
return;
}
/* Take a received Request sample and send a new Reply sample */
// Make sure that all RPC Entities are enabled
if (!service->is_enabled())
{
ret = service->enable();
if (RETCODE_OK != ret)
{
// Error
return;
}
}
// Enabling the service enables the registered Replier unless
// the creation of the internal DataWriter and DataReader failed.
// We can make sure that they have been created correctly by checking if the Replier is enabled.
if (!replier->is_enabled())
{
// Error
return;
}
RequestInfo received_request_info;
// Wait for some time until a Request sample is received
replier->get_replier_reader()->wait_for_unread_message(Duration_t{3,0});
void* received_data = nullptr;
ret = replier->take_request(received_data, received_request_info);
if (RETCODE_OK != ret)
{
// Error
return;
}
// ... Process received data
// Send a Reply with the received related_sample_identity
void* reply_data = reply_type_support->create_data();
ret = replier->send_reply(reply_data, received_request_info);
if (RETCODE_OK != ret)
{
// Error
return;
}
/* Delete created Replier */
ret = participant->delete_service_replier(replier->get_service_name(), replier);
if (RETCODE_OK != ret)
{
// Error
return;
}