Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(xml_FILE rsc_service.xml)
SET(SRCS_lib
logger.cpp
logger.h
connection.cpp
connection.h
data_writer_task.cpp
data_writer_task.h
session.cpp
session.h
session_handler.cpp
session_handler.h
)
NGL_ADD_LIBRARY2(WS AAR SV rscCommon SHARED ${SRCS_lib})
NGL_TARGET_LINK_LIBRARIES(rscCommon
PRIVATE
LtsPluginLoader
PUBLIC
ddsconnector
NGLLogger
Qt5::Core
)
## currently no ruting service in guez
#IF (NOT GUEZ_MODE)#
#SET(SRCS_exe
# main_handler.cpp
# main_handler.h
# main.cpp
# partition_handler.cpp
# partition_handler.h
#)
# make sure xml file is properly installed
#CODEGEN_HANDLE_SVC_XML(SRCS_exe ${xml_FILE})
#NGL_ADD_SVC_ICON(SRCS_exe)
#NGL_ADD_EXECUTABLE(AAR SV svcRoutingServiceNG ${SRCS_exe})
#NGL_TARGET_LINK_LIBRARIES(svcRoutingServiceNG
# rscCommon
# Qt5::Core
# ddsgen
# ddsconnector
# RTI::nddsc
# RTI::nddscore
# RTI::nddscpp2
# LtsCommandLineParser
# NGLLogger
# nglcoreapplication
# routing_plugin#
# ddscore
# svcCoreClient
# svcExmClient
#)
#NGL_INSTALL_TARGET(svcRoutingServiceNG)
#NGL_INSTALL(AAR SV FILES log4cxx_rsc.props DESTINATION bin)
#NGL_ADD_TARGET_LINK(svcRoutingServiceNG sRSC)
#ENDIF()
+188
View File
@@ -0,0 +1,188 @@
/**
* @RDE_HEADER@
* Routing Test - main connection handling
* $Id$
* $HeadURL$
* $Author$
*/
#include "connection.h"
#include "data_writer_task.h"
#include <QCoreApplication>
#include <QElapsedTimer>
#include <DDS/DDSConnector/publisher.h>
#include <DDS/DDSConnector/subscriber.h>
namespace RoutingService
{
Connection::Connection(const dds::domain::DomainParticipant &domainParticipant,
const std::string &partition,
const std::vector<TopicDispatcherInterface *> &topicsToRoute,
const std::string &desc)
: m_output(nullptr)
, m_domainParticipant(domainParticipant)
, m_publisher(new DDSConnector::Publisher(domainParticipant, partition))
, m_subscriber(new DDSConnector::Subscriber(domainParticipant, partition, false))
, m_dataWriterTask(nullptr)
, m_topicsToRoute(topicsToRoute)
, m_partition(partition)
, m_description(desc)
, m_logger(getLogger("Connection"))
{
INFO_LOG(m_logger) << "Create connection: " << partition
<< ", domain: " << domainParticipant.domain_id()
<< ", direction: " << m_description
<< " (" << this << ")";
}
Connection::~Connection()
{
setOutput(nullptr);
shutdown();
try
{
if (m_subscriber)
m_subscriber->getDdsSubscriber().close();
}
catch (const dds::core::Exception &ex)
{
ERROR_LOG(m_logger) << "sub close ex: " << ex.what();
}
m_subscriber = nullptr;
try
{
if (m_publisher)
m_publisher->getDdsPublisher().close();
}
catch (const dds::core::Exception &ex)
{
ERROR_LOG(m_logger) << "pub close ex: " << ex.what();
}
m_publisher = nullptr;
m_domainParticipant = nullptr;
}
void Connection::setOutput(Connection *output)
{
if (m_output == output)
return;
m_output = output;
}
bool Connection::initialize()
{
DEBUG_LOG(m_logger) << "initialize new connection for " << m_partition
<< ", direction: " << m_description
<< " (" << this << ")";
if (m_writerThread.valid())
shutdown();
m_dataWriterTask.reset(new DataWriterTask);
if (!m_output)
{
ERROR_LOG(m_logger) << "Error initializing connection for " << m_partition
<< ", direction: " << m_description << " - no output set!";
return false;
}
m_writerThread = std::async(std::launch::async, [this]() { this->m_dataWriterTask->writeSamples();});
return initTopics();
}
void Connection::shutdown()
{
if (m_topicsToRoute.empty())
return;
QElapsedTimer timer;
timer.start();
DEBUG_LOG(m_logger) << "shutting down connection for " << m_partition
<< ", direction: " << m_description
<< " (" << this << "), dwt: " << m_dataWriterTask.get();
// inform DataWriterTask about its destruction in the near future
// it removes it not yet sent samples and does not enqueue new samples
if (m_dataWriterTask)
m_dataWriterTask->shutdown();
// now remove topics, they don't have outstanding loans since dataWrterTask does
// not enqueue samples anymore
for (auto topic : m_topicsToRoute)
{
if (timer.elapsed() > 1000)
{
QCoreApplication::processEvents(); // for e.g. paceMaker
timer.start();
}
topic->shutdown();
}
qDeleteAll(m_topicsToRoute);
m_topicsToRoute.clear();
// now we can wait until the data writer task has finished
if (m_dataWriterTask)
{
m_writerThread.wait();
m_dataWriterTask = nullptr;
}
}
dds::domain::DomainParticipant Connection::domainParticipant() const
{
return m_domainParticipant;
}
dds::pub::Publisher Connection::publisher() const
{
return m_publisher->getDdsPublisher();
}
dds::sub::Subscriber Connection::subscriber() const
{
return m_subscriber->getDdsSubscriber();
}
bool Connection::initTopics()
{
DEBUG_LOG(m_logger) << "Init topics for " << m_partition
<< ", direction: " << m_description;
if (!m_output)
return false;
QElapsedTimer timer;
timer.start();
auto dpOut = m_output->domainParticipant();
auto pubOut = m_output->publisher();
for (auto dp : m_topicsToRoute)
{
if (!dp)
continue;
if (!dp->init(m_dataWriterTask.get(),
m_domainParticipant,
m_subscriber->getDdsSubscriber(),
dpOut,
pubOut))
return false;
if (timer.elapsed() > 1000)
{
QCoreApplication::processEvents(); // for e.g. paceMaker
timer.start();
}
}
return true;
}
} // namespace RoutingService
+59
View File
@@ -0,0 +1,59 @@
/**
* @RDE_HEADER@
* Routing Test - main connection handling
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <DDS/DDSConnector/dds_connector.h>
#include <future>
#include "logger.h"
namespace RoutingService
{
class DataWriterTask;
class TopicDispatcherInterface;
class Connection
{
public:
Connection(const dds::domain::DomainParticipant &domainParticipant,
const std::string &partition,
const std::vector<TopicDispatcherInterface *> &topicsToRoute,
const std::string &desc);
~Connection();
// only valid before initialize() !
void setOutput(Connection *output);
bool initialize();
void shutdown();
dds::domain::DomainParticipant domainParticipant() const;
dds::pub::Publisher publisher() const;
dds::sub::Subscriber subscriber() const;
private:
bool initTopics();
private:
Connection *m_output;
dds::domain::DomainParticipant m_domainParticipant;
std::unique_ptr<DDSConnector::Publisher> m_publisher;
std::unique_ptr<DDSConnector::Subscriber> m_subscriber;
std::future<void> m_writerThread;
std::unique_ptr<DataWriterTask> m_dataWriterTask;
std::vector<TopicDispatcherInterface *> m_topicsToRoute;
std::string m_partition;
std::string m_description;
NGL::INGLLogger &m_logger;
};
} // namespace RoutingService
+105
View File
@@ -0,0 +1,105 @@
/**
* @RDE_HEADER@
* Routing Test - data writer thread
* $Id$
* $HeadURL$
* $Author$
*/
#include "data_writer_task.h"
namespace RoutingService
{
DataWriterTask::DataWriterTask()
: m_doShutdown(false)
, m_logger(getLogger("DataWriterTask"))
{
DEBUG_LOG(m_logger) << this << ": init ";
}
DataWriterTask::~DataWriterTask()
{
std::lock_guard<std::mutex> lock(m_queueLock);
DEBUG_LOG(m_logger) << this << ": Cleaning up remaining writers: " << m_writerQueue.size();
while (!m_writerQueue.empty())
{
delete m_writerQueue.front();
m_writerQueue.pop();
}
}
void DataWriterTask::enqueue(SampleWriterInterface *swi)
{
std::lock_guard<std::mutex> lock(m_queueLock);
TRACE_LOG(m_logger) << this << ": enqueue " << swi << " shutdown: " << m_doShutdown;
if (m_doShutdown)
{
delete swi;
return;
}
m_writerQueue.push(swi);
m_waitForDataCondition.notify_one();
}
void DataWriterTask::shutdown()
{
std::lock_guard<std::mutex> l(m_queueLock);
m_doShutdown = true;
DEBUG_LOG(m_logger) << this << ": Cleaning up remaining writers: " << m_writerQueue.size();
while (!m_writerQueue.empty())
{
delete m_writerQueue.front();
m_writerQueue.pop();
}
m_waitForDataCondition.notify_one();
}
bool DataWriterTask::waitForData()
{
TRACE_LOG(m_logger) << this << ": waiting for data ";
std::unique_lock<std::mutex> waitCondLock(m_queueLock);
while (true)
{
if (m_doShutdown)
return false;
if (!m_writerQueue.empty())
return true;
m_waitForDataCondition.wait(waitCondLock); // m_queueLock gets unlocked inside wait()
// m_queueLock is locked now
}
return true; // dead code ...
}
SampleWriterInterface *DataWriterTask::getNextSampleWriter()
{
std::lock_guard<std::mutex> lock(m_queueLock);
if (m_writerQueue.empty())
return nullptr;
TRACE_LOG(m_logger) << this << ": getData() queue size: " << m_writerQueue.size();
auto ret = m_writerQueue.front();
m_writerQueue.pop();
return ret;
}
void DataWriterTask::writeSamples()
{
while (true)
{
if (!waitForData())
return;
SampleWriterInterface *swi = nullptr;
while ((swi = getNextSampleWriter()) != nullptr)
{
swi->writeSamples();
TRACE_LOG(swi->logger()) << this << ": delete " << swi;
delete swi;
}
}
}
} // namespace RoutingService
+41
View File
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* Routing Test - data writer thread
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <queue>
#include <mutex>
#include <condition_variable>
#include <DDS/Routing/routing_plugin.h>
#include "logger.h"
namespace RoutingService
{
class DataWriterTask final : public DataWriterTaskInterface
{
public:
DataWriterTask();
~DataWriterTask();
void enqueue(SampleWriterInterface *swi) override;
void shutdown();
bool waitForData();
SampleWriterInterface *getNextSampleWriter();
void writeSamples();
private:
std::queue<SampleWriterInterface *> m_writerQueue;
std::mutex m_queueLock;
std::condition_variable m_waitForDataCondition;
bool m_doShutdown;
NGL::INGLLogger &m_logger;
};
} // namespace RoutingService
+84
View File
@@ -0,0 +1,84 @@
log4j.reset=true
log4j.rootLogger=WARN, file
# Service: RoutingService
###########################################################
#log4j.logger.RSC=WARN
#log4j.logger.RSC.Connection=DEBUG
#log4j.logger.RSC.Session=DEBUG
#log4j.logger.RSC.PartitionHandler=DEBUG
#log4j.logger.RSC.DataWriterTask=DEBUG
#log4j.logger.RSC.AVM.ActiveFrequencyPlanning=DEBUG
#log4j.logger.RSC.ASM.Asset=DEBUG
#log4j.logger.RSC.SRP.StartReplay=TRACE
# File
###########################################################
log4j.appender.file=Lts::RollingFileAppender
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=9
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
# Appnd_Console
###########################################################
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
# Appnd_Syslog
###########################################################
log4j.appender.syslog=org.apache.log4j.SyslogAppender
log4j.appender.syslog.Threshold=ERROR
log4j.appender.syslog.SysLogHost=localhost
log4j.appender.syslog.Facility=LOCAL7
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
###########################################################
###########################################################
###########################################################
# 1) Available Levels in LOG4CXX Version 0.10.0:
# TRACE,
# DEBUG,
# INFO,
# WARN,
# ERROR
# FATAL
#
# d = date/time
# p = priority (Level)
# c = category/channel
# m = message
# F = file
# L = line
# n = platform dependent line separator character or characters.
# ....
#
# Examples for console:
# a)
# %d %p %c #%m# (%.50F:%L)%n
# date/time
# priority
# category/channel
# #message#
# (Maximal 50Character des Filename von rechts:Line)
# line separator
#
# b)
# %d (%.15F:%L) %-5p %c |#| %m%n
# date/time
# (Maximal 15Character des Filename von rechts:Line)
# priority, Right pad with spaces if the priority name is less than 5 characters long.
# category/channel
# message
# line separator
#
# Examples for files:
+37
View File
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Building Config - logging facility
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace RoutingService
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "RSC.";
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(sizeof(ns) + len);
loggerName.append(ns, sizeof(ns) - 1);
loggerName.append(name, len);
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
} // namespace RoutingService
+22
View File
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Logging for ExerciseManagement
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
#include <RoutingServiceNG/rsccommon_export.h>
namespace RoutingService
{
using LOGGER_T = NGL::INGLLogger &;
RSCCOMMON_EXPORT LOGGER_T getLogger(const char *name);
} // namespace RoutingService
+67
View File
@@ -0,0 +1,67 @@
/**
* @RDE_HEADER@
* main (RoutingTest)
* $Id$
* $HeadURL$
* $Author$
*/
#include <nglapplication/nglcoreapplication.h>
#include <NGLLogger/INGLLogger.h>
#include <LtsCommandLineParser/LtsCommandLineParser.h>
#include "main_handler.h"
#ifdef Q_OS_LINUX
#include <sys/resource.h>
#endif
int main(int argc, char **argv)
{
NGLCoreApplication app(argc, argv);
app.createLogger("RSC", "log4cxx_rsc.props");
#ifdef Q_OS_LINUX
constexpr int fdLimit = 100;
struct rlimit rl;
if (getrlimit (RLIMIT_NOFILE, &rl) == 0)
{
if (rl.rlim_cur < fdLimit || rl.rlim_max < fdLimit)
{
struct rlimit rlNew = rl;
rlNew.rlim_cur = fdLimit;
rlNew.rlim_max = fdLimit;
if (rlNew.rlim_max < rlNew.rlim_cur)
rlNew.rlim_cur = rlNew.rlim_max;
if (rlNew.rlim_cur != rl.rlim_cur)
{
if (setrlimit (RLIMIT_NOFILE, &rlNew) == 0)
NOTICE_LOG(app.baseLogger()) << "setting RLIMIT_NOFILE to " << rlNew.rlim_cur;
else
WARNING_LOG(app.baseLogger()) << "failed setting RLIMIT_NOFILE to " << fdLimit;
}
}
}
#endif
LtsCommandLineParser::LtsCommandLineParser options;
if (!options.init())
return -1;
int ret = 0;
{
std::unique_ptr<RoutingService::MainHandler> handler(new RoutingService::MainHandler());
// todo: make configurable
if (!handler->init(options.domainId(),
1,
7400))
return -2;
STARTUP_LOG(app.baseLogger());
ret = app.exec();
SHUTDOWN_LOG(app.baseLogger());
}
return ret;
}
+104
View File
@@ -0,0 +1,104 @@
/**
* @RDE_HEADER@
* Routing Test - main object
* $Id$
* $HeadURL$
* $Author$
*/
#include "main_handler.h"
#include <LtsPluginManager/lts_plugin_loader.h>
#include <DDS/Generic/topic_type_plugin.h>
#include <DDS/QosProfile/DDS_DefaultQos.h>
#include <ExerciseManagement/exm_dtc.h>
#include <rti/config/Logger.hpp>
#include <nglapplication/nglloggerhandler.h>
#include <Core/core_dts_types.h>
#include <DDS/Core/pacemaker.h>
#include <DDS/DTS/generic_dts_impl.h>
namespace RoutingService
{
MainHandler::MainHandler()
: m_logger(getLogger("MainHandler"))
{
}
MainHandler::~MainHandler()
{
m_pacemaker = nullptr;
shutdown();
}
bool MainHandler::init(int domainIdIn, int domainIdOut, unsigned short tcpPortOut)
{
shutdown();
if (!DDS::QosProfile::setDefault())
{
ERROR_LOG(m_logger) << "Error setting default QoS from xml-file ";
return false;
}
NGL::LoggerHandler *lh = NGL::LoggerHandler::getLoggerHandler();
if (lh)
{
const QByteArray postfix = lh->loggerNamePostfix().toLocal8Bit() + "_dds_";
const QByteArray prefix = lh->loggerNamePrefix().toLocal8Bit();
rti::config::Logger &ddsLogger = rti::config::Logger::instance();
//ddsLogger.output_file(fdopen(STDOUT_FILENO, "w"));
ddsLogger.output_file_set(postfix.data(), prefix.data(), 10 * 1024 * 1024, 10);
ddsLogger.verbosity(rti::config::Verbosity_def::WARNING);
//ddsLogger.verbosity_by_category(rti::config::LogCategory_def::COMMUNICATION, rti::config::Verbosity_def::STATUS_ALL);
}
std::shared_ptr<DDSConnector::DdsConnector> ddsConnectorIn(
new DDSConnector::DdsConnector(domainIdIn, IDL::PartitionType::Global));
ddsConnectorIn->initDomainParticipant();
ddsConnectorIn->initPublisherSubscriber(); // for ExerciseManagement::Exercise, Core::SituationReplay, Heartbeat
QUrl tcpDiscoveryUrl;
tcpDiscoveryUrl.setPort(tcpPortOut);
std::shared_ptr<DDSConnector::DdsConnector> ddsConnectorOut(
new DDSConnector::DdsConnector(domainIdOut, IDL::PartitionType::Global, 0, tcpDiscoveryUrl));
ddsConnectorOut->initDomainParticipant();
m_sessionHandler.reset(new SessionHandler(IDL::PartitionType::Exercise, ddsConnectorIn, ddsConnectorOut));
m_pacemaker = std::make_shared<Core::Pacemaker>(ddsConnectorIn);
m_pacemaker->setNewState(Core::RunningState::Starting);
m_partitionHandler.reset(new PartitionHandler(ddsConnectorIn));
connect(m_partitionHandler.get(), &PartitionHandler::createSession,
m_sessionHandler.get(), &SessionHandler::onCreateSession);
connect(m_partitionHandler.get(), &PartitionHandler::destroySession,
m_sessionHandler.get(), &SessionHandler::onDestroySession);
if (!m_partitionHandler->init() ||
!m_sessionHandler->init())
{
m_pacemaker->setNewState(Core::RunningState::StartingError);
return false;
}
const QString ex_0(QString::fromStdString(DDSConnector::DdsConnector::getPartitionString(IDL::PartitionType::Global)));
m_sessionHandler->onCreateSession(ex_0, ex_0);
m_pacemaker->setNewState(Core::RunningState::Running);
return true;
}
void MainHandler::shutdown()
{
if (m_sessionHandler)
m_sessionHandler->shutdown();
m_sessionHandler = nullptr;
m_partitionHandler = nullptr;
}
} // namespace RoutingService
+45
View File
@@ -0,0 +1,45 @@
/**
* @RDE_HEADER@
* Routing Test - main object
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QObject>
#include "logger.h"
#include "partition_handler.h"
#include "session_handler.h"
#include "session.h"
#include <DDS/DDSConnector/dds_connector.h>
namespace Core
{
class Pacemaker;
}
namespace RoutingService
{
class TopicDispatcherInterface;
class MainHandler : public QObject
{
public:
explicit MainHandler();
~MainHandler();
bool init(int domainIdIn, int domainIdOut, unsigned short tcpPortOut);
void shutdown();
private:
std::unique_ptr<SessionHandler> m_sessionHandler;
std::unique_ptr<PartitionHandler> m_partitionHandler;
std::shared_ptr<Core::Pacemaker> m_pacemaker;
NGL::INGLLogger &m_logger;
};
} // namespace RoutingService
+105
View File
@@ -0,0 +1,105 @@
/**
* @RDE_HEADER@
* Routing Test - Watch for Exercises and create routes
* $Id$
* $HeadURL$
* $Author$
*/
#include "partition_handler.h"
#include <DDS/DDSConnector/dds_connector.h>
namespace RoutingService
{
PartitionHandler::PartitionHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, QObject *parent)
: QObject(parent)
, m_exmDtc(ExerciseManagement::Interface::Dtc::create(ddsConnector))
, m_destroyTimer(new QTimer(this))
, m_logger(getLogger("PartitionHandler"))
{
m_exmDtc->enableExercise();
m_destroyTimer->setInterval(1000);
m_destroyTimer->setSingleShot(false);
connect(m_destroyTimer, &QTimer::timeout, this, &PartitionHandler::onDestroyTimerTimeout);
}
PartitionHandler::~PartitionHandler()
{
qDeleteAll(m_destroyMap);
}
bool PartitionHandler::init()
{
connect(m_exmDtc.get(), &ExerciseManagement::Interface::Dtc::exerciseChanged,
this, &PartitionHandler::onExerciseChanged);
m_exmDtc->exercises([this](const ExerciseManagement::Exercise &exercise) {onExerciseChanged(exercise, DataModification::eAdded);});
return true;
}
void PartitionHandler::partitionModified(const QString &partitionName, const ExerciseManagement::ExerciseState &state)
{
if (state == ExerciseManagement::ExerciseState::Unknown ||
state == ExerciseManagement::ExerciseState::Terminated)
{
partitionRemoved(partitionName);
return;
}
m_destroyMap.remove(partitionName);
auto it = m_activeSessions.find(partitionName);
if (it != m_activeSessions.end())
return;
m_activeSessions.insert(partitionName);
if (!m_destroyTimer->isActive())
m_destroyTimer->start();
emit createSession(partitionName, partitionName);
}
void PartitionHandler::partitionRemoved(const QString &partitionName)
{
QElapsedTimer *et = new QElapsedTimer;
et->start();
m_destroyMap.insert(partitionName, et);
}
void PartitionHandler::onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification modType)
{
const QString partitionName(QString::fromStdString(DDSConnector::DdsConnector::getPartitionString(IDL::PartitionType::Exercise, data.id())));
DEBUG_LOG(m_logger) << "onExerciseChanged: " << data << ", modType: " << modType;
switch (modType)
{
case DataModification::eRemoved:
partitionRemoved(partitionName);
break;
case DataModification::eAdded:
case DataModification::eModified:
partitionModified(partitionName, data.state());
break;
}
}
void PartitionHandler::onDestroyTimerTimeout()
{
auto it = m_destroyMap.begin();
while (it != m_destroyMap.end())
{
QElapsedTimer *et = it.value();
if (et->elapsed() < 5 * 1000)
{
++it;
continue;
}
DEBUG_LOG(m_logger) << "onDestroyTimerTimeout for session " << it.key() << " triggered";
delete et;
m_activeSessions.remove(it.key());
emit destroySession(it.key(), it.key());
it = m_destroyMap.erase(it);
}
}
} // namespace RoutingService
+47
View File
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Routing Test - Watch for Exercises and create routes
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QElapsedTimer>
#include <QObject>
#include <QSet>
#include <QTimer>
#include <ExerciseManagement/exm_dtc.h>
#include "logger.h"
namespace RoutingService
{
class PartitionHandler : public QObject
{
Q_OBJECT
public:
explicit PartitionHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
QObject *parent = nullptr);
~PartitionHandler();
bool init();
private:
void partitionModified(const QString &partitionName, const ExerciseManagement::ExerciseState &state);
void partitionRemoved(const QString &partitionName);
private Q_SLOTS:
void onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification modType);
void onDestroyTimerTimeout();
Q_SIGNALS:
void createSession(const QString &partitionNameSv, const QString &partitionNameWs);
void destroySession(const QString &partitionNameSv, const QString &partitionNameWs);
private:
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
QMap<QString, QElapsedTimer *> m_destroyMap;
QSet<QString> m_activeSessions;
QTimer *m_destroyTimer;
NGL::INGLLogger &m_logger;
};
} // namespace RoutingService
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<service namespace="RoutingService" procNames="RoutingServiceNG" abbreviation="RSC" exerciseDependency="Global" groups="Core">
<rcs>
<Id Id="$Id$"/>
<HeadURL HeadURL="$HeadURL$"/>
<Author Author="$Author$"/>
</rcs>
<tables/>
<dbServiceStructs/>
<topicTypes/>
<functionTopics/>
<enumerations/>
</service>
+58
View File
@@ -0,0 +1,58 @@
/**
* @RDE_HEADER@
* Routing Test - handle a session (connection to and from sv for a specific partition)
* $Id$
* $HeadURL$
* $Author$
*/
#include "session.h"
namespace RoutingService
{
Session::Session(const QString &partitionNameSv, const QString &partitionNameWs)
: m_partitionNameSv(partitionNameSv.toStdString())
, m_partitionNameWs(partitionNameWs.toStdString())
, m_logger(getLogger("Session"))
{}
Session::~Session()
{
shutdown();
}
bool Session::init(const dds::domain::DomainParticipant &dpIn,
const dds::domain::DomainParticipant &dpOut,
const std::vector<TopicDispatcherInterface *> &topicsToRouteToWs,
const std::vector<TopicDispatcherInterface *> &topicsToRouteToSv)
{
DEBUG_LOG(m_logger) << "Creating new session for " << m_partitionNameSv << "-" << m_partitionNameWs;
m_connectionSvToWs.reset(new Connection(dpIn, m_partitionNameSv, topicsToRouteToWs, "route to WS"));
m_connectionWsToSv.reset(new Connection(dpOut, m_partitionNameWs, topicsToRouteToSv, "route from WS"));
m_connectionSvToWs->setOutput(m_connectionWsToSv.get());
m_connectionWsToSv->setOutput(m_connectionSvToWs.get());
return m_connectionSvToWs->initialize() && m_connectionWsToSv->initialize();
}
void Session::shutdown()
{
DEBUG_LOG(m_logger) << "Shutting down session for " << m_partitionNameSv << "-" << m_partitionNameWs;
if (m_connectionSvToWs)
{
m_connectionSvToWs->shutdown();
m_connectionSvToWs = nullptr;
}
if (m_connectionWsToSv)
{
m_connectionWsToSv->shutdown();
m_connectionWsToSv = nullptr;
}
}
} // namespace RoutingService
+36
View File
@@ -0,0 +1,36 @@
/**
* @RDE_HEADER@
* Routing Test - handle a session (connection to and from sv for a specific partition)
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <string>
#include "connection.h"
namespace RoutingService
{
class Session
{
public:
explicit Session(const QString &partitionNameSv, const QString &partitionNameWs);
~Session();
bool init(const dds::domain::DomainParticipant &dpIn,
const dds::domain::DomainParticipant &dpOut,
const std::vector<TopicDispatcherInterface *> &topicsToRouteToWs,
const std::vector<TopicDispatcherInterface *> &topicsToRouteToSv);
void shutdown();
private:
std::string m_partitionNameSv;
std::string m_partitionNameWs;
std::unique_ptr<Connection> m_connectionSvToWs;
std::unique_ptr<Connection> m_connectionWsToSv;
NGL::INGLLogger &m_logger;
};
} // namespace RoutingService
+140
View File
@@ -0,0 +1,140 @@
/**
* @RDE_HEADER@
* Routing Test - main object
* $Id$
* $HeadURL$
* $Author$
*/
#include "session_handler.h"
#include <LtsPluginManager/lts_plugin_loader.h>
#include <DDS/Generic/topic_type_plugin.h>
#include <QVector>
namespace RoutingService
{
SessionHandler::SessionHandler(IDL::PartitionType partitionType,
const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnectorSv,
const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnectorWs)
: m_partitionType(partitionType)
, m_ddsConnectorSv(ddsConnectorSv)
, m_ddsConnectorWs(ddsConnectorWs)
, m_logger(getLogger("SessionHandler"))
{
}
SessionHandler::~SessionHandler()
{
shutdown();
LtsPluginManager::LtsPluginLoader::getInstance()->unloadAllPlugins();
m_topicTypePlugins.clear();
}
bool SessionHandler::init()
{
return loadPlugins();
}
void SessionHandler::shutdown()
{
qDeleteAll(m_sessionMap);
m_sessionMap.clear();
m_ddsConnectorWs = nullptr;
m_ddsConnectorSv = nullptr;
}
void SessionHandler::onCreateSession(const QString &partitionNameSv, const QString &partitionNameWs)
{
const QString partitionName = partitionNameSv + QLatin1Char('-') + partitionNameWs;
if (m_sessionMap.contains(partitionName))
{
WARNING_LOG(m_logger) << "Got create session for " << partitionName << ", but is already created";
return;
}
Session *session = new Session(partitionNameSv, partitionNameWs);
if (!session->init(m_ddsConnectorSv->getDomainParticipant(),
m_ddsConnectorWs->getDomainParticipant(),
topicsToRouteToWs(),
topicsToRouteToSv()))
{
WARNING_LOG(m_logger) << "Can not initialize session for " << partitionName << ", routing will not work...!";
delete session;
return;
}
m_sessionMap[partitionName] = session;
INFO_LOG(m_logger) << "Successfully created session for " << partitionName;
}
void SessionHandler::onDestroySession(const QString &partitionNameSv, const QString &partitionNameWs)
{
const QString partitionName = partitionNameSv + QLatin1Char('-') + partitionNameWs;
auto it = m_sessionMap.find(partitionName);
if (it == m_sessionMap.end())
{
WARNING_LOG(m_logger) << "Got destroy session for " << partitionName << ", but is not created (already destroyed?)";
return;
}
Session *session = it.value();
session->shutdown();
delete session;
m_sessionMap.erase(it);
INFO_LOG(m_logger) << "Successfully destroyed session for " << partitionName;
}
bool SessionHandler::loadPlugins()
{
auto cb = [this](const LtsPluginManager::PluginInstance & pi)
{
return loadPlugin(pi);
};
return LtsPluginManager::LtsPluginLoader::getInstance()->loadPlugins(LtsPluginManager::PluginType::TOPIC_TYPE, cb);
}
bool SessionHandler::loadPlugin(const LtsPluginManager::PluginInstance &pi)
{
DDSGeneric::TopicTypePlugin *typePlugin = dynamic_cast<DDSGeneric::TopicTypePlugin *>(pi.plugin);
if (!typePlugin)
return false;
// We don't load some plugins which are global since they are not needed since r49652ff
static const QVector<QString> skipList({QStringLiteral("ASM"),
QStringLiteral("AVM"),
QStringLiteral("FLM"),
QStringLiteral("ISM"),
QStringLiteral("MSG"),
QStringLiteral("OPM"),
QStringLiteral("PDM"),
});
if (skipList.contains(pi.pluginName.toUpper()))
DEBUG_LOG(m_logger) << "Skipping plugin " << pi.pluginName.toUpper() << " - is global";
m_topicTypePlugins.push_back(typePlugin);
return true;
}
std::vector<TopicDispatcherInterface *> SessionHandler::topicsToRouteToWs() const
{
std::vector<TopicDispatcherInterface *> ret;
for (const auto typePlugin : m_topicTypePlugins)
{
const auto topicsToRouteToWs = typePlugin->topicsToRouteToWs(m_partitionType);
ret.insert(ret.end(), topicsToRouteToWs.begin(), topicsToRouteToWs.end());
}
return ret;
}
std::vector<TopicDispatcherInterface *> SessionHandler::topicsToRouteToSv() const
{
std::vector<TopicDispatcherInterface *> ret;
for (const auto typePlugin : m_topicTypePlugins)
{
const auto topicsToRouteToSv = typePlugin->topicsToRouteToSv(m_partitionType);
ret.insert(ret.end(), topicsToRouteToSv.begin(), topicsToRouteToSv.end());
}
return ret;
}
} // namespace RoutingService
+64
View File
@@ -0,0 +1,64 @@
/**
* @RDE_HEADER@
* Routing Test - main object
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QObject>
#include <QMap>
#include <RoutingServiceNG/rsccommon_export.h>
#include "logger.h"
#include "session.h"
#include <DDS/DDSConnector/dds_connector.h>
namespace LtsPluginManager
{
struct PluginInstance;
}
namespace DDSGeneric
{
class TopicTypePlugin;
}
namespace RoutingService
{
class TopicDispatcherInterface;
class RSCCOMMON_EXPORT SessionHandler : public QObject
{
public:
SessionHandler(IDL::PartitionType partitionType,
const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnectorSv,
const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnectorWs);
~SessionHandler();
bool init();
void shutdown();
public Q_SLOTS:
void onCreateSession(const QString &partitionNameSv, const QString &partitionNameWs);
void onDestroySession(const QString &partitionNameSv, const QString &partitionNameWs);
private:
bool loadPlugins();
bool loadPlugin(const LtsPluginManager::PluginInstance &pi);
std::vector<TopicDispatcherInterface *> topicsToRouteToWs() const;
std::vector<TopicDispatcherInterface *> topicsToRouteToSv() const;
private:
std::vector<DDSGeneric::TopicTypePlugin *> m_topicTypePlugins;
IDL::PartitionType m_partitionType;
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnectorSv;
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnectorWs;
QMap<QString, Session *> m_sessionMap;
NGL::INGLLogger &m_logger;
};
} // namespace RoutingService