Skip to content

[23069] Generate code for interface servers #465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a68c65c
Refs #23069. Skeleton for server creation code.
MiguelCompany Apr 21, 2025
39f8863
Refs #23069. Skeleton for server class.
MiguelCompany Apr 21, 2025
0fcc536
Refs #23069. Initial implementation for run and stop.
MiguelCompany Apr 22, 2025
c5a4fc2
Refs #23069. Request validation.
MiguelCompany Apr 22, 2025
a909f73
Refs #23069. Initial processing code.
MiguelCompany Apr 22, 2025
9a3490c
Refs #23069. Prepare method per operation.
MiguelCompany Apr 23, 2025
1e1eac4
Refs #23069. Thread pool implementation.
MiguelCompany Apr 23, 2025
3c185d2
Refs #23069. Generate operation prototypes.
MiguelCompany Apr 23, 2025
e257269
Refs #23069. Generate operation empty implementations.
MiguelCompany Apr 23, 2025
4147ace
Refs #23069. Generate skeleton for calling operations.
MiguelCompany Apr 23, 2025
728d569
Refs #23069. Code for calling basic operations.
MiguelCompany Apr 23, 2025
84fbc28
Refs #23069. Code for handling user exceptions.
MiguelCompany Apr 23, 2025
0d8dd7e
Refs #23069. Code for output feed writers.
MiguelCompany Apr 24, 2025
9b44aa6
Refs #23069. Code for handling output feed operations.
MiguelCompany Apr 24, 2025
aff0ef1
Refs #23069. Refactor to improve readability.
MiguelCompany Apr 24, 2025
a3d52bc
Refs #23069. Generate code to handle output feed cancellation.
MiguelCompany Apr 24, 2025
fd9db15
Refs #23069. Fix client code for output feed cancellation.
MiguelCompany Apr 24, 2025
8bfefc3
Refs #23069. Infrastructure for input feed processing.
MiguelCompany Apr 24, 2025
8b32798
Refs #23069. Generate code for input feed readers.
MiguelCompany Apr 24, 2025
b28059c
Refs #23069. Improve readability.
MiguelCompany Apr 24, 2025
a23f554
Refs #23069. Code for operations with input feeds.
MiguelCompany Apr 24, 2025
9bc0014
Refs #23069. Generate declatation of implementation interface.
MiguelCompany Apr 25, 2025
0181e32
Refs #23069. ServerLogic depends on implementation interface.
MiguelCompany Apr 25, 2025
1793cc2
Refs #23069. Generate empty implementation interface.
MiguelCompany Apr 25, 2025
78b6d49
Refs #23069. Fix linters.
MiguelCompany Apr 25, 2025
a828f72
Refs #23069. Avoid processing `feed_cancel_` when not generated.
MiguelCompany May 5, 2025
6ee8714
Refs #23069. Log error when trying to cancel a non-feed request.
MiguelCompany May 5, 2025
ec1cbe3
Refs #23069. Cancel requests before terminating thread pool.
MiguelCompany May 5, 2025
60f7f34
Refs #23079. Change dll export macro.
MiguelCompany Apr 30, 2025
667699f
Refs #23079. Remove unnecessary namespace aliasing.
MiguelCompany Apr 30, 2025
c13121a
Refs #23079. Remove detail namespace in server implementation.
MiguelCompany Apr 30, 2025
c1f325a
Refs #23079. Avoid nested structures (not supported by Swig).
MiguelCompany Apr 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ paramTypeByRef(typecode) ::= <%
$typecode.cppTypename$&
%>

paramTypeByValue(typecode, feed) ::= <%
paramTypeByValue(typecode, feed, is_server) ::= <%
$if(feed)$
$if(is_server)$
eprosima::fastdds::dds::rpc::RpcServerReader<$typecode.cppTypename$>&
$else$
std::shared_ptr<eprosima::fastdds::dds::rpc::RpcClientWriter<$typecode.cppTypename$>>&
$endif$
$else$
$if(typecode.primitive)$
$typecode.cppTypename$
Expand All @@ -39,7 +43,7 @@ $endif$
%>

