/** * @RDE_HEADER@ * ISM Test Import XML * $Id$ * $HeadURL$ * $Author$ * Created by Iuliana Ojog, SLSE, 2016-11-28 */ #include "ism_import_buildings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace InfrastructureManagement; // ------------------------------------------------------------------------------ IsmImportBuildings::IsmImportBuildings(QObject *parent) : QObject(parent) , m_logger(getLogger("ImportXml")) { qRegisterMetaType("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) { 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 &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> 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> oldNamePaths; QVector 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 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 mainStructureElements = m_dtc->mainStructureElements(); for (auto it = mainStructureElements.constBegin(); it != mainStructureElements.constEnd(); ++it) { if (it.value().name() == name) return it.value(); } return MainStructureElement(); } // ------------------------------------------------------------------------------ QHash > IsmImportBuildings::MountingPointPlanByScheduleOfStructureElements(const QVector &structureElementIds) const { m_dtc->waitForHistoricalDataMainSchedule(); QHash > 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 IsmImportBuildings::mountingsOfStructureElements(const QVector &structureElementIds) const { m_dtc->waitForHistoricalDataMountingPointAsset(); QMap mountings = m_dtc->mountingPointAssets(); QVector result; for (auto it = mountings.constBegin(); it != mountings.constEnd(); ++it) { if (structureElementIds.contains(it.value().structureElementId())) result.append(it.value()); } return result; } // ------------------------------------------------------------------------------ QVector IsmImportBuildings::pathWithNames(const StructureElement &structureElement, const MainStructureElement &mainStructureElement) const { QVector 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 &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 > &oldNamePaths, const QVector &mountings, const QHash > &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 newMountingPointIds; for (const StructureElement &structureElement : newMainStructureElement.elements()) { if (structureElement.structureElementTypeId() != StructureElementType::MountingPoint) continue; newMountingPointIds.append(structureElement.id()); } QMap > 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 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 removeBuildingIds() const { QVector 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 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 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 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 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; }