1027 lines
37 KiB
C++
Executable File
1027 lines
37 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* ISM Test Import XML
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Iuliana Ojog, SLSE, 2016-11-28
|
|
*/
|
|
|
|
#include "ism_import_buildings.h"
|
|
#include <InfrastructureManagement/parse_building_xml.h>
|
|
|
|
#include <nglapplication/nglcoreapplication.h>
|
|
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
|
|
|
#include <QFile>
|
|
#include <QTextStream>
|
|
#include <QTimer>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonArray>
|
|
#include <QtWebSockets/QWebSocket>
|
|
#include <QUrl>
|
|
|
|
#include <QThread>
|
|
|
|
#include <InfrastructureManagement/ism_ftc.h>
|
|
#include <InfrastructureManagement/ism_dtc.h>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
using namespace InfrastructureManagement;
|
|
// ------------------------------------------------------------------------------
|
|
IsmImportBuildings::IsmImportBuildings(QObject *parent)
|
|
: QObject(parent)
|
|
, m_logger(getLogger("ImportXml"))
|
|
{
|
|
qRegisterMetaType<Core::FunctionReply>("Core::FunctionReply");
|
|
connect(this, &IsmImportBuildings::importDone, this, &IsmImportBuildings::importNext);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
bool IsmImportBuildings::init(int domainId, const QUrl &tcpDiscoveryUrl)
|
|
{
|
|
INFO_LOG(m_logger) << "init begin";
|
|
|
|
// initialize DDS, always on exercise 0
|
|
m_ddsConnector.reset(new DDSConnector::DdsConnector(domainId, IDL::PartitionType::Global, 0, 0, tcpDiscoveryUrl));
|
|
if (!m_ddsConnector->init())
|
|
return false;
|
|
m_ddsConnector->initPublisherSubscriber();
|
|
|
|
DEBUG_LOG(m_logger) << "create dtc";
|
|
m_dtc = InfrastructureManagement::Interface::Dtc::create(m_ddsConnector);
|
|
|
|
DEBUG_LOG(m_logger) << "create ftc";
|
|
m_ftc = InfrastructureManagement::Interface::Ftc::create(m_ddsConnector);
|
|
|
|
DEBUG_LOG(m_logger) << "init dtc & ftc";
|
|
bool bRet = m_ftc->enableMainStructureElementModify() &&
|
|
m_ftc->enableMainStructureElementRemove() &&
|
|
m_ftc->enableMountingPointAssetRemove() &&
|
|
m_ftc->enableMountingPointAssetModify() &&
|
|
m_ftc->enableMountingPointPlanModify() &&
|
|
m_ftc->enableStructureElementModify() &&
|
|
m_dtc->enableMainStructureElement() &&
|
|
m_dtc->enableInstrumentationAsset() &&
|
|
m_dtc->enableMountingPointAsset() &&
|
|
m_dtc->enableMainSchedule();
|
|
|
|
DEBUG_LOG(m_logger) << "init dtc, ftc end - bRet = " << bRet;
|
|
|
|
DEBUG_LOG(m_logger) << "Domain Id = " << domainId;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::import(const ImportData &importData)
|
|
{
|
|
m_currentData = importData;
|
|
QTimer::singleShot(0, this, &IsmImportBuildings::doImport);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::import(const QVector<ImportData> &importData)
|
|
{
|
|
m_importData = importData;
|
|
if (m_importData.isEmpty())
|
|
{
|
|
QCoreApplication::quit();
|
|
return;
|
|
}
|
|
DEBUG_LOG(m_logger) << "Trying to import " << m_importData.size() << " buildings";
|
|
m_curImportIdx = 0;
|
|
import(m_importData.at(m_curImportIdx));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::remove(const QVector<int> &ids)
|
|
{
|
|
m_idsToBeRemoved = ids;
|
|
removeNext();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::removeNext()
|
|
{
|
|
if (m_idsToBeRemoved.isEmpty())
|
|
{
|
|
if (m_isInRestoringMode)
|
|
return;
|
|
QCoreApplication::quit();
|
|
return;
|
|
}
|
|
|
|
remove(m_idsToBeRemoved.front());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::importNext()
|
|
{
|
|
if (m_curImportIdx < 0 || m_curImportIdx + 1 >= m_importData.size())
|
|
{
|
|
QCoreApplication::quit();
|
|
return;
|
|
}
|
|
++m_curImportIdx;
|
|
import(m_importData.at(m_curImportIdx));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::remove(int buildingId)
|
|
{
|
|
bool assetsMounted = false;
|
|
|
|
m_dtc->waitForHistoricalDataMainStructureElement();
|
|
m_dtc->waitForHistoricalDataInstrumentationAsset();
|
|
m_dtc->waitForHistoricalDataMountingPointAsset();
|
|
|
|
auto predicate = [](const InfrastructureManagement::InstrumentationAsset & a)
|
|
{
|
|
return (!a.isDeleted() && (a.mountingPointTypeId() != InfrastructureManagement::MountingPointType::BuildingControlUnit));
|
|
};
|
|
|
|
QMap<int, QVector<InfrastructureManagement::InstrumentationAsset>> assetsMapBuilding;
|
|
m_dtc->getAllAssetsPerBuilding(predicate, assetsMapBuilding);
|
|
|
|
DEBUG_LOG(m_logger) << "assetsMapBuilding.size = " << assetsMapBuilding.size();
|
|
|
|
assetsMounted = (assetsMapBuilding[buildingId].size() > 0);
|
|
|
|
DEBUG_LOG(m_logger) << "Building id = " << buildingId << " has assets mounted = " << assetsMounted;
|
|
|
|
// cfroebel 2018-11-30:
|
|
// Currently the ISM service fails to correctly remove a building when it has mounted assets (other than BCU).
|
|
// It then removes the building but leaves the assets in a mounted state.
|
|
// Thus for now we need to check here whether the building has mounted assets or not.
|
|
if (assetsMounted)
|
|
{
|
|
QString msg = QStringLiteral("Not possible to remove building with id %1 because there are assets mounted!").arg(buildingId);
|
|
ERROR_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
m_idsToBeRemoved.pop_front();
|
|
IsmImportBuildings::removeNext();
|
|
}
|
|
else
|
|
IsmImportBuildings::doRemove(buildingId);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::doImport()
|
|
{
|
|
INFO_LOG(m_logger) << "trying to Import / Modify";
|
|
ParseBuildingXml buildingXml(m_currentData.xmlFileName,
|
|
m_currentData.vulFileName,
|
|
m_currentData.egcuToRoomFileName,
|
|
m_currentData.soundAreaFileName,
|
|
m_currentData.geoPos,
|
|
m_currentData.angleDegree);
|
|
if (!buildingXml.parseXml())
|
|
{
|
|
ERROR_LOG(m_logger) << "Can not parse building files: " << buildingXml.lastError();
|
|
std::cerr << "Can not parse building files name: " << m_currentData.xmlFileName
|
|
<< " error: " << buildingXml.lastError() << std::endl;
|
|
QCoreApplication::exit(1);
|
|
return;
|
|
}
|
|
INFO_LOG(m_logger) << "Sending request";
|
|
|
|
MainStructureElementModifyRequest req = buildingXml.parsedRequest();
|
|
QByteArray propertiesBa = QByteArray::fromStdString(req.properties());
|
|
QJsonParseError parserError;
|
|
const QJsonDocument doc(QJsonDocument::fromJson(propertiesBa, &parserError));
|
|
if (parserError.error != QJsonParseError::NoError)
|
|
WARNING_LOG(m_logger) << "Error parsing json document: " << parserError.errorString() << " '" << propertiesBa << "'";
|
|
DEBUG_LOG(m_logger) << "json to parse: " << doc.toJson();
|
|
QJsonObject obj(doc.object());
|
|
if (m_currentData.exerciseId > 0)
|
|
{
|
|
QJsonArray array;
|
|
array.push_back(m_currentData.exerciseId);
|
|
obj.insert(QLatin1String("available_in_exercise"), array);
|
|
req.properties(QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString());
|
|
}
|
|
|
|
if (m_currentData.buildingId > 0)
|
|
req.id(m_currentData.buildingId);
|
|
req.externalWlsId(m_currentData.externalWlsId);
|
|
req.groupId(m_currentData.bauabschnitt);
|
|
req.structureElementTypeId(InfrastructureManagement::StructureElementType::Building);
|
|
|
|
// check if building exists
|
|
MainStructureElement oldMainStructureElement = mainStructureElementByName(req.name());
|
|
std::string msg;
|
|
QMap<qint32, QVector<std::string>> oldNamePaths;
|
|
QVector<MountingPointAsset> mountings;
|
|
|
|
if (oldMainStructureElement != MainStructureElement())
|
|
{
|
|
m_isInRestoringMode = true;
|
|
msg = "Building " + req.name() + " already exists. All related data is now saved.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
|
|
msg = "Fetching IDs of MountingPints.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
QVector<qint32> mountingPointIds;
|
|
for (const StructureElement &structureElement : oldMainStructureElement.elements())
|
|
{
|
|
if (structureElement.structureElementTypeId() != StructureElementType::MountingPoint)
|
|
continue;
|
|
mountingPointIds.append(structureElement.id());
|
|
}
|
|
|
|
msg = "Fetching MountingPointAssets.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
// get mountings of mounting points of this building
|
|
mountings = mountingsOfStructureElements(mountingPointIds);
|
|
|
|
// qint32 unmountCounter = 0;
|
|
if (!mountings.isEmpty())
|
|
{
|
|
msg = "Removing MountingPointAssets.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
unmountAssetsOfBuliding(oldMainStructureElement.id());
|
|
// // remove mounting point assets
|
|
// for (const MountingPointAsset &mountingPointAsset : mountings)
|
|
// {
|
|
// ++unmountCounter;
|
|
// m_ftc->mountingPointAssetRemoveRequest(Core::RemoveElementRequest(mountingPointAsset.id()), [this, &unmountCounter](const Core::FunctionReplyObject &rep){this->onMountingPointAssetRemoveReply(rep); --unmountCounter;});
|
|
// }
|
|
}
|
|
|
|
msg = "Fetching MountingPointPlans.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
// get mounting points in plans of this building
|
|
auto mppsBySchedule = MountingPointPlanByScheduleOfStructureElements(mountingPointIds);
|
|
|
|
// Don't know, why these are deleted anyways...
|
|
for (auto it = mppsBySchedule.cbegin(); it != mppsBySchedule.cend(); ++it)
|
|
{
|
|
INFO_LOG(m_logger) << "Removing MountingPointPlans.";
|
|
auto copy = it.value();
|
|
for (auto &elem : copy)
|
|
elem.mountingPointState() = MountingPointState_def::Idle;
|
|
m_ftc->mountingPointPlanModifyRequest(MountingPointPlanModifyRequest(it.key(),copy), this);
|
|
}
|
|
msg = "Fetching paths of MountingPoints by name ... for later reconstruction.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
for (const StructureElement &structureElement : oldMainStructureElement.elements())
|
|
oldNamePaths.insert(structureElement.id(), pathWithNames(structureElement, oldMainStructureElement));
|
|
|
|
//msg = "Waiting for removing operations.";
|
|
connect(this, &IsmImportBuildings::removeDone, this, [this, oldMainStructureElement, oldNamePaths, mountings, mppsBySchedule, req]()
|
|
{
|
|
connect(this, &IsmImportBuildings::importDone, this, [this, oldMainStructureElement, oldNamePaths, mountings, mppsBySchedule]()
|
|
{
|
|
restoreData(oldMainStructureElement, oldNamePaths, mountings, mppsBySchedule);
|
|
});
|
|
createNewMainStructureElement(req);
|
|
});
|
|
// while(unmountCounter)
|
|
// {
|
|
// std::cerr << "Unmount counter: " << unmountCounter << std::endl;
|
|
// QThread::sleep(1);
|
|
// }
|
|
remove(oldMainStructureElement.id());
|
|
}
|
|
else
|
|
createNewMainStructureElement(req);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::doRemove(int buildingId)
|
|
{
|
|
std::string msg = "Trying to Remove building with id " + QString::number(buildingId).toStdString();
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
if (!m_ftc->mainStructureElementRemoveRequest(MainStructureElementRemoveRequest(buildingId), this))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error requesting remove";
|
|
std::cerr << "Error requesting remove" << std::endl;
|
|
QCoreApplication::exit(1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
MainStructureElement IsmImportBuildings::mainStructureElementByName(const std::string &name) const
|
|
{
|
|
m_dtc->waitForHistoricalDataMainStructureElement();
|
|
|
|
QMap<qint32, MainStructureElement> mainStructureElements = m_dtc->mainStructureElements();
|
|
|
|
for (auto it = mainStructureElements.constBegin(); it != mainStructureElements.constEnd(); ++it)
|
|
{
|
|
if (it.value().name() == name)
|
|
return it.value();
|
|
}
|
|
|
|
return MainStructureElement();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
QHash<int, std::vector<MountingPointPlan> > IsmImportBuildings::MountingPointPlanByScheduleOfStructureElements(const QVector<qint32> &structureElementIds) const
|
|
{
|
|
m_dtc->waitForHistoricalDataMainSchedule();
|
|
|
|
QHash<int, std::vector<MountingPointPlan> > result;
|
|
|
|
for (const MainSchedule &schedule : m_dtc->mainSchedules())
|
|
{
|
|
for (const MountingPointPlan &plan : schedule.elements())
|
|
{
|
|
if (structureElementIds.contains(plan.structureElementId()))
|
|
result[schedule.id()].push_back(plan);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
QVector<MountingPointAsset> IsmImportBuildings::mountingsOfStructureElements(const QVector<qint32> &structureElementIds) const
|
|
{
|
|
m_dtc->waitForHistoricalDataMountingPointAsset();
|
|
|
|
QMap<qint32, MountingPointAsset> mountings = m_dtc->mountingPointAssets();
|
|
QVector<MountingPointAsset> result;
|
|
|
|
for (auto it = mountings.constBegin(); it != mountings.constEnd(); ++it)
|
|
{
|
|
if (structureElementIds.contains(it.value().structureElementId()))
|
|
result.append(it.value());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
QVector<std::string> IsmImportBuildings::pathWithNames(const StructureElement &structureElement, const MainStructureElement &mainStructureElement) const
|
|
{
|
|
QVector<std::string> result;
|
|
result.reserve(structureElement.path().size());
|
|
for (int32_t structureElementId : structureElement.path())
|
|
result.push_back(structureElementNameById(structureElementId, mainStructureElement.elements()));
|
|
|
|
return result;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
std::string IsmImportBuildings::structureElementNameById(qint32 id, const std::vector<StructureElement> &structureElements) const
|
|
{
|
|
for (const StructureElement &structureElement : structureElements)
|
|
{
|
|
if (structureElement.id() == id)
|
|
return structureElement.name();
|
|
}
|
|
|
|
return std::string();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
StructureElement IsmImportBuildings::structureElementById(qint32 id, const MainStructureElement &mainStructureElement) const
|
|
{
|
|
for (const StructureElement &structureElement : mainStructureElement.elements())
|
|
{
|
|
if (structureElement.id() == id)
|
|
return structureElement;
|
|
}
|
|
|
|
return StructureElement();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::createNewMainStructureElement(const MainStructureElementModifyRequest &request)
|
|
{
|
|
std::string msg = "Creating new MainStructureElement.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
if (!m_ftc->mainStructureElementModifyRequest(request, this))
|
|
{
|
|
if (m_currentData.buildingId > 0)
|
|
ERROR_LOG(m_logger) << "Error requesting update";
|
|
else
|
|
ERROR_LOG(m_logger) << "Error requesting create";
|
|
std::cerr << "Error requesting update/create" << std::endl;
|
|
QCoreApplication::exit(1);
|
|
return;
|
|
}
|
|
INFO_LOG(m_logger) << "Waiting for answer";
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::restoreData(const MainStructureElement &oldMainStructureElement,
|
|
const QMap<qint32, QVector<std::string> > &oldNamePaths,
|
|
const QVector<MountingPointAsset> &mountings,
|
|
const QHash<int, std::vector<MountingPointPlan> > &mountingPointPlansBySchedule)
|
|
{
|
|
std::string msg;
|
|
if (oldMainStructureElement == MainStructureElement())
|
|
return;
|
|
|
|
MainStructureElement newMainStructureElement = mainStructureElementByName(oldMainStructureElement.name());
|
|
if (newMainStructureElement == MainStructureElement())
|
|
{
|
|
FATAL_LOG(m_logger) << "There was no new MainStructureElement created. Please consider restoring the database by backup.";
|
|
QCoreApplication::exit(1);
|
|
}
|
|
|
|
QVector<qint32> newMountingPointIds;
|
|
for (const StructureElement &structureElement : newMainStructureElement.elements())
|
|
{
|
|
if (structureElement.structureElementTypeId() != StructureElementType::MountingPoint)
|
|
continue;
|
|
newMountingPointIds.append(structureElement.id());
|
|
}
|
|
QMap<qint32, QVector<std::string> > newNamePaths;
|
|
INFO_LOG(m_logger) << "Restoring mounting point data.";
|
|
for (const StructureElement &structureElement : newMainStructureElement.elements())
|
|
newNamePaths.insert(structureElement.id(), pathWithNames(structureElement, oldMainStructureElement));
|
|
|
|
if (oldNamePaths.size() != newNamePaths.size())
|
|
INFO_LOG(m_logger) << "old name path size: " + QString::number(oldNamePaths.size()).toStdString() + " , new name path size: " + QString::number(newNamePaths.size()).toStdString();;
|
|
|
|
QMap<qint32, qint32> oldStructureElementIdToNewStructureElementId;
|
|
for (auto it = oldNamePaths.constBegin(); it != oldNamePaths.constEnd(); ++it)
|
|
{
|
|
for (auto innerIt = newNamePaths.constBegin(); innerIt != newNamePaths.constEnd(); ++innerIt)
|
|
{
|
|
if (it.value() == innerIt.value())
|
|
{
|
|
oldStructureElementIdToNewStructureElementId.insert(it.key(), innerIt.key());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
StructureElementModifyRequest modifyRequest;
|
|
modifyRequest.mainStructureElementId(newMainStructureElement.id());
|
|
for (auto it = oldStructureElementIdToNewStructureElementId.constBegin(); it != oldStructureElementIdToNewStructureElementId.constEnd(); ++it)
|
|
{
|
|
StructureElement oldStructureElement = structureElementById(it.key(), oldMainStructureElement);
|
|
|
|
if (!oldStructureElement.barcode().size() && !oldStructureElement.properties().size())
|
|
continue;
|
|
|
|
StructureElement newStructureElement = structureElementById(it.value(), newMainStructureElement);
|
|
|
|
newStructureElement.barcode(oldStructureElement.barcode());
|
|
newStructureElement.properties(oldMainStructureElement.properties());
|
|
|
|
modifyRequest.elements().push_back(newStructureElement);
|
|
}
|
|
if (modifyRequest.elements().size())
|
|
m_ftc->structureElementModifyRequest(modifyRequest, this);
|
|
|
|
if (!mountings.isEmpty())
|
|
{
|
|
msg = "Restoring MountingPointAssets.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
// restore mountings
|
|
for (const MountingPointAsset &mountingPointAsset : mountings)
|
|
{
|
|
if (!oldStructureElementIdToNewStructureElementId.contains(mountingPointAsset.structureElementId()))
|
|
{
|
|
msg = "There is no new StructureElement ID to old StructureElement ID " + QString::number(mountingPointAsset.structureElementId()).toStdString() + ". If somethind else looks suspicious, restore database data by backup.";
|
|
FATAL_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
continue;
|
|
}
|
|
MountingPointAssetModifyRequest mountingRequest;
|
|
mountingRequest.assetId(mountingPointAsset.assetId());
|
|
mountingRequest.structureElementId(oldStructureElementIdToNewStructureElementId.value(mountingPointAsset.id()));
|
|
|
|
m_ftc->mountingPointAssetModifyRequest(mountingRequest, this);
|
|
}
|
|
}
|
|
|
|
if (mountingPointPlansBySchedule.empty())
|
|
return;
|
|
|
|
msg = "Restoring MountingPointPlans.";
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
// restore mounting point plans
|
|
MountingPointPlanModifyRequest createRequest;
|
|
for (auto it = mountingPointPlansBySchedule.cbegin(); it != mountingPointPlansBySchedule.cend(); ++it)
|
|
{
|
|
createRequest.mountingPointScheduleId() = it.key();
|
|
// NO constRef! We change values...
|
|
for(MountingPointPlan mountingPointPlan : it.value())
|
|
{
|
|
if (!oldStructureElementIdToNewStructureElementId.contains(mountingPointPlan.structureElementId()))
|
|
{
|
|
FATAL_LOG(m_logger) <<"There is no new StructureElement ID to old StructureElement ID " + QString::number(mountingPointPlan.structureElementId()).toStdString() + ". If somethind else looks suspicious, restore database data by backup.";
|
|
continue;
|
|
// mountingPointPlan.structureElementId() = oldStructureElementIdToNewStructureElementId.value(mountingPointPlan.structureElementId());
|
|
// createRequest.mountingPointPlans().push_back(mountingPointPlan);
|
|
}
|
|
}
|
|
if (!createRequest.mountingPointPlans().empty())
|
|
m_ftc->mountingPointPlanModifyRequest(createRequest, this);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::unmountAssetsOfBuliding(qint32 buildingId)
|
|
{
|
|
QWebSocket socket;
|
|
std::string msg;
|
|
|
|
QUrl url;
|
|
url.setPort(2080);
|
|
url.setHost(QLatin1String("localhost"));
|
|
socket.open(url);
|
|
|
|
while(socket.state() != QAbstractSocket::ConnectedState)
|
|
{
|
|
msg = "Waiting for socket to open";
|
|
std::cerr << msg << std::endl;
|
|
INFO_LOG(m_logger) << msg;
|
|
QThread::sleep(1);
|
|
}
|
|
|
|
QJsonObject jsonObj;
|
|
QJsonObject dataObj;
|
|
jsonObj.insert(QLatin1String("type"), QLatin1String("unmountObject"));
|
|
jsonObj.insert(QLatin1String("uuid"), QLatin1String("UUID"));
|
|
dataObj.insert(QLatin1String("objectId"), buildingId);
|
|
jsonObj.insert(QLatin1String("data"), dataObj);
|
|
|
|
bool hasAnswer = false;
|
|
|
|
connect(&socket, &QWebSocket::textMessageReceived, this, [this, &hasAnswer](const QString &message)
|
|
{
|
|
std::string msg = "Got reply: " + message.toStdString();
|
|
std::cerr << msg << std::endl;
|
|
INFO_LOG(m_logger) << msg;
|
|
hasAnswer = true;
|
|
});
|
|
|
|
socket.sendTextMessage(QString::fromLatin1(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact)));
|
|
|
|
while(!hasAnswer)
|
|
{
|
|
msg = "Waiting for socket to answer";
|
|
std::cerr << msg << std::endl;
|
|
INFO_LOG(m_logger) << msg;
|
|
QThread::sleep(1);
|
|
}
|
|
|
|
socket.close();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
void IsmImportBuildings::onMainStructureElementModifyReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
if (handleReply(replyObject))
|
|
emit importDone();
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
void IsmImportBuildings::onMainStructureElementRemoveReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
int buildingId = -1;
|
|
if (!m_idsToBeRemoved.isEmpty())
|
|
m_idsToBeRemoved.front();
|
|
|
|
if (replyObject.error())
|
|
{
|
|
QString msg = QStringLiteral("Failed to remove building with id %1: %2").arg(buildingId).arg(QString::fromStdString(replyObject()));
|
|
ERROR_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
}
|
|
else
|
|
{
|
|
QString msg = QStringLiteral("Removed building with id %1").arg(buildingId);
|
|
INFO_LOG(m_logger) << msg;
|
|
std::cerr << msg << std::endl;
|
|
}
|
|
|
|
emit removeDone();
|
|
if (!m_idsToBeRemoved.isEmpty())
|
|
m_idsToBeRemoved.pop_front();
|
|
removeNext();
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
void IsmImportBuildings::onMountingPointPlanModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
{
|
|
ERROR_LOG(m_logger) << reply.error();
|
|
std::cerr << reply.error() << std::endl;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
void IsmImportBuildings::onMountingPointAssetRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
ERROR_LOG(m_logger) << "REMOVE REPLY";
|
|
if (reply.error())
|
|
{
|
|
ERROR_LOG(m_logger) << reply.error();
|
|
std::cerr << reply.error() << std::endl;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
void IsmImportBuildings::onMountingPointAssetModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
{
|
|
ERROR_LOG(m_logger) << reply.error();
|
|
std::cerr << reply.error() << std::endl;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
void IsmImportBuildings::onStructureElementModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
{
|
|
ERROR_LOG(m_logger) << reply.error();
|
|
std::cerr << reply.error() << std::endl;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
bool IsmImportBuildings::handleReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
if (replyObject.error())
|
|
{
|
|
ERROR_LOG(m_logger) << "Got Reply error: " << replyObject.translated();
|
|
std::cerr << "Error importing building" << std::endl;
|
|
QCoreApplication::exit(1);
|
|
return false;
|
|
}
|
|
if (replyObject.id() > 0)
|
|
{
|
|
const QString buildingName = m_currentData.xmlFileName.split(QLatin1Char('.')).first();
|
|
NOTICE_LOG(m_logger) << "Imported building '" << buildingName << "' with id " << replyObject.id() << " (groupId = " << m_currentData.bauabschnitt << ")";
|
|
std::cerr << "Imported building '" << qPrintable(buildingName) << "' with id " << replyObject.id() << " (groupId = " << m_currentData.bauabschnitt << ")" << std::endl;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
|
{
|
|
public:
|
|
CmdLineParser()
|
|
: LtsCommandLineParser(ProvideCommandLineParameterOptions(TcpConnectionUrl | DomainId))
|
|
{
|
|
addOption({QStringList() << QLatin1String("f") << QLatin1String("importFileName"),
|
|
QLatin1String("Import buildings specified in csv file"),
|
|
QLatin1String("csv file")
|
|
});
|
|
addOption({QStringList() << QLatin1String("x") << QLatin1String("xmlFile"),
|
|
QLatin1String("Import building xml file"),
|
|
QLatin1String("xml file")
|
|
});
|
|
// v ist schon belegt ...
|
|
addOption({QStringList() << QLatin1String("y") << QLatin1String("vulnerabilityFile"),
|
|
QLatin1String("Import vulnerability (damage) xml file"),
|
|
QLatin1String("vul file")
|
|
});
|
|
addOption({QStringList() << QLatin1String("z") << QLatin1String("egcuToRoomFile"),
|
|
QLatin1String("Import Egcu to Room xml file"),
|
|
QLatin1String("egcu file")
|
|
});
|
|
addOption({QStringList() << QLatin1String("s") << QLatin1String("soundAreasFile"),
|
|
QLatin1String("Import SoundAreas xml file"),
|
|
QLatin1String("soundAreas file")
|
|
});
|
|
addOption({QStringList{QStringLiteral("r"), QStringLiteral("removeBuilding")},
|
|
QStringLiteral("Remove a building from the database (handle with care!). Can be given multiple times or as a comma-separated list"),
|
|
QStringLiteral("id")
|
|
});
|
|
addOption({QStringList() << QLatin1String("u") << QLatin1String("updateBuilding"),
|
|
QLatin1String("Update a building from the database (handle with care!)"),
|
|
QLatin1String("id")
|
|
});
|
|
addOption({ QStringList() << QLatin1String("p") << QLatin1String("position"),
|
|
QLatin1String("The position to place the building (lon,lat,z,rotationDegree)"),
|
|
QLatin1String("lon,lat,z,rotDegree")
|
|
});
|
|
addOption({QStringList() << QLatin1String("e") << QLatin1String("availableInExercise"),
|
|
QLatin1String("Make building available in exercise"),
|
|
QLatin1String("exerciseId")
|
|
});
|
|
addOption({QStringList() << QLatin1String("w") << QLatin1String("wirelessLocationId"),
|
|
QLatin1String("The external wls id to use for this building (default: 0)"),
|
|
QLatin1String("externalWlsId")
|
|
});
|
|
}
|
|
QString csvFile() const { return value(QLatin1String("f")); }
|
|
QString xmlFile() const { return value(QLatin1String("x")); }
|
|
QString vulnerabilityFile() const { return value(QLatin1String("y")); }
|
|
QString egcuToRoomFile() const { return value(QLatin1String("z")); }
|
|
QString soundAreaFile() const { return value(QLatin1String("s")); }
|
|
|
|
bool removeBuilding() const { return isSet(QLatin1String("r")); }
|
|
|
|
QVector<int> removeBuildingIds() const
|
|
{
|
|
QVector<int> ids;
|
|
|
|
const auto optionValues = values(QStringLiteral("r"));
|
|
for (const auto &optionValue : optionValues)
|
|
{
|
|
const auto idsAsString = optionValue.split(QLatin1Char(','));
|
|
for (const auto &idAsString : idsAsString)
|
|
ids.push_back(idAsString.toInt());
|
|
}
|
|
|
|
return ids;
|
|
}
|
|
|
|
bool updateBuilding() const { return isSet(QLatin1String("u")); }
|
|
int updateBuildingId() const { return value(QLatin1String("u")).toInt(); }
|
|
|
|
int availableExerciseId() const { return value(QLatin1String("e")).toInt(); }
|
|
int externalWlsId() const { return value(QLatin1String("w")).toInt(); }
|
|
|
|
QString positionString() const { return value(QLatin1String("p")); }
|
|
};
|
|
|
|
static bool parsePositionString(const QStringRef &positionString,
|
|
Core::GeoPosition &pos,
|
|
double &rotationDegree)
|
|
{
|
|
QVector<QStringRef> parts = positionString.split(QLatin1Char(','));
|
|
if (parts.size() != 4)
|
|
return false;
|
|
bool bOk;
|
|
pos.lon(parts.at(0).toDouble(&bOk));
|
|
if (!bOk)
|
|
return false;
|
|
pos.lat(parts.at(1).toDouble(&bOk));
|
|
if (!bOk)
|
|
return false;
|
|
pos.z(parts.at(2).toDouble(&bOk));
|
|
if (!bOk)
|
|
return false;
|
|
rotationDegree = parts.at(3).toDouble(&bOk);
|
|
if (!bOk)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
struct csvFileIndex
|
|
{
|
|
csvFileIndex()
|
|
{
|
|
reset();
|
|
}
|
|
int idxXmlFile;
|
|
int idxVulnerabilityFile;
|
|
int idxPosition;
|
|
int idxEgcuToRoomFile;
|
|
int idxExternalWlsId;
|
|
int idxBauabschnitt; // akn groupId
|
|
|
|
void reset()
|
|
{
|
|
idxXmlFile = 0;
|
|
idxVulnerabilityFile = 1;
|
|
idxPosition = 2;
|
|
// optional
|
|
idxEgcuToRoomFile = -1;
|
|
idxExternalWlsId = -1;
|
|
idxBauabschnitt = -1;
|
|
}
|
|
|
|
bool parseHeader(QString &headerline)
|
|
{
|
|
// should look like:
|
|
// #xmlFile;vulnerabilityFile;position
|
|
// #xmlFile;vulnerabilityFile;egcuToRoomFile;position
|
|
|
|
std::cout << " detecting order of columns: '" << headerline << "'" << std::endl;
|
|
std::cerr << " (#xmlFile;vulnerabilityFile;[egcuToRoomFile];position,[externalWlsId])" << std::endl;
|
|
|
|
headerline = headerline.trimmed();
|
|
if (headerline.startsWith(QLatin1Char('#')))
|
|
headerline.remove(0, 1);
|
|
else
|
|
{
|
|
std::cerr << " no header found, assume defaults..." << std::endl;
|
|
reset();
|
|
return true; // use defaults
|
|
}
|
|
|
|
QStringList sl = headerline.split(QLatin1Char(';'));
|
|
idxXmlFile = sl.indexOf(QStringLiteral("xmlFile"));
|
|
idxVulnerabilityFile = sl.indexOf(QStringLiteral("vulnerabilityFile"));
|
|
idxPosition = sl.indexOf(QStringLiteral("position"));
|
|
// optional:
|
|
idxEgcuToRoomFile = sl.indexOf(QStringLiteral("egcuToRoomFile"));
|
|
idxExternalWlsId = sl.indexOf(QStringLiteral("externalWlsId"));
|
|
idxBauabschnitt = sl.indexOf(QStringLiteral("bauabschnitt"));
|
|
|
|
std::cout << " detect following order: " << std::endl;
|
|
std::cout << " idxXmlFile= " << idxXmlFile << std::endl;
|
|
std::cout << " idxVulnerabilityFile= " << idxVulnerabilityFile << std::endl;
|
|
std::cout << " idxPosition= " << idxPosition << std::endl;
|
|
std::cout << " idxEgcuToRoomFile= " << idxEgcuToRoomFile << std::endl;
|
|
std::cout << " idxExternalWlsId= " << idxExternalWlsId << std::endl;
|
|
std::cout << " idxBauabschnitt= " << idxBauabschnitt << std::endl;
|
|
|
|
if ((idxXmlFile >= 0) && (idxVulnerabilityFile >= 0) && (idxPosition >= 0))
|
|
return true;
|
|
else
|
|
{
|
|
std::cerr << " parsing header failed, assume defaults..." << std::endl;
|
|
reset();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
int main(int argc, char **argv)
|
|
{
|
|
NGLCoreApplication app(argc, argv);
|
|
app.createLogger("ISM", 0);
|
|
|
|
NOTICE_LOG(app.baseLogger()) << "Starting...";
|
|
|
|
CmdLineParser options;
|
|
if (!options.init())
|
|
{
|
|
FATAL_LOG(app.baseLogger()) << "init failed";
|
|
std::cerr << "init failed" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
int iRet = -1;
|
|
{
|
|
std::unique_ptr<InfrastructureManagement::IsmImportBuildings> importXml(new InfrastructureManagement::IsmImportBuildings);
|
|
if (!importXml->init(options.domainId(), options.tcpConnectionUrl()))
|
|
{
|
|
FATAL_LOG(app.baseLogger()) << "Can not init, domainId=" << options.domainId() << ", tcpConnectionUrl: '" << options.tcpConnectionUrl().toDisplayString() << "'";
|
|
std::cerr << "Can not init, domainId=" << options.domainId() << ", tcpConnectionUrl: '" << options.tcpConnectionUrl().toDisplayString() << "'" << std::endl;
|
|
return -2;
|
|
}
|
|
|
|
if (options.removeBuilding())
|
|
importXml->remove(options.removeBuildingIds());
|
|
else
|
|
{
|
|
const QString csvFile = options.csvFile();
|
|
NOTICE_LOG(app.baseLogger()) << "using csvFile '" << csvFile << "'";
|
|
if (csvFile.isEmpty())
|
|
{
|
|
InfrastructureManagement::IsmImportBuildings::ImportData data;
|
|
const QString ps = options.positionString();
|
|
if (!parsePositionString(QStringRef(&ps), data.geoPos, data.angleDegree))
|
|
{
|
|
ERROR_LOG(app.baseLogger()) << "Error parsing position string! str='" << ps << "'" ;
|
|
std::cerr << "Error parsing position string! str='" << ps << "'" << std::endl;
|
|
return -3;
|
|
}
|
|
data.xmlFileName = options.xmlFile();
|
|
data.vulFileName = options.vulnerabilityFile();
|
|
data.egcuToRoomFileName = options.egcuToRoomFile();
|
|
data.soundAreaFileName = options.soundAreaFile();
|
|
data.exerciseId = options.availableExerciseId();
|
|
data.bauabschnitt = 1;
|
|
data.externalWlsId = options.externalWlsId();
|
|
if (options.updateBuilding())
|
|
data.buildingId = options.updateBuildingId();
|
|
importXml->import(data);
|
|
}
|
|
else
|
|
{
|
|
QFile f(csvFile);
|
|
if (!f.open(QIODevice::ReadOnly))
|
|
{
|
|
WARNING_LOG(app.baseLogger()) << "Can not open file '" << csvFile << "' for reading: " << f.errorString();
|
|
std::cerr << "Can not open file '" << csvFile << "' for reading: " << f.errorString() << std::endl;
|
|
return -4;
|
|
}
|
|
|
|
QTextStream ts(&f);
|
|
QString line;
|
|
csvFileIndex cfi;
|
|
bool bIsHeaderParesed = false;
|
|
InfrastructureManagement::IsmImportBuildings::ImportData data;
|
|
// exerciseId
|
|
data.exerciseId = options.availableExerciseId();
|
|
|
|
QVector<InfrastructureManagement::IsmImportBuildings::ImportData> dataVec;
|
|
while (ts.readLineInto(&line))
|
|
{
|
|
std::cerr << "line '" << line << "'" << std::endl;
|
|
|
|
// read header (at first line)
|
|
if (!bIsHeaderParesed)
|
|
{
|
|
bIsHeaderParesed = true;
|
|
line = line.trimmed();
|
|
if (line.startsWith(QLatin1Char('#')))
|
|
{
|
|
cfi.parseHeader(line);
|
|
continue;
|
|
} else {
|
|
std::cerr << " no header found, assume defaults..." << std::endl;
|
|
}
|
|
}
|
|
|
|
const QVector<QStringRef> parts = line.splitRef(QLatin1Char(';'));
|
|
if (parts.size() < 3 || parts.size() > 6)
|
|
{
|
|
WARNING_LOG(app.baseLogger()) << "Can not parse line: '" << line << "' - skipping";
|
|
continue;
|
|
}
|
|
|
|
// xmlFile
|
|
data.xmlFileName = parts.at(cfi.idxXmlFile).toString();
|
|
|
|
// vulnerabilityFile
|
|
data.vulFileName = parts.at(cfi.idxVulnerabilityFile).toString();
|
|
|
|
// position
|
|
if (!parsePositionString(parts.at(cfi.idxPosition), data.geoPos, data.angleDegree))
|
|
{
|
|
ERROR_LOG(app.baseLogger()) << "Can not parse position string of line = '" << line << "'";
|
|
std::cerr << "Can not parse position string of line = '" << line << "'" << std::endl;
|
|
ERROR_LOG(app.baseLogger()) << "Can not parse position string: '" << parts.at(cfi.idxPosition).toString() << "'";
|
|
std::cerr << "Can not parse position string: '" << parts.at(cfi.idxPosition).toString() << "'" << std::endl;
|
|
return -5;
|
|
}
|
|
|
|
//
|
|
// optional:
|
|
//
|
|
// egcuToRoomFile
|
|
if ((cfi.idxEgcuToRoomFile>=0) && (parts.size() > cfi.idxEgcuToRoomFile))
|
|
data.egcuToRoomFileName = parts.at(cfi.idxEgcuToRoomFile).toString();
|
|
|
|
// externalWlsId
|
|
data.externalWlsId = 0;
|
|
if ((cfi.idxExternalWlsId>=0) && (parts.size() > cfi.idxExternalWlsId))
|
|
data.externalWlsId = parts.at(cfi.idxExternalWlsId).toInt();
|
|
|
|
// bauabschnitt
|
|
// Normally '-1', but Steve and Iuliana use '0' as default.
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::UnknownGroup;
|
|
if ((cfi.idxBauabschnitt>=0) && (parts.size() > cfi.idxBauabschnitt))
|
|
{
|
|
// postprocessing uses ba0 -> 0 , ba1 -> 1 ...
|
|
// DB: ism.ism_buildung_group is different: Section0 -> 2 ; Section1 = 3 ; ...
|
|
const int ba = parts.at(cfi.idxBauabschnitt).toInt();
|
|
switch (ba) {
|
|
case 0:
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section0;
|
|
break;
|
|
case 1:
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section1;
|
|
break;
|
|
case 2:
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section2;
|
|
break;
|
|
case 3:
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section3;
|
|
break;
|
|
case 4:
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section4;
|
|
break;
|
|
case 5:
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Salchau;
|
|
break;
|
|
default:
|
|
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::UnknownGroup;
|
|
break;
|
|
}
|
|
}
|
|
|
|
dataVec += data;
|
|
} // while
|
|
importXml->import(dataVec);
|
|
}
|
|
}
|
|
|
|
STARTUP_LOG(app.baseLogger());
|
|
|
|
iRet = app.exec();
|
|
|
|
SHUTDOWN_LOG(app.baseLogger());
|
|
}
|
|
return iRet;
|
|
}
|