331 lines
12 KiB
C++
331 lines
12 KiB
C++
|
|
|
|
#include "CppTopicGeneratorGrantlee.h"
|
|
|
|
#include "StructBuilder.h"
|
|
|
|
#include <NGLLogger/INGLLogger.h>
|
|
#include <QtCore/QCryptographicHash>
|
|
#include <ktexttemplate/context.h>
|
|
|
|
#ifdef RTI_HEADER_AVAILABLE
|
|
#include <dds/core/xtypes/EnumType.hpp>
|
|
#endif
|
|
|
|
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();
|
|
}
|
|
|
|
bool CppTopicGeneratorGrantlee::initDataTopics()
|
|
{
|
|
DataTopicsWrapper* dataTopicsWrapper = new DataTopicsWrapper(QString(), this);
|
|
const auto dataTopics = m_reader->getIdlStructInformation();
|
|
QVector<IdlData> keyColumns;
|
|
QVector<IdlData> 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<QString> exportedSubTopics;
|
|
DataTopicsWrapper* subTopicsWrapper = new DataTopicsWrapper(QString(), this);
|
|
const QVector<QSharedPointer<DataTypeInfo>> serializeTopics = m_structBuilder->getSerializeFromToJsonTopics();
|
|
for (const QSharedPointer<DataTypeInfo>& 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<MemberInformationListWrapper*> jsonTopics;
|
|
const QMap<QString, QVector<MemberInformation>> 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<IdlData>& keyColumns,
|
|
QVector<IdlData>& 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);
|
|
}
|
|
|
|
bool CppTopicGeneratorGrantlee::initFunctionTopics()
|
|
{
|
|
|
|
const QVector<FunctionTopic> 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;
|
|
}
|
|
|
|
bool CppTopicGeneratorGrantlee::handleIdlStruct(const CompleteTopicTypeInformation& csi, QSet<QString>& idlStructNames,
|
|
QVector<IdlStructWrapper*>& idlStructs)
|
|
{
|
|
if (!csi.isValid())
|
|
return true;
|
|
|
|
if (idlStructNames.contains(csi.name))
|
|
return true;
|
|
|
|
if (csi.hasBaseValue())
|
|
{
|
|
const CompleteTopicTypeInformation ctti =
|
|
m_structBuilder->topicTypeInformationByStructType(csi.baseValueType, false);
|
|
if (ctti.isValid())
|
|
{
|
|
#ifdef RTI_HEADER_AVAILABLE
|
|
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;
|
|
}
|
|
#else
|
|
// RTI not available - skip extensibility check (assume EXTENSIBLE)
|
|
Q_UNUSED(ctti.extensibility);
|
|
#endif
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Current structName: " << csi.name;
|
|
idlStructs += new IdlStructWrapper(csi, this);
|
|
|
|
idlStructNames.insert(csi.name);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CppTopicGeneratorGrantlee::initIdlStructs()
|
|
{
|
|
|
|
const QVector<CompleteTopicTypeInformation> csiData = m_structBuilder->topicTypeInformations();
|
|
|
|
QSet<QString> idlStructNames;
|
|
QVector<IdlStructWrapper*> idlStructs;
|
|
idlStructs.reserve(csiData.size());
|
|
for (const CompleteTopicTypeInformation& csi : csiData)
|
|
{
|
|
if (!handleIdlStruct(csi, idlStructNames, idlStructs))
|
|
return false;
|
|
}
|
|
|
|
m_ctx->insert(QStringLiteral("idl_structs"), QVariant::fromValue(idlStructs));
|
|
|
|
const QVector<EnumInformation> enumerations = m_structBuilder->enumInformations();
|
|
QVector<IdlEnumWrapper*> idlEnumerations;
|
|
idlEnumerations.reserve(enumerations.size());
|
|
for (const EnumInformation& ei : enumerations)
|
|
idlEnumerations += new IdlEnumWrapper(ei, this);
|
|
m_ctx->insert(QStringLiteral("idl_enums"), QVariant::fromValue(idlEnumerations));
|
|
|
|
exportUsedServices(m_reader);
|
|
return true;
|
|
}
|
|
|
|
CompleteTopicTypeInformation
|
|
CppTopicGeneratorGrantlee::topicTypeInformationByDerivedTopic(const CompleteTopicTypeInformation& tti) const
|
|
{
|
|
if (tti.baseValueType.isEmpty())
|
|
return CompleteTopicTypeInformation();
|
|
QString baseValueType = tti.baseValueType;
|
|
|
|
if (tti.name.contains(QLatin1String("::")) && !tti.baseValueType.contains(QLatin1String("::")))
|
|
{
|
|
const QStringList sl = tti.name.split(QStringLiteral("::"));
|
|
baseValueType = sl.at(0) + QLatin1String("::") + tti.baseValueType;
|
|
}
|
|
DEBUG_LOG(m_logger) << "topicTypeInformationByStructName(" << baseValueType << ")";
|
|
return m_structBuilder->topicTypeInformationByStructType(baseValueType);
|
|
}
|