/** * The PartyHandler class manages all party related function topics and holds classes for * further party data. * $Id$ * $HeadURL$ * $Author$ * Created by Hannes Baeuerle, SLSE, 2016-05-12 */ #include "PartyHandling/party_handler.h" #include "PartyHandling/party.h" #include #include #include "main_handler.h" namespace ParticipantManagement { //------------------------------------------------------------------------------------------ PartyHandling::PartyHandler::PartyHandler(MainHandler *mainHandler) : ModifyPartyDataRequestHandler(mainHandler->fts()) , RemovePartyRequestHandler(mainHandler->fts()) , SyncPartiesRequestHandler(mainHandler->exerciseId() <= 0 ? nullptr : mainHandler->fts()) , ChangePartyUsedStateRequestHandler(mainHandler->fts()) , m_mainHandler(mainHandler) , m_logger(getLogger("PartyHandler")) { } //------------------------------------------------------------------------------------------ PartyHandling::PartyHandler::~PartyHandler() { qDeleteAll(m_parties); } //------------------------------------------------------------------------------------------ PartyHandling::Party *PartyHandling::PartyHandler::partyById(int32_t partyId) const { return m_parties.value(partyId, nullptr); } //------------------------------------------------------------------------------------------ bool PartyHandling::PartyHandler::init() { qDeleteAll(m_parties); m_parties.clear(); QVector partyVec; // read parties from db if (!m_mainHandler->db()->select(partyVec)) { ERROR_LOG(m_logger) << "Error while reading party data from database"; return false; } // if there are no parties in db and this instance of ParticipantManagement runs not in ex_0 // parties are fetched from ex_0 PPM if (m_mainHandler->exerciseId() > 0 && partyVec.isEmpty()) partyVec = loadDefaultParties(true); if (partyVec.isEmpty()) { ERROR_LOG(m_logger) << "Error while reading party data from database"; return false; } for ( Database::PpmParty currentParty : qAsConst(partyVec)) { resetAdlerProperties(currentParty.properties, currentParty.id); PartyHandling::Party *newParty = new PartyHandling::Party(currentParty); m_parties.insert(currentParty.id, newParty); m_mainHandler->dts()->publish(newParty->toDdsParty()); } return true; } //------------------------------------------------------------------------------------------ void PartyHandling::PartyHandler::resetAdlerProperties( QString &properties, const int partyId) { DEBUG_LOG(m_logger) << "properties: " << properties; QJsonObject obj = QJsonDocument::fromJson(properties.toUtf8()).object(); if (!obj.contains(QStringLiteral("Adler"))) return; const ParticipantManagement::ConnectState connectState = m_mainHandler->ddsHandler()->dtc()->saaConnectedState(partyId); if (connectState == ParticipantManagement::ConnectState::Undefined) return; DEBUG_LOG(m_logger) << "connectState: " << connectState; if (connectState != ParticipantManagement::ConnectState::Disconnected) { QJsonObject propAdler = obj[QStringLiteral("Adler")].toObject(); propAdler[QStringLiteral("saaConnectedState")] = ParticipantManagement::ConnectState::Disconnected; obj[QStringLiteral("Adler")] = propAdler; const QByteArray propertiesStr = QJsonDocument(obj).toJson(QJsonDocument::Compact); properties = QString::fromStdString(propertiesStr.data()); INFO_LOG(m_logger) << "isSaaConnected set to false"; } } //------------------------------------------------------------------------------------------ QVector PartyHandling::PartyHandler::loadDefaultParties(bool withInsert) const { QVector partyVec; if (!m_mainHandler->dbEx0()->select(partyVec)) ERROR_LOG(m_logger) << "Error while reading party data from database (ex_0)"; auto cb = [](const Database::PpmParty &p1,const Database::PpmParty &p2) -> bool { return p1.id < p2.id; }; std::sort(partyVec.begin(), partyVec.end(), cb); if (withInsert) { for (auto it = partyVec.begin(); it != partyVec.end(); ++it) { // just inserting a new party, means is not in use (*it).isUsedBy = false; m_mainHandler->db()->insert(*it); } m_mainHandler->db()->fixUpSequencePpmParty(); } return partyVec; } //------------------------------------------------------------------------------------------ void PartyHandling::PartyHandler::onModifyPartyDataRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::Party &request) { auto ret = modifyPartyDataRequest(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_mainHandler->fts()->modifyPartyDataReply(cookie, ret); } //------------------------------------------------------------------------------------------ Core::FunctionReplyObject PartyHandling::PartyHandler::modifyPartyDataRequest(const ParticipantManagement::Party &request) { DEBUG_LOG(m_logger) << "onModifyPartyDataRequest: " << request; Party *partyToPublish = m_parties.value(request.id()); if (!partyToPublish && request.id() >= 0) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Could not modify party with id %1, because no party with that id exists")) .arg(request.id()); if (!partyToPublish) // create new party { DEBUG_LOG(m_logger) << "Creating new party"; // insert into database Database::PpmParty newDbParty; newDbParty.color = request.color(); newDbParty.fadingColor = request.fadingColor(); newDbParty.name = QString::fromStdString(request.name()); newDbParty.roleId = request.role(); newDbParty.isUsedBy = request.isUsedBy(); newDbParty.hlaForceIdentifier = request.hlaForceIdentifier().underlying(); newDbParty.properties = QString::fromStdString(request.properties()); if (!m_mainHandler->db()->insert(newDbParty)) { QString errText = m_mainHandler->db()->getLastError().databaseText(); ERROR_LOG(m_logger) << "Error inserting Party into database: " << errText; return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Error inserting new party to database: %1")).arg(errText); } partyToPublish = new Party(newDbParty); m_parties.insert(partyToPublish->id(), partyToPublish); } else // modify existing party { DEBUG_LOG(m_logger) << "Modifying party with id " << partyToPublish->id(); if (!partyToPublish->hasChanges(request, true)) partyToPublish = nullptr; // so it will not be published at the end of this method ... else // update in database { if (!m_mainHandler->db()->update(partyToPublish->toDbParty())) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Error updating party in database")); } } if (partyToPublish) { auto party = partyToPublish->toDdsParty(); m_mainHandler->dts()->publish(party); } return Core::FunctionReplyObject(request.id()); } //------------------------------------------------------------------------------------------ void PartyHandling::PartyHandler::onRemovePartyRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::RemovePartyRequest &request) { DEBUG_LOG(m_logger) << "onRemovePartyRequest: " << request; auto ret = removePartyRequest(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_mainHandler->fts()->removePartyReply(cookie, ret); } //------------------------------------------------------------------------------------------ Core::FunctionReplyObject PartyHandling::PartyHandler::removePartyRequest(const ParticipantManagement::RemovePartyRequest &request) { DEBUG_LOG(m_logger) << "onRemovePartyRequest " << request; if (request.partyId() < 0) return Core::FunctionReplyObject(tr_lts("dds", "Got request to delete a party, but no valid party id to delete")); Party *partyToDelete = m_parties.value(request.partyId()); if (!partyToDelete) return Core::FunctionReplyObject(tr_lts("dds", "Could not delete party with id %1, because no party with that id exists")) .arg(request.partyId()); if (partyToDelete->isUsedBy() == true) return Core::FunctionReplyObject(tr_lts("dds", "Not possible to delete a party in use")); DEBUG_LOG(m_logger) << "Removing party with ID " << request.partyId(); return removeParty(partyToDelete); } //------------------------------------------------------------------------------------------ Core::FunctionReplyObject PartyHandling::PartyHandler::removeParty(Party *partyToDelete) { const int partyId = partyToDelete->id(); // delete from db if (!m_mainHandler->db()->removePpmParty(partyId)) return Core::FunctionReplyObject(tr_lts("dds", "Error removing party with id %1 from database")).arg(partyId); // delete from dds m_mainHandler->dts()->removePartyByKey(partyId); // delete from map m_parties.remove(partyId); delete partyToDelete; return Core::FunctionReplyObject(partyId); } //------------------------------------------------------------------------------------------ void PartyHandling::PartyHandler::onSyncPartiesRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::SyncPartiesRequest &request) { DEBUG_LOG(m_logger) << "onSyncPartiesRequest: " << request; Core::FunctionReplyObject rep; QVector partyVec = loadDefaultParties(false); for (auto it = partyVec.begin(); it != partyVec.end(); ++it) { int partyId = (*it).id; DEBUG_LOG(m_logger) << "Checking Party Id: " << partyId; Database::PpmParty partyEx0 = (*it); if (!m_parties.contains(partyId)) { // just inserting a new party, means is not yet in use partyEx0.isUsedBy = false; if (!m_mainHandler->db()->insert(partyEx0)) { QString errText = m_mainHandler->db()->getLastError().databaseText(); WARNING_LOG(m_logger) << "Error inserting new party with id " << partyId << " to database: " << errText; continue; } else { DEBUG_LOG(m_logger) << "Inserting Party Id: " << partyId; PartyHandling::Party *newParty = new PartyHandling::Party(partyEx0); m_parties.insert(partyEx0.id, newParty); m_mainHandler->dts()->publish(newParty->toDdsParty()); } } else { Party *partyEx = m_parties.value(partyId); bool hasChanges = partyEx0.color != partyEx->toDbParty().color || partyEx0.fadingColor != partyEx->toDbParty().fadingColor || partyEx0.name != partyEx->toDbParty().name || partyEx0.hlaForceIdentifier != partyEx->toDbParty().hlaForceIdentifier || partyEx0.roleId != partyEx->toDbParty().roleId; DEBUG_LOG(m_logger) << "Has changes = " << hasChanges; if (hasChanges) { ParticipantManagement::Party req; req.id(partyId); // taking new properties from ex_0 req.color(partyEx0.color); req.fadingColor(partyEx0.fadingColor); req.name(partyEx0.name.toStdString()); req.role(partyEx0.roleId); req.hlaForceIdentifier(static_cast(partyEx0.hlaForceIdentifier)); // this remains as it is req.isUsedBy(partyEx->isUsedBy()); auto ret = modifyPartyDataRequest(req); if (ret.error()) WARNING_LOG(m_logger) << ret(); } } } // now checking for non-existent parties in ex_0 const auto partiesCopy(m_parties); for (Party *curParty : partiesCopy) { bool found = false; for (auto it = partyVec.begin(); it != partyVec.end(); ++it) { int partyId = (*it).id; if (partyId == curParty->id()) { found = true; break; } } if (!found) { DEBUG_LOG(m_logger) << "Party id to be deleted = " << curParty->id(); if (curParty->isUsedBy()) INFO_LOG(m_logger) << "Party with id " << curParty->id() << " cannot be deleted, is in use"; else { auto ret = removeParty(curParty); // removed from map etc if (ret.error()) WARNING_LOG(m_logger) << ret(); } } } m_mainHandler->db()->fixUpSequencePpmParty(); m_mainHandler->fts()->syncPartiesReply(cookie, rep); } //------------------------------------------------------------------------------------------ void PartyHandling::PartyHandler::onChangePartyUsedStateRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::ChangePartyUsedStateRequest &request) { DEBUG_LOG(m_logger) << "onChangePartyUsedStateRequest: " << request; auto ret = changePartyUsedStateRequest(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_mainHandler->fts()->changePartyUsedStateReply(cookie, ret); } //------------------------------------------------------------------------------------------ Core::FunctionReplyObject PartyHandling::PartyHandler::changePartyUsedStateRequest(const ParticipantManagement::ChangePartyUsedStateRequest &request) { Party *party = m_parties.value(request.partyId()); if (!party) return Core::FunctionReplyObject(request.partyId(), tr_lts("dds", "Could not modify party with id %1, because no party with that id exists")) .arg(request.partyId()); ParticipantManagement::Party ddsParty = party->toDdsParty(); ddsParty.isUsedBy(request.isUsedBy()); if (party->hasChanges(ddsParty, false)) { if (!m_mainHandler->db()->update(party->toDbParty())) return Core::FunctionReplyObject(request.partyId(), tr_lts("dds", "Error updating party used state in database")); DEBUG_LOG(m_logger) << "Change used state for party " << party->id() << " to " << party->isUsedBy(); m_mainHandler->dts()->publish(party->toDdsParty()); } return Core::FunctionReplyObject(request.partyId()); } } // namespace ParticipantManagement