Files
qt5-legatus-legacy/Lts/Services/ParticipantManagement/TemplateHandling/template_handler.cpp
T
2026-08-13 18:33:10 +02:00

382 lines
15 KiB
C++
Executable File

/**
* The TemplateHandler class manages all template related function topics and holds classes for
* further tempalte data.
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-07-27
*/
#include "template_handler.h"
#include "template.h"
#include "main_handler.h"
#include <TypeHandling/type_donator.h>
#include <ngldb/dbtransaction.h>
#include <QtCore/QFuture>
#include <QtCore/QThread>
#include <QtConcurrent/QtConcurrent>
namespace ParticipantManagement
{
namespace TemplateHandling
{
TemplateHandler::TemplateHandler(MainHandler *mainHandler)
: Interface::Fts::ModifyTemplateDataRequestHandler(mainHandler->exerciseId() <= 0 ? mainHandler->fts() : nullptr)
, m_mainHandler(mainHandler)
, m_logger(getLogger("TemplateHandler"))
{}
TemplateHandler::~TemplateHandler()
{
qDeleteAll(m_templates);
}
bool TemplateHandler::init()
{
auto cb = [this](const Database::PpmTemplate &currentTemplate)
{
Template *newTemplate = new Template(currentTemplate);
m_templates.insert(newTemplate->id(), newTemplate);
};
if (!m_mainHandler->db()->select(cb))
{
ERROR_LOG(m_logger) << "Error while reading template data from database";
return false;
}
// build hierarchy an publish
m_mainHandler->exAnyDts()->enableTemplateParticipant();
for (auto it = m_templates.begin(); it != m_templates.end(); ++it)
{
it.value()->hasNewInferiorStructure(inferiorIdsForTemplate(it.key()));
m_mainHandler->exAnyDts()->publish(it.value()->toDdsTemplateParticipant());
}
return true;
}
void TemplateHandler::onModifyTemplateDataRequest(const rti::core::SampleIdentity &cookie,
const ParticipantManagement::ModifyTemplateDataRequest &request)
{
DEBUG_LOG(m_logger) << "onModifyTemplateDataRequest: " << request;
const auto ret = modifyTemplateDataRequest(request);
if (ret.error())
WARNING_LOG(m_logger) << ret();
m_mainHandler->fts()->modifyTemplateDataReply(cookie, ret);
}
Core::FunctionReplyObject TemplateHandler::modifyTemplateDataRequest(const ParticipantManagement::ModifyTemplateDataRequest &request)
{
QVector<Template *> templatesWithChanges;
QHash<int32_t, int32_t> modIdToTemplateId; // <modId, templateId>
QVector<ParticipantManagement::TemplateData> templatesToBeCreatedOrModified;
templatesToBeCreatedOrModified.reserve(request.data().size());
DBTransaction removeTransaction(m_mainHandler->db()->database());
// first remove templates which are marked to be removed
for (const TemplateData &currentTemplate : request.data())
{
if (currentTemplate.isDeleted())
{
if (currentTemplate.templateId() <= 0)
return Core::FunctionReplyObject(tr_lts("dds",
"Internal error - Not possible to remove templateData with modId %1, because it does not have templateId set"))
.arg(currentTemplate.modId());
const auto ret = deleteTemplateById(currentTemplate.templateId(), true);
if (ret.error())
return ret;
}
else
templatesToBeCreatedOrModified.append(currentTemplate);
}
removeTransaction.commit();
DEBUG_LOG(m_logger) << "Starting validating ModifyTemplateDataRequest";
if (templatesToBeCreatedOrModified.size() >= 1000) // concurrent validation for big requests
{
QVector<QFuture<Core::FunctionReplyObject>> futureVec;
int vecSize = templatesToBeCreatedOrModified.size();
if (templatesToBeCreatedOrModified.size() % QThread::idealThreadCount())
vecSize += (QThread::idealThreadCount() - (vecSize % QThread::idealThreadCount()));
const int range = vecSize / QThread::idealThreadCount();
futureVec.reserve(vecSize);
for (int startIndex = 0; startIndex < templatesToBeCreatedOrModified.size(); startIndex += range)
{
QFuture<Core::FunctionReplyObject> fut = QtConcurrent::run(this,
&TemplateHandler::validateTemplateData,
templatesToBeCreatedOrModified,
modIdToTemplateId,
startIndex,
range);
futureVec += fut;
}
for (const QFuture<Core::FunctionReplyObject> &currentFut : qAsConst(futureVec))
{
Core::FunctionReplyObject ret = currentFut.result();
if (ret.error())
return ret;;
}
}
else
{
for (const ParticipantManagement::TemplateData &currentTemplate : qAsConst(templatesToBeCreatedOrModified))
{
DEBUG_LOG(m_logger) << "Validating template: " << currentTemplate;
auto ret = validateTemplateData(templatesToBeCreatedOrModified, modIdToTemplateId, currentTemplate);
if (ret.error())
return ret;
}
}
DBTransaction trans(m_mainHandler->db()->database());
// only continue if there was no error detected
DEBUG_LOG(m_logger) << "ModifyTemplateDataRequest has valid data";
// create new and update existing templates
DEBUG_LOG(m_logger) << "Creating new and updating existing templates ...";
for (const TemplateData &currentData : qAsConst(templatesToBeCreatedOrModified))
{
Template *templateToUpdate = m_templates.value(modIdToTemplateId.value(currentData.modId()));
if (!templateToUpdate)
{
DEBUG_LOG(m_logger) << "Creating new template: " << currentData;
const auto ret = createNewTemplate(currentData, modIdToTemplateId, templatesWithChanges);
if (ret.error())
return ret;
}
else
{
// update existing template
if (templateToUpdate->hasToBeChanged(currentData) &&
!templatesWithChanges.contains(templateToUpdate))
{
DEBUG_LOG(m_logger) << "Template changed: " << templateToUpdate->toDdsTemplateParticipant();
templatesWithChanges.append(templateToUpdate);
}
}
}
DEBUG_LOG(m_logger) << "New templates created and existing templates updated";
// build hierarchy
for (const TemplateData &currentData : qAsConst(templatesToBeCreatedOrModified)) // first set superiorIds
{
Template *templateToUpdate = m_templates.value(modIdToTemplateId.value(currentData.modId()), nullptr);
const int superiorId = modIdToTemplateId.value(currentData.superiorModId());
if (!templateToUpdate->hasNewSuperiorId(superiorId) ||
templatesWithChanges.contains(templateToUpdate))
continue;
templatesWithChanges.append(templateToUpdate);
}
for (Template *currentTemplate : qAsConst(m_templates)) // set inferiorIds
{
if (!currentTemplate->hasNewInferiorStructure(inferiorIdsForTemplate(currentTemplate->id())) ||
templatesWithChanges.contains(currentTemplate))
continue;
DEBUG_LOG(m_logger) << "Template got new inferiors: " << currentTemplate->toDdsTemplateParticipant();
templatesWithChanges.append(currentTemplate);
}
// update in Database
for (Template *currentTemplate : qAsConst(templatesWithChanges))
{
if (!m_mainHandler->db()->update(currentTemplate->dbEntry()))
return Core::FunctionReplyObject(tr_lts("dds", "Could not update template data in database, template data may be inconsistent"));
}
trans.commit();
// finally ... publish template data via dds if no error occured
for (Template *currentTemplate : qAsConst(templatesWithChanges))
m_mainHandler->exAnyDts()->publish(currentTemplate->toDdsTemplateParticipant());
return Core::FunctionReplyObject();
}
std::vector<int32_t> TemplateHandler::inferiorIdsForTemplate(int32_t superiorTemplateId) const
{
std::vector<int32_t> result;
result.reserve(10);
for (Template *currentTemplate : qAsConst(m_templates))
{
if (currentTemplate->superiorId() == superiorTemplateId)
{
DEBUG_LOG(m_logger) << "Building hierarchy, parentId: " << superiorTemplateId << " has child " << currentTemplate->id();
result.push_back(currentTemplate->id());
}
}
return result;
}
Core::FunctionReplyObject TemplateHandler::createNewTemplate(const ParticipantManagement::TemplateData &currentData,
QHash<int32_t, int32_t> &modIdToTemplateId,
QVector<Template *> &templatesWithChanges)
{
// create new template
Database::PpmTemplate newDbTemplate;
newDbTemplate.typeId = currentData.typeId();
newDbTemplate.name = QString::fromStdString(currentData.name());
newDbTemplate.symbol = QString::fromStdString(currentData.symbol());
newDbTemplate.info = QString::fromStdString(currentData.info());
newDbTemplate.designator = QString::fromStdString(currentData.designator());
newDbTemplate.tacticalIdentifier = QString::fromStdString(currentData.tacticalIdentifier());
newDbTemplate.superiorId = modIdToTemplateId.value(currentData.superiorModId(), 0);
newDbTemplate.hierarchyNumber = currentData.hierarchyNumber();
newDbTemplate.equipmentNumber = currentData.equipmentNumber();
// creating db entry
if (!m_mainHandler->db()->insert(newDbTemplate))
return Core::FunctionReplyObject(tr_lts("dds",
"Error inserting new template into database, template data may be inconsistent"));
// adding the new template
Template *newTemplate = new Template(newDbTemplate);
m_templates.insert(newTemplate->id(), newTemplate);
modIdToTemplateId.insert(currentData.modId(), newTemplate->id());
if (!templatesWithChanges.contains(newTemplate))
templatesWithChanges.append(newTemplate);
return Core::FunctionReplyObject();
}
Core::FunctionReplyObject TemplateHandler::validateTemplateData(const QVector<TemplateData> &dataVec,
QHash<int32_t, int32_t> &modIdToTemplateId,
const ParticipantManagement::TemplateData &templateToValidate)
{
if (templateToValidate.templateId() != 0)
{
DEBUG_LOG(m_logger) << "Checking template id";
Template *existingTemplate = m_templates.value(templateToValidate.templateId(), nullptr);
if (existingTemplate == nullptr)
return Core::FunctionReplyObject(tr_lts("dds",
"Could not execute ModifyTemplateDataRequest, because an invalid template ID (%1) was given"))
.arg(templateToValidate.templateId());
DEBUG_LOG(m_logger) << "... ok";
{
QMutexLocker l(&m_mutex);
modIdToTemplateId.insert(templateToValidate.modId(), existingTemplate->id()); /* register template to indicate that this template
should just be modified and not newly created */
}
}
// superior ids valid?
if (templateToValidate.superiorModId() > 0)
{
DEBUG_LOG(m_logger) << "checking superiorIds";
// superior exists?
bool isExistingSuperiorId = false;
for (const TemplateData &dat : dataVec)
{
if (templateToValidate.superiorModId() == dat.modId())
{
isExistingSuperiorId = true;
break; // for (const TemplateData &dat : dataVec)
}
}
if (!isExistingSuperiorId)
return Core::FunctionReplyObject(tr_lts("dds",
"Could not execute ModifyTemplateDataRequest, the data set with modId %1 has an invalid superiorModId %2"))
.arg(templateToValidate.modId())
.arg(templateToValidate.superiorModId());
DEBUG_LOG(m_logger) << "... ok";
if (templateToValidate.hierarchyNumber() <= 0)
return Core::FunctionReplyObject(tr_lts("dds",
"Could not execute ModifyTemplateDataRequest, because a data set has a superior but no hierarchyNumber set"));
// all hierarchy numbers with same superior unique?
DEBUG_LOG(m_logger) << "Checking hierarchyNumbers";
for (const TemplateData &dat : dataVec)
{
// operator==() on optionals returns false if not set ...
if (dat.modId() != templateToValidate.modId() &&
dat.superiorModId() == templateToValidate.superiorModId() &&
dat.hierarchyNumber() == templateToValidate.hierarchyNumber())
return Core::FunctionReplyObject(tr_lts("dds",
"Could not execute ModifyTemplateDataRequest, because for superiorModId %1 hierarchyNumber %2 is not unique"))
.arg(dat.superiorModId())
.arg(dat.hierarchyNumber());
}
DEBUG_LOG(m_logger) << "... ok";
}
// typeId valid?
DEBUG_LOG(m_logger) << "Checking typeId";
if (m_mainHandler->typeHandler()->typeById(templateToValidate.typeId()) == nullptr)
return Core::FunctionReplyObject(tr_lts("dds",
"Could not execute ModifyTemplateDataRequest, because data set with modId %1 has invalid typeId %2"))
.arg(templateToValidate.modId())
.arg(templateToValidate.typeId());
DEBUG_LOG(m_logger) << "... ok";
return Core::FunctionReplyObject();
}
Core::FunctionReplyObject TemplateHandler::validateTemplateData(const QVector<TemplateData> &dataVec,
QHash<int32_t, int32_t> &modIdToTemplateId,
int startIndex,
int range)
{
int endIndex;
if (startIndex + range > dataVec.size())
endIndex = dataVec.size() - startIndex - 1;
else
endIndex = startIndex + range - 1;
for (int currentIndex = startIndex; currentIndex <= endIndex; ++currentIndex)
{
const ParticipantManagement::TemplateData &templateToValidate = dataVec.at(currentIndex);
auto ret = validateTemplateData(dataVec, modIdToTemplateId, templateToValidate);
if (ret.error())
return ret;
}
return Core::FunctionReplyObject();
}
Core::FunctionReplyObject TemplateHandler::deleteTemplateById(int32_t templateId, bool isTriggeredFromFtRequest)
{
Template *templateToBeRemoved = m_templates.value(templateId);
if (!templateToBeRemoved)
return Core::FunctionReplyObject(tr_lts("dds", "Can not find template with id %1 which should be removed")).arg(templateId);
const auto inferiors(inferiorIdsForTemplate(templateId));
for(int32_t currentInferiorTemplateId : inferiors)
{
const Core::FunctionReplyObject ret = deleteTemplateById(currentInferiorTemplateId);
if (ret.error())
return ret;
}
if (!m_mainHandler->db()->removePpmTemplate(templateId))
return Core::FunctionReplyObject(tr_lts("dds", "Could not remove template with id %1 from database")).arg(templateId);
m_mainHandler->exAnyDts()->removeTemplateParticipantByKey(templateId);
m_templates.remove(templateId);
if (isTriggeredFromFtRequest && templateToBeRemoved->superiorId()) // refresh inferiors from parent and publish in dds
{
Template *parentTemplate = m_templates.value(templateToBeRemoved->superiorId());
if (parentTemplate->hasNewInferiorStructure(inferiorIdsForTemplate(parentTemplate->id())))
m_mainHandler->exAnyDts()->publish(parentTemplate->toDdsTemplateParticipant());
}
delete templateToBeRemoved;
return Core::FunctionReplyObject();
}
} // namespace ParticipantManagement
} // namespace TemplateHandling