/** * @RDE_HEADER@ * Generate an dtc/dts interface file from idl-struct defined in a xml-file * $Id$ * $HeadURL$ * $Author$ * Created by Hanna E. Rathje, SLSE, 2016-01-05 */ #include "CppTopicGeneratorGrantlee.h" #include "StructBuilder.h" #include #include #include using namespace CodeGen; CppTopicGeneratorGrantlee::CppTopicGeneratorGrantlee() : GeneratorGrantleeBase("CodeGen.CppTopicGeneratorGrantlee") {} bool CppTopicGeneratorGrantlee::init(const XmlReader *reader, StructBuilder *structBuilder) { m_reader = reader; if (!GeneratorGrantleeBase::initInternal(reader, structBuilder)) return false; addCustomFunctions(reader->getCustomFunctions()); return initDataTopics() && initFunctionTopics() && initIdlStructs(); } /* * DataTopics -> DataTopicWrapper */ bool CppTopicGeneratorGrantlee::initDataTopics() { DataTopicsWrapper *dataTopicsWrapper = new DataTopicsWrapper(QString(), this); const auto dataTopics = m_reader->getIdlStructInformation(); QVector keyColumns; QVector trColumns; for (const CodeGen::TopicTypeInformation &tti : dataTopics) { if (!tti.isDataObject) continue; keyColumns.clear(); trColumns.clear(); const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(tti.name); if (!ctti.isValid()) { ERROR_LOG(m_logger) << "could not find informations for struct " << tti.name; continue; } DataTopicWrapper *dtw = dataTopicsWrapper->addDataTopic(ctti); getSpecialColumns(ctti, keyColumns, trColumns); if (keyColumns.size() == 1) dtw->setKeyColumnData(keyColumns.first()); dtw->setTrColumns(trColumns); if (ctti.recordTopic) { const CompleteTableInformation cti(m_structBuilder->getRecordingTopicTable(ctti.name)); if (!cti.isEmpty()) dtw->setRecordTableInformation(cti); } else { if (ctti.isDataObject) m_structBuilder->buildJSonStructureInformationFromIdlData(ctti); } } m_ctx->insert(QStringLiteral("dataTopics"), dataTopicsWrapper); QSet exportedSubTopics; DataTopicsWrapper *subTopicsWrapper = new DataTopicsWrapper(QString(), this); const QVector> serializeTopics = m_structBuilder->getSerializeFromToJsonTopics(); for (const QSharedPointer &dti : serializeTopics) { if (exportedSubTopics.contains(dti->idlType())) continue; if (dti->isStructure()) { const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(dti->idlType()); if (!ctti.isValid()) { ERROR_LOG(m_logger) << "could not find informations for struct " << dti->idlType(); continue; } const CompleteTableInformation cti(m_structBuilder->getRecordingTopicTable(ctti.name)); if (cti.isEmpty()) { ERROR_LOG(m_logger) << "could not find informations for struct " << dti->idlType(); continue; } DEBUG_LOG(m_logger) << "Adding substruct topic " << ctti.name; DataTopicWrapper *dtw = subTopicsWrapper->addDataTopic(ctti); dtw->setRecordTableInformation(cti); exportedSubTopics += dti->idlType(); } } m_ctx->insert(QStringLiteral("serializeTopics"), subTopicsWrapper); QVector jsonTopics; const QMap> jsonExport = m_structBuilder->jsonStructureInformation(); for (auto it = jsonExport.begin(); it != jsonExport.end(); ++it) { MemberInformationListWrapper *mil = new MemberInformationListWrapper(it.key(), it.value(), this); jsonTopics += mil; } m_ctx->insert(QStringLiteral("jsonTopics"), QVariant::fromValue(jsonTopics)); return true; } bool CppTopicGeneratorGrantlee::getSpecialColumns(const CompleteTopicTypeInformation &tti, QVector &keyColumns, QVector &trColumns) const { DEBUG_LOG(m_logger) << "Get special columns for " << tti.name << " - base is " << tti.baseValueType; if (!tti.isValid()) { ERROR_LOG(m_logger) << "tti is not valid ..."; return false; } for (const IdlData &ci : tti.members) { if (ci.isKey) keyColumns += ci; if (ci.isTranslatable) trColumns += ci; } if (tti.baseValueType.isEmpty()) return true; return getSpecialColumns(topicTypeInformationByDerivedTopic(tti), keyColumns, trColumns); } /* * FunctionTopics -> FunctionTopicWrapper */ bool CppTopicGeneratorGrantlee::initFunctionTopics() { //INFO_LOG(m_logger) << "IN CppFunctionTopicInterfaceGenerator:init()"; const QVector functionTopics = m_reader->getFunctionTopics(); FunctionTopicsWrapper *functionTopicsWrapper(new FunctionTopicsWrapper(QStringLiteral("functionTopics"), this)); for (const FunctionTopic &ft : functionTopics) { if (!handleStruct(ft, functionTopicsWrapper)) return false; } m_ctx->insert(QStringLiteral("functionTopics"), functionTopicsWrapper); return true; } bool CppTopicGeneratorGrantlee::handleStruct(const FunctionTopic &ft, FunctionTopicsWrapper *functionTopicsWrapper) { DEBUG_LOG(m_logger) << "handling FunctionTopic: " << ft.name; const CompleteTopicTypeInformation siRequest = m_structBuilder->topicTypeInformationByStructType(ft.requestTopicType); if (!siRequest.isValid()) { WARNING_LOG(m_logger) << "Could not get topic informations about request topic " << ft.requestTopicName; return false; } const CompleteTopicTypeInformation siReply = m_structBuilder->topicTypeInformationByStructType(ft.replyTopicType); if (!siReply.isValid()) { WARNING_LOG(m_logger) << "Could not get topic informations about reply topic " << ft.replyTopicType; return false; } FunctionTopicWrapper *ftw = functionTopicsWrapper->addFunctionTopic(ft, siRequest, siReply); const QByteArray hash = QCryptographicHash::hash(ft.requestTopicName.toUtf8(), QCryptographicHash::Sha3_512).toHex().left(16); ftw->setReplyHandlerHash(QStringLiteral("0x") + QString::fromLatin1(hash) + QStringLiteral("LL")); if (!addRequesterRequestParams(ft.name, siRequest, ftw) || !addRequesterReplyParams(ft.name, siReply, ftw)) return false; return true; } bool CppTopicGeneratorGrantlee::addRequesterRequestParams(const QString &request_name, const CompleteTopicTypeInformation &request, FunctionTopicWrapper *ftw) { if (request.hasBaseValue()) { const CompleteTopicTypeInformation siBase = m_structBuilder->topicTypeInformationByStructType(request.baseValueType); if (!siBase.isValid()) { WARNING_LOG(m_logger) << "Could not get topic informations about base request topic " << request.baseValueType; return false; } if (!addRequesterRequestParams(request_name, siBase, ftw)) return false; } ftw->addRequestParams(request.members); return true; } bool CppTopicGeneratorGrantlee::addRequesterReplyParams(const QString &request_name, const CompleteTopicTypeInformation &reply, FunctionTopicWrapper *ftw) { if (reply.hasBaseValue()) { const CompleteTopicTypeInformation siBase = m_structBuilder->topicTypeInformationByStructType(reply.baseValueType); if (!siBase.isValid()) { WARNING_LOG(m_logger) << "Could not get topic informations about base reply topic " << reply.baseValueType; return false; } if (!addRequesterReplyParams(request_name, siBase, ftw)) return false; } ftw->addReplyParams(reply.members); return true; } /* * IDL / DDS -> IdlStructWrapper */ bool CppTopicGeneratorGrantlee::handleIdlStruct(const CompleteTopicTypeInformation &csi, QSet &idlStructNames, QVector &idlStructs) { if (!csi.isValid()) return true; // Struct already exported? if (idlStructNames.contains(csi.name)) return true; //INFO_LOG(m_logger) << "handle idlStruct: " << csi.name << "\t : " << csi.baseValueType; // Is the baseStruct already exported & part of the current idl file? if (csi.hasBaseValue()) { const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(csi.baseValueType, false); if (ctti.isValid()) { if (ctti.extensibility == dds::core::xtypes::ExtensibilityKind_def::FINAL) { ERROR_LOG(m_logger) << "Base struct (" << ctti.name << ") has final extensibility - this is not allowed"; return false; } if (!idlStructNames.contains(csi.baseValueType)) { if (!handleIdlStruct(ctti, idlStructNames, idlStructs)) return false; } } else { const int idx = csi.baseValueType.indexOf(QLatin1String("::")); if (idx < 0) { ERROR_LOG(m_logger) << "idlStruct '" << csi.baseValueType << "' not found in idl-file"; return false; } } } // Are parts of columns idlStructs? for (const IdlData &idlData : csi.members) { QString idlType; DEBUG_LOG(m_logger) << "member: " << idlData.type << " - " << idlData.name << " " << idlData.dataTypeInfo->isStructure() << " " << idlData.dataTypeInfo->isSequence(); if (idlData.dataTypeInfo->isStructure()) idlType = idlData.dataTypeInfo->idlType(); else if (idlData.dataTypeInfo->isSequence()) { if (idlData.dataTypeInfo->innerDataType()->isStructure()) idlType = idlData.dataTypeInfo->innerDataType()->idlType(); } if (idlType.isEmpty()) continue; if (!handleIdlStruct(m_structBuilder->topicTypeInformationByStructType(idlType, false), idlStructNames, idlStructs)) return false; } // Handle current struct DEBUG_LOG(m_logger) << "Current structName: " << csi.name; idlStructs += new IdlStructWrapper(csi, this); // Add structName to list of exported idlStructs idlStructNames.insert(csi.name); return true; } bool CppTopicGeneratorGrantlee::initIdlStructs() { //INFO_LOG(m_logger) << "IN IdlGeneratorGrantlee:init()"; const QVector csiData = m_structBuilder->topicTypeInformations(); QSet idlStructNames; QVector idlStructs; idlStructs.reserve(csiData.size()); for (const CompleteTopicTypeInformation &csi : csiData) { if (!handleIdlStruct(csi, idlStructNames, idlStructs)) return false; } // (!) No sorting of idlStruct since dependencies of idlStructs m_ctx->insert(QStringLiteral("idl_structs"), QVariant::fromValue(idlStructs)); const QVector enumerations = m_structBuilder->enumInformations(); QVector idlEnumerations; idlEnumerations.reserve(enumerations.size()); for (const EnumInformation &ei : enumerations) idlEnumerations += new IdlEnumWrapper(ei, this); m_ctx->insert(QStringLiteral("idl_enums"), QVariant::fromValue(idlEnumerations)); // export the used services with the corresponding idl files exportUsedServices(m_reader); return true; } // Common CompleteTopicTypeInformation CppTopicGeneratorGrantlee::topicTypeInformationByDerivedTopic(const CompleteTopicTypeInformation &tti) const { if (tti.baseValueType.isEmpty()) return CompleteTopicTypeInformation(); QString baseValueType = tti.baseValueType; // if tti is from another service, baseValue is also from this other service // except it's from another service, then baseValue has '::' in it's name if (tti.name.contains(QLatin1String("::")) && !tti.baseValueType.contains(QLatin1String("::"))) { // Add Service name to baseValueType name const QVector sl = tti.name.splitRef(QStringLiteral("::")); baseValueType = sl.at(0) + QLatin1String("::") + tti.baseValueType; } DEBUG_LOG(m_logger) << "topicTypeInformationByStructName(" << baseValueType << ")"; return m_structBuilder->topicTypeInformationByStructType(baseValueType); }