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

+160
View File
@@ -0,0 +1,160 @@
#
# $Id$
# $HeadURL$
# $Author$
#
INCLUDE(MacroRTIDDSGen)
INCLUDE(MacroCodeGenIdl)
SET(xml_FILE msg_service.xml)
#
# --- Library svcMsgCommon --------------------------------------------------------------------------------
#
SET(SRCS_common
msg_export.h
logger.cpp
logger.h
)
# Generate msg_enums.idl / msg.idl
CODEGEN_IDL_SVC(SRCS_common ${xml_FILE})
# Generate msg_db_impl.cpp/.h, msg_db.h
CODEGEN_DATABASE(SRCS_common ${xml_FILE})
# Generate *.cpp/*.hpp from idl
RTIDDSGEN(SRCS_common msg_enums.idl)
RTIDDSGEN(SRCS_common msg.idl)
# Generate msg_dt[s,c]_types.h, msg_ft[s,c]_types.h
CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
# generate msg_[d|f]tc.h
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE})
NGL_ADD_LIBRARY(AAR SV WS svcMsgCommon SHARED ${SRCS_common})
NGL_TARGET_INCLUDE_DIRECTORIES(svcMsgCommon
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(svcMsgCommon
PRIVATE
RTI::nddscpp2
PUBLIC
Qt5::Core
ddscore
ngldb
LtsCommandLineParser
NGLLogger
)
NGL_INSTALL_TARGET(svcMsgCommon)
#
# --- Library svcMsgClient --------------------------------------------------------------------------------
#
SET(SRCS_client
msg_export.h
)
# generate msg_[d|f]tc_impl.[cpp|h]
CODEGEN_CLIENT_TOPICS_IMPL(SRCS_client ${xml_FILE})
NGL_ADD_LIBRARY(AAR SV WS svcMsgClient SHARED ${SRCS_client})
NGL_TARGET_INCLUDE_DIRECTORIES(svcMsgClient
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(svcMsgClient
PRIVATE
RTI::nddscpp2
ddsconnector
PUBLIC
svcMsgCommon
ddsftc
)
NGL_INSTALL_TARGET(svcMsgClient)
#
# --- Library svcMsgServer --------------------------------------------------------------------------------
#
SET(SRCS_server
msg_export.h
)
# generate msg_[d|f]ts.h, msg_[d|f]ts_impl.[cpp|h]
CODEGEN_SERVER_TOPICS(SRCS_server ${xml_FILE})
NGL_ADD_LIBRARY(AAR SV svcMsgServer SHARED ${SRCS_server})
NGL_TARGET_INCLUDE_DIRECTORIES(svcMsgServer
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(svcMsgServer
PRIVATE
RTI::nddscpp2
ddsconnector
ddsfts
PUBLIC
svcMsgCommon
ngldb
)
NGL_INSTALL_TARGET(svcMsgServer)
#
# --- Topic Type Plugin --------------------------------------------------------------
#
CREATE_TOPIC_TYPE_PLUGIN(${xml_FILE})
#
# --- Executable svcMessaging (sMSG) -------------------------------------------------
#
SET(SRCS_exe
main.cpp
main_handler.cpp
main_handler.h
settings.cpp
settings.h
dds_handler.cpp
dds_handler.h
exercise_handler.cpp
exercise_handler.h
exercises_handler.cpp
exercises_handler.h
handler_operator_message.cpp
handler_operator_message.h
log4cxx_msg.props
${xml_FILE}
)
# Generate msg.sql, msg.xml
CODEGEN_SQL(SRCS_exe ${xml_FILE})
NGL_ADD_SVC_ICON(SRCS_exe)
NGL_ADD_EXECUTABLE(AAR SV svcMessaging ${SRCS_exe})
NGL_TARGET_LINK_LIBRARIES(svcMessaging
Qt5::Core
svcMsgCommon
svcMsgServer
svcTabClient
svcOpmClient
svcOssClient
svcPpmClient
svcCoreClient
ddsconnector
nglsettings
ProjectConfig
NGLLogger
nglcoreapplication
ngltools
)
NGL_INSTALL_TARGET(svcMessaging)
NGL_INSTALL(AAR SV FILES log4cxx_msg.props DESTINATION bin)
NGL_ADD_TARGET_LINK(svcMessaging sMSG)
# Uncomment if necessary
#ADD_SUBDIRECTORY(UnitTests)
ADD_SUBDIRECTORY(ModuleTests)
+48
View File
@@ -0,0 +1,48 @@
#
# $Id$
# $HeadURL$
# $Author$
#
IF(BUILD_TESTING)
IF(TARGET svcMsgClient AND TARGET svcTabServer)
####################################
# Message Test
####################################
SET(SRCS_TEST_MSG
msg_tests.cpp
)
SET(HDRS_TEST_MSG
msg_tests.h
)
NGL_TARGET_INCLUDE_DIRECTORIES(msgTests
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
# Testing FunctionTopic Functionality (FTC)
ADD_EXECUTABLE(msgTests ${SRCS_TEST_MSG} ${HDRS_TEST_MSG})
TARGET_LINK_LIBRARIES(msgTests
Qt5::Core
Qt5::Test
RTI::nddscpp2
svcMsgClient
svcTabClient
svcTabServer
svcCoreClient
LtsCommandLineParser
ddsconnector
nglcoreapplication
)
IF(NOT BUILD_RPM)
NGL_INSTALL(AAR SV TARGETS msgTests DESTINATION bin/test)
NGL_INSTALL(AAR SV FILES ../log4cxx_msg.props DESTINATION bin/test)
ENDIF()
ENDIF()
ENDIF()
+441
View File
@@ -0,0 +1,441 @@
/**
* Msg Function Topic Module Test
* $Id$
* $HeadURL$
* $Author$
*/
#include "msg_tests.h"
#include <nglapplication/nglcoreapplication.h>
#include <LtsCommandLineParser/LtsCommandLineParser.h>
#include <QTimer>
#include <QDateTime>
#include <Messaging/msg_ftc.h>
/* ----------------------------------------------------------------------------------
* HOW TO RUN THE TESTS
* ----------------------------------------------------------------------------------
* 0. Preconditions:
* Start with an empty database (BUILD)
* make db
*
* Preconditions:
* For test 1, 2, 3:
* - User 1,2,3 in DB
*
* For test 4 and 5:
* - exercise with Observer/Controller ( ppm.ppm_equipment_type = 20 )equipmentNumber 2500, 2501
* - empty table msg.msg_message_operator_data
*
* Please start in order 1, 2, 3, ...
*
* Start services: (SV)
* ./bin/svcMessaging &
* -t 1 = CreateOperatorMessage
* -t 2 = SetIsRead
* -t 3 = SetDeleted
* -t 4 = Send to Tetra
* -t 5 = receive from Tetra
*/
namespace Messaging
{
MsgTests::MsgTests(QObject *parent)
: QObject(parent)
, m_testId(0)
, m_bTestsSuccessful(true)
, m_messageCount(0)
, m_msgIdSendMessage(1) // Result from last test
, m_msgIdRecvMessage(3) // Result from last test
, m_numberMessages(3) // Result from last test
, m_testStep(TestCase::CreateOperator)
, m_logger(getLogger("MsgTests"))
{}
MsgTests::~MsgTests()
{}
bool MsgTests::init(int domainId, int testId)
{
INFO_LOG(m_logger) << "init begin";
m_testId = testId;
m_ddsConnector.reset(new DDSConnector::DdsConnector(domainId, IDL::PartitionType::Any));
if (!m_ddsConnector->init())
return false;
m_ddsConnector->initPublisherSubscriber();
m_ftc = Messaging::Interface::Ftc::create(m_ddsConnector);
bool bRet = m_ftc->enableAll();
m_dtc = Messaging::Interface::Dtc::create(m_ddsConnector);
bRet &= m_dtc->enableAll();
return bRet;
} // init
void MsgTests::startTest()
{
INFO_LOG(m_logger) << "startTest m_testId=" << m_testId;
if (m_testId <= 1) // CreateOperatorMessage
{
m_testStep = TestCase::CreateOperator;
QTimer::singleShot(0, this, &MsgTests::tryCreateOperatorMessage);
}
else if (m_testId == 2) // SetIsRead
{
m_testStep = TestCase::SetIsRead;
MsgTests::markMessageAsRead();
}
else if (m_testId == 3) // SetDeleted
{
m_testStep = TestCase::SetDeleted;
MsgTests::markMessageAsDeleted();
}
else if (m_testId == 4) // send to TETRA
{
m_testStep = TestCase::SendToTetra;
QTimer::singleShot(0, this, &MsgTests::tryCreateOperatorMessage);
}
else if (m_testId == 5) // receive from TETRA
{
m_testStep = TestCase::ReceiveFromTetra;
QTimer::singleShot(0, this, &MsgTests::tryCreateOperatorMessage);
}
} // startTest
void MsgTests::tryCreateOperatorMessage()
{
INFO_LOG(m_logger) << "trying to send createRequest Operator Message";
Messaging::AddressType receiverType;
Messaging::AddressType senderType;
std::vector<int32_t> recipientIds;
int32_t sender = 3;
std::string subject = "subject Operator";
recipientIds.resize(2);
int exerciseId = 42;
switch (m_testStep)
{
case TestCase::CreateOperator:
{
receiverType = Messaging::AddressType_def::type::Operator;
senderType = Messaging::AddressType_def::type::Operator;
m_expectedMessage = "msg Operator: " + QDateTime::currentDateTimeUtc().toString().toStdString();
recipientIds[0] = 1;
recipientIds[1] = 2;
break;
}
case TestCase::SendToTetra:
{
receiverType = Messaging::AddressType_def::type::ObserverController;
senderType = Messaging::AddressType_def::type::Operator;
m_expectedMessage = "msg to OC: " + QDateTime::currentDateTimeUtc().toString().toStdString();
recipientIds[0] = 57; // Participant id for eq-number 2500
recipientIds[1] = 58; // Participant id for eq-number 2501
break;
}
case TestCase::ReceiveFromTetra:
{
receiverType = Messaging::AddressType_def::type::Operator;
senderType = Messaging::AddressType_def::type::ObserverController;
m_expectedMessage = "msg from OC: " + QDateTime::currentDateTimeUtc().toString().toStdString();
sender = 2500;
recipientIds[0] = 1;
recipientIds[1] = 2;
break;
}
default:
return;
}
if (!m_ftc->createOperatorMessageRequest(CreateOperatorMessageRequest(recipientIds, exerciseId, sender, subject, m_expectedMessage, senderType, receiverType), this))
{
ERROR_LOG(m_logger) << "Error requesting create data";
failExit();
}
} // tryCreateOperatorMessage
void MsgTests::checkMessageOnDdsAfterCreate()
{
// read from dds, check if data is as expected
m_messageCount = 0;
m_dtc->waitForHistoricalDataOperatorMessage();
const QMap<int, Messaging::OperatorMessage> messages = m_dtc->operatorMessages();
for (const auto &om : messages)
{
INFO_LOG(m_logger) << "checkMessageOnDdsAfterCreate om.id = " << om.id();
if (om.message() == m_expectedMessage)
{
DEBUG_LOG(m_logger) << "senderId: " << om.senderId() << ", recipientId: " << om.recipientId();
if (om.senderId() != 0 && om.recipientId() == 0)
{
m_msgIdSendMessage = om.id();
DEBUG_LOG(m_logger) << "m_msgIdSendMessage=" << m_msgIdSendMessage;
++m_messageCount;
}
if (om.senderId() != 0 && om.recipientId() != 0)
{
m_msgIdRecvMessage = om.id();
DEBUG_LOG(m_logger) << "m_msgIdRecvMessage=" << m_msgIdRecvMessage;
++m_messageCount;
}
}
// msg count == 3 -> one for sender, two for receiver
if (m_messageCount == 3)
{
INFO_LOG(m_logger) << "Success: receiving messages - got: " << m_messageCount << " expected: 3";
ExitSuccess();
return;
}
}
if (m_testStep == TestCase::ReceiveFromTetra || m_testStep == TestCase::SendToTetra)
{
ExitSuccess();
return;
}
ERROR_LOG(m_logger) << "Error receiving messages - got: " << m_messageCount << " expected: 3";
failExit();
} // checkMessageOnDdsAfterCreate
void MsgTests::checkMessageOnDdsAfterModify()
{
// read from dds, check if data is as expected
int isRead = 0;
INFO_LOG(m_logger) << "checkMessageOnDdsAfterModify";
m_dtc->waitForHistoricalDataOperatorMessage();
const QMap<int, Messaging::OperatorMessage> messages = m_dtc->operatorMessages();
switch (m_testStep)
{
case TestCase::SetIsRead:
{
for (const auto &om : messages)
{
DEBUG_LOG(m_logger) << "om.id()=" << om.id() << " om.isRead()=" << om.isRead();
if (om.id() == m_msgIdRecvMessage && om.isRead() == true)
++isRead;
}
if (isRead == 1)
{
INFO_LOG(m_logger) << "modify messages isRead = TRUE: Success ";
ExitSuccess();
return;
}
ERROR_LOG(m_logger) << "Error modify messages - got: " << isRead << " expected: 1";
failExit();
break;
}
case TestCase::SetDeleted:
{
// Message removed from DDS
DEBUG_LOG(m_logger) << "m_numberMessages= " << m_numberMessages << " messages.size()= " << messages.size();
if (m_numberMessages > messages.size())
{
INFO_LOG(m_logger) << "modify messages isDeleted = TRUE: Success ";
ExitSuccess();
return;
}
ERROR_LOG(m_logger) << "Error modify messages - got: " << messages.size() << " expected less than " << m_numberMessages;
failExit();
break;
}
case TestCase::SendToTetra:
{
DEBUG_LOG(m_logger) << "SendToTetra reply m_numberMessages= " << m_numberMessages << " messages.size()= " << messages.size();
ExitSuccess();
break;
}
case TestCase::ReceiveFromTetra:
{
DEBUG_LOG(m_logger) << "ReceiveFromTetra reply m_numberMessages= " << m_numberMessages << " messages.size()= " << messages.size();
ExitSuccess();
break;
}
default:
{
INFO_LOG(m_logger) << "Nothing to do in this TestCase";
}
}
} // checkMessageOnDdsAfterModify
void MsgTests::checkMessageOnDdsAfterDelete()
{
// read from dds, check if data is as expected
int isDeleted = 0;
INFO_LOG(m_logger) << "checkMessageOnDdsAfterModify";
m_dtc->waitForHistoricalDataOperatorMessage();
const QMap<int, Messaging::OperatorMessage> messages = m_dtc->operatorMessages();
for (const auto &om : messages)
{
if (om.id() == m_msgIdRecvMessage && om.isDeleted() == true)
++isDeleted;
}
if (isDeleted == 1)
{
INFO_LOG(m_logger) << "modify messages delete: Success ";
return;
}
ERROR_LOG(m_logger) << "Error modify messages - got: " << isDeleted << " expected: 1";
failExit();
} // checkMessageOnDdsAfterDelete
void MsgTests::markMessageAsRead()
{
INFO_LOG(m_logger) << "trying to mark Message as read m_msgIdRecvMessage =" << m_msgIdRecvMessage;
int32_t id = m_msgIdRecvMessage;
bool isRead = true;
bool isSend = false;
bool isDeleted = false;
if (!m_ftc->modifyOperatorMessageRequest(ModifyOperatorMessageRequest(id, isRead, isSend, isDeleted), this))
{
ERROR_LOG(m_logger) << "Error mark Message as read";
failExit();
}
} // markMessageAsRead
void MsgTests::markMessageAsDeleted()
{
INFO_LOG(m_logger) << "trying to mark Message as deleted m_msgIdRecvMessage =" << m_msgIdRecvMessage;
int32_t id = m_msgIdRecvMessage;
bool isRead = true;
bool isSend = false;
bool isDeleted = true;
m_dtc->waitForHistoricalDataOperatorMessage();
DEBUG_LOG(m_logger) << "m_numberMessages =" << m_numberMessages;
if (!m_ftc->modifyOperatorMessageRequest(ModifyOperatorMessageRequest(id, isRead, isSend, isDeleted), this))
{
ERROR_LOG(m_logger) << "Error mark Message as deleted";
failExit();
}
} // markMessageAsDeleted
void MsgTests::onCreateOperatorMessageReply(const Core::FunctionReplyObject &replyObject)
{
INFO_LOG(m_logger) << "onCreateOperatorMessageReply, error = " << replyObject.error();
if (replyObject.error())
{
ERROR_LOG(m_logger) << "Error creating new message - aborting";
failExit();
}
else
{
switch (m_testStep)
{
case TestCase::CreateOperator:
case TestCase::SendToTetra:
case TestCase::ReceiveFromTetra:
// 1s - wait until data is delivered
QTimer::singleShot(1000, this, &MsgTests::checkMessageOnDdsAfterCreate);
break;
default:
INFO_LOG(m_logger) << "Nothing to do in this Case";
}
}
} // onCreateOperatorMessageReply
void MsgTests::onModifyOperatorMessageReply(const Core::FunctionReplyObject &replyObject)
{
INFO_LOG(m_logger) << "onModifyOperatorMessageReply, error = " << replyObject.error();
if (replyObject.error())
{
ERROR_LOG(m_logger) << "Error modify message - aborting";
failExit();
}
else
{
// 1s - wait until data is delivered
QTimer::singleShot(1000, this, &MsgTests::checkMessageOnDdsAfterModify);
}
} // onModifyOperatorMessageReply
/*
void MsgTests::onSendEquipmentMessageReply(const Core::FunctionReplyObject &replyObject)
{
INFO_LOG(m_logger) << "************** onSendEquipmentMessageReply TODO isRead = TRUE setzen: id = **********************";
}
*/
void MsgTests::failExit()
{
m_bTestsSuccessful = false;
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
} // failExit
void MsgTests::ExitSuccess()
{
DEBUG_LOG(m_logger) << "SUCCESS";
m_bTestsSuccessful = true;
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
} // ExitSuccess
}
// ------------------------------------------------------------------
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
{
public:
CmdLineParser()
: LtsCommandLineParser()
{
addOption({ QStringList() << QLatin1String("t") << QLatin1String("testId")
, QLatin1String("TestId.")
, QLatin1String("Default: 0 (all tests)")
, QLatin1String("0")
});
}
int testId() const { return isSet(QLatin1String("t")) ? value(QLatin1String("t")).toInt() : -1; }
};
// ------------------------------------------------------------------
int main(int argc, char **argv)
{
NGLCoreApplication app(argc, argv);
app.createLogger("MSG", 0);
CmdLineParser options;
if (!options.init())
return -1;
int iRet = -1;
{
std::unique_ptr<Messaging::MsgTests> msgTests(new Messaging::MsgTests);
if (!msgTests->init(options.domainId(), options.testId()))
return iRet;
msgTests->startTest();
STARTUP_LOG(app.baseLogger());
app.exec();
iRet = msgTests->testsSuccessful() ? 0 : 1;
SHUTDOWN_LOG(app.baseLogger());
}
return iRet;
} // main
+79
View File
@@ -0,0 +1,79 @@
/**
* ModuleTests for Msg
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <Messaging/msg_dtc.h>
#include <Messaging/msg_ftc.h>
#include <Messaging/msg_ftc_types.h>
#include <Messaging/logger.h>
#include <DDS/DDSConnector/dds_connector.h>
enum class TestCase
{
CreateOperator = 0,
SetIsRead = 1,
SetDeleted = 2,
SendToTetra = 3,
ReceiveFromTetra = 4
};
namespace Messaging
{
class MsgTests : public QObject
, protected Messaging::Interface::Ftc::CreateOperatorMessageReplyHandler
, protected Messaging::Interface::Ftc::ModifyOperatorMessageReplyHandler
{
Q_OBJECT
public:
explicit MsgTests(QObject *parent = nullptr);
~MsgTests();
bool init(int domainId, int testId);
bool testsSuccessful() const
{
return m_bTestsSuccessful;
}
public Q_SLOTS:
void startTest();
protected Q_SLOTS:
void tryCreateOperatorMessage();
void checkMessageOnDdsAfterCreate();
void checkMessageOnDdsAfterModify();
void checkMessageOnDdsAfterDelete();
void markMessageAsRead();
void markMessageAsDeleted();
protected:
void onCreateOperatorMessageReply(const Core::FunctionReplyObject &replyObject) override final;
void onModifyOperatorMessageReply(const Core::FunctionReplyObject &replyObject) override final;
void failExit();
void ExitSuccess();
private:
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
std::shared_ptr<Messaging::Interface::Ftc> m_ftc;
std::shared_ptr<Messaging::Interface::Dtc> m_dtc;
int m_testId;
bool m_bTestsSuccessful;
std::string m_expectedMessage;
int m_messageCount;
int m_msgIdSendMessage;
int m_msgIdRecvMessage;
int m_numberMessages;
TestCase m_testStep;
NGL::INGLLogger &m_logger;
};
} // namespace Messaging
+63
View File
@@ -0,0 +1,63 @@
/**
* DdsHandler for DDS
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLSE, 2015-09-02
*/
#include "dds_handler.h"
#include <DDS/Core/pacemaker.h>
namespace Messaging
{
DdsHandler::DdsHandler(int domainId)
: m_ddsConnector(std::make_shared<DDSConnector::DdsConnector>(domainId, IDL::PartitionType::AllExercises))
, m_logger(getLogger("DdsHandler"))
{
DEBUG_LOG(m_logger) << "DdsHandler(" << domainId << ") for partition: " << m_ddsConnector->getDefaultPartition();
} // end of ctor()DdsHandler
//-----------------------------------------------------------------------------
bool DdsHandler::init(const QStringList &qosFileList)
{
if (!m_ddsConnector->init(qosFileList))
{
ERROR_LOG(m_logger) << "Error initializing dds connections - aborting";
return false;
}
// default initialize Publisher and Subscriber
m_ddsConnector->initPublisherSubscriber();
// Pacemaker
m_pacemaker = std::make_shared<Core::Pacemaker>(m_ddsConnector);
// DTC Core (to get partitionTime)
m_dtcCore = Core::Interface::Dtc::create(m_ddsConnector);
m_dtcCore->enablePartitionTime();
// DTS
m_ddsDts = Messaging::Interface::Dts::create(m_ddsConnector);
bool bRet = m_ddsDts->enableAll();
INFO_LOG(m_logger) << "Dts initialised";
// FTS
m_ddsFts = Messaging::Interface::Fts::create(m_ddsConnector);
bRet &= m_ddsFts->enableAll();
INFO_LOG(m_logger) << "Fts initialised";
return bRet;
} // end of init()
//-----------------------------------------------------------------------------
qint64 DdsHandler::currentPartitionTime() const
{
return m_dtcCore->partitionTime().timeStamp();
}
} // Namespace Messaging
+57
View File
@@ -0,0 +1,57 @@
/**
* DdsHandler for DDS
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLSE, 2015-09-02
*/
#pragma once
#include <DDS/DDSConnector/dds_connector.h>
#include <DDS/Core/topic_lock_master.h>
#include <DDS/Core/core_dtc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <Messaging/msg_dts.h>
#include <Messaging/msg_fts.h>
#include "logger.h"
namespace Core
{
class Pacemaker;
}
namespace Messaging
{
class DdsHandler final : public QObject
{
Q_OBJECT
public:
explicit DdsHandler(int domainId);
bool init(const QStringList &qosFileList = QStringList());
bool enableEquipmentMessage();
std::shared_ptr<DDSConnector::DdsConnector> ddsConnector() const { return m_ddsConnector; }
std::shared_ptr<Core::Pacemaker> pacemaker() const { return m_pacemaker; }
std::shared_ptr<Core::TopicLockMaster> topicLockMaster() const { return m_topicLockMaster; }
std::shared_ptr<Messaging::Interface::Dts> dts() const { return m_ddsDts; }
std::shared_ptr<Messaging::Interface::Fts> fts() const { return m_ddsFts; }
qint64 currentPartitionTime() const;
private:
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
std::shared_ptr<Core::Interface::Dtc> m_dtcCore;
std::shared_ptr<Core::Pacemaker> m_pacemaker;
std::shared_ptr<Core::TopicLockMaster> m_topicLockMaster;
std::shared_ptr<Messaging::Interface::Dts> m_ddsDts;
std::shared_ptr<Messaging::Interface::Fts> m_ddsFts;
NGL::INGLLogger &m_logger;
};
}
+83
View File
@@ -0,0 +1,83 @@
/**
* Send a function topic to TrainingAreabase in a specific exercise
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-12-13
*/
#include "exercise_handler.h"
namespace Messaging
{
ExerciseHandler::ExerciseHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, const int exerciseId)
: m_ddsConnector(std::make_shared<DDSConnector::DdsConnector>(ddsConnector->getDomainId(), IDL::PartitionType::Exercise, exerciseId))
, m_exerciseId(exerciseId)
, m_idleTimer(new QTimer(this))
, m_logger(getLogger("ExerciseHandler"))
{
connect(m_idleTimer, &QTimer::timeout,
this, &ExerciseHandler::exerciseHandlerIdleTimeout);
m_idleTimer->setSingleShot(true);
m_idleTimer->setInterval(60 * 60 * 1000); // 1h
}
bool ExerciseHandler::init()
{
m_ddsConnector->initPublisherSubscriber();
DEBUG_LOG(m_logger) << "ExerciseHandler::init m_ddsConnector=" << m_ddsConnector
<< " m_exerciseId=" << m_exerciseId;
m_tabFtc = TrainingAreaBase::Interface::Ftc::create(m_ddsConnector);
bool retVal = m_tabFtc->enableSendEquipmentMessage();
if (!retVal)
return false;
m_ossFtc = OcSituationServer::Interface::Ftc::create(m_ddsConnector);
retVal = m_ossFtc->enableSendEquipmentMessageOc();
return retVal;
}
bool ExerciseHandler::sendEquipmentMessage(const TrainingAreaBase::SendEquipmentMessageRequest &request)
{
if (!m_tabFtc)
return false;
DEBUG_LOG(m_logger) << "ExerciseHandler::sendEquipmentMessage: " << request;
m_idleTimer->stop();
return m_tabFtc->sendEquipmentMessageRequest(request, this);
}
bool ExerciseHandler::sendOcEquipmentMessage(const OcSituationServer::SendEquipmentMessageRequest &request)
{
if (!m_ossFtc)
return false;
DEBUG_LOG(m_logger) << "ExerciseHandler::sendOcEquipmentMessage: "<< request;
m_idleTimer->stop();
return m_ossFtc->sendEquipmentMessageOcRequest(request, this);
}
int ExerciseHandler::exerciseId() const
{
return m_exerciseId;
}
void ExerciseHandler::onSendEquipmentMessageReply(const Core::FunctionReplyObject &replyObject)
{
DEBUG_LOG(m_logger)<<"ExerciseHandler::onSendEquipmentMessageReply";
m_idleTimer->start();
if (replyObject.error())
ERROR_LOG(m_logger) << replyObject();
emit equipmentMessageReply(replyObject.id(), !replyObject.error());
}
void ExerciseHandler::onSendEquipmentMessageOcReply(const Core::FunctionReplyObject &replyObject)
{
DEBUG_LOG(m_logger)<<"ExerciseHandler::onSendEquipmentMessageOcReply";
m_idleTimer->start();
if (replyObject.error())
ERROR_LOG(m_logger) << replyObject();
emit equipmentMessageOcReply(replyObject.id(), !replyObject.error());
}
} // namespace Messaging
+48
View File
@@ -0,0 +1,48 @@
/**
* Send a function topic to TrainingAreabase in a specific exercise
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-12-13
*/
#pragma once
#include "dds_handler.h"
#include "logger.h"
#include <QObject>
#include <QTimer>
#include <TrainingAreaBase/tab_ftc.h>
#include <OcSituationServer/oss_ftc.h>
namespace Messaging
{
class ExerciseHandler final : public QObject,
public TrainingAreaBase::Interface::Ftc::SendEquipmentMessageReplyHandler,
public OcSituationServer::Interface::Ftc::SendEquipmentMessageOcReplyHandler
{
Q_OBJECT
public:
ExerciseHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
const int exerciseId);
bool init();
bool sendEquipmentMessage(const TrainingAreaBase::SendEquipmentMessageRequest &request);
bool sendOcEquipmentMessage(const OcSituationServer::SendEquipmentMessageRequest &request);
int exerciseId() const;
Q_SIGNALS:
void exerciseHandlerIdleTimeout();
void equipmentMessageReply(int msgId, bool sentSuccessful);
void equipmentMessageOcReply(int replyId, bool sentSuccessful);
private:
void onSendEquipmentMessageReply(const Core::FunctionReplyObject &replyObject) override;
void onSendEquipmentMessageOcReply(const Core::FunctionReplyObject &replyObject) override;
private:
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
std::shared_ptr<TrainingAreaBase::Interface::Ftc> m_tabFtc;
std::shared_ptr<OcSituationServer::Interface::Ftc> m_ossFtc;
int m_exerciseId;
QTimer *m_idleTimer; //<! timer to delete ExerciseHandler after n seconds when no longer needed
LOGGER_T m_logger;
};
} // namespace Messaging
+162
View File
@@ -0,0 +1,162 @@
/**
* Get information about (O/C) participants to be able to send/receive messages for them
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-12-13
*/
#include "exercises_handler.h"
#include "exercise_handler.h"
// subscribe to ex_* to gather
// 1. PPM::EquipmentExerciseMapping
// 2. TAB::EquipmentMessage
// create ExerciseHandler per Exercise (on demand when a message should be send to an O/C)
namespace Messaging
{
ExercisesHandler::ExercisesHandler(const std::shared_ptr<DdsHandler> &ddsHandler)
: m_ddsHandler(ddsHandler)
, m_logger(getLogger("ExercisesHandler"))
{
}
ExercisesHandler::~ExercisesHandler()
{
qDeleteAll(m_exerciseHandler);
}
bool ExercisesHandler::init()
{
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector());
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::equipmentExerciseMappingChanged,
this, &ExercisesHandler::onEquipmentExerciseMappingChanged);
if (!m_ppmDtc->enableEquipmentExerciseMapping())
return false;
ERROR_LOG(m_logger) << "# eem: " << m_ppmDtc->equipmentExerciseMappings().size();
return true;
}
int ExercisesHandler::findEquipmentNumber(int participantId, int exerciseId)
{
QPair<int,int> exePart;
exePart.first = exerciseId;
exePart.second = participantId;
return m_participant2EquipNumber.value(exePart);
}
bool ExercisesHandler::sendEquipmentMessage(const TrainingAreaBase::SendEquipmentMessageRequest &request)
{
if (request.equipmentNumbers().size() == 0)
return false;
const int equipmentNumber = request.equipmentNumbers().at(0);
auto it = m_equipNo2ExerciseId.constFind(equipmentNumber);
if (it == m_equipNo2ExerciseId.cend())
{
ERROR_LOG(m_logger) << "Can not send equipment message to training area - equipment number "
<< equipmentNumber << " not known";
return false;
}
ExerciseHandler *exH = exerciseHandlerForExerciseId(it.value());
return exH->sendEquipmentMessage(request);
}
bool ExercisesHandler::sendOcEquipmentMessage(const OcSituationServer::SendEquipmentMessageRequest &request)
{
if (request.equipmentNumbers().size() == 0)
return false;
const int equipmentNumber = request.equipmentNumbers().at(0);
auto it = m_equipNo2ExerciseId.constFind(equipmentNumber);
if (it == m_equipNo2ExerciseId.cend())
{
ERROR_LOG(m_logger) << "Can not send equipment message to training area - equipment number "
<< equipmentNumber << " not known";
return false;
}
ExerciseHandler *exH = exerciseHandlerForExerciseId(it.value());
return exH->sendOcEquipmentMessage(request);
}
ExerciseHandler *ExercisesHandler::exerciseHandlerForExerciseId(int exerciseId)
{
const auto itEH = m_exerciseHandler.find(exerciseId);
if (itEH != m_exerciseHandler.end())
return itEH.value();
DEBUG_LOG(m_logger) << "new ExerciseHandler for id " << exerciseId;
auto exH = new ExerciseHandler(m_ddsHandler->ddsConnector(), exerciseId);
bool result = exH->init();
DEBUG_LOG(m_logger)<<"result init ="<<result;
connect(exH, &ExerciseHandler::exerciseHandlerIdleTimeout,
this, &ExercisesHandler::onExerciseHandlerIdleTimeout);
m_exerciseHandler[exerciseId] = exH;
return exH;
}
void ExercisesHandler::onEquipmentExerciseMappingChanged(const ParticipantManagement::EquipmentExerciseMapping &data,
DataModification modType)
{
DEBUG_LOG(m_logger) << "onEquipmentExerciseMappingChanged";
for (auto it = m_equipNo2ExerciseId.begin(); it != m_equipNo2ExerciseId.end(); )
{
if (it.value() != data.exerciseId())
++it;
else
it = m_equipNo2ExerciseId.erase(it);
}
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
for (const ParticipantManagement::Equipment2ParticipantId &e2p : data.mapping())
{
m_equipNo2ExerciseId[e2p.equipmentNumber()] = data.exerciseId();
QPair<int,int> exePart;
exePart.first = data.exerciseId();
exePart.second = e2p.participantId();
m_participant2EquipNumber[exePart] = e2p.equipmentNumber();
}
break;
case DataModification::eRemoved:
break;
}
}
void ExercisesHandler::onEquipmentMessageChanged(const TrainingAreaBase::EquipmentMessage &data, const DataModification modType)
{
DEBUG_LOG(m_logger) << "onEquipmentMessageChanged";
if (modType != DataModification::eAdded &&
modType != DataModification::eModified)
return;
const int equipmentNumber = data.equipmentNumber();
const auto it = m_equipNo2ExerciseId.constFind(equipmentNumber);
if (it == m_equipNo2ExerciseId.constEnd())
{
ERROR_LOG(m_logger) << "Got EquipmentMessage from unknown participant with equipment number " << equipmentNumber;
return;
}
emit messageFromTrainingArea(data);
}
void ExercisesHandler::onExerciseHandlerIdleTimeout()
{
DEBUG_LOG(m_logger)<<"onExerciseHandlerIdleTimeout";
ExerciseHandler *exH = qobject_cast<ExerciseHandler *>(sender());
if (!exH)
return;
const int exerciseId = exH->exerciseId();
auto it = m_exerciseHandler.find(exerciseId);
if (it != m_exerciseHandler.end())
{
exH->deleteLater();
m_exerciseHandler.erase(it);
}
}
} // namespace Messaging
+53
View File
@@ -0,0 +1,53 @@
/**
* Get information about (O/C) participants to be able to send/receive messages for them
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-12-13
*/
#pragma once
#include "dds_handler.h"
#include "logger.h"
#include <QObject>
#include <QHash>
#include <ParticipantManagement/ppm_dtc.h>
#include <OcSituationServer/oss_dtc.h>
#include <TrainingAreaBase/tab.hpp>
#include <DDS/DDSConnector/dds_connector.h>
namespace Messaging
{
class ExerciseHandler;
class ExercisesHandler final : public QObject
{
Q_OBJECT
public:
explicit ExercisesHandler(const std::shared_ptr<DdsHandler> &ddsHandler);
~ExercisesHandler();
bool init();
bool sendEquipmentMessage(const TrainingAreaBase::SendEquipmentMessageRequest &request);
bool sendOcEquipmentMessage(const OcSituationServer::SendEquipmentMessageRequest &request);
int findEquipmentNumber(int participantId, int exerciseId);
Q_SIGNALS:
void messageFromTrainingArea(const TrainingAreaBase::EquipmentMessage &data);
private Q_SLOTS:
void onEquipmentExerciseMappingChanged(const ParticipantManagement::EquipmentExerciseMapping &data, DataModification modType);
void onEquipmentMessageChanged(const TrainingAreaBase::EquipmentMessage &data, const DataModification modType);
void onExerciseHandlerIdleTimeout();
private:
ExerciseHandler *exerciseHandlerForExerciseId(int exerciseId);
private:
std::shared_ptr<DdsHandler> m_ddsHandler;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
QHash<int, ExerciseHandler *> m_exerciseHandler;
// QHash< QPair<exerciseId,ParticipantId>, equipmentNumber>
QHash<QPair<int,int>, int> m_participant2EquipNumber;
QHash<int, int> m_equipNo2ExerciseId;
LOGGER_T m_logger;
};
} // namespace Messaging
+366
View File
@@ -0,0 +1,366 @@
/**
* Handler for message data request
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-10-12
*/
#include "handler_operator_message.h"
namespace Messaging
{
HandlerOperatorMessage::HandlerOperatorMessage(const std::shared_ptr<DdsHandler> &ddsHandler,
const std::shared_ptr<DatabaseInterface> &db,
const std::shared_ptr<ExercisesHandler> &exercisesHandler,
QObject *parent)
: QObject(parent)
, CreateOperatorMessageRequestHandler(ddsHandler->fts())
, ModifyOperatorMessageRequestHandler(ddsHandler->fts())
, m_ddsHandler(ddsHandler)
, m_db(db)
, m_exercisesHandler(exercisesHandler)
, m_logger(getLogger("HandlerOperatorMessage"))
{
} // end of ctor()
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool HandlerOperatorMessage::init()
{
INFO_LOG(m_logger) << "Start HandlerOperatorMessage.";
// read data from db-table 'msg_message_data'
// add to internal buffer
auto cbMsgData = [this] (const Database::MsgMessageData &data)
{
if (data.isDeleted)
return;
m_dbOperatorMessageData.insert(data.id, data);
m_ddsHandler->dts()->publish(toDdsData(data));
};
if (!m_db->select(cbMsgData)) // TODO (CE): nicht alle selektieren, nur die, die nicht gelöscht sind
{
ERROR_LOG(m_logger) << "Error reading data from database 'msg_message_data'!";
return false;
}
// Signal von tabDtc verbinden ( void equipmentMessageChanged(const TrainingAreaBase::EquipmentMessage &data, DataModification modType))
// enableEquipmentMessage zum abbonieren der EquipmentMessages
// Alle derzeit vorhandenen Messages auslesen (equipmentMessages()) und verarbeiten
connect(m_exercisesHandler.get(), &ExercisesHandler::messageFromTrainingArea,
this, &HandlerOperatorMessage::onMesssageFromTrainingArea);
//OperatorManagement::Interface::Dtc
m_opmDtc = OperatorManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector());
// Operator Management to get Username from operator
connect(m_opmDtc.get(), &OperatorManagement::Interface::Dtc::userChanged,
this, &HandlerOperatorMessage::onOperatorChanged);
m_opmDtc->enableUser();
return true;
} // end of init()
//-----------------------------------------------------------------------------
void HandlerOperatorMessage::onCreateOperatorMessageRequest(const rti::core::SampleIdentity &cookie,
const CreateOperatorMessageRequest &request)
{
DEBUG_LOG(m_logger) << "onCreateOperatorMessageRequest" << request;
auto ret = createOperatorMessageRequest(request);
if (ret.error())
WARNING_LOG(m_logger) << ret();
m_ddsHandler->fts()->createOperatorMessageReply(cookie, ret);
}
Core::FunctionReplyObject HandlerOperatorMessage::createOperatorMessageRequest(const CreateOperatorMessageRequest &request)
{
// 1. In DB eintragen
// 2. publishen
// 3. in interne Verwaltung eintragen
// 4. mit ok antworten
Database::MsgMessageData newMsg;
newMsg.timeStamp = m_ddsHandler->currentPartitionTime();
newMsg.senderId = request.senderId();
INFO_LOG(m_logger) << "newMsg.senderId=" << newMsg.senderId;
newMsg.subject = QString::fromStdString(request.subject());
newMsg.message = QString::fromStdString(request.message());
newMsg.senderType = request.senderType();
INFO_LOG(m_logger) << "newMsg.senderType.underlying()=" << newMsg.senderType.underlying();
newMsg.senderText = toAddressStr(newMsg.senderType, newMsg.senderId, request.exerciseId());
newMsg.recipientType = request.recipientType();
newMsg.exerciseId = request.exerciseId();
QString recipientText;
for (int32_t i : request.recipientIds())
{
recipientText.append(toAddressStr(newMsg.recipientType, i, newMsg.exerciseId));
recipientText.append(QString::fromStdString(" "));
}
newMsg.isRead = false;
newMsg.isDeleted = false;
INFO_LOG(m_logger) << "newMsg.senderType=" << newMsg.senderType << " newMsg.receiverType=" << newMsg.recipientType;
// Insert message for sender
newMsg.recipientId = 0;
newMsg.recipientText = recipientText;
// Only Operator messages
Core::FunctionReplyObject ret(newMsg.id);
if (newMsg.senderType == Messaging::AddressType_def::type::Operator)
ret = insertInDbAndPublish(newMsg);
const int correspondingOutboxMsgId = ret.id();
if (!ret.error() )
{
INFO_LOG(m_logger) << "insert message for each receiver";
// Insert message for each receiver
//newMsg.senderId = 0; WHY?
//if (correspondingOutboxMsgId > 0) // messages received from TETRA dont have a corresponding outbox id
newMsg.correspondingOutboxMessageId = correspondingOutboxMsgId; // can be also 0 - from TETRA
for (const auto recipientId : request.recipientIds())
{
newMsg.recipientId = recipientId;
newMsg.recipientText = toAddressStr(newMsg.recipientType, newMsg.recipientId, newMsg.exerciseId);
INFO_LOG(m_logger) << "recipientId: " << newMsg.recipientId;
ret = insertInDbAndPublish(newMsg);
if (ret.error())
break;
}
}
if (ret.error())
WARNING_LOG(m_logger) << ret();
return ret;
} // end of onCreateOperatorMessageRequest()
//-----------------------------------------------------------------------------
void HandlerOperatorMessage::onModifyOperatorMessageRequest(const rti::core::SampleIdentity &cookie,
const ModifyOperatorMessageRequest &request)
{
// 1. schauen ob es diese Message überhaupt gibt
// 2. aktualisieren in DB
// 3. interne Verwaltung aktualisieren
// 4. neu publishen bzw. von dds löschen
// 5. mit ok antworten
auto it = m_dbOperatorMessageData.find(request.id());
if (it == m_dbOperatorMessageData.end())
{
const auto ret = Core::FunctionReplyObject(0, tr_lts("dds", "Could not find message with id %1")).arg(request.id());
m_ddsHandler->fts()->modifyOperatorMessageReply(cookie, ret);
return;
}
Database::MsgMessageData data = it.value();
data.isDeleted = request.isDeleted();
data.isSend = request.isSend();
data.isRead = request.isRead();
const auto ret = modifyDbAndPublish(data);
m_ddsHandler->fts()->modifyOperatorMessageReply(cookie, ret);
} // end of onModifyOperatorMessageRequest()
//-----------------------------------------------------------------------------
OperatorMessage HandlerOperatorMessage::toDdsData(const Database::MsgMessageData &dbData)
{
OperatorMessage ddsData;
ddsData.id(dbData.id);
ddsData.senderId(dbData.senderId);
ddsData.recipientId(dbData.recipientId);
ddsData.exerciseId(dbData.exerciseId);
ddsData.subject(dbData.subject.toStdString());
ddsData.message(dbData.message.toStdString());
ddsData.recipientText(dbData.recipientText.toStdString());
ddsData.senderText(dbData.senderText.toStdString());
ddsData.isRead(dbData.isRead);
ddsData.isSend(dbData.isSend);
ddsData.isDeleted(dbData.isDeleted);
ddsData.senderType(dbData.senderType);
ddsData.recipientType(dbData.recipientType);
ddsData.correspondingOutboxMessageId(dbData.correspondingOutboxMessageId); // can also be 0
ddsData.timeStamp(dbData.timeStamp);
return ddsData;
} // end of toDdsData()
//-----------------------------------------------------------------------------
// Insert in db and publish
Core::FunctionReplyObject HandlerOperatorMessage::insertInDbAndPublish(Database::MsgMessageData newMsg)
{
// Length Check:
if (newMsg.recipientType == Messaging::AddressType_def::type::ObserverController)
{
newMsg.subject = newMsg.subject.left(m_maxSubjectLength);
newMsg.message = newMsg.message.left(m_maxOcContentLength);
}
if (newMsg.recipientType == Messaging::AddressType_def::type::Participant)
{
newMsg.subject = newMsg.subject.left(m_maxSubjectLength);
newMsg.message.clear();
}
DEBUG_LOG(m_logger) << "newMsg.senderId = " << newMsg.senderId;
if (!m_db->insert(newMsg))
return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding message to database"));
m_dbOperatorMessageData.insert(newMsg.id, newMsg);
if ((newMsg.recipientType == Messaging::AddressType_def::type::ObserverController)
|| (newMsg.recipientType == Messaging::AddressType_def::type::Participant))
{
int32_t equipmentNumber = m_exercisesHandler->findEquipmentNumber(newMsg.recipientId, newMsg.exerciseId);
int32_t participantId = newMsg.recipientId;
INFO_LOG(m_logger) << "equipmentNumber: " << equipmentNumber << ", participantId: " << participantId << ", exerciseId: " << newMsg.exerciseId;
// Length Check:
const auto subject = newMsg.subject.toStdString();
const auto message = newMsg.message.toStdString();
INFO_LOG(m_logger) << "Message to OC: subject =" << subject << " Message =" << message;
// only send to Tetra:
if (newMsg.recipientId > 0)
{
int senderId = m_dbOperatorMessageData[newMsg.correspondingOutboxMessageId].senderId;
AddressType senderType = m_dbOperatorMessageData[newMsg.correspondingOutboxMessageId].senderType;
INFO_LOG(m_logger) << "SendEquipmentMessageRequest id =" << newMsg.id;
INFO_LOG(m_logger) << " equipmentNumber=" << equipmentNumber
<< " participantId=" << participantId
<< " newMsg.id=" << newMsg.id
<< " newMsg.senderId=" << senderId
<< " newMsg.adressType=" << senderType
<< " subject=" << subject
<< " message=" << message;
static int s_requestId = 1;
if (newMsg.recipientType == Messaging::AddressType_def::type::ObserverController)
{
INFO_LOG(m_logger) << "Send to OC senderId=" << newMsg.senderId << " sendertype: " << newMsg.senderType << " subject " << subject;
m_exercisesHandler->sendOcEquipmentMessage({s_requestId++,
{equipmentNumber},
//newMsg.id,
newMsg.senderId,
newMsg.senderType,
subject,
message
});
}
else
{
m_exercisesHandler->sendEquipmentMessage({s_requestId++,
{equipmentNumber},
newMsg.id,
senderId,
subject,
message
});
}
}
//m_ddsHandler->tabFtc()->sendEquipmentMessageRequest(...);
//onsendEquipmentMessageReply implementieren und dort gelesen = true;
}
m_ddsHandler->dts()->publish(toDdsData(newMsg));
INFO_LOG(m_logger) << "insertInDbAndPublish id=" << newMsg.id;
if (newMsg.recipientType == Messaging::AddressType_def::type::ObserverController && newMsg.recipientId > 0)
{
INFO_LOG(m_logger) << "O/C-Message in Member-Variable kopieren: id = " << newMsg.id;
}
return Core::FunctionReplyObject(newMsg.id);
} // end of insertInDbAndPublish()
// Modify db and publish
Core::FunctionReplyObject HandlerOperatorMessage::modifyDbAndPublish(const Database::MsgMessageData &modMsg)
{
INFO_LOG(m_logger) << "modifyDbAndPublish" << " id=" << modMsg.id <<
" isDeleted=" << modMsg.isDeleted <<
" modMsg.isRead=" << modMsg.isRead <<
" modMsg.isSend=" << modMsg.isSend <<
" modMsg.sender=" << modMsg.senderId <<
" modMsg.receiver=" << modMsg.recipientId;
if (!m_db->update(modMsg))
return Core::FunctionReplyObject(modMsg.id,
tr_lts("dds", "Error updating message with id %1 to database")).arg(modMsg.id);
m_dbOperatorMessageData[modMsg.id] = modMsg;
if (modMsg.isDeleted)
{
INFO_LOG(m_logger) << "Remove LTS_OperatorMessage from DDS id=" << modMsg.id;
m_ddsHandler->dts()->removeOperatorMessageByKey(modMsg.id);
}
else
m_ddsHandler->dts()->publish(toDdsData(modMsg));
return Core::FunctionReplyObject(modMsg.id);
} // end of modifyDbAndPublish()
// Receive from Tetra
void HandlerOperatorMessage::onMesssageFromTrainingArea(const TrainingAreaBase::EquipmentMessage &data)
{
INFO_LOG(m_logger) << "************ onMesssageFromTrainingArea ********************";
onEquipmentMessageChanged(data, DataModification::eAdded);
}
// Receive from Tetra
void HandlerOperatorMessage::onEquipmentMessageChanged(const TrainingAreaBase::EquipmentMessage &data, const DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
CreateOperatorMessageRequest request;
DEBUG_LOG(m_logger) << "onEquipmentMessageChanged: " << data;
request.senderType() = Messaging::AddressType_def::type::Participant;
request.senderId(data.sender());
DEBUG_LOG(m_logger) << "request.senderId = " << request.senderId();
request.recipientType(Messaging::AddressType_def::type::Operator);
request.recipientIds().push_back(data.receiver());
request.subject() = data.subject();
request.message() = data.text();
createOperatorMessageRequest(request);
// Todo Fragen, ob die Meldung vom DDS geloescht werden soll.
} // end of onEquipmentMessageChanged
void HandlerOperatorMessage::onOperatorChanged(const OperatorManagement::User &data)
{
DEBUG_LOG(m_logger) << "************** onOperatorChanged ";
m_operatorMap.insert(data.id(), data.name());
} // end of onOperatorChanged
QString HandlerOperatorMessage::toAddressStr(const AddressType addressType, const qint32 addressId, int exerciseId)
{
QString result;
switch (addressType.underlying())
{
case AddressType::Operator:
// nicht per Request sondern hier aus OPM holen
result = QString::fromStdString(m_operatorMap.value(addressId, "Unknown Operator"));
break;
case AddressType::ObserverController:
{
int equipNumber = m_exercisesHandler->findEquipmentNumber(addressId, exerciseId);
if (equipNumber > 0)
result += QStringLiteral(" - ") + QString::number(equipNumber);
break;
}
case AddressType::Participant:
result = QLatin1String("Participant:") + QString::number(addressId);
break;
default:
result = QString::fromStdString("No valid addressType:");
QString numberStr ;
numberStr.setNum(addressType.underlying());
result.append(numberStr);
}
return result;
} // end of toAddressStr
} // namespace Messaging
+72
View File
@@ -0,0 +1,72 @@
/**
* Handler for table-io message data request
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-10-12
*/
#pragma once
#include <QObject>
#include "dds_handler.h"
#include "exercises_handler.h"
#include "logger.h"
#include <Messaging/msg_fts.h>
#include <Messaging/msg_db.h>
#include <TrainingAreaBase/tab.hpp>
#include <OperatorManagement/opm_dtc.h>
namespace Messaging
{
class HandlerOperatorMessage final
: public QObject
, protected Interface::Fts::CreateOperatorMessageRequestHandler
, protected Interface::Fts::ModifyOperatorMessageRequestHandler
{
Q_OBJECT
public:
explicit HandlerOperatorMessage(const std::shared_ptr<DdsHandler> &ddsHandler,
const std::shared_ptr<DatabaseInterface> &db,
const std::shared_ptr<ExercisesHandler> &exercisesHandler,
QObject *parent = nullptr);
bool init();
private Q_SLOTS:
void onMesssageFromTrainingArea(const TrainingAreaBase::EquipmentMessage &data);
void onEquipmentMessageChanged(const TrainingAreaBase::EquipmentMessage &data, const DataModification modType);
void onOperatorChanged(const OperatorManagement::User &data);
private: // methods
void onCreateOperatorMessageRequest(const rti::core::SampleIdentity &cookie,
const CreateOperatorMessageRequest &request) override;
Core::FunctionReplyObject createOperatorMessageRequest(const CreateOperatorMessageRequest &request);
void onModifyOperatorMessageRequest(const rti::core::SampleIdentity &cookie,
const ModifyOperatorMessageRequest &request) override;
// convert methodes
static OperatorMessage toDdsData(const Database::MsgMessageData &dbData); // db -> dds
QString toAddressStr(const AddressType addressType, const qint32 addressId, int exerciseId);
Core::FunctionReplyObject insertInDbAndPublish(Database::MsgMessageData newMsg);
Core::FunctionReplyObject modifyDbAndPublish(const Database::MsgMessageData &modMsg);
private: // attributes
std::shared_ptr<DdsHandler> m_ddsHandler;
std::shared_ptr<DatabaseInterface> m_db;
std::shared_ptr<ExercisesHandler> m_exercisesHandler;
QMap<int, Database::MsgMessageData> m_dbOperatorMessageData;
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
//std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
QMap<int, std::string> m_operatorMap;
NGL::INGLLogger &m_logger;
static const unsigned int m_maxSubjectLength = 80;
static const unsigned int m_maxOcContentLength = 1024;
};
} // namespace Messaging
+81
View File
@@ -0,0 +1,81 @@
log4j.reset=true
log4j.rootLogger=WARN, file
# Service: Messaging
###########################################################
#log4j.logger.MSG=INFO
#log4j.logger.MSG.DdsHandler=INFO
#log4j.logger.MSG.ExerciseHandler=INFO
#log4j.logger.MSG.ExercisesHandler=INFO
#log4j.logger.MSG.HandlerOperatorMessage=INFO
# 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$
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace Messaging
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "MSG.";
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 Messaging
+23
View File
@@ -0,0 +1,23 @@
/**
* @RDE_HEADER@
* Logging for Messaging
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
#include "msg_export.h"
namespace Messaging
{
using LOGGER_T = NGL::INGLLogger &;
MSG_COMMON_EXPORT LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace Messaging
+42
View File
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* main for Messaging
* $Id$
* $HeadURL$
* $Author$
*/
#include <nglapplication/nglcoreapplication.h>
#include <LtsCommandLineParser/LtsCommandLineParser.h>
#include "main_handler.h"
#include "logger.h"
#include "settings.h"
int main(int argc, char **argv)
{
NGLCoreApplication app(argc, argv);
LtsCommandLineParser::LtsCommandLineParser options;
if (!options.init())
return -1;
app.createLogger("MSG", options.exerciseId());
Messaging::Settings::setIniFile(options.iniFile());
int iRet = -3;
{
std::unique_ptr<Messaging::MainHandler> mainHandler(new Messaging::MainHandler);
if (!mainHandler->init(options.domainId()))
return iRet;
STARTUP_LOG(app.baseLogger());
iRet = app.exec();
SHUTDOWN_LOG(app.baseLogger());
}
return iRet;
}
+92
View File
@@ -0,0 +1,92 @@
/**
* MainHandler for MessageDataManagement
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-09-21
*/
#include "main_handler.h"
#include "settings.h"
#include <DDS/Core/pacemaker.h>
#include <ngldb/db_service_handler.h>
namespace Messaging
{
MainHandler::MainHandler()
: m_logger(getLogger("MainHandler"))
{
INFO_LOG(m_logger) << "MainHandler::MainHandler";
} // end of ctor()
//-----------------------------------------------------------------------------
MainHandler::~MainHandler()
{
INFO_LOG(m_logger) << "MainHandler::~MainHandler";
m_handlerOperatorMessage = nullptr;
m_exercisesHandler = nullptr;
m_ddsHandler = nullptr;
m_dbHandler = nullptr;
} // end of dtor()
//-----------------------------------------------------------------------------
bool MainHandler::init(int domainId)
{
INFO_LOG(m_logger) << "Start MessageDataManagement MainHandler. domainId ="<<domainId;
// initialize DDS
m_ddsHandler = std::make_shared<DdsHandler>(domainId);
if (!m_ddsHandler->init())
{
ERROR_LOG(m_logger) << "Initialisation DdsHandler failed.";
if (m_ddsHandler->pacemaker())
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError);
return false;
}
INFO_LOG(m_logger) << "m_ddsHandler initialized. ";
// initialize database
m_dbHandler = std::make_shared<DbHandler>();
if (!m_dbHandler->init(0, Settings::settings()))
{
ERROR_LOG(m_logger) << "Initialisation DbHandler failed.";
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError);
return false;
}
INFO_LOG(m_logger) << "DbHandler initialized. ";
INFO_LOG(m_logger) << "create HandlerExercises. ";
m_exercisesHandler = std::make_shared<ExercisesHandler>(m_ddsHandler);
if (!m_exercisesHandler->init())
{
ERROR_LOG(m_logger) << "create HandlerExercise failed.";
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError);
return false;
}
INFO_LOG(m_logger) << "m_exercisesHandler="<<m_exercisesHandler;
// create HandlerCreate
INFO_LOG(m_logger) << "create HandlerCreate. ";
m_handlerOperatorMessage = std::make_shared<HandlerOperatorMessage>(m_ddsHandler, m_dbHandler->db(), m_exercisesHandler);
if (!m_handlerOperatorMessage->init())
{
ERROR_LOG(m_logger) << "create HandlerMarkAsDelete failed.";
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::StartingError);
return false;
}
INFO_LOG(m_logger) << "HandlerCreate initialized. ";
m_ddsHandler->pacemaker()->setNewState(Core::RunningState::Running);
//m_ddsHandler->enableEquipmentMessage();
return true;
} // end of init()
//-----------------------------------------------------------------------------
} // namespace Messaging
+43
View File
@@ -0,0 +1,43 @@
/**
* MainHandler for Messaging
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-09-21
*/
#pragma once
#include "handler_operator_message.h"
#include "dds_handler.h"
#include "exercises_handler.h"
#include "logger.h"
#include <DDS/DDSConnector/dds_connector.h>
namespace NGLDB
{
template <typename DB> class DbServiceHandler;
}
namespace Messaging
{
using DbHandler = NGLDB::DbServiceHandler<DatabaseInterface>;
class MainHandler final
{
public:
MainHandler();
~MainHandler();
bool init(int domainId);
private: // attributes
std::shared_ptr<DdsHandler> m_ddsHandler; ///< Pointer to DDS handler
std::shared_ptr<DbHandler> m_dbHandler; ///< Pointer to DB handler
std::shared_ptr<ExercisesHandler> m_exercisesHandler; ///<Messages from OC
std::shared_ptr<HandlerOperatorMessage> m_handlerOperatorMessage; ///< Messages between Operators / O/C
NGL::INGLLogger &m_logger; ///< Interface to the Logging-Facility
};
} // namespace MessagingDataManagement
+52
View File
@@ -0,0 +1,52 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLSE, 2015-08-04
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef MSG_COMMON_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define MSG_COMMON_EXPORT
# else
# if defined(MAKE_SVCMSGCOMMON_LIB)
# define MSG_COMMON_EXPORT Q_DECL_EXPORT
# ifndef WIN32
# ifdef NDDSUSERDllExport
# undef NDDSUSERDllExport
# endif
# define NDDSUSERDllExport Q_DECL_EXPORT
# endif
# else
# define MSG_COMMON_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
#ifndef MSG_CLIENT_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define MSG_CLIENT_EXPORT
# else
# if defined(MAKE_SVCMSGCLIENT_LIB)
# define MSG_CLIENT_EXPORT Q_DECL_EXPORT
# else
# define MSG_CLIENT_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
#ifndef MSG_SERVER_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define MSG_SERVER_EXPORT
# else
# if defined(MAKE_SVCMSGSERVER_LIB)
# define MSG_SERVER_EXPORT Q_DECL_EXPORT
# else
# define MSG_SERVER_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
+108
View File
@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<service namespace="Messaging" abbreviation="MSG" procNames="Messaging" exerciseDependency="Global" groups="Core" prio="3">
<rcs>
<Id Id="$Id$"/>
<HeadURL HeadURL="$HeadURL$"/>
<Author Author="$Author$"/>
</rcs>
<operatorRights offset="21">
<guiPlugin name="Messaging" offset="1">
<operatorRightGroup name="Messages" description="Edit and Send Operator and OC Messages">
<operatorRight right="MessagesShow" value="1" description="Show (own) Messages"/>
<operatorRight right="MessagesSend" value="2" description="Edit and Send Operator Messages"/>
<operatorRight right="MessagesSendOc" value="3" description="Send Messages to O/C"/>
</operatorRightGroup>
</guiPlugin>
</operatorRights>
<tables>
<table name="address_type">
<column name="id" datatype="integer" isPrimaryKey="1">
<sequence start="1" increment="1"/>
</column>
<column name="name" datatype="text"/>
</table>
<table name="msg_message_operator_data">
<column name="id" datatype="integer" isPrimaryKey="1">
<sequence start="1" increment="1"/>
</column>
<column name="time_stamp" datatype="bigint"/>
<column name="sender_id" datatype="integer" default="1"/>
<column name="recipient_id" datatype="integer"/>
<column name="exercise_id" datatype="integer"/>
<column name="is_read" datatype="boolean"/>
<column name="is_send" datatype="boolean"/>
<column name="is_deleted" datatype="boolean"/>
<column name="subject" datatype="text"/>
<column name="message" datatype="text"/>
<column name="sender_text" datatype="text"/>
<column name="recipient_text" datatype="text"/>
<column name="recipient_type" datatype="integer" isForeignKey="1"/>
<column name="sender_type" datatype="integer" isForeignKey="1"/>
<column name="corresponding_outbox_message_id" datatype="integer" default="0"/>
<constraint name="UQ_msg_message_data_id" type="unique">
<column name="id"/>
</constraint>
<constraint name="IDX_msg_message_operator_is_deleted" type="index">
<column name="is_deleted"/>
</constraint>
<foreignKey name="FK_msg_message_operator_data_address_type_recv">
<source table="msg_message_operator_data" column="recipient_type"/>
<destination table="address_type" column="id"/>
</foreignKey>
<foreignKey name="FK_msg_message_operator_data_address_type_send">
<source table="msg_message_operator_data" column="sender_type"/>
<destination table="address_type" column="id"/>
</foreignKey>
</table>
</tables>
<views/>
<dbServiceStructs>
<serviceStruct name="MsgMessageData" table="msg_message_operator_data"/>
<table name="msg_message_operator_data"/>
</dbServiceStructs>
<topicTypes>
<topicType name="CreateOperatorMessageRequest">
<column name="recipientIds" idlType="sequence&lt;long&gt;" comment="Dependent on recipientType: - OperatorId, - ParticipantId"/>
<column name="exerciseId" idlType="long"/>
<column name="senderId" idlType="long" comment="Dependent on senderType: - OperatorId, - ParticipantId (or EqId?)"/>
<column name="subject" idlType="string"/>
<column name="message" idlType="string" comment="Shall be empty if Receiver is Non-O/C Participant. Not optional though."/>
<column name="senderType" idlType="AddressType"/>
<column name="recipientType" idlType="AddressType"/>
</topicType>
<topicType name="ModifyOperatorMessageRequest">
<column name="id" idlType="long" isKey="1"/>
<column name="isRead" idlType="boolean"/>
<column name="isSend" idlType="boolean"/>
<column name="isDeleted" idlType="boolean"/>
</topicType>
<topicType name="OperatorMessage" isDataObject="1" autosubscribe="1" routeToClient="1" routeToServer="0" routeInReplay="0">
<column name="id" idlType="long" isKey="1"/>
<column name="senderId" idlType="long"/>
<column name="recipientId" idlType="long"/>
<column name="exerciseId" idlType="long"/>
<column name="subject" idlType="string"/>
<column name="message" idlType="string"/>
<column name="isRead" idlType="boolean"/>
<column name="isSend" idlType="boolean"/>
<column name="isDeleted" idlType="boolean"/>
<column name="senderText" idlType="string"/>
<column name="recipientText" idlType="string"/>
<column name="senderType" idlType="AddressType"/>
<column name="recipientType" idlType="AddressType"/>
<column name="correspondingOutboxMessageId" idlType="long"/>
<column name="timeStamp" idlType="long long"/>
</topicType>
</topicTypes>
<functionTopics>
<functionTopic name="ModifyOperatorMessage" requestTopicType="ModifyOperatorMessageRequest" replyTopicType="Core::FunctionReply" requestTopicName="ModifyOperatorMessageRequest" replyTopicName="ModifyOperatorMessageReply" routeInReplay="0"/>
<functionTopic name="CreateOperatorMessage" requestTopicType="CreateOperatorMessageRequest" replyTopicType="Core::FunctionReply" requestTopicName="CreateOperatorMessageRequest" replyTopicName="CreateOperatorMessageReply" routeInReplay="0"/>
</functionTopics>
<enumerations>
<enumeration name="AddressType" table="address_type">
<attribute key="Operator" value="1"/>
<attribute key="ObserverController" value="2"/>
<attribute key="Participant" value="3"/>
</enumeration>
</enumerations>
</service>
+42
View File
@@ -0,0 +1,42 @@
/**
* Settings for Messaging
* $Id$
* $HeadURL$
* $Author$
*/
#include "settings.h"
#include <QtCore/QSettings>
#include <nglsettings/nglsettings_settings.h>
#include <ngltools/ngltools_filesystem.h>
namespace Messaging
{
class NGLSettingsClass : public NGL::Settings
{
public:
NGLSettingsClass()
: NGL::Settings(s_iniFile.isEmpty() ? NGL::findProjectConfigFile() : s_iniFile)
{}
static void setIniFile(const QString &fn)
{
s_iniFile = fn;
}
static QString s_iniFile;
};
QString NGLSettingsClass::s_iniFile;
Q_GLOBAL_STATIC(NGLSettingsClass, s)
//-----------------------------------------------------------------------------
NGL::Settings *Settings::settings()
{
return s();
}
//-----------------------------------------------------------------------------
void Settings::setIniFile(const QString &ini)
{
NGLSettingsClass::setIniFile(ini);
}
} // namespace Messaging
+24
View File
@@ -0,0 +1,24 @@
/**
* Settings for Messaging
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QString>
namespace NGL
{
class Settings;
}
namespace Messaging
{
namespace Settings
{
NGL::Settings *settings();
void setIniFile(const QString &ini);
}
} // namespace Messaging