Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+413
@@ -0,0 +1,413 @@
|
||||
/**
|
||||
* Handler for one indirect fire single object
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "object_exercise.h"
|
||||
|
||||
#include "convert_db_to_dds.h"
|
||||
#include "dds_handler.h"
|
||||
#include "exercise_state_machine.h"
|
||||
#include "object_exercise_phase.h"
|
||||
#include "handler_exercise.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <DBAdministration/copy_exercise.h>
|
||||
#include <DBAdministration/exercise_table_generator.h>
|
||||
#include <Common/ProjectConfig/project_defines.h>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
|
||||
ObjectExercise::ObjectExercise(const std::shared_ptr<DdsHandler> &ddsHandler,
|
||||
const std::shared_ptr<DatabaseInterface> &db,
|
||||
const std::shared_ptr<DBAdministration::ExerciseTableGenerator> &exTblGen,
|
||||
HandlerExercise *exHandler)
|
||||
: QObject(exHandler)
|
||||
, m_ddsHandler(ddsHandler)
|
||||
, m_db(db)
|
||||
, m_exTblGen(exTblGen)
|
||||
, m_exerciseHandler(exHandler)
|
||||
, m_copyExercise(nullptr)
|
||||
, m_logger(getLogger("ObjectExercise"))
|
||||
{
|
||||
m_stateMachine = new ExerciseStateMachine(this);
|
||||
}
|
||||
|
||||
ObjectExercise::~ObjectExercise()
|
||||
{
|
||||
delete m_copyExercise;
|
||||
delete m_stateMachine;
|
||||
}
|
||||
|
||||
bool ObjectExercise::isValid() const
|
||||
{
|
||||
return m_data.id > 0;
|
||||
}
|
||||
|
||||
bool ObjectExercise::isStopped() const
|
||||
{
|
||||
return ( isValid() && m_data.exerciseStateId == ExerciseManagement::ExerciseState::Stopped);
|
||||
}
|
||||
|
||||
bool ObjectExercise::isRunning() const
|
||||
{
|
||||
return (m_data.exerciseStateId == ExerciseManagement::ExerciseState::Started);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectExercise::createObject(const Database::ExmExercise &data, bool forceInsert)
|
||||
{
|
||||
m_data = data;
|
||||
fixupTimeZone();
|
||||
|
||||
if (m_data.id <= 0 || forceInsert)
|
||||
{
|
||||
m_data.exerciseStateId = ExerciseManagement::ExerciseState::Created;
|
||||
m_data.created = QDateTime::currentDateTimeUtc();
|
||||
|
||||
if (!m_db->insert(m_data))
|
||||
{
|
||||
QString errText = m_db->getLastError().databaseText();
|
||||
ERROR_LOG(m_logger) << "Error inserting exercise into database: " << errText;
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Error inserting ExmExercise-data into database: %1")).arg(errText);
|
||||
}
|
||||
|
||||
// Id is serial -> will be generated by db => inside m_data after db-insert
|
||||
DEBUG_LOG(m_logger) << "New exerciseId: " << m_data.id;
|
||||
|
||||
// Create exercise-schema
|
||||
if (!m_exTblGen->createExerciseSchema(m_data.id))
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Error creating database schema for exercise with id %1")).arg(m_data.id);
|
||||
|
||||
// Create tables/views/indexes for each service
|
||||
if (!m_exTblGen->executeSql(m_data.id))
|
||||
{
|
||||
// Remove already created schema & user
|
||||
m_exTblGen->dropExerciseSchema(m_data.id, false);
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Error creating database tables/indexes/views for exercise with id %1")).arg(m_data.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Additional writing of sqlFiles
|
||||
if (m_logger.isDebugEnabled())
|
||||
m_exTblGen->writeExerciseServicesSql(m_data.id);
|
||||
|
||||
INFO_LOG(m_logger) << "Exercise created sucessfully.";
|
||||
|
||||
// Publish Data via DTS
|
||||
onPublishData();
|
||||
|
||||
return Core::FunctionReplyObject(m_data.id);
|
||||
}
|
||||
|
||||
void ObjectExercise::initStateMachine()
|
||||
{
|
||||
// Start ExerciseStateMachine
|
||||
m_stateMachine->init();
|
||||
INFO_LOG(m_logger) << "StateMachine: currentState" << m_stateMachine->getCurrentState();
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectExercise::updateObject(const Database::ExmExercise &data)
|
||||
{
|
||||
if ( !isValid() || !isEditable())
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Trying to update an already removed ExmExercise object"));
|
||||
|
||||
m_data.id = data.id;
|
||||
m_data.name = data.name;
|
||||
m_data.beginTime = data.beginTime;
|
||||
m_data.endTime = data.endTime;
|
||||
m_data.startTime = data.startTime;
|
||||
m_data.stopTime = data.stopTime;
|
||||
m_data.trainingAreaId = data.trainingAreaId;
|
||||
m_data.radioGroupId = data.radioGroupId;
|
||||
m_data.activePhaseId = data.activePhaseId;
|
||||
m_data.symbolFillTypeId = data.symbolFillTypeId;
|
||||
m_data.forces = data.forces;
|
||||
m_data.description = data.description;
|
||||
m_data.defaultTimeZone = data.defaultTimeZone;
|
||||
m_data.linkedExerciseId = data.linkedExerciseId;
|
||||
m_data.sendToWms = data.sendToWms;
|
||||
m_data.transferred = data.transferred;
|
||||
m_data.hasHlaInterface = data.hasHlaInterface;
|
||||
m_data.operatorId = data.operatorId;
|
||||
m_data.workstationId = data.workstationId;
|
||||
|
||||
fixupTimeZone();
|
||||
|
||||
INFO_LOG(m_logger) << "Trying to updateObject ExerciseData with id = " << data.id;
|
||||
|
||||
if (!m_db->update(m_data))
|
||||
{
|
||||
QString errText = m_db->getLastError().databaseText();
|
||||
ERROR_LOG(m_logger) << "Failed to update ExerciseData with id = " << data.id << ": " << m_db->getLastError().databaseText();
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Error updating ExmExercise-data in database: %1")).arg(errText);
|
||||
}
|
||||
|
||||
// Change state if different
|
||||
if (m_data.exerciseStateId != data.exerciseStateId)
|
||||
{
|
||||
Core::FunctionReplyObject retOb = switchToState(data.exerciseStateId, data.operatorId, data.workstationId);
|
||||
if (retOb.error())
|
||||
return retOb;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "ExerciseData changed sucessfully.";
|
||||
|
||||
onPublishData();
|
||||
|
||||
return Core::FunctionReplyObject(m_data.id);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectExercise::removeObject(bool force)
|
||||
{
|
||||
if (isRunning() && !force)
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Exercise still running"));
|
||||
|
||||
// Change State to terminated
|
||||
if (!setExerciseState(ExerciseManagement::ExerciseState::Terminated))
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "ExerciseState cannot be changed to terminated"));
|
||||
|
||||
if (!m_exTblGen->dropExerciseSchema(m_data.id, false))
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Exercise %1 (%2) can not be removed")).arg(m_data.name).arg(m_data.id);
|
||||
|
||||
if (!m_db->removeExmExercise(m_data.id))
|
||||
{
|
||||
QString errText = m_db->getLastError().databaseText();
|
||||
ERROR_LOG(m_logger) << "Cannot remove exercise id = " << m_data.id << "from database: " << errText;
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Exercise %1 (%2) can not be removed: %3")).arg(m_data.name).arg(m_data.id).arg(errText);
|
||||
}
|
||||
|
||||
m_ddsHandler->dts()->removeExerciseByKey(m_data.id);
|
||||
sendStateToServiceManagement(m_data.exerciseStateId); // terminated
|
||||
|
||||
INFO_LOG(m_logger) << "Exercise dropped sucessfully.";
|
||||
|
||||
return Core::FunctionReplyObject(m_data.id);
|
||||
}
|
||||
|
||||
bool ObjectExercise::setLinkedExerciseId(int newLinkedExerciseId)
|
||||
{
|
||||
m_data.linkedExerciseId = newLinkedExerciseId;
|
||||
if (!m_db->update(m_data))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to update ExerciseData with id = " << m_data.id << " : " << m_db->getLastError().text();
|
||||
return false;
|
||||
}
|
||||
onPublishData();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjectExercise::setSendToWms(bool bSend)
|
||||
{
|
||||
m_data.sendToWms = bSend;
|
||||
if (!m_db->update(m_data))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to update ExerciseData with id = " << m_data.id << " : " << m_db->getLastError().text();
|
||||
return false;
|
||||
}
|
||||
onPublishData();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ObjectExercise::setExerciseState(const ExerciseState &exerciseState)
|
||||
{
|
||||
if (m_data.exerciseStateId == exerciseState)
|
||||
return true;
|
||||
|
||||
if (!isValid() || !isEditable())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Trying to update an already removed ExmExercise object";
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "## m_data.exerciseStateId = " << m_data.exerciseStateId;
|
||||
DEBUG_LOG(m_logger) << "## exerciseState = " << exerciseState;
|
||||
|
||||
m_data.exerciseStateId = exerciseState;
|
||||
if (m_data.exerciseStateId == ExerciseManagement::ExerciseState::Stopped ||
|
||||
m_data.exerciseStateId == ExerciseManagement::ExerciseState::Terminated ||
|
||||
m_data.exerciseStateId == ExerciseManagement::ExerciseState::Unknown)
|
||||
m_data.radioGroupId.clear();
|
||||
|
||||
QDateTime changed = QDateTime::currentDateTimeUtc();
|
||||
|
||||
if (m_data.exerciseStateId == ExerciseState::Started)
|
||||
m_data.startTime = changed;
|
||||
|
||||
if (m_data.exerciseStateId == ExerciseState::Stopped)
|
||||
m_data.stopTime = changed;
|
||||
|
||||
if (!m_db->update(m_data))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating ExmExercise-data in database (exerciseState) for exercise id = " << m_data.id << " : " << m_db->getLastError().text();;
|
||||
return false;
|
||||
}
|
||||
|
||||
Database::ExmExerciseStateChange stateChange;
|
||||
stateChange.exerciseId = m_data.id;
|
||||
stateChange.exerciseStateId = m_data.exerciseStateId;
|
||||
stateChange.operatorId = m_data.operatorId;
|
||||
stateChange.workstationId = m_data.workstationId;
|
||||
stateChange.changedAt = changed.currentMSecsSinceEpoch();
|
||||
|
||||
// record exerciseStateChange
|
||||
if (!m_db->insert(stateChange))
|
||||
WARNING_LOG(m_logger) << "Recording change of exerciseState failed: " << m_db->getLastError().text();;
|
||||
|
||||
// Publish Data via DTS
|
||||
onPublishData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectExercise::onPublishData()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Publish ExmExercise-data to dds (" << m_data.id << ", " << m_data.name << ") ...";
|
||||
|
||||
if (!m_ddsHandler->dts()->publish(convert(m_data)))
|
||||
ERROR_LOG(m_logger) << "Error publishing ExmExercise-data to dds";
|
||||
|
||||
}
|
||||
|
||||
void ObjectExercise::fixupTimeZone()
|
||||
{
|
||||
if (m_data.defaultTimeZone.isEmpty())
|
||||
m_data.defaultTimeZone = QLatin1Char('Z'); // zulu
|
||||
const char tz = m_data.defaultTimeZone.at(0).toLatin1();
|
||||
if (tz < 'A' || tz == 'J' || tz > 'Z')
|
||||
m_data.defaultTimeZone = QLatin1Char('Z'); // zulu
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectExercise::switchToState(const ExerciseState &newExerciseState, int operatorId, int workstationId)
|
||||
{
|
||||
Core::FunctionReplyObject ret;
|
||||
INFO_LOG(m_logger) << "-------------- switchToState: " << newExerciseState
|
||||
<< ", currentState = " << m_stateMachine->getCurrentState();
|
||||
m_data.operatorId = operatorId;
|
||||
m_data.workstationId = workstationId;
|
||||
|
||||
bool ok = m_stateMachine->switchToState(newExerciseState);
|
||||
if (!ok)
|
||||
{
|
||||
ret = Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Error switching to state %1")).arg(newExerciseState.underlying());
|
||||
}
|
||||
NOTICE_LOG(m_logger) << "-------------- after switch: currentState" << m_stateMachine->getCurrentState();
|
||||
NOTICE_LOG(m_logger) << "-> OperatorId: " << m_data.operatorId << ", workstationId: " << m_data.workstationId;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s_requestId = 0;
|
||||
bool ObjectExercise::sendStateToServiceManagement(ExerciseState state)
|
||||
{
|
||||
Core::ServiceGroupType sgt = Core::ServiceGroupType::Core; // invalid here
|
||||
switch (state.underlying())
|
||||
{
|
||||
case ExerciseState::Created:
|
||||
sgt = Core::ServiceGroupType::ExercisePreparation;
|
||||
break;
|
||||
case ExerciseState::Started:
|
||||
sgt = Core::ServiceGroupType::ExerciseExecution;
|
||||
break;
|
||||
case ExerciseState::Paused:
|
||||
sgt = Core::ServiceGroupType::ExercisePaused;
|
||||
break;
|
||||
case ExerciseState::Stopped:
|
||||
sgt = Core::ServiceGroupType::ExerciseAfterActionReview;
|
||||
break;
|
||||
case ExerciseState::Terminated:
|
||||
sgt = Core::ServiceGroupType::Master; // Master + ExerciseId != 0 -> stopp all groups for this exercise
|
||||
break;
|
||||
case ExerciseState::Unknown:
|
||||
break;
|
||||
}
|
||||
if (sgt == Core::ServiceGroupType::Core)
|
||||
return false;
|
||||
|
||||
if (sgt != Core::ServiceGroupType::Master)
|
||||
DEBUG_LOG(m_logger) << "Ex " << m_data.id << " - Trying to enable service group " << sgt;
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Ex " << m_data.id << " - Trying to stop all services";
|
||||
|
||||
// if there is an old group, stop them
|
||||
ServiceManagement::GroupRequest request(sgt,
|
||||
m_ddsHandler->ddsConnector()->getDomainId(),
|
||||
m_data.id,
|
||||
0,
|
||||
++s_requestId,
|
||||
{});
|
||||
#ifndef EXM_OBJECT_EXERCISE_NO_HANDLER
|
||||
if (!m_exerciseHandler || !m_exerciseHandler->startGroupRequest(request))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Ex " << m_data.id << " - Failed to start group " << sgt;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (sgt != Core::ServiceGroupType::Master)
|
||||
DEBUG_LOG(m_logger) << "Ex " << m_data.id << " - Sent start group " << sgt;
|
||||
else
|
||||
DEBUG_LOG(m_logger) << "Ex " << m_data.id << " - Sent stop all services";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ObjectExercise::transferExerciseToEvaluationDb()
|
||||
{
|
||||
if (m_data.transferred)
|
||||
return true;
|
||||
|
||||
if (!m_copyExercise)
|
||||
m_copyExercise = new DBAdministration::CopyExercise(m_logger, DBAdministration::CopyExercise::CopyForEvaluation, this);
|
||||
|
||||
connect(m_copyExercise, &DBAdministration::CopyExercise::copyDbFinished,
|
||||
this, &ObjectExercise::onTransferDbFinished);
|
||||
connect(m_copyExercise, &DBAdministration::CopyExercise::copyDbFailed,
|
||||
this, &ObjectExercise::onErrorOccured);
|
||||
|
||||
if (!m_copyExercise->init(m_data.id,
|
||||
Settings::serverDatabaseHost(),
|
||||
Settings::serverDatabaseName(),
|
||||
Settings::evaluationDatabaseHost(),
|
||||
Settings::evaluationDatabaseName()) ||
|
||||
!m_copyExercise->doCopy())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not backup exercise database to evaluation server";
|
||||
return false;
|
||||
}
|
||||
NOTICE_LOG(m_logger) << "Ex " << m_data.id << " - Started copying exercise from "
|
||||
<< Settings::serverDatabaseHost() << ":" << Settings::serverDatabaseName()
|
||||
<< " to " << Settings::evaluationDatabaseHost() << ":" << Settings::evaluationDatabaseName();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectExercise::onTransferDbFinished()
|
||||
{
|
||||
NOTICE_LOG(m_logger) << "Ex " << m_data.id << " - Finished copying exercise from "
|
||||
<< Settings::serverDatabaseHost() << ":" << Settings::serverDatabaseName()
|
||||
<< " to " << Settings::evaluationDatabaseHost() << ":" << Settings::evaluationDatabaseName();
|
||||
|
||||
m_data.transferred = true;
|
||||
if (!m_db->update(m_data))
|
||||
ERROR_LOG(m_logger) << "Error updating ExmExercise-data (transferred) in database (exerciseState) for exercise id = " << m_data.id << " : " << m_db->getLastError().text();;
|
||||
|
||||
delete m_copyExercise;
|
||||
m_copyExercise = nullptr;
|
||||
|
||||
//publish because we changed transferred
|
||||
onPublishData();
|
||||
}
|
||||
|
||||
void ObjectExercise::onErrorOccured()
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Ex " << m_data.id << " - Copying exercise from "
|
||||
<< Settings::serverDatabaseHost() << ":" << Settings::serverDatabaseName()
|
||||
<< " to " << Settings::evaluationDatabaseHost() << ":" << Settings::evaluationDatabaseName();
|
||||
delete m_copyExercise;
|
||||
m_copyExercise = nullptr;
|
||||
}
|
||||
|
||||
} // Namespace ExerciseManagement
|
||||
Reference in new issue
Block a user