382 lines
15 KiB
C++
Executable File
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 ¤tTemplate)
|
|
{
|
|
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 ¤tTemplate : 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> ¤tFut : qAsConst(futureVec))
|
|
{
|
|
Core::FunctionReplyObject ret = currentFut.result();
|
|
if (ret.error())
|
|
return ret;;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (const ParticipantManagement::TemplateData ¤tTemplate : 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 ¤tData : 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 ¤tData : 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 ¤tData,
|
|
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
|