/** * Handler for base download coordination * $Id$ * $HeadURL$ * $Author$ * Created by Philipp Dassow, NLST, 15-03-2018 */ #include "handler_base_download.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "copy_database.h" #include "main_handler.h" #include "settings.h" #include "WebSocketInterface/Messages/reply_message.h" namespace OcBaseDownload { HandlerBaseDownload::HandlerBaseDownload(MainHandler *mainHandler, QObject *parent) : QObject(parent) , Interface::Fts::StartBaseDownloadRequestHandler(mainHandler->dds()->fts()) , Interface::Fts::LifeUpdateRequestHandler(mainHandler->dds()->fts()) , m_fts(mainHandler->dds()->fts()) , m_scmDtc(mainHandler->scmDtc()) , m_scmFtc(mainHandler->scmFtc()) , m_baseDownloadReplyUpdateTimer(new QTimer(this)) , m_mainHandler(mainHandler) , m_exerciseId(0) , m_operatorId(9) , m_hostname(NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET)) , m_currentState(NotStarted) , m_remoteDbRetryCounter(0) , m_copyDatabase(new CopyDatabase(getLogger("HandlerBaseDownload"), this)) , m_exTblGen(new DBAdministration::ExerciseTableGenerator(getLogger("ExerciseTableGenerator"), NGL::directory(NGL::FileType::ConfigFile, QLatin1String("xml")), this)) , m_logger(getLogger("HandlerBaseDownload")) { connect(m_baseDownloadReplyUpdateTimer, &QTimer::timeout, this, &HandlerBaseDownload::updateBaseDownloadReply); m_baseDownloadReplyUpdateTimer->setInterval(3000); connect(m_copyDatabase, &CopyDatabase::copyDbFailed, this, &HandlerBaseDownload::onCopyDbFailed); connect(m_copyDatabase, &CopyDatabase::copyDbFinished, this, &HandlerBaseDownload::onCopyDbFinished); connect(m_copyDatabase, &CopyDatabase::dropDatabaseFailed, this, &HandlerBaseDownload::onDropOldDatabaseFailed); connect(m_copyDatabase, &CopyDatabase::dropDatabaseFinished, this, &HandlerBaseDownload::onDropOldDatabaseFinished); connect(m_exTblGen, &DBAdministration::ExerciseTableGenerator::aliveSignal, this, &HandlerBaseDownload::updateBaseDownloadReply); connect(m_exTblGen, &DBAdministration::ExerciseTableGenerator::aliveSignal, mainHandler->dds()->pacemaker().get(), &Core::Pacemaker::publishState); } HandlerBaseDownload::~HandlerBaseDownload() { m_fts = nullptr; m_scmDtc = nullptr; m_scmFtc = nullptr; delete m_baseDownloadReplyUpdateTimer; } bool HandlerBaseDownload::init() { // SCM DTC enable if (!m_scmDtc->enableServiceInformation() || !m_scmDtc->enableGroupInformation()) { ERROR_LOG(m_logger) << "Enabling SCM Data-Topics failed."; return false; } // SCM FTC enable if (!m_scmFtc->enableRestartGroup() || !m_scmFtc->enableStopGroup()) { ERROR_LOG(m_logger) << "Enabling SCM Function-Topics failed."; return false; } INFO_LOG(m_logger) << "HandlerBaseDownload initialised!"; return true; } void HandlerBaseDownload::handleErrorMessage(const QString &err) { QString text = QString::fromLatin1(tr_lts("dds", "Got ErrorMessage via web socket: %1")).arg(err); cleanup(Core::FtReplyState::Error, text.toStdString()); } void HandlerBaseDownload::receiveAsmData() { using namespace AssetManagement; auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(0, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); if (!m_dataVecMap.contains(DbDataType::AsmTrainingArea)) { QVector asmTrainingAreas; if (remoteDbIfc->select(asmTrainingAreas)) { storeToDataVecMap(DbDataType::AsmTrainingArea, std::vector(asmTrainingAreas.begin(), asmTrainingAreas.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::AsmTechnicalArea)) { QVector asmTechnicalAreas; if (remoteDbIfc->select(asmTechnicalAreas)) { storeToDataVecMap(DbDataType::AsmTechnicalArea, std::vector(asmTechnicalAreas.begin(), asmTechnicalAreas.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::AsmLocation)) { QVector asmLocations; if (remoteDbIfc->select(asmLocations)) { storeToDataVecMap(DbDataType::AsmLocation, std::vector(asmLocations.begin(), asmLocations.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::AsmAsset)) { QVector asmAssets; if (remoteDbIfc->select(asmAssets)) { storeToDataVecMap(DbDataType::AsmAsset, std::vector(asmAssets.begin(), asmAssets.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } checkForAsmFinished(); } void HandlerBaseDownload::receiveExmData() { // handling EXM data using namespace ExerciseManagement; auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(0, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); if (!m_dataVecMap.contains(DbDataType::ExmExercise)) { QVector exmExercises; if (remoteDbIfc->select(exmExercises)) { storeToDataVecMap(DbDataType::ExmExercise, std::vector(exmExercises.begin(), exmExercises.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::ExmExercisePhase)) { QVector exmExercisePhases; if (remoteDbIfc->select(exmExercisePhases)) { storeToDataVecMap(DbDataType::ExmExercisePhase, std::vector(exmExercisePhases.begin(), exmExercisePhases.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::ExmExerciseStateChange)) { QVector exmExerciseStateChanges; if (remoteDbIfc->select(exmExerciseStateChanges)) { storeToDataVecMap(DbDataType::ExmExerciseStateChange, std::vector(exmExerciseStateChanges.begin(), exmExerciseStateChanges.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } checkForExmFinished(); } void HandlerBaseDownload::receiveIsmData() { // handling ISM data using namespace InfrastructureManagement; auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(0, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); if (!m_dataVecMap.contains(DbDataType::IsmAsset)) { QVector ismAssets; if (remoteDbIfc->select(ismAssets)) { storeToDataVecMap(DbDataType::IsmAsset, std::vector(ismAssets.begin(), ismAssets.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::IsmSpecialArea)) { QVector ismSpecialAreas; if (remoteDbIfc->select(ismSpecialAreas)) { storeToDataVecMap(DbDataType::IsmSpecialArea, std::vector(ismSpecialAreas.begin(), ismSpecialAreas.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::IsmMainStructureElement)) { QVector ismMainStructureElements; if (remoteDbIfc->select(ismMainStructureElements)) { storeToDataVecMap(DbDataType::IsmMainStructureElement, std::vector(ismMainStructureElements.begin(), ismMainStructureElements.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::IsmStructureElement)) { QVector ismStructureElements; if (remoteDbIfc->select(ismStructureElements)) { storeToDataVecMap(DbDataType::IsmStructureElement, std::vector(ismStructureElements.begin(), ismStructureElements.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::IsmStructureElementFootprint)) { QVector ismStructureElementFootprints; if (remoteDbIfc->select(ismStructureElementFootprints)) { storeToDataVecMap(DbDataType::IsmStructureElementFootprint, std::vector(ismStructureElementFootprints.begin(), ismStructureElementFootprints.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::IsmMountingPointAsset)) { QVector ismMountingPointAssets; if (remoteDbIfc->select(ismMountingPointAssets)) { storeToDataVecMap(DbDataType::IsmMountingPointAsset, std::vector(ismMountingPointAssets.begin(), ismMountingPointAssets.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::IsmMountingPointSchedule)) { QVector ismMountingPointSchedules; if (remoteDbIfc->select(ismMountingPointSchedules)) { storeToDataVecMap(DbDataType::IsmMountingPointSchedule, std::vector(ismMountingPointSchedules.begin(), ismMountingPointSchedules.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::IsmMountingPointPlan)) { QVector ismMountingPointPlans; if (remoteDbIfc->select(ismMountingPointPlans)) { storeToDataVecMap(DbDataType::IsmMountingPointPlan, std::vector(ismMountingPointPlans.begin(), ismMountingPointPlans.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } checkForIsmFinished(); } void HandlerBaseDownload::receivePpmEx0Data() { // handling PPM Ex0 data using namespace ParticipantManagement; auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(0, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); if (!m_dataVecMap.contains(DbDataType::PpmEquipmentType)) { QVector ppmEquipmentTypes; if (remoteDbIfc->select(ppmEquipmentTypes)) { storeToDataVecMap(DbDataType::PpmEquipmentType, std::vector(ppmEquipmentTypes.begin(), ppmEquipmentTypes.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::PpmType)) { QVector ppmTypes; if (remoteDbIfc->select(ppmTypes)) { storeToDataVecMap(DbDataType::PpmType, std::vector(ppmTypes.begin(), ppmTypes.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } checkForPpmEx0Finished(); } void HandlerBaseDownload::receivePpmExNData() { // handling PPM ExN data using namespace ParticipantManagement; auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(m_exerciseId, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); if (!m_dataVecMap.contains(DbDataType::PpmParty)) { QVector ppmParties; if (remoteDbIfc->select(ppmParties)) { storeToDataVecMap(DbDataType::PpmParty, std::vector(ppmParties.begin(), ppmParties.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::PpmParticipant)) { QVector ppmParticipants; if (remoteDbIfc->select(ppmParticipants)) { storeToDataVecMap(DbDataType::PpmParticipant, std::vector(ppmParticipants.begin(), ppmParticipants.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } checkForPpmExNFinished(); } void HandlerBaseDownload::receiveOpmData() { // handling OPM data using namespace OperatorManagement; auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(0, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); if (!m_dataVecMap.contains(DbDataType::OpmGroup)) { QVector opmGroups; if (remoteDbIfc->select(opmGroups)) { storeToDataVecMap(DbDataType::OpmGroup, std::vector(opmGroups.begin(), opmGroups.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::OpmGroupGroup)) { QVector opmGroupGroups; if (remoteDbIfc->select(opmGroupGroups)) { storeToDataVecMap(DbDataType::OpmGroupGroup, std::vector(opmGroupGroups.begin(), opmGroupGroups.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::OpmOperator)) { QVector opmOperators; if (remoteDbIfc->select(opmOperators)) { storeToDataVecMap(DbDataType::OpmOperator, std::vector(opmOperators.begin(), opmOperators.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::OpmOperatorExercise)) { QVector opmOperatorExercises; if (remoteDbIfc->select(opmOperatorExercises)) { storeToDataVecMap(DbDataType::OpmOperatorExercise, std::vector(opmOperatorExercises.begin(), opmOperatorExercises.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::OpmSettings)) { QVector opmSettings; if (remoteDbIfc->select(opmSettings)) { storeToDataVecMap(DbDataType::OpmSettings, std::vector(opmSettings.begin(), opmSettings.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::OpmAccessControlLevel)) { QVector opmAccessControlLevel; if (remoteDbIfc->select(opmAccessControlLevel)) { storeToDataVecMap(DbDataType::OpmAccessControlLevel, std::vector(opmAccessControlLevel.begin(), opmAccessControlLevel.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::OpmAclAllow)) { QVector opmAclAllows; if (remoteDbIfc->select(opmAclAllows)) { storeToDataVecMap(DbDataType::OpmAclAllow, std::vector(opmAclAllows.begin(), opmAclAllows.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } if (!m_dataVecMap.contains(DbDataType::OpmAclDeny)) { QVector opmAclDenys; if (remoteDbIfc->select(opmAclDenys)) { storeToDataVecMap(DbDataType::OpmAclDeny, std::vector(opmAclDenys.begin(), opmAclDenys.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } checkForOpmFinished(); } void HandlerBaseDownload::receiveFlmData() { // handling FLM data using namespace FileManagement; auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(0, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); QVector flmFolders; if (!m_dataVecMap.contains(DbDataType::FlmFolder)) { if (remoteDbIfc->select(flmFolders)) { storeToDataVecMap(DbDataType::FlmFolder, std::vector(flmFolders.begin(), flmFolders.end())); m_remoteDbRetryCounter = 0; } else { retryCurrentSelect(); return; } } if (flmFolders.isEmpty()) { auto foldersDataVec = getDbDataVec(DbDataType::FlmFolder); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) flmFolders = QVector(foldersDataVec.begin(), foldersDataVec.end()); // since qt5.14 #else flmFolders = flmFolders.fromStdVector(foldersDataVec); #endif } if (!m_dataVecMap.contains(DbDataType::FlmFileContent)) { int snapshotFolderId = getFolderId(flmFolders, QStringLiteral("Snapshots"), m_exerciseId); //this is DONE BY HAND!!!! so very uncool //I HATE YOU SO MUCH YOU FUCKING FUCK FUCK! still is! const QString where = QStringLiteral(" WHERE ((exercise_id is null OR exercise_id = ") + QString::number(m_exerciseId) + QStringLiteral(") and file_type_id in (1,2,6,7,8) )"); const QString where2 = QStringLiteral(" or (exercise_id = ") + QString::number(m_exerciseId) + QStringLiteral(" and file_type_id in (4,5) and folder_id=") + QString::number(snapshotFolderId)+QStringLiteral(" )"); const QString tableName(QStringLiteral("flm.flm_file_content")); const QString stmt(QStringLiteral("SELECT id, name, is_template, folder_id, file_category_id, file_type_id, file_status_id, exercise_id, phase_id, operator_id, content, properties, is_used_by, used_by, last_modified" " FROM ") + tableName + where + where2); ERROR_LOG(m_logger) << "FUCK FUCK WE ARE HERE!" << " snapshid id is= " << snapshotFolderId << " also my statement: " << stmt; std::unique_ptr query = std::unique_ptr(new NSqlQuery(remoteDbIfc->database(), m_logger)); query->prepare(stmt); QVector dataVec; if (query->exec()) { Database::FlmFileContent data; while (query->next()) { int i = 0; data.id = query->value(i++).toLongLong(); data.name = query->value(i++).toString(); data.isTemplate = query->value(i++).toBool(); data.folderId = query->value(i++).toLongLong(); data.fileCategoryId = static_cast(query->value(i++).toInt()); data.fileTypeId = static_cast(query->value(i++).toInt()); data.fileStatusId = static_cast(query->value(i++).toInt()); data.exerciseId = query->value(i++); data.phaseId = query->value(i++); data.operatorId = query->value(i++).toInt(); data.content = query->value(i++).toByteArray(); QVariant xx = query->value(i++); data.properties = xx.isNull() ? QStringLiteral("{}") : xx.toString(); data.isUsedBy = query->value(i++).toBool(); data.usedBy = query->value(i++).toInt(); data.lastModified = query->value(i++).toLongLong(); if ((data.fileTypeId == FileManagement::FileType::Jpg || data.fileTypeId == FileManagement::FileType::Png) && data.folderId != snapshotFolderId) { DEBUG_LOG(m_logger) << "skip"; continue; } // ERROR_LOG(m_logger) << "ADD " << data.name; dataVec.append(data); } } if (!dataVec.isEmpty()) { ERROR_LOG(m_logger) << "Data vec has sisze: " << dataVec.size(); storeToDataVecMap(DbDataType::FlmFileContent, std::vector(dataVec.begin(), dataVec.end())); m_remoteDbRetryCounter = 0; } else retryCurrentSelect(); } checkForFlmFinished(); } int HandlerBaseDownload::getFolderId(const QVector &dataVec, const QString &folderName, int exerciseId) const { int parentFolder = 0; if (exerciseId > 0) { const QString exName = QLatin1String("$EX_") + QString::number(exerciseId); parentFolder = getFolderId(dataVec, exName, 0); } for (const auto &fld : dataVec) { if (fld.name == folderName) { if (exerciseId > 0 && parentFolder > 0) { if (fld.path().size() > 1 && fld.path().at(fld.path().size() - 2) == parentFolder) return fld.id; } else return fld.id; } } return 0; } bool HandlerBaseDownload::openDbConnection(const QString &databaseName) { if (m_dbConnection.isValid()) { m_exTblGen->close(); closeDb(m_dbConnection); } bool bOk; m_dbConnection = openDb(databaseName, false, &bOk); if (!bOk) return false; return m_exTblGen->init(m_dbConnection, QStringLiteral("exm")); } bool HandlerBaseDownload::openRemoteDbConnection(const QString &remoteDatabaseName) { if (m_remoteDbConnection.isValid()) closeDb(m_remoteDbConnection); bool bOk; m_remoteDbConnection = openDb(remoteDatabaseName, true, &bOk); if (!bOk) return false; return true; } QSqlDatabase HandlerBaseDownload::openDb(const QString &databaseName, bool remote, bool *bOk) { if (bOk) *bOk = true; // open postgres db, read table structure, read static data auto s = Settings::settings(); const QString dbUser(QStringLiteral("ets_exm")); const QString dbPasswd(QStringLiteral("ets11de")); QSqlDatabase dbConnection = DBConnection::open(m_logger, dbUser, dbPasswd, s->databaseDriver(), remote ? m_hostname : s->databaseHostname(), remote ? Settings::remoteDbName() : databaseName); DEBUG_LOG(m_logger) << "Trying to open database " << s->databaseHostname() << ":" << databaseName; if (!dbConnection.isOpen()) { ERROR_LOG(m_logger) << "Error opening database " << s->databaseHostname() << ":" << databaseName; if (bOk) *bOk = false; } else NOTICE_LOG(m_logger) << "Opened database connection " << dbConnection.connectionName(); return dbConnection; } void HandlerBaseDownload::closeDb(QSqlDatabase &dbConn) { const QString connName = dbConn.connectionName(); NOTICE_LOG(m_logger) << "Closing database connection " << connName; dbConn.close(); dbConn = QSqlDatabase(); QSqlDatabase::removeDatabase(connName); } template const std::vector &HandlerBaseDownload::getDbDataVec(DbDataType type) const { return static_cast*>(m_dataVecMap[type])->data(); } template inline void storeVector(const QVector &vec, QPair> &storage) { storage.first = true; storage.second = vec; } void HandlerBaseDownload::updateBaseDownloadReply() { NOTICE_LOG(m_logger) << "updateBaseDownloadReply..."; m_fts->startBaseDownloadReply(m_baseDownloadCookie, m_reply); } void HandlerBaseDownload::onStartBaseDownloadRequest(const rti::core::SampleIdentity &cookie, const StartBaseDownloadRequest &request) { DEBUG_LOG(m_logger) << "Got Request, check for old one : " << request.hostname(); if (request.timeStamp() < (QDateTime::currentMSecsSinceEpoch() - 10 * 1000)) //(5Sekunden) { DEBUG_LOG(m_logger) << "old call? ignore! "; m_reply.progress(0); m_reply.errorString(std::string()); m_reply.currentStep(std::string()); m_reply.replyState(Core::FtReplyState::Error); m_fts->startBaseDownloadReply(m_baseDownloadCookie, m_reply); return; } // m_webSocket->setCurrentDownload(WebSocketInterface::CurrentDownload::BASE); m_baseDownloadCookie = cookie; m_exerciseId = request.exerciseId(); m_operatorId = request.loggedInOperatorId(); m_hostname = Settings::remoteDbHostName(); m_reply.progress(0); m_reply.errorString(std::string()); m_reply.currentStep(std::string()); m_reply.replyState(Core::FtReplyState::InProgress); m_fts->startBaseDownloadReply(m_baseDownloadCookie, m_reply); m_baseDownloadReplyUpdateTimer->start(); m_currentState = NotStarted; QTimer::singleShot(0, this, &HandlerBaseDownload::switchState); } void HandlerBaseDownload::onLifeUpdateRequest(const rti::core::SampleIdentity &cookie, const LiveUpdateRequest &request) { // handling PPM ExN data using namespace ParticipantManagement; m_exerciseId = request.timeStamp(); //m_hostname = QStringLiteral("EXCDBS01"); openRemoteDbConnection(QStringLiteral("lts_ets_pro")); openDbConnection(currentDatabaseName()); auto remoteDb = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!remoteDb->init(m_exerciseId, m_remoteDbConnection)) return; auto remoteDbIfc = remoteDb->db(); QVector ppmParticipants; if (remoteDbIfc->select(ppmParticipants)) { storeToDataVecMap(DbDataType::PpmParticipant, std::vector(ppmParticipants.begin(), ppmParticipants.end())); insertPpmExNDbData(true); } //Opm & OpmExercise? m_fts->lifeUpdateReply(cookie, Core::FunctionReplyObject()); } void HandlerBaseDownload::switchLog(HandlerBaseDownload::State state, const std::string ¤tStep) { NOTICE_LOG(m_logger) << "Switching state from " << m_currentState << " to " << state << " - " << currentStep; m_currentState = state; m_reply.currentStep(currentStep); if (state != Finished) { m_reply.progress(m_reply.progress() + SingleStepSize); updateBaseDownloadReply(); } else m_reply.progress(100); // updateBaseDownloadReply is called in cleanup which is executed next m_baseDownloadReplyUpdateTimer->start(); } void HandlerBaseDownload::stateFinished() { m_remoteDbRetryCounter = 0; m_currentState = static_cast(m_currentState | Finished); QTimer::singleShot(0, this, &HandlerBaseDownload::switchState); checkAliveTimer(); } void HandlerBaseDownload::switchState() { switch (m_currentState) { case NotStarted: { m_aliveTimer.start(); switchLog(DropOldDatabaseRequest, tr_lts("dds", "Removing outdated database(s)")); dropOldDatabase(); break; } case DropOldDatabaseFinished: { switchLog(CopyDatabaseRequest, tr_lts("dds", "Creating new database")); copyDatabase(); break; } case CopyDatabaseFinished: { switchLog(AsmDownloadRequest, tr_lts("dds", "Requesting asset management data.")); if (openRemoteDbConnection(QStringLiteral("lts_ets_pro"))) receiveAsmData(); else cleanup(Core::FtReplyState::Error, tr_lts("dds", "Cannot connect to remote Database!")); break; } case AsmDownloadFinished: { switchLog(ExmDownloadRequest, tr_lts("dds", "Requesting exercise management data.")); receiveExmData(); break; } case ExmDownloadFinished: { switchLog(IsmDownloadRequest, tr_lts("dds", "Requesting infrastructure management data.")); receiveIsmData(); break; } case IsmDownloadFinished: { switchLog(PpmDownloadEx0Request, tr_lts("dds", "Requesting participant management data.")); receivePpmEx0Data(); break; } case PpmDownloadEx0Finished: { switchLog(PpmDownloadExNRequest, tr_lts("dds", "Requesting participant management data.")); receivePpmExNData(); break; } case PpmDownloadExNFinished: { switchLog(OpmDownloadRequest, tr_lts("dds", "Requesting operator management data.")); receiveOpmData(); break; } case OpmDownloadFinished: { switchLog(FlmDownloadRequest, tr_lts("dds", "Requesting file management data.")); receiveFlmData(); break; } case FlmDownloadFinished: { closeDb(m_remoteDbConnection); if (!openDbConnection(nextDatabaseName())) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Could not open DB.")); return; } removeOldExercises(); break; } case DeletingOldExerciseFinished: { replaceAsmDbData(); break; } case InsertingAsmDataFinished: { replacePpmEx0DbData(); break; } case InsertingPpmEx0DataFinished: { switchLog(InsertingExmData, tr_lts("dds", "Creating new exercise.")); createNewExercise(); replaceExmDbData(); break; } case InsertingExmDataFinished: { replaceOpmDbData(); break; } case InsertingOpmDataFinished: { replaceIsmDbData(); break; } case InsertingIsmDataFinished: { insertPpmExNDbData(); break; } case InsertingPpmExNDataFinished: { replaceFlmDbData(); break; } case InsertingFlmDataFinished: { copyFromOldDatabase(); break; } case CopyDataFinished: { updateLtsConfig(); break; } case UpdatingLtsConfigFinished: { switchLog(Finished, tr_lts("dds", "Base download finished.")); cleanup(Core::FtReplyState::Completed); break; } case Finished: break; default: { ERROR_LOG(m_logger) << "State " << m_currentState << " is not handled properly."; break; } } } void HandlerBaseDownload::dropOldDatabase() { QString dbNameTmpl = nextDatabaseName(); const int idx = dbNameTmpl.lastIndexOf(QLatin1Char('_')); Q_ASSERT(idx > 0); bool bOk; const int curId = dbNameTmpl.midRef(idx + 1).toInt(&bOk); if (!openDbConnection(currentDatabaseName())) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Could not open DB.")); return; } Q_ASSERT(bOk); dbNameTmpl = dbNameTmpl.left(idx + 1); QSqlQuery q(m_dbConnection); if (!q.exec(QStringLiteral("SELECT datname FROM pg_catalog.pg_database WHERE datname LIKE '%1%'").arg(dbNameTmpl))) { stateFinished(); return; } while (q.next()) { const QString val = q.value(0).toString(); const int revId = val.midRef(idx + 1).toInt(&bOk); if (!bOk) continue; DEBUG_LOG(m_logger) << val << ", " << revId << ", " << curId; if (revId < curId - 1 || revId >= curId) m_databasesToDrop += val; } if (m_databasesToDrop.isEmpty()) { stateFinished(); return; } m_copyDatabase->dropDatabase(m_databasesToDrop.takeLast()); } void HandlerBaseDownload::onDropOldDatabaseFailed() { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Dropping old databases failed.")); } void HandlerBaseDownload::onDropOldDatabaseFinished() { if (m_databasesToDrop.isEmpty()) { stateFinished(); return; } m_copyDatabase->dropDatabase(m_databasesToDrop.takeLast()); } void HandlerBaseDownload::copyDatabase() { m_copyDatabase->init(QStringLiteral("localhost"), currentDatabaseName(), nextDatabaseName()); m_copyDatabase->doCopy(); } void HandlerBaseDownload::onCopyDbFailed() { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Copyping database failed.")); } void HandlerBaseDownload::onCopyDbFinished() { stateFinished(); } void HandlerBaseDownload::checkForAsmFinished() { DEBUG_LOG(m_logger) << "Checking if all ASM base data arrived."; if (m_dataVecMap.contains(AsmTrainingArea) && m_dataVecMap.contains(AsmLocation) && m_dataVecMap.contains(AsmAsset) && m_dataVecMap.contains(AsmTechnicalArea)) { INFO_LOG(m_logger) << "All ASM base data arrived."; stateFinished(); } checkAliveTimer(); } void HandlerBaseDownload::checkForExmFinished() { DEBUG_LOG(m_logger) << "Checking if all EXM base data arrived."; if (m_dataVecMap.contains(ExmExercise) && m_dataVecMap.contains(ExmExercisePhase) && m_dataVecMap.contains(ExmExerciseStateChange)) { INFO_LOG(m_logger) << "All EXM base data arrived."; stateFinished(); } checkAliveTimer(); } void HandlerBaseDownload::checkForIsmFinished() { DEBUG_LOG(m_logger) << "Checking if all ISM base data arrived."; if (m_dataVecMap.contains(IsmAsset) && m_dataVecMap.contains(IsmMainStructureElement) && m_dataVecMap.contains(IsmStructureElement) && m_dataVecMap.contains(IsmStructureElementFootprint) && m_dataVecMap.contains(IsmMountingPointAsset) && m_dataVecMap.contains(IsmMountingPointSchedule) && m_dataVecMap.contains(IsmMountingPointPlan)) { INFO_LOG(m_logger) << "All ISM base data arrived."; stateFinished(); } checkAliveTimer(); } void HandlerBaseDownload::checkForPpmEx0Finished() { DEBUG_LOG(m_logger) << "Checking if all PPM Ex0 base data arrived."; if (m_dataVecMap.contains(PpmEquipmentType) && m_dataVecMap.contains(PpmType)) { INFO_LOG(m_logger) << "All PPM Ex0 base data arrived."; stateFinished(); } } void HandlerBaseDownload::checkForPpmExNFinished() { DEBUG_LOG(m_logger) << "Checking if all PPM ExN base data arrived."; if (m_dataVecMap.contains(PpmParty) && m_dataVecMap.contains(PpmParticipant)) { INFO_LOG(m_logger) << "All PPM ExN base data arrived."; stateFinished(); } checkAliveTimer(); } void HandlerBaseDownload::checkForOpmFinished() { DEBUG_LOG(m_logger) << "Checking if all OPM base data arrived."; if (m_dataVecMap.contains(OpmGroup) && m_dataVecMap.contains(OpmGroupGroup) && m_dataVecMap.contains(OpmOperator) && m_dataVecMap.contains(OpmOperatorExercise) && m_dataVecMap.contains(OpmSettings) && m_dataVecMap.contains(OpmAccessControlLevel) && m_dataVecMap.contains(OpmAclAllow) && m_dataVecMap.contains(OpmAclDeny)) { INFO_LOG(m_logger) << "All OPM base data arrived."; stateFinished(); } checkAliveTimer(); } void HandlerBaseDownload::checkForFlmFinished() { DEBUG_LOG(m_logger) << "Checking if all FLM base data arrived."; if (m_dataVecMap.contains(FlmFolder) && m_dataVecMap.contains(FlmFileContent)) { INFO_LOG(m_logger) << "All FLM base data arrived."; stateFinished(); } checkAliveTimer(); } void HandlerBaseDownload::removeOldExercises() { switchLog(DeletingOldExercise, tr_lts("dds", "Deleting previous exercise data if existing.")); auto exmDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!exmDbHandler->init(0, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise exmDbHandler")); return; } QVector exercises; exmDbHandler->db()->select(exercises); for (const auto &ex : qAsConst(exercises)) { if (m_exTblGen->dropExerciseSchema(ex.id, false)) continue; cleanup(Core::FtReplyState::Error, tr_lts("dds", "Can not remove old exercise data")); return; } stateFinished(); } void HandlerBaseDownload::replaceAsmDbData() { switchLog(InsertingAsmData, tr_lts("dds", "Inserting new asset management data.")); auto asmDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!asmDbHandler->init(0, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise asmDbHandler")); return; } DBTransaction trans(m_dbConnection); // clear old data asmDbHandler->db()->truncateAsmTrainingArea(); asmDbHandler->db()->truncateAsmTechnicalArea(); asmDbHandler->db()->truncateAsmLocation(); asmDbHandler->db()->truncateAsmAsset(); checkAliveTimer(); // insert new data auto trainingAreaData = getDbDataVec(AsmTrainingArea); asmDbHandler->db()->upsert(trainingAreaData); auto technicalAreaData = getDbDataVec(AsmTechnicalArea); asmDbHandler->db()->upsert(technicalAreaData); auto locationData = getDbDataVec(AsmLocation); asmDbHandler->db()->upsert(locationData); auto assetData = getDbDataVec(AsmAsset); asmDbHandler->db()->upsert(assetData); if (!trans.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Error while inserting ASM data into database.")); return; } stateFinished(); } void HandlerBaseDownload::createNewExercise() { if (!m_exTblGen->createExerciseSchema(m_exerciseId) || !m_exTblGen->executeSql(m_exerciseId)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Can not create exercise schema")); return; } } void HandlerBaseDownload::replaceExmDbData() { auto exmDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!exmDbHandler->init(0, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise exmDbHandler")); return; } DBTransaction trans(m_dbConnection); // clear old data exmDbHandler->db()->truncateExmExercisePhase(); exmDbHandler->db()->truncateExmExerciseStateChange(); checkAliveTimer(); // insert new data for (auto exercise : getDbDataVec(ExmExercise)) { if (exercise.id == m_exerciseId) exmDbHandler->db()->upsert(exercise); } for (auto exPhase : getDbDataVec(ExmExercisePhase)) { if (exPhase.exerciseId == m_exerciseId) exmDbHandler->db()->upsert(exPhase); } for (auto exStateChange : getDbDataVec(ExmExerciseStateChange)) { if (exStateChange.exerciseId == m_exerciseId) exmDbHandler->db()->upsert(exStateChange); } if (!trans.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Error while inserting EXM data into database.")); return; } stateFinished(); } void HandlerBaseDownload::replaceIsmDbData() { switchLog(InsertingIsmData, tr_lts("dds", "Inserting new infrastructure management data.")); auto ismDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!ismDbHandler->init(0, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise ismDbHandler")); return; } DBTransaction trans(m_dbConnection); // clear old data ismDbHandler->db()->truncateIsmAsset(); ismDbHandler->db()->truncateIsmMainStructureElement(); ismDbHandler->db()->truncateIsmStructureElement(); ismDbHandler->db()->truncateIsmStructureElementFootprint(); ismDbHandler->db()->truncateIsmMountingPointAsset(); ismDbHandler->db()->truncateIsmMountingPointSchedule(); ismDbHandler->db()->truncateIsmMountingPointPlan(); checkAliveTimer(); // insert new data auto assetData = getDbDataVec(IsmAsset); ismDbHandler->db()->upsert(assetData); auto mainStructureElement = getDbDataVec(IsmMainStructureElement); ismDbHandler->db()->upsert(mainStructureElement); auto structureElementData = getDbDataVec(IsmStructureElement); ismDbHandler->db()->upsert(structureElementData); auto structureElementFootprintData = getDbDataVec(IsmStructureElementFootprint); ismDbHandler->db()->upsert(structureElementFootprintData); auto mountingPointAssetData = getDbDataVec(IsmMountingPointAsset); ismDbHandler->db()->upsert(mountingPointAssetData); auto specialAreaData = getDbDataVec(IsmSpecialArea); ismDbHandler->db()->upsert(specialAreaData); QSet insertedSchedules; for (auto schedule : getDbDataVec(IsmMountingPointSchedule)) { if (!schedule.exerciseId.isNull() && schedule.exerciseId.canConvert()) { if (schedule.exerciseId.toInt() == m_exerciseId) { ismDbHandler->db()->insert(schedule); insertedSchedules.insert(schedule.id); } } } for (auto plan : getDbDataVec(IsmMountingPointPlan)) { if (insertedSchedules.contains(plan.mountingPointScheduleId)) ismDbHandler->db()->upsert(plan); } if (!trans.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Error while inserting ISM data into database.")); return; } stateFinished(); } static inline void removePoolParty(std::vector &partyData) { partyData.erase(std::remove_if(partyData.begin(), partyData.end(), [](const ParticipantManagement::Database::PpmParty & p) { return p.id == 0;}), partyData.end()); } void HandlerBaseDownload::replacePpmEx0DbData() { switchLog(InsertingPpmEx0Data, tr_lts("dds", "Inserting new participant management base data.")); auto ppmDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!ppmDbHandler->init(0, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise ppmDbHandler")); return; } DBTransaction trans(m_dbConnection); // clear old data ppmDbHandler->db()->truncatePpmEquipmentType(); ppmDbHandler->db()->truncatePpmType(); ppmDbHandler->db()->truncatePpmParty(); checkAliveTimer(); // insert new data auto equipmentTypeData = getDbDataVec(PpmEquipmentType); ppmDbHandler->db()->upsert(equipmentTypeData); if (!trans.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "!!!!!Error while inserting PPM data for exercise 0 into database.")); return; } DBTransaction trans2(m_dbConnection); auto typeData = getDbDataVec(PpmType); // adding special type for flat structure (units) ParticipantManagement::Database::PpmType newType; // for all newType.equipmentTypeId = QVariant(); // for the support party newType.id = Settings::unitOffset(); newType.typeClassId = ParticipantManagement::TypeClass::SupportUnit; newType.name = QStringLiteral("Type for flat unit structure: support"); typeData.push_back(newType); //for the "rest" newType.id = Settings::unitOffset() + 1; newType.typeClassId = ParticipantManagement::TypeClass::Unit; newType.name = QStringLiteral("Type for flat unit structure"); newType.symbol = QStringLiteral("M25D|CMPL|10011000131211000000"); newType.disEntities = LtsUtils::BigintArray::fromPgString(QStringLiteral("{4055234000000043055}")); // got from test-db typeData.push_back(newType); ppmDbHandler->db()->upsert(typeData); if (!trans2.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "22222Error while inserting PPM data for exercise 0 into database.")); return; } DBTransaction trans3(m_dbConnection); auto partyData = getDbDataVec(PpmParty); removePoolParty(partyData); ppmDbHandler->db()->upsert(partyData); if (!trans3.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "333Error while inserting PPM data for exercise 0 into database.")); return; } stateFinished(); } void HandlerBaseDownload::insertPpmExNDbData(bool live) { if (!live) switchLog(InsertingPpmExNData, tr_lts("dds", "Inserting new participants.")); auto ppmDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!ppmDbHandler->init(m_exerciseId, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise ppmDbHandler")); return; } DBTransaction trans(m_dbConnection); std::vector participantData; QMap partyToUnit; QHash m_type2TypeClass; if (!live) { for (const auto &type : getDbDataVec(PpmType)) m_type2TypeClass[type.id] = type.typeClassId; } //we need to create parties now // creating dummy unit for each party for a flat structure ParticipantManagement::Database::PpmParticipant newEntry; // adding Participants from dataVec std::vector newParticipants; // unit default data newEntry.hierarchyNumber = 1; if (!live) { auto partyData = getDbDataVec(PpmParty); removePoolParty(partyData); ppmDbHandler->db()->upsert(partyData); #ifdef GUEZ_MODE for (const auto &party : partyData) { if (party.id != 1) { // normal parties newEntry.typeId = Settings::unitOffset() + 1; // typeId is created during InsertingPpmEx0Data newEntry.symbol = QStringLiteral("M25D|CMPL|10031000131211000000"); } else { // special for support newEntry.typeId = Settings::unitOffset(); // typeId is created during InsertingPpmEx0Data newEntry.symbol = QStringLiteral("M25D|CMPL|10214000001315060000"); } newEntry.id = Settings::unitOffset() + party.id; newEntry.partyId = party.id; newEntry.name = QStringLiteral("Root unit for party: %1").arg(ParticipantManagement::trPartyName(party.name.toStdString())); participantData.push_back(newEntry); partyToUnit.insert(party.id, newEntry.id); TRACE_LOG(m_logger) << "Adding: " << newEntry.name << " to participantData."; } // insert pseudo-units ppmDbHandler->db()->upsert(participantData); #endif } DEBUG_LOG(m_logger) << "Now add participants: " << getDbDataVec(PpmParticipant).size(); for (const auto &participant : getDbDataVec(PpmParticipant)) { if (participant.partyId == 0) continue; // no participants of party: pool const auto typeClass = m_type2TypeClass.value(participant.typeId); auto newParticipant = participant; #ifdef GUEZ_MODE if (typeClass == ParticipantManagement::TypeClass::Unit || typeClass == ParticipantManagement::TypeClass::SupportUnit) continue; newParticipant.superiorId = partyToUnit.value(participant.partyId); newParticipant.hierarchyNumber = participant.id; #endif DEBUG_LOG(m_logger) << "XXXXXXXX Adding Participant: " << newParticipant.id << " typeId: " << newParticipant.typeId << " typeClass: " << typeClass << " supperioer " << newParticipant.superiorId; newParticipants.push_back(std::move(newParticipant)); } // insert modified participants ppmDbHandler->db()->upsert(newParticipants); if (!trans.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Error while inserting new participants into database.")); return; } if (!live) stateFinished(); } void HandlerBaseDownload::replaceOpmDbData() { switchLog(InsertingOpmData, tr_lts("dds", "Inserting new operator management data.")); auto opmDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!opmDbHandler->init(0, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise opmDbHandler")); return; } DBTransaction trans(m_dbConnection); // clear old data opmDbHandler->db()->truncateOpmGroup(); opmDbHandler->db()->truncateOpmGroupGroup(); opmDbHandler->db()->truncateOpmOperator(); opmDbHandler->db()->truncateOpmOperatorExercise(); opmDbHandler->db()->truncateOpmSettings(); opmDbHandler->db()->truncateOpmAccessControlLevel(); opmDbHandler->db()->truncateOpmAclAllow(); opmDbHandler->db()->truncateOpmAclDeny(); checkAliveTimer(); // insert new data auto groupData = getDbDataVec(OpmGroup); opmDbHandler->db()->upsert(groupData); auto groupGroupData = getDbDataVec(OpmGroupGroup); opmDbHandler->db()->upsert(groupGroupData); auto operatorData = getDbDataVec(OpmOperator); opmDbHandler->db()->upsert(operatorData); checkAliveTimer(); // insert only OpmOperatorExercise with valid foreign key for (auto opEx : getDbDataVec(OpmOperatorExercise)) { if (opEx.exerciseId == m_exerciseId) opmDbHandler->db()->upsert(opEx); } auto settingsData = getDbDataVec(OpmSettings); opmDbHandler->db()->upsert(settingsData); auto accessControlLevelData = getDbDataVec(OpmAccessControlLevel); opmDbHandler->db()->upsert(accessControlLevelData); auto aclAllowData = getDbDataVec(OpmAclAllow); opmDbHandler->db()->upsert(aclAllowData); auto aclDenyData = getDbDataVec(OpmAclDeny); opmDbHandler->db()->upsert(aclDenyData); if (!trans.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Error while inserting OPM data into database.")); return; } stateFinished(); } void HandlerBaseDownload::replaceFlmDbData() { switchLog(InsertingFlmData, tr_lts("dds", "Inserting new file management data.")); auto flmDbHandler = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!flmDbHandler->init(0, m_dbConnection)) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Couldn't initialise flmDbHandler")); return; } m_aliveTimer.start(); DBTransaction trans(m_dbConnection); // clear old data flmDbHandler->db()->truncateFlmFolder(); flmDbHandler->db()->truncateFlmFileContent(); checkAliveTimer(); // insert new data auto folderData = getDbDataVec(FlmFolder); flmDbHandler->db()->upsert(folderData); checkAliveTimer(); auto fileContentData = getDbDataVec(FlmFileContent); flmDbHandler->db()->upsert(fileContentData); if (!trans.commit()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Error while inserting FLM data into database.")); return; } stateFinished(); } template inline void resetVector(QPair> &dbVector) { dbVector.first = false; dbVector.second.clear(); } void HandlerBaseDownload::cleanup(const Core::FtReplyState &replyState, const std::string &errStr) { if (errStr.size() > 0) ERROR_LOG(m_logger) << "Base Download ended with error: " << errStr; // cleanup db data qDeleteAll(m_dataVecMap); m_dataVecMap.clear(); // close db m_exTblGen->close(); closeDb(m_dbConnection); closeDb(m_remoteDbConnection); // prepare reply m_reply.errorString(errStr); m_reply.replyState(replyState); m_baseDownloadReplyUpdateTimer->stop(); m_fts->startBaseDownloadReply(m_baseDownloadCookie, m_reply); m_currentState = NotStarted; m_exerciseId = 0; m_reply.progress(0); m_reply.errorString(std::string()); m_reply.currentStep(std::string()); m_hostname = NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET); } void HandlerBaseDownload::retryCurrentSelect() { m_remoteDbRetryCounter++; switchState(); } void HandlerBaseDownload::copyFromOldDatabase() { switchLog(CopyDataRequest, tr_lts("dds", "Copying data from old to new database")); bool bOk = false; QSqlDatabase dbIn = openDb(currentDatabaseName(), false, &bOk); if (!bOk) { // not nice but should not kill base download stateFinished(); return; } // global schemas, one transaction for all { DBTransaction trans(m_dbConnection); copyOldOpmData(dbIn, m_dbConnection); checkAliveTimer(); copyOldFlmData(dbIn, m_dbConnection); checkAliveTimer(); copyOldMsgData(dbIn, m_dbConnection); checkAliveTimer(); trans.commit(); } // exercise data, only if old ex_NN schema exists const QString schemaName = QLatin1String("ex_") + QString::number(m_exerciseId); if (m_exTblGen->existsSchema(schemaName, dbIn)) { DEBUG_LOG(m_logger) << "### Copying old files from schema " << schemaName; { // own transaction when old ex_N schema does not exist. DBTransaction trans(m_dbConnection); copyOldMrkData(dbIn, m_dbConnection); checkAliveTimer(); trans.commit(); } { // own transaction when old ex_N schema does not exist. DBTransaction trans(m_dbConnection); copyOldEvlData(dbIn, m_dbConnection); checkAliveTimer(); trans.commit(); } { // own old orders when old ex_N schema does not exist. DBTransaction trans(m_dbConnection); copyOldEscData(dbIn, m_dbConnection); checkAliveTimer(); trans.commit(); } { // own transaction when old ex_N schema does not exist. DBTransaction trans(m_dbConnection); copyOldFltData(dbIn, m_dbConnection); checkAliveTimer(); trans.commit(); } { // Copy recording tables and some aes tables without DBInterface, own transaction // alphabetically sorted QStringList tableList; // tableList << schemaName + QLatin1String(".aes_entity"); // this table has no DBInterface // tableList << schemaName + QLatin1String(".aes_mine"); // this table has no DBInterface // tableList << schemaName + QLatin1String(".aes_explosion"); // this table has no DBInterface tableList << schemaName + QLatin1String(".rec_aes_filter"); tableList << schemaName + QLatin1String(".rec_aes_item_view"); tableList << schemaName + QLatin1String(".rec_b_c_contamination"); tableList << schemaName + QLatin1String(".rec_borderline"); tableList << schemaName + QLatin1String(".rec_charge_administration"); tableList << schemaName + QLatin1String(".rec_danger_area"); tableList << schemaName + QLatin1String(".rec_dus_mine_state"); tableList << schemaName + QLatin1String(".rec_dus_single_mine"); tableList << schemaName + QLatin1String(".rec_dus_single_mine_state"); tableList << schemaName + QLatin1String(".rec_dynamic_participant_data"); tableList << schemaName + QLatin1String(".rec_equipment_position"); // equipment_number negative ? tableList << schemaName + QLatin1String(".rec_explosion_area"); tableList << schemaName + QLatin1String(".rec_explosion_single"); tableList << schemaName + QLatin1String(".rec_mine_area"); tableList << schemaName + QLatin1String(".rec_mine_corridor"); tableList << schemaName + QLatin1String(".rec_mine_triggered"); tableList << schemaName + QLatin1String(".rec_n_contamination"); tableList << schemaName + QLatin1String(".rec_participant"); tableList << schemaName + QLatin1String(".rec_participant_position"); tableList << schemaName + QLatin1String(".rec_party"); tableList << schemaName + QLatin1String(".rec_snapshot"); // not sure we need this, we have data in ex_NN.mrk_snapshot tableList << schemaName + QLatin1String(".rec_symbol_appearance"); tableList << schemaName + QLatin1String(".rec_triggered_impacts"); //tableList << schemaName + QLatin1String(".rec_bridge_status"); //TODO: add more tables if needed, check data in these tables, z.B. in rec_equipment_position.equipment_number is always negative (?!) DBTransaction trans(m_dbConnection); for (const QString &table : qAsConst(tableList)) { if (!copyTable(dbIn, m_dbConnection, table)) ERROR_LOG(m_logger) << "Failed to copy table " << table; checkAliveTimer(); } trans.commit(); } { // own transaction when old ex_N schema does not exist. DBTransaction trans(m_dbConnection); copyOldAesData(dbIn, m_dbConnection); checkAliveTimer(); trans.commit(); } } closeDb(dbIn); stateFinished(); } void HandlerBaseDownload::copyOldOpmData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { using namespace OperatorManagement; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(0, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(0, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); QVector opmSettings; dbIfcOld->select(opmSettings); dbIfcNew->truncateOpmSettings(); for (Database::OpmSettings &s : opmSettings) { s.id = 0; dbIfcNew->insert(s); } dbIfcNew->fixUpSequenceOpmSettings(); } void HandlerBaseDownload::copyOldEvlData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { using namespace Evaluations; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(m_exerciseId, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(m_exerciseId, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); QVector evlComment; QVector evlCriterium; QVector evlElement; QVector evlSchema; dbIfcOld->select(evlComment); dbIfcOld->select(evlCriterium); dbIfcOld->select(evlElement); dbIfcOld->select(evlSchema); dbIfcNew->truncateEvlComment(); dbIfcNew->truncateEvlCriterium(); dbIfcNew->truncateEvlElement(); dbIfcNew->truncateEvlSchema(); // schema and criterium first for (Database::EvlSchema &s : evlSchema) dbIfcNew->insert(s); for (Database::EvlCriterium &s : evlCriterium) dbIfcNew->insert(s); for (Database::EvlElement &s : evlElement) dbIfcNew->insert(s); for (Database::EvlComment &s : evlComment) dbIfcNew->insert(s); dbIfcNew->fixUpSequenceEvlComment(); dbIfcNew->fixUpSequenceEvlCriterium(); dbIfcNew->fixUpSequenceEvlElement(); dbIfcNew->fixUpSequenceEvlSchema(); } void HandlerBaseDownload::copyOldMsgData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { using namespace Messaging; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(0, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(0, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); QVector msgData; dbIfcOld->select(msgData); dbIfcNew->truncateMsgMessageData(); for (Database::MsgMessageData &m : msgData) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceMsgMessageData(); } void HandlerBaseDownload::copyOldFlmData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { using namespace FileManagement; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(0, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(0, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); QVector flmData; dbIfcOld->select(flmData); //dbIfcNew->truncateFlmFileContent(); std::vector flmDataToCopy; QVector flmFolderData; dbIfcNew->select(flmFolderData); qint64 folderId = -1; for (const auto &folder : qAsConst(flmFolderData)) { if (folder.name == QStringLiteral("Snapshots")) { folderId = folder.id; Database::FlmFolder parentFolder; dbIfcNew->selectFlmFolder(folder.parentId, parentFolder); if (parentFolder.name == QLatin1String("$EX_") + QString::number(m_exerciseId)) break; } } // There is a folder "Snapshots" for each exercise, getting the "right" one is done using flm dtc custom function getFolderId(folderName, exerciseId) // or this database select parentId when flm dtc is not available if (folderId > 0) // found Snapshots folder for the exercise id { for (auto data : qAsConst(flmData)) { if (data.folderId == folderId || //snapshots (data.fileTypeId.underlying() == FileManagement::FileType::Pdf)) //old PDF { data.id = 0; flmDataToCopy.push_back(data); } } } dbIfcNew->insert(flmDataToCopy); dbIfcNew->fixUpSequenceFlmFileContent(); } void HandlerBaseDownload::copyOldMrkData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { using namespace MarkerManagement; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(m_exerciseId, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(m_exerciseId, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); // no longer save snapshot , copy flm instead ? QVector snaData; dbIfcOld->select(snaData); dbIfcNew->truncateMrkSnapshot(); for (Database::MrkSnapshot &m : snaData) dbIfcNew->insert(m); QVector mrkData; dbIfcOld->select(mrkData); dbIfcNew->truncateMrkMarker(); for (Database::MrkMarker &m : mrkData) dbIfcNew->insert(m); QVector mrkDatad; dbIfcOld->select(mrkDatad); dbIfcNew->truncateMrkMarkerDescription(); for (Database::MrkMarkerDescription &m : mrkDatad) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceMrkMarker(); dbIfcNew->fixUpSequenceMrkMarkerDescription(); dbIfcNew->fixUpSequenceMrkSnapshot(); } void HandlerBaseDownload::copyOldEscData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { using namespace EffectShowClient; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(m_exerciseId, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(m_exerciseId, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); QVector orderData; dbIfcOld->select(orderData); dbIfcNew->truncateEscOrder(); for (Database::EscOrder &m : orderData) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceEscOrder(); } void HandlerBaseDownload::copyOldFltData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { using namespace FilterManagement; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(m_exerciseId, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(m_exerciseId, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); QVector fltData; dbIfcOld->select(fltData); dbIfcNew->truncateAesFilter(); for (Database::AesFilter &m : fltData) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesFilter(); QVector symData; dbIfcOld->select(symData); dbIfcNew->truncateSymbolAppearance(); for (Database::SymbolAppearance &m : symData) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceSymbolAppearance(); } void HandlerBaseDownload::copyOldAesData(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut) const { //WE NEED FURTHER TESTING!!!!! return; using namespace AreaEffectSimulation; auto dbOld = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbOld->init(m_exerciseId, dbIn)) return; auto dbNew = std::unique_ptr>(new NGLDB::DbServiceHandler()); if (!dbNew->init(m_exerciseId, dbOut)) return; auto dbIfcOld = dbOld->db(); auto dbIfcNew = dbNew->db(); QVector asi; dbIfcOld->select(asi); dbIfcNew->truncateAesAirSupportImpact(); for (Database::AesAirSupportImpact &m : asi) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesAirSupportImpact(); QVector bc; dbIfcOld->select(bc); dbIfcNew->truncateAesBCContamination(); for (Database::AesBCContamination &m : bc) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesBCContamination(); QVector b; dbIfcOld->select(b); dbIfcNew->truncateAesBorderline(); for (Database::AesBorderline &m : b) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesBorderline(); QVector bs; dbIfcOld->select(bs); dbIfcNew->truncateAesBorderlineSegment(); for (Database::AesBorderlineSegment &m : bs) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesBorderlineSegment(); QVector dsm; dbIfcOld->select(dsm); dbIfcNew->truncateAesDusSingleMine(); for (Database::AesDusSingleMine &m : dsm) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesDusSingleMine(); QVector da; dbIfcOld->select(da); dbIfcNew->truncateAesDangerArea(); for (Database::AesDangerArea &m : da) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesDangerArea(); QVector ds; dbIfcOld->select(ds); dbIfcNew->truncateAesDangerSegment(); for (Database::AesDangerSegment &m : ds) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesDangerSegment(); QVector ma; dbIfcOld->select(ma); dbIfcNew->truncateAesMineArea(); for (Database::AesMineArea &m : ma) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesMineArea(); QVector mas; dbIfcOld->select(mas); dbIfcNew->truncateAesMineAreaSegment(); for (Database::AesMineAreaSegment &m : mas) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesMineAreaSegment(); QVector matm; dbIfcOld->select(matm); dbIfcNew->truncateAesMineAreaTriggeredMines(); for (Database::AesMineAreaTriggeredMines &m : matm) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesMineAreaTriggeredMines(); QVector mc; dbIfcOld->select(mc); dbIfcNew->truncateAesMineCorridor(); for (Database::AesMineCorridor &m : mc) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesMineCorridor(); QVector mcs; dbIfcOld->select(mcs); dbIfcNew->truncateAesMineCorridorSegment(); for (Database::AesMineCorridorSegment &m : mcs) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesMineCorridorSegment(); QVector gp; dbIfcOld->select(gp); dbIfcNew->truncateAesGasPipe(); for (Database::AesGasPipe &m : gp) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesGasPipe(); QVector gps; dbIfcOld->select(gps); dbIfcNew->truncateAesGasPipeSegment(); for (Database::AesGasPipeSegment &m : gps) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesGasPipeSegment(); QVector n; dbIfcOld->select(n); dbIfcNew->truncateAesNContamination(); for (Database::AesNContamination &m : n) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesNContamination(); QVector ea; dbIfcOld->select(ea); dbIfcNew->truncateAesExplosionArea(); for (Database::AesExplosionArea &m : ea) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesExplosionArea(); QVector es; dbIfcOld->select(es); dbIfcNew->truncateAesExplosionSingle(); for (Database::AesExplosionSingle &m : es) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesExplosionSingle(); QVector ca; dbIfcOld->select(ca); dbIfcNew->truncateAesChargeAdministration(); for (Database::AesChargeAdministration &m : ca) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesChargeAdministration(); QVector fa; dbIfcOld->select(fa); dbIfcNew->truncateAesFunctionalArea(); for (Database::AesFunctionalArea &m : fa) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesFunctionalArea(); QVector ra; dbIfcOld->select(ra); dbIfcNew->truncateAesReconArea(); for (Database::AesReconArea &m : ra) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesReconArea(); QVector ta; dbIfcOld->select(ta); dbIfcNew->truncateAesTechnicalArea(); for (Database::AesTechnicalArea &m : ta) dbIfcNew->insert(m); dbIfcNew->fixUpSequenceAesTechnicalArea(); } void HandlerBaseDownload::updateLtsConfig() { switchLog(UpdatingLtsConfig, tr_lts("dds", "Updating local configuration file and restarting services")); const QString conf = NGL::findProjectConfigFile(); if (conf.isEmpty()) { cleanup(Core::FtReplyState::Error, tr_lts("dds", "Error while updating local configuration file.")); return; } { QSettings s(conf, QSettings::IniFormat); s.setValue(QStringLiteral("Global") + QStringLiteral("/DatabaseName"), nextDatabaseName()); } m_stopGroupIds.clear(); ServiceManagement::GroupRequest request; const QMap groups = m_scmDtc->groupInformations(); for (const auto &group : groups) { if (group.type() == Core::ServiceGroupType::Master || group.type() == Core::ServiceGroupType::Core) continue; request.type(group.type()); request.domainId(group.domainId()); request.exercisePartitionId(group.exercisePartitionId()); request.replayPartitionId(group.replayPartitionId()); request.requestId(group.id()); m_stopGroupIds += group.id(); m_scmFtc->stopGroupRequest(request, this); } if (m_stopGroupIds.isEmpty()) restartCoreGroup(); else QTimer::singleShot(30 * 1000, this, &HandlerBaseDownload::restartCoreGroup); // don't wait longer than 30s for the stop replies } void HandlerBaseDownload::onStopGroupReply(const Core::FunctionReplyObject &reply) { if (reply.error()) { cleanup(Core::FtReplyState::Error, reply.str()); return; } if (!m_stopGroupIds.remove(reply.id())) WARNING_LOG(m_logger) << "Got unknown reply id for stop group request: " << reply.id(); if (!m_stopGroupIds.isEmpty()) return; restartCoreGroup(); } void HandlerBaseDownload::restartCoreGroup() { // now restart CORE (which restarts EXM and therefore also starts the exercise specific services) ServiceManagement::GroupRequest request; const QMap groups = m_scmDtc->groupInformations(); for (const auto &group : groups) { if (group.type() != Core::ServiceGroupType::Core) continue; request.type(group.type()); request.domainId(group.domainId()); request.exercisePartitionId(group.exercisePartitionId()); request.replayPartitionId(group.replayPartitionId()); request.requestId(group.id()); break; // only one core } // we are also restarted... so answer here directly with 'finished' stateFinished(); if (request.type() != Core::ServiceGroupType::Core) WARNING_LOG(m_logger) << "Could not find core group to restart..."; const auto restartCb = [this, request]() { m_scmFtc->restartGroupRequest(request, this); }; QTimer::singleShot(5000, this, restartCb); } void HandlerBaseDownload::onRestartGroupReply(const Core::FunctionReplyObject &reply) { if (reply.error()) { cleanup(Core::FtReplyState::Error, reply.str()); return; } // we won't get here since we're restarted too ERROR_LOG(m_logger) << "onRestartGroupReply?"; stateFinished(); } QString HandlerBaseDownload::currentDatabaseName() const { auto s = Settings::settings(); return s->databaseName(); } QString HandlerBaseDownload::nextDatabaseName() const { const QString dbName = currentDatabaseName(); int idx = dbName.lastIndexOf(QLatin1Char('_')); bool bOk; int id = dbName.midRef(idx + 1).toInt(&bOk) + 1; return bOk ? QString(dbName.left(idx + 1) + QString::number(id)) : QString(dbName + QLatin1Char('_') + QString::number(id)); } void HandlerBaseDownload::checkAliveTimer() { if (m_aliveTimer.elapsed() > 2000) // longer than 2 sec -> send heartbeat { m_mainHandler->dds()->pacemaker()->publishState(); updateBaseDownloadReply(); m_aliveTimer.start(); } } bool HandlerBaseDownload::copyTable(const QSqlDatabase &dbIn, const QSqlDatabase &dbOut, QString tableName) { NSqlQuery qIn(dbIn); NSqlQuery qOut(dbOut); DEBUG_LOG(m_logger) << "Copying " << tableName << " started"; const QSqlRecord record = dbIn.record(tableName); if (record.isEmpty()) { ERROR_LOG(m_logger) << "Empty record for " << tableName; return false; } QStringList selectTableColumns; QStringList insertTablePlaceholder; selectTableColumns.reserve(record.count()); insertTablePlaceholder.reserve(record.count()); for (int i = 0; i < record.count(); ++i) { const QSqlField &f = record.field(i); selectTableColumns += f.name(); insertTablePlaceholder += QLatin1Char(':') + f.name(); } const QString selectTableCommand(QStringLiteral("SELECT %1 FROM %2") .arg(selectTableColumns.join(QStringLiteral(", ")), tableName)); const QString insertTableCommand(QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") .arg(tableName, selectTableColumns.join(QStringLiteral(", ")), insertTablePlaceholder.join(QStringLiteral(", ")))); DEBUG_LOG(m_logger) << selectTableCommand; DEBUG_LOG(m_logger) << insertTableCommand; if (!qOut.prepare(insertTableCommand)) { ERROR_LOG(m_logger) << "qOut prepare failed... " << qOut.lastError().text(); return false; } if (!qIn.exec(selectTableCommand)) { ERROR_LOG(m_logger) << "qIn select failed... " << qIn.lastError().text(); DEBUG_LOG(m_logger) << "FAILED statement: " << selectTableCommand; qIn.finish(); return false; } while (qIn.next()) { for (int i = 0; i < insertTablePlaceholder.size(); ++i) qOut.bindValue(insertTablePlaceholder.at(i), qIn.value(i)); if (!qOut.exec()) { ERROR_LOG(m_logger) << "qOut insert failed.. " << qOut.lastError().text(); DEBUG_LOG(m_logger) << "FAILED statement: " << insertTableCommand; qOut.finish(); return false; } checkAliveTimer(); } DEBUG_LOG(m_logger) << "Copying " << tableName << " finished"; if (!fixUpSequence(dbOut, tableName)) WARNING_LOG(m_logger) << "Failed to update sequence for table " << tableName; return true; } bool HandlerBaseDownload::fixUpSequence(const QSqlDatabase &dbOut, const QString &tableName) { NSqlQuery qOut(dbOut); QString seqName, keyField; if (tableName.contains(QStringLiteral(".rec_")) && !tableName.contains(QStringLiteral(".rec_snapshot"))) { seqName = tableName + QStringLiteral("_rec_id_seq"); keyField = QStringLiteral("rec_id"); } else { seqName = tableName + QStringLiteral("_id_seq"); keyField = QStringLiteral("id"); } DEBUG_LOG(m_logger) << "Updating sequence " << seqName << " for table " << tableName; const QString stmt(QStringLiteral("SELECT setval('%1', COALESCE((SELECT MAX(%2)+1 FROM %3), 1), false)").arg(seqName, keyField, tableName)); if (!qOut.exec(stmt)) { ERROR_LOG(m_logger) << "FAILED to update sequence for table " << tableName << " : " << qOut.lastError().text(); DEBUG_LOG(m_logger) << "FAILED statement: " << stmt; qOut.finish(); return false; } return true; } } // namespace OcBaseDownload