paramDeclarations(params, initialSeparator="") ::= <<
$if(params)$$initialSeparator$$endif$$params : {param | /*$param.comment$*/ $if(param.output)$$paramTypeByRef(typecode=param.typecode)$$else$$paramTypeByValue(typecode=param.typecode, feed=param.annotationFeed)$$endif$ $param.name$}; anchor, separator=",\n"$
$if(params)$$initialSeparator$$endif$$params : {param | /*$param.comment$*/ $if(param.output)$$paramTypeByRef(typecode=param.typecode)$$else$$paramTypeByValue(typecode=param.typecode, feed=param.annotationFeed, is_server=false)$$endif$ $param.name$}; anchor, separator=",\n"$
>>

object_serialization(ctx, object) ::= <<
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/eprosima/fastdds/fastddsgen.java
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,9 @@ private Project parseIDL(
tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSPubSubTypeSource.stg");
tmanager.addGroup("com/eprosima/fastdds/idl/templates/ClientHeader.stg");
tmanager.addGroup("com/eprosima/fastdds/idl/templates/ClientSource.stg");
tmanager.addGroup("com/eprosima/fastdds/idl/templates/ServerHeader.stg");
tmanager.addGroup("com/eprosima/fastdds/idl/templates/ServerSource.stg");
tmanager.addGroup("com/eprosima/fastdds/idl/templates/ServerImplementation.stg");

if (generate_typeobjectsupport_)
{
Expand Down Expand Up @@ -1072,6 +1075,21 @@ private Project parseIDL(
{
project.addCommonSrcFile(relative_dir + ctx.getFilename() + "Client.cxx");
}
if (returnedValue &=
Utils.writeFile(output_dir + ctx.getFilename() + "Server.hpp",
maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/ServerHeader.stg"), m_replace))
{
project.addCommonIncludeFile(relative_dir + ctx.getFilename() + "Server.hpp");
}
if (returnedValue &=
Utils.writeFile(output_dir + ctx.getFilename() + "Server.cxx",
maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/ServerSource.stg"), m_replace))
{
project.addCommonSrcFile(relative_dir + ctx.getFilename() + "Server.cxx");
}
returnedValue &=
Utils.writeFile(output_dir + ctx.getFilename() + "ServerImpl.hpp",
maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/ServerImplementation.stg"), m_replace);
}

if (ctx.existsLastStructure())
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/eprosima/fastdds/idl/grammar/Operation.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public boolean isAnnotationMutable()
return false;
}

public boolean isHasInputFeeds()
{
return m_hasInputFeeds;
}

@Override
public void add(com.eprosima.idl.parser.tree.Param param)
{
Expand All @@ -81,6 +86,7 @@ public void add(com.eprosima.idl.parser.tree.Param param)
{
// Take note that there is at least one input feed
m_context.setThereIsInputFeed(true);
m_hasInputFeeds = true;
}
}

Expand Down Expand Up @@ -242,4 +248,5 @@ public StructTypeCode getResultTypeCode()
private StructTypeCode m_in_type = null;
private StructTypeCode m_out_type = null;
private StructTypeCode m_result_type = null;
private boolean m_hasInputFeeds = false;
}
26 changes: 14 additions & 12 deletions src/main/java/com/eprosima/fastdds/idl/templates/ClientSource.stg
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,7 @@ $if(operation.annotationFeed)$
bool& should_remove) override
{
should_remove = false;
if (cancelled_ ||
(req_info.related_sample_identity != info.related_sample_identity))
if (req_info.related_sample_identity != info.related_sample_identity)
{
return;
}
Expand All @@ -433,23 +432,26 @@ $if(operation.annotationFeed)$
{
const auto& out = result.result.value();
{
if (out.return_.has_value())
if (out.finished_.has_value())
{
// Store the return value
// Store the finished value
std::lock_guard<std::mutex> _(mtx_);
queue_.push(out.return_.value());
finished_ = true;
cv_.notify_all();
}
else if (out.return_.has_value())
{
if (!cancelled_)
{
// Store the return value
std::lock_guard<std::mutex> _(mtx_);
queue_.push(out.return_.value());
cv_.notify_all();
}

// Should be kept in order to receive further values
should_remove = false;
}
else if (out.finished_.has_value())
{
// Store the finished value
std::lock_guard<std::mutex> _(mtx_);
finished_ = true;
cv_.notify_all();
}
else
{
set_invalid_reply(*this);
Expand Down
144 changes: 144 additions & 0 deletions src/main/java/com/eprosima/fastdds/idl/templates/ServerHeader.stg
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Copyright 2025 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

group ProtocolHeader;

import "eprosima.stg"
import "com/eprosima/fastcdr/idl/templates/FastCdrCommon.stg"

main(ctx, definitions) ::= <<
$fileHeader(ctx=ctx, file=[ctx.filename, "Server.hpp"], description=["Server implementation for interfaces"])$

#ifndef FAST_DDS_GENERATED__$ctx.headerGuardName$_SERVER_HPP
#define FAST_DDS_GENERATED__$ctx.headerGuardName$_SERVER_HPP

#include <memory>

#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/qos/ReplierQos.hpp>
#include <fastdds/dds/rpc/exceptions.hpp>
#include <fastdds/dds/rpc/interfaces.hpp>
#include <fastdds/rtps/common/Guid.hpp>
#include <fastdds/rtps/common/RemoteLocators.hpp>

#include "$ctx.filename$.hpp"

$definitions; separator="\n"$

#endif // FAST_DDS_GENERATED__$ctx.headerGuardName$_CLIENT_HPP

>>

module(ctx, parent, module, definition_list) ::= <<
namespace $module.name$ {

$definition_list$

} // namespace $module.name$

>>

interface(ctx, parent, interface, export_list) ::= <<
struct $interface.name$Server
{
/**
* @brief Context for a client request.
*/
struct ClientContext
{
virtual ~ClientContext() = default;

/**
* @brief Get the GUID of the client that made the request.
*
* @return The GUID of the client that made the request.
*/
virtual const eprosima::fastdds::rtps::GUID_t& get_client_id() const = 0;

/**
* @brief Get the locators of the client that made the request.
*
* @return The locators of the client that made the request.
*/
virtual const eprosima::fastdds::rtps::RemoteLocatorList& get_client_locators() const = 0;
};

struct IServerImplementation
{
virtual ~IServerImplementation() = default;

$interface.all_operations:{op | $operation_prototype(op)$}; separator="\n\n"$
};

virtual ~$interface.name$Server() = default;

/**
* @brief Run the server.
*
* This method starts the server and begins processing requests.
* The method will block until the server is stopped.
*/
virtual void run() = 0;

/**
* @brief Stop the server.
*
* This method stops the server and releases all resources.
* It will cancel all pending requests, and wait for all processing threads to finish before returning.
*/
virtual void stop() = 0;

};

/**
* @brief Create a $interface.name$Server instance.
*
* @param part The DomainParticipant to use for the server.
* @param service_name The name of the service.
* @param qos The QoS settings for the server.
* @param thread_pool_size The size of the thread pool to use for processing requests.
* When set to 0, a new thread will be created when no threads are available.
* @param implementation The implementation of the server interface.
*/
extern $ctx.fileNameUpper$_DllAPI std::shared_ptr<$interface.name$Server> create_$interface.name$Server(
eprosima::fastdds::dds::DomainParticipant& part,
const char* service_name,
const eprosima::fastdds::dds::ReplierQos& qos,
size_t thread_pool_size,
std::shared_ptr<$interface.name$Server::IServerImplementation> implementation);
>>

operation_prototype(op) ::= <<
$if(op.annotationFeed)$
virtual void $op.name$(
const ClientContext& info,
$if(op.parameters)$
$operation_parameters(op.parameters)$,
$endif$
/*result*/ eprosima::fastdds::dds::rpc::RpcServerWriter<$paramRetType(op.rettype)$>& result_writer) = 0;
$else$
$if(op.parameters)$
virtual $paramRetType(op.rettype)$ $op.name$(
const ClientContext& info,
$operation_parameters(op.parameters)$) = 0;
$else$
virtual $paramRetType(op.rettype)$ $op.name$(
const ClientContext& info) = 0;
$endif$
$endif$
>>

operation_parameters(params) ::= <<
$params : {param | /*$param.comment$*/ $if(param.output)$$paramTypeByRef(typecode=param.typecode)$$else$$paramTypeByValue(typecode=param.typecode, feed=param.annotationFeed, is_server=true)$$endif$ $param.name$}; anchor, separator=",\n"$
>>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2025 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

group ProtocolHeader;

import "eprosima.stg"
import "com/eprosima/fastcdr/idl/templates/FastCdrCommon.stg"

main(ctx, definitions) ::= <<
$fileHeader(ctx=ctx, file=[ctx.filename, "ServerImpl.hpp"], description=["Server implementation for interfaces"])$

#ifndef FAST_DDS_GENERATED__$ctx.headerGuardName$_SERVERIMPL_HPP
#define FAST_DDS_GENERATED__$ctx.headerGuardName$_SERVERIMPL_HPP

#include "$ctx.filename$.hpp"
#include "$ctx.filename$Server.hpp"

$definitions; separator="\n"$

#endif // FAST_DDS_GENERATED__$ctx.headerGuardName$_SERVERIMPL_HPP

>>

module(ctx, parent, module, definition_list) ::= <<
namespace $module.name$ {

$definition_list$

} // namespace $module.name$

>>

interface(ctx, parent, interface, export_list) ::= <<
//{ interface $interface.name$

namespace detail {

namespace fdds = eprosima::fastdds::dds;
namespace frpc = eprosima::fastdds::dds::rpc;
namespace frtps = eprosima::fastdds::rtps;

struct $interface.name$ServerImplementation :
public $interface.name$Server::IServerImplementation
{

$interface.all_operations:{op | $operation_implementation(interface, op)$}; separator="\n"$

};

} // namespace detail

//} interface $interface.name$

>>

operation_implementation(interface, op) ::= <<
$if(op.annotationFeed)$
void $op.name$(
const $interface.name$Server::ClientContext& info,
$if(op.parameters)$
$operation_parameters(op.parameters)$,
$endif$
/*result*/ frpc::RpcServerWriter<$paramRetType(op.rettype)$>& result_writer) override
$else$
$if(op.parameters)$
$paramRetType(op.rettype)$ $op.name$(
const $interface.name$Server::ClientContext& info,
$operation_parameters(op.parameters)$) override
$else$
$paramRetType(op.rettype)$ $op.name$(
const $interface.name$Server::ClientContext& info) override
$endif$
$endif$
{
static_cast<void>(info);
$op.parameters : {param | static_cast<void>($param.name$);}; anchor, separator="\n"$
$if(op.annotationFeed)$
static_cast<void>(result_writer);
$endif$
throw frpc::RemoteUnsupportedError("Operation '$op.name$' is not implemented");
}
>>

operation_parameters(params) ::= <<
$params : {param | /*$param.comment$*/ $if(param.output)$$paramTypeByRef(typecode=param.typecode)$$else$$paramTypeByValue(typecode=param.typecode, feed=param.annotationFeed, is_server=true)$$endif$ $param.name$}; anchor, separator=",\n"$
>>
Loading