Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+426
@@ -0,0 +1,426 @@
|
||||
/**
|
||||
* Block/unblock topics
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2018-01-15
|
||||
*/
|
||||
|
||||
#include "handler_locked_topics.h"
|
||||
#include "main_handler.h"
|
||||
#include "handler_operator.h"
|
||||
#include <DDS/FTS/generic_fts_impl.h>
|
||||
#include <DDS/DTS/generic_dts_impl.h>
|
||||
#include <DDS/Core/function_reply_object.h>
|
||||
|
||||
#include <QMutableHashIterator>
|
||||
|
||||
|
||||
namespace OperatorManagement
|
||||
{
|
||||
HandlerLockedTopics::HandlerLockedTopics(MainHandler &mainHandler,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("HandlerLockedTopics"))
|
||||
{}
|
||||
|
||||
bool HandlerLockedTopics::init()
|
||||
{
|
||||
m_db = m_mainHandler.db();
|
||||
auto ddsConnector = m_mainHandler.dds()->ddsConnector();
|
||||
if (!m_db || !ddsConnector)
|
||||
return false;
|
||||
|
||||
ddsConnector->initSubscriber();
|
||||
|
||||
{
|
||||
m_ftsTryLockEntity.reset(ddsConnector->createFTS<FTS::TryLockEntity>());
|
||||
const auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::TryLockEntityRequest & request)
|
||||
{
|
||||
this->onTryLockEntityRequest(cookie, request);
|
||||
};
|
||||
m_ftsTryLockEntity->setSubscriberCallback(cb);
|
||||
}
|
||||
|
||||
{
|
||||
m_ftsTryUnlockEntity.reset(ddsConnector->createFTS<FTS::TryUnlockEntity>());
|
||||
const auto cb = [this](const rti::core::SampleIdentity & cookie, const Core::TryUnlockEntityRequest & request)
|
||||
{
|
||||
this->onTryUnlockEntityRequest(cookie, request);
|
||||
};
|
||||
m_ftsTryUnlockEntity->setSubscriberCallback(cb);
|
||||
}
|
||||
|
||||
auto cbDatabase = [this](const Database::OpmLockedTopics & data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Locked topic from db: " << data.exerciseId.toInt() << ", " << data.workstationId
|
||||
<< ", " << data.operatorId << data.entityTypeName;
|
||||
m_lockedTopics.insert(Core::key(data.entityId, data.exerciseId.isNull() ? 0 : data.exerciseId.toInt(), data.entityTypeName), data);
|
||||
};
|
||||
m_db->selectByLocked(cbDatabase, true);
|
||||
|
||||
m_dtsLockedEntity.reset(ddsConnector->createDTS<DTS::LockedEntityImpl>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool needsUnlock(int operatorId, int workstationId, const Database::OpmLockedTopics &data)
|
||||
{
|
||||
// same operator -> check if other workstation
|
||||
if (operatorId == data.operatorId)
|
||||
{
|
||||
return true; // NT, 18.09.20 remove. From former (crashed) session, independent from workstation
|
||||
|
||||
// if (workstationId == 0) // logout
|
||||
// return true;
|
||||
// if (workstationId != data.workstationId) // logged in on another workstation
|
||||
// return true;
|
||||
// return false;
|
||||
|
||||
}
|
||||
// other operator on a workstation previously locked by another operator -> unlock
|
||||
if (workstationId != 0 && workstationId == data.workstationId)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandlerLockedTopics::operatorLoggedInOut(int operatorId, int workstationId)
|
||||
{
|
||||
// check if there are stale locks (e.g. by crashing client) - then remove all of them - if there are any
|
||||
|
||||
DEBUG_LOG(m_logger) << "operatorLoggedInOut: " << workstationId << ", " << operatorId;
|
||||
|
||||
// Ueberall wurden - ohne erase wohlgemerkt - mutable Iteratoren verwendet. Nur hier - wo erase verwendet wurde - nicht! :')
|
||||
QMutableHashIterator<Core::key, Database::OpmLockedTopics> it(m_lockedTopics);
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
const auto lockedTopic = it.next().value();
|
||||
|
||||
DEBUG_LOG(m_logger) << "check if unlock: id=" << lockedTopic.id
|
||||
<< ", exId=" << lockedTopic.exerciseId.toInt()
|
||||
<< ", wsId=" << lockedTopic.workstationId
|
||||
<< ", opId=" << lockedTopic.operatorId;
|
||||
if (!needsUnlock(operatorId, workstationId, lockedTopic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Unlocking topic: id=" << lockedTopic.id
|
||||
<< ", exId=" << lockedTopic.exerciseId.toInt()
|
||||
<< ", wsId=" << lockedTopic.workstationId
|
||||
<< ", opId=" << lockedTopic.operatorId;
|
||||
unlockInDb(lockedTopic);
|
||||
removeLockedEntity(lockedTopic.id);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerLockedTopics::onTryLockEntityRequest(const rti::core::SampleIdentity &cookie,
|
||||
const Core::TryLockEntityRequest &request)
|
||||
{
|
||||
if (m_logger.isDebugEnabled())
|
||||
dumpLockedTopics(__LINE__);
|
||||
|
||||
auto ret = tryLock(request);
|
||||
if (!ret.errorString().empty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << Core::FunctionReplyObject(ret.FunctionReply::id(), ret.errorString(), ret.errorParams()).translated() << " - " << request;
|
||||
}
|
||||
else if (ret.alreadyLocked())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "onTryLockEntityRequest failed because the topic was already locked by ws " << ret.alreadyLocked().get().workstationName() << " and op " << ret.alreadyLocked().get().operatorName() << " - " << request;
|
||||
}
|
||||
m_ftsTryLockEntity->sendReply(cookie, ret);
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
dumpLockedTopics(__LINE__);
|
||||
}
|
||||
|
||||
Core::TryLockEntityReply lockErrorReply(const long topicId, const std::string &msg)
|
||||
{
|
||||
return Core::TryLockEntityReply(-1, msg, { std::to_string(topicId) }, {}, {});
|
||||
}
|
||||
|
||||
Core::TryLockEntityReply lockAlreadyLockedReply(const std::string &ws, const QString &op)
|
||||
{
|
||||
return Core::TryLockEntityReply(-1, {}, {},{}, Core::LockEntityError(ws, op.toStdString()));
|
||||
}
|
||||
|
||||
Core::TryLockEntityReply lockSuccessReply(const Database::OpmLockedTopics &dbStruct)
|
||||
{
|
||||
return Core::TryLockEntityReply(dbStruct.id, {}, {}, {}, {});
|
||||
}
|
||||
|
||||
Core::TryLockEntityReply HandlerLockedTopics::tryLock(const Core::TryLockEntityRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "tryLock : " << request;
|
||||
|
||||
const auto topicId = request.entityId();
|
||||
|
||||
const Core::key k(request.entityId(), request.exerciseId(), QString::fromStdString(request.entityTypeName()));
|
||||
Database::OpmLockedTopics dbStruct(toDb(request));
|
||||
auto it = m_lockedTopics.constFind(k);
|
||||
if (it == m_lockedTopics.constEnd())
|
||||
{
|
||||
// noch nicht vorhanden -> add
|
||||
dbStruct.timeStampLock = QDateTime::currentMSecsSinceEpoch();
|
||||
if (!m_db->insert(dbStruct))
|
||||
{
|
||||
return lockErrorReply(topicId, tr_lts("dds", "Failed to lock element with id %1 in database"));
|
||||
}
|
||||
|
||||
m_lockedTopics.insert(k, dbStruct);
|
||||
Core::LockedEntity lckEntity(request.operatorId(), request.workstationId(),
|
||||
request.exerciseId(), request.entityId(),
|
||||
request.entityTypeName(), dbStruct.id);
|
||||
publishLockedEntity(lckEntity);
|
||||
return lockSuccessReply(dbStruct);
|
||||
}
|
||||
|
||||
// NOTE: don't check if there is already a lock for that exact same key (same op, ws, topic, ...): Reason: Szenario: in 2 sitmaps "Exercise Purpose" aufschalten... 2. Dlg muss gelockt werden !!!
|
||||
|
||||
// already locked by another user
|
||||
const Database::OpmLockedTopics &data = *it;
|
||||
const auto opName = m_mainHandler.getHandlerOperator()->operatorNameById(data.operatorId);
|
||||
const auto wsName = m_mainHandler.dds()->dtcAsm()->asset(data.workstationId).name();
|
||||
|
||||
return lockAlreadyLockedReply(wsName, opName);
|
||||
}
|
||||
|
||||
//Core::TryLockEntityReply HandlerLockedTopics::tryLockModify(const Core::TryLockEntityRequest &request)
|
||||
//{
|
||||
// DEBUG_LOG(m_logger) << "tryLockModify: " << request;
|
||||
|
||||
// const auto lockEntityId = request.id();
|
||||
|
||||
// // requestedKey == new key
|
||||
// const Core::key requestedKey(request.entityId(), request.exerciseId(), QString::fromStdString(request.entityTypeName()));
|
||||
|
||||
// // is requested topic already locked?
|
||||
// {
|
||||
// auto it = m_lockedTopics.constFind(requestedKey);
|
||||
// if (it != m_lockedTopics.constEnd())
|
||||
// {
|
||||
// // vorhanden -> locked by another user/dlg
|
||||
// // or be me??? (locked by this dialog instance / topicId ?
|
||||
// const Database::OpmLockedTopics &data = it.value();
|
||||
// if (lockEntityId != data.id)
|
||||
// {
|
||||
// // vorhanden and locked by another user/dlg:
|
||||
// // "release" my *former* lock:
|
||||
// removeReleaseOutdatedLock(lockEntityId);
|
||||
|
||||
// const auto opName = m_mainHandler->getHandlerOperator()->operatorNameById(data.operatorId);
|
||||
// const auto wsName = m_mainHandler->dds()->dtcAsm()->asset(data.workstationId).name();
|
||||
|
||||
// return lockAlreadyLockedReply(wsName, opName);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // not already lock -> 'update' the entry:
|
||||
// //
|
||||
// // 1) DB-Update
|
||||
// //
|
||||
// Database::OpmLockedTopics dbStruct(toDb(request));
|
||||
// dbStruct.id = lockEntityId; // to enable dbUpdate :-)
|
||||
// dbStruct.timeStampLock = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
// if (!m_db->update(dbStruct))
|
||||
// {
|
||||
// return lockErrorReply(lockEntityId, tr_lts("dds", "Failed to update lock entity (%1) in database"));
|
||||
// }
|
||||
|
||||
// //
|
||||
// // 2) DDS-Update
|
||||
// //
|
||||
// Core::LockedEntity lckEntity(request.operatorId(), request.workstationId(),
|
||||
// request.exerciseId(), request.entityId(),
|
||||
// request.entityTypeName(), dbStruct.id);
|
||||
// publishLockedEntity(lckEntity);
|
||||
|
||||
|
||||
// //
|
||||
// // 3) QHash-Update
|
||||
// //
|
||||
|
||||
// // update both: key and value!!! by removing the key-value-pair with topicId ...
|
||||
// {
|
||||
// auto lockedTopicIt = std::find_if(m_lockedTopics.constBegin(), m_lockedTopics.constEnd(),
|
||||
// [&lockEntityId](const Database::OpmLockedTopics &lockedTopic)
|
||||
// {
|
||||
// return (lockEntityId == lockedTopic.id);
|
||||
// });
|
||||
|
||||
// if (lockedTopicIt == m_lockedTopics.constEnd())
|
||||
// {
|
||||
// return lockErrorReply(lockEntityId, tr_lts("dds", "Failed to update lock entity (%1) on the heap"));
|
||||
// }
|
||||
|
||||
// const Database::OpmLockedTopics &lockedTopic = *lockedTopicIt;
|
||||
// DEBUG_LOG(m_logger) << LOGFUNCTION << ": locked topic id " << lockedTopic.id;
|
||||
// // ... and then reinserting the updated lock entity (as the id has now changed) - while the key (op, ws, exc, topic id) stays the same!
|
||||
// m_lockedTopics[requestedKey] = dbStruct;
|
||||
// }
|
||||
|
||||
// return lockSuccessReply(dbStruct); // success
|
||||
//}
|
||||
|
||||
//bool HandlerLockedTopics::removeReleaseOutdatedLock(const int lockEntityId)
|
||||
//{
|
||||
// DEBUG_LOG(m_logger) << "removeReleaseOutdatedLock: lockEntityId = " << lockEntityId;
|
||||
|
||||
// auto lockedTopicIt = std::find_if(m_lockedTopics.constBegin(), m_lockedTopics.constEnd(),
|
||||
// [&lockEntityId](const Database::OpmLockedTopics &lockedTopic)
|
||||
// {
|
||||
// return (lockEntityId == lockedTopic.id);
|
||||
// });
|
||||
|
||||
// if (lockedTopicIt == m_lockedTopics.constEnd())
|
||||
// {
|
||||
// ERROR_LOG(m_logger) << LOGFUNCTION << ": Failed to release outdated lock as lock entity id ("<<lockedTopicIt<<") was not found!";
|
||||
// Q_ASSERT(false);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// const Database::OpmLockedTopics &lockedTopic = *lockedTopicIt;
|
||||
// DEBUG_LOG(m_logger) << LOGFUNCTION << ": found lock entity " << lockEntityId;
|
||||
|
||||
// unlockInDb(lockedTopic);
|
||||
// removeLockedEntity(lockEntityId);
|
||||
|
||||
// m_lockedTopics.erase(lockedTopicIt);
|
||||
|
||||
// return true;
|
||||
//}
|
||||
|
||||
void HandlerLockedTopics::onTryUnlockEntityRequest(const rti::core::SampleIdentity &cookie,
|
||||
const Core::TryUnlockEntityRequest &request)
|
||||
{
|
||||
if (m_logger.isDebugEnabled())
|
||||
dumpLockedTopics(__LINE__);
|
||||
|
||||
auto ret = tryUnlock(request);
|
||||
if (!ret.errorString().empty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << Core::FunctionReplyObject(ret.FunctionReply::id(), ret.errorString(), ret.errorParams()).translated() << " - " << request;
|
||||
}
|
||||
m_ftsTryUnlockEntity->sendReply(cookie, ret);
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
dumpLockedTopics(__LINE__);
|
||||
}
|
||||
|
||||
Core::FunctionReply HandlerLockedTopics::tryUnlock(const Core::TryUnlockEntityRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "tryUnlock: " << request;
|
||||
|
||||
const auto lockEntityId = request.id();
|
||||
|
||||
auto lockedTopicIt = std::find_if(m_lockedTopics.constBegin(), m_lockedTopics.constEnd(),
|
||||
[lockEntityId](const Database::OpmLockedTopics &lockedTopic)
|
||||
{
|
||||
return (lockEntityId == lockedTopic.id);
|
||||
});
|
||||
|
||||
if (lockedTopicIt == m_lockedTopics.constEnd())
|
||||
{
|
||||
// nicht vorhanden => unlock nicht möglich
|
||||
return Core::FunctionReply(-1, tr_lts("dds", "Failed to unlock unknown lock with id %1."), {}, { std::to_string(lockEntityId) });
|
||||
}
|
||||
|
||||
// found => unlock
|
||||
const Database::OpmLockedTopics &lockedTopic = *lockedTopicIt;
|
||||
unlockInDb(lockedTopic);
|
||||
removeLockedEntity(lockedTopic.id);
|
||||
m_lockedTopics.erase(lockedTopicIt);
|
||||
return Core::FunctionReply(); // success!
|
||||
}
|
||||
|
||||
void HandlerLockedTopics::unlockInDb(const Database::OpmLockedTopics &data)
|
||||
{
|
||||
Database::OpmLockedTopics dbStruct(data);
|
||||
dbStruct.locked = false;
|
||||
dbStruct.timeStampUnlock = QDateTime::currentMSecsSinceEpoch();
|
||||
m_db->update(dbStruct);
|
||||
}
|
||||
|
||||
Database::OpmLockedTopics HandlerLockedTopics::toDb(const Core::LockedEntityBase &request)
|
||||
{
|
||||
Database::OpmLockedTopics ret;
|
||||
ret.locked = true;
|
||||
ret.entityId = request.entityId();
|
||||
ret.entityTypeName = QString::fromStdString(request.entityTypeName());
|
||||
ret.operatorId = request.operatorId();
|
||||
ret.workstationId = request.workstationId();
|
||||
ret.exerciseId = request.exerciseId() ? QVariant(request.exerciseId()) : QVariant();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool HandlerLockedTopics::publishLockedEntity(const Core::LockedEntity &entity)
|
||||
{
|
||||
if (m_dtsLockedEntity)
|
||||
{
|
||||
m_dtsLockedEntity->write(entity);
|
||||
return true;
|
||||
}
|
||||
ERROR_LOG(m_logger) << "Publishing LockedEntity " << entity.id() << " failed: DTS not available!";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HandlerLockedTopics::removeLockedEntity(int64_t id)
|
||||
{
|
||||
Core::LockedEntity entity;
|
||||
entity.id(id);
|
||||
if (m_dtsLockedEntity)
|
||||
{
|
||||
m_dtsLockedEntity->remove(entity);
|
||||
return true;
|
||||
}
|
||||
ERROR_LOG(m_logger) << "Removing LockedEntity " << entity.id() << " failed: DTS not available!";
|
||||
return false;
|
||||
}
|
||||
|
||||
//Core::key HandlerLockedTopics::topicIdToKey(long id)
|
||||
//{
|
||||
// QHashIterator<Core::key, Database::OpmLockedTopics> it (m_lockedTopics);
|
||||
|
||||
// while (it.hasNext())
|
||||
// {
|
||||
// it.next();
|
||||
// const Database::OpmLockedTopics &topicRef = it.value();
|
||||
// if (topicRef.id == id)
|
||||
// {
|
||||
// return it.key();
|
||||
// }
|
||||
// } // while (it.hasNext())
|
||||
|
||||
// return {};
|
||||
//}
|
||||
|
||||
void HandlerLockedTopics::dumpLockedTopics(int line)
|
||||
{
|
||||
QHashIterator<Core::key, Database::OpmLockedTopics> it (m_lockedTopics);
|
||||
|
||||
INFO_LOG(m_logger) << " dump m_lockedTopics, START size= " << m_lockedTopics.size()
|
||||
<< " (callerline=" << line << ")";
|
||||
while (it.hasNext())
|
||||
{
|
||||
it.next();
|
||||
const Core::key &keyRef = it.key();
|
||||
const Database::OpmLockedTopics &valRef = it.value();
|
||||
INFO_LOG(m_logger) << " entityTypeName=" << keyRef.entityTypeName << "'"
|
||||
<< ", entityId=" << keyRef.entityId
|
||||
<< ", exerciseId=" << keyRef.exerciseId
|
||||
<< " - eTN=" << valRef.entityTypeName
|
||||
<< ", entityId=" << valRef.entityId
|
||||
<< ", exId=" << valRef.exerciseId.toInt()
|
||||
<< ", opId=" << valRef.operatorId;
|
||||
}
|
||||
INFO_LOG(m_logger) << " dump m_lockedTopics, END size= " << m_lockedTopics.size();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in new issue
Block a user