355 lines
12 KiB
C++
Executable File
355 lines
12 KiB
C++
Executable File
/**
|
|
* @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 <QCryptographicHash>
|
|
#include <NGLLogger/INGLLogger.h>
|
|
#include <grantlee/context.h>
|
|
|
|
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<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);
|
|
}
|
|
|
|
/*
|
|
* FunctionTopics -> FunctionTopicWrapper
|
|
*/
|
|
bool CppTopicGeneratorGrantlee::initFunctionTopics()
|
|
{
|
|
//INFO_LOG(m_logger) << "IN CppFunctionTopicInterfaceGenerator:init()";
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* IDL / DDS -> IdlStructWrapper
|
|
*/
|
|
bool CppTopicGeneratorGrantlee::handleIdlStruct(const CompleteTopicTypeInformation &csi,
|
|
QSet<QString> &idlStructNames,
|
|
QVector<IdlStructWrapper *> &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<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;
|
|
}
|
|
// (!) No sorting of idlStruct since dependencies of idlStructs
|
|
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));
|
|
|
|
// 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<QStringRef> sl = tti.name.splitRef(QStringLiteral("::"));
|
|
baseValueType = sl.at(0) + QLatin1String("::") + tti.baseValueType;
|
|
}
|
|
DEBUG_LOG(m_logger) << "topicTypeInformationByStructName(" << baseValueType << ")";
|
|
return m_structBuilder->topicTypeInformationByStructType(baseValueType);
|
|
}
|