/** * The GroupHandler class handles all group related classes and writes the groups state to DDS. * $Id$ * $HeadURL$ * $Author$ * Created by Hannes Baeuerle, SLSE, 2016-02-15 */ #include "group_handler.h" #include "group.h" #include "heartbeat_listener.h" #include "service_donator.h" namespace ServiceManagement { GroupHandler::GroupHandler(const std::shared_ptr &ddsHandler, const std::shared_ptr &donator) : QObject() , Interface::Fts::StartGroupRequestHandler(ddsHandler->fts()) , Interface::Fts::StopGroupRequestHandler(ddsHandler->fts()) , Interface::Fts::RestartGroupRequestHandler(ddsHandler->fts()) , m_serviceDonator(donator) , m_ddsHandler(ddsHandler) , m_heartbeatListener(new HeartbeatListener(ddsHandler->connector(), donator)) , m_logger(getLogger("GroupHandler")) { } GroupHandler::~GroupHandler() { qDeleteAll(m_groups); m_groups.clear(); qDeleteAll(m_groupSchemes); m_groupSchemes.clear(); delete m_heartbeatListener; } bool GroupHandler::init(int32_t coreDomain) { DEBUG_LOG(m_logger) << "Initializing GroupHandler ..."; bool bAllPartsInitialized = m_heartbeatListener->init() && startGroupCore(coreDomain); if (bAllPartsInitialized) DEBUG_LOG(m_logger) << "GroupHandler successfully initialized."; else ERROR_LOG(m_logger) << "GroupHandler initialization failed."; return bAllPartsInitialized; } void GroupHandler::addServiceLink(int serviceId, Core::ServiceGroupType groupType) { groupSchemeFromType(groupType)->addServiceId(serviceId); } QVector GroupHandler::groups() const { return m_groups; } GroupScheme *GroupHandler::groupSchemeFromType(Core::ServiceGroupType type) { for (GroupScheme *scheme : qAsConst(m_groupSchemes)) { if (scheme->groupType == type) return scheme; } // TODO: make generic ... QMap groupNameMapping; groupNameMapping.insert(Core::ServiceGroupType_def::Master, QLatin1String("Master")); groupNameMapping.insert(Core::ServiceGroupType_def::Core, QLatin1String("Core")); groupNameMapping.insert(Core::ServiceGroupType_def::ExercisePreparation, QLatin1String("ExercisePreparation")); groupNameMapping.insert(Core::ServiceGroupType_def::ExerciseExecution, QLatin1String("ExerciseExecution")); groupNameMapping.insert(Core::ServiceGroupType_def::ExercisePaused, QLatin1String("ExercisePaused")); groupNameMapping.insert(Core::ServiceGroupType_def::ExerciseAfterActionReview, QLatin1String("ExerciseAfterActionReview")); groupNameMapping.insert(Core::ServiceGroupType_def::Playback, QLatin1String("Playback")); // if no scheme with type type exists, it will be newly generated and added GroupScheme *newScheme = new GroupScheme(type, groupNameMapping.value(type)); m_groupSchemes.append(newScheme); return newScheme; } Group *GroupHandler::getGroup(const GroupRequest &groupToFind) const { for (Group *group : m_groups) { if (group->type() == groupToFind.type() && group->exercisePartitionId() == groupToFind.exercisePartitionId() && group->domainId() == groupToFind.domainId() && group->replayPartitionId() == groupToFind.replayPartitionId()) return group; } return nullptr; } Group *GroupHandler::getSimilarGroup(const GroupRequest &groupToFind) const { const std::vector possibleTypes = {Core::ServiceGroupType::ExercisePreparation, Core::ServiceGroupType::ExerciseExecution, Core::ServiceGroupType::ExercisePaused, Core::ServiceGroupType::ExerciseAfterActionReview}; bool bSimilar = false; for (const auto &type : possibleTypes) { if (type != groupToFind.type()) continue; bSimilar = true; break; } if (!bSimilar) return nullptr; for(auto type : possibleTypes) { // don't find ourself ... if (type == groupToFind.type()) continue; GroupRequest similarGroup(groupToFind); similarGroup.type(type); Group *groupFound = getGroup(similarGroup); if (groupFound) return groupFound; } return nullptr; } bool GroupHandler::startGroupCore(int32_t domainId) { if (domainId != m_ddsHandler->connector()->getDomainId()) { ERROR_LOG(m_logger) << "Could not start group Core for domain " << domainId << ", this ServiceManagement instance only supports domain " << m_ddsHandler->connector()->getDomainId(); return false; } DEBUG_LOG(m_logger) << "Starting core group ..."; GroupRequest groupToSearch; groupToSearch.type(Core::ServiceGroupType::Core); groupToSearch.domainId(domainId); Group *coreGroup = getGroup(groupToSearch); if (coreGroup == nullptr) { GroupScheme *coreScheme = groupSchemeFromType(groupToSearch.type()); if (coreScheme == nullptr) { ERROR_LOG(m_logger) << "Could not start core group because there are no services linked to it"; return false; } coreGroup = new Group(m_ddsHandler, m_serviceDonator, groupToSearch, coreScheme, this); m_groups.append(coreGroup); } coreGroup->start(); return true; } void GroupHandler::onStartGroupRequest(const rti::core::SampleIdentity &cookie, const GroupRequest &request) { auto ret = onStartGroup(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_ddsHandler->fts()->startGroupReply(cookie, ret); } void GroupHandler::slotStartGroupRequest(const GroupRequest &request) { auto ret = onStartGroup(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); emit startGroupReply(ret); } Core::FunctionReplyObject GroupHandler::onStartGroup(const GroupRequest &request) { DEBUG_LOG(m_logger) << "New StartGroupRequest: " << request; if (request.domainId() != m_ddsHandler->connector()->getDomainId()) return Core::FunctionReplyObject(request.requestId(), tr_lts("dds", "This instance of ServiceManagement only allows to start a group in domain %1. Domain %2 was provided")) .arg(m_ddsHandler->connector()->getDomainId()) .arg(request.domainId()); // special case: request.type == Master, ExerciseId != 0 -> stopp all if (request.type() == Core::ServiceGroupType::Master && request.exercisePartitionId() != 0) return onStopAllForExercise(request.domainId(), request.exercisePartitionId()); Group *existingGroup = getGroup(request); // check if it's a Exercise group and search a group with the same exercise/domain -id // if the group does not exist, it is newly created (normal case) if (existingGroup == nullptr) { GroupScheme *scheme = groupSchemeFromType(request.type()); if (scheme == nullptr) return Core::FunctionReplyObject(request.requestId(), tr_lts("dds", "Starting attempt of non existing group: %1")).arg(request.type().underlying()); existingGroup = new Group(m_ddsHandler, m_serviceDonator, request, scheme, this); m_groups.append(existingGroup); } Group *similarGroup = getSimilarGroup(request); // if there is a similar group, we should take the services from there (to avoid restarting services on exeuction -> pause or pause -> resume) if (similarGroup) { DEBUG_LOG(m_logger) << "Taking existing services from group " << similarGroup->type() << " to " << existingGroup->type(); existingGroup->takeServicesFromGroup(similarGroup); similarGroup->stop(); m_groups.removeAll(similarGroup); similarGroup->deleteLater(); similarGroup = nullptr; } existingGroup->start(); return Core::FunctionReplyObject(request.requestId()); } Core::FunctionReplyObject GroupHandler::onStopAllForExercise(int domainId, int exercisePartitionId) { DEBUG_LOG(m_logger) << "Stopping all proces for domain " << domainId << ", partition " << exercisePartitionId; QVector stillAliveGroups; int cntStopped = 0; int cntAlive = 0; for (Group *group : qAsConst(m_groups)) { if (group->exercisePartitionId() == exercisePartitionId && group->domainId() == domainId) { group->stop(); group->deleteLater(); ++cntStopped; } else { stillAliveGroups += group; ++cntAlive; } } m_groups = stillAliveGroups; DEBUG_LOG(m_logger) << "Stopping all proces for domain " << domainId << ", partition " << exercisePartitionId << " - done. Stopped " << cntStopped << " groups" << ", still alive: " << cntAlive; return Core::FunctionReplyObject(exercisePartitionId); } void GroupHandler::onStopGroupRequest(const rti::core::SampleIdentity &cookie, const GroupRequest &request) { auto ret = onStopGroup(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_ddsHandler->fts()->stopGroupReply(cookie, ret); } void GroupHandler::slotStopGroupRequest(const GroupRequest &request) { auto ret = onStopGroup(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); emit stopGroupReply(ret); } Core::FunctionReplyObject GroupHandler::onStopGroup(const GroupRequest &request) { DEBUG_LOG(m_logger) << "New StopGroupRequest: " << request; Group *existingGroup = getGroup(request); if (existingGroup == nullptr) return Core::FunctionReplyObject(request.requestId(), tr_lts("dds", "Could not stop Group, because it does not exist")); existingGroup->stop(); // delete this group since no longer needed m_groups.removeAll(existingGroup); delete existingGroup; return Core::FunctionReplyObject(request.requestId()); } void GroupHandler::onRestartGroupRequest(const rti::core::SampleIdentity &cookie, const GroupRequest &request) { auto ret = onRestartGroup(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_ddsHandler->fts()->restartGroupReply(cookie, ret); } Core::FunctionReplyObject GroupHandler::onRestartGroup(const GroupRequest &request) { DEBUG_LOG(m_logger) << "New RestartGroupRequest: " << request; Group *existingGroup = getGroup(request); if (existingGroup == nullptr) return Core::FunctionReplyObject(tr_lts("dds", "Could not restart Group, because it does not exist")); existingGroup->restart(); return Core::FunctionReplyObject(existingGroup->id()); } } // namespace ServiceManagement