ddl/mapping/configuration/map_configuration.cpp
2019-12-12 14:41:47 +01:00

1283 lines
37 KiB
C++

/**
* @file
*
* @copyright
* @verbatim
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
This Source Code Form is subject to the terms of the Mozilla
Public License, v. 2.0. If a copy of the MPL was not distributed
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
@endverbatim
*/
#include "map_configuration.h"
#include <algorithm>
#include "a_util/result/error_def.h"
#include "legacy_error_macros.h"
#include "ddlrepresentation/ddlelement.h"
#include "ddlrepresentation/ddlcomplex.h"
#include "ddlrepresentation/ddldatatype.h"
#include "mapping/ddl_helper.h"
namespace mapping
{
namespace oo
{
//define all needed error types and values locally
_MAKE_RESULT(-5, ERR_INVALID_ARG)
_MAKE_RESULT(-9, ERR_INVALID_FLAGS)
_MAKE_RESULT(-11, ERR_INVALID_FILE)
_MAKE_RESULT(-19, ERR_NOT_SUPPORTED)
_MAKE_RESULT(-20, ERR_NOT_FOUND)
_MAKE_RESULT(-38, ERR_FAILED)
_MAKE_RESULT(-40, ERR_INVALID_STATE)
_MAKE_RESULT(-42, ERR_INVALID_TYPE)
}
}
using namespace mapping::oo;
MapConfiguration::MapConfiguration()
: _ddl_ref(NULL)
, _checked_for_consistency(false)
, _is_consistent(false)
{
}
MapConfiguration::MapConfiguration(const ddl::DDLDescription* pDDL)
: _ddl_ref(pDDL)
, _checked_for_consistency(false)
, _is_consistent(false)
{
}
MapConfiguration::~MapConfiguration()
{
reset();
}
MapConfiguration::MapConfiguration(const MapConfiguration& oOther)
{
_ddl_ref = oOther._ddl_ref;
_header = oOther._header;
_sources = oOther._sources;
_targets = oOther._targets;
_checked_for_consistency = oOther._checked_for_consistency;
_is_consistent = oOther._is_consistent;
for (MapTransformationList::const_iterator it = oOther._transforms.begin();
it != oOther._transforms.end(); ++it)
{
_transforms.push_back((*it)->clone());
}
repairConfigReferences(*this);
}
MapConfiguration& MapConfiguration::operator=(const MapConfiguration& oOther)
{
MapConfiguration oCopy(oOther);
oCopy.swap(*this);
return *this;
}
void MapConfiguration::reset()
{
_errors.clear();
_header.reset();
_sources.clear();
_targets.clear();
_checked_for_consistency = false;
_is_consistent = false;
for (MapTransformationList::iterator it = _transforms.begin();
it != _transforms.end(); ++it)
{
delete *it;
}
_transforms.clear();
}
a_util::result::Result MapConfiguration::loadFromFile(const std::string& strFilePath,
uint32_t ui32Flags)
{
a_util::xml::DOM oDom;
if(!oDom.load(strFilePath))
{
appendError(oDom.getLastError());
return ERR_INVALID_FILE;
}
return loadFromDOM(oDom, ui32Flags);
}
a_util::result::Result MapConfiguration::loadFromDOM(a_util::xml::DOM& oDom, uint32_t ui32Flags)
{
bool bLoad = (ui32Flags & mc_load_mapping) == mc_load_mapping;
bool bMerge = (ui32Flags & mc_merge_mapping) == mc_merge_mapping;
// only one of them supported
if (!(bLoad | bMerge))
{
return ERR_NOT_SUPPORTED;
}
// Clear list and verify ddl description exists
resetErrors();
// we parse into a temporary config to be able to check for validity before
// overwriting/resetting the current configuration
MapConfiguration oTmp(_ddl_ref);
if (isFailed(MapConfiguration::loadMappingFromDOM(oDom, oTmp)))
{
// preserve errors
std::swap(_errors, oTmp._errors);
return ERR_FAILED;
}
if (bLoad)
{
// check for consistency
if (isFailed(oTmp.checkMappingConsistency()))
{
// preserve errors
std::swap(_errors, oTmp._errors);
return ERR_FAILED;
}
if (isFailed(oTmp.checkDDLConsistency()))
{
// preserve errors
std::swap(_errors, oTmp._errors);
return ERR_INVALID_TYPE;
}
// the config should replace the current one -> swap
swap(oTmp);
}
else if (bMerge)
{
// since we allow partial mapping configurations,
// we need to merge before checking consistency
MapConfiguration oCopy(*this);
a_util::result::Result nResult = oCopy.merge(oTmp);
if (isOk(nResult))
{
nResult = oCopy.checkMappingConsistency();
}
if (isFailed(nResult))
{
// preserve errors
std::swap(_errors, oCopy._errors);
return ERR_FAILED;
}
if (isFailed(oCopy.checkDDLConsistency()))
{
// preserve errors
std::swap(_errors, oCopy._errors);
return ERR_INVALID_TYPE;
}
// all ok? now we can swap
swap(oCopy);
}
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::loadFromDOMWithoutDDLConsistency(a_util::xml::DOM& oDom,
uint32_t ui32Flags)
{
bool bLoad = (ui32Flags & mc_load_mapping) == mc_load_mapping;
bool bMerge = (ui32Flags & mc_merge_mapping) == mc_merge_mapping;
// only one of them supported
if (!(bLoad | bMerge))
{
return ERR_NOT_SUPPORTED;
}
// Clear list
_errors.clear();
// we parse into a temporary config to be able to check for validity before
// overwriting/resetting the current configuration
MapConfiguration oTmp(_ddl_ref);
if (isFailed(MapConfiguration::loadMappingFromDOM(oDom, oTmp)))
{
// preserve errors
std::swap(_errors, oTmp._errors);
return ERR_FAILED;
}
if (bLoad)
{
// check for consistency
if (isFailed(oTmp.checkMappingConsistency()))
{
// preserve errors
std::swap(_errors, oTmp._errors);
return ERR_FAILED;
}
// the config should replace the current one -> swap
swap(oTmp);
}
else if (bMerge)
{
// since we allow partial mapping configurations,
// we need to merge before checking consistency
MapConfiguration oCopy(*this);
a_util::result::Result nResult = oCopy.merge(oTmp);
if (isOk(nResult))
{
nResult = oCopy.checkMappingConsistency();
}
if (isFailed(nResult))
{
// preserve errors
std::swap(_errors, oCopy._errors);
return ERR_FAILED;
}
// all ok? now we can swap
swap(oCopy);
}
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::loadPartiallyFromFile(const std::string& strFilePath,
uint32_t ui32Flags)
{
a_util::xml::DOM oDom;
if(!oDom.load(strFilePath))
{
appendError(oDom.getLastError());
return ERR_INVALID_FILE;
}
return loadPartiallyFromDOM(oDom, ui32Flags);
}
a_util::result::Result MapConfiguration::loadPartiallyFromDOM(a_util::xml::DOM& oDom,
uint32_t ui32Flags)
{
_errors.clear();
bool bLoad = (ui32Flags & mc_load_mapping) == mc_load_mapping;
bool bMerge = (ui32Flags & mc_merge_mapping) == mc_merge_mapping;
// only one of them supported
if (!(bLoad | bMerge))
{
return ERR_INVALID_FLAGS;
}
// we parse into a temporary config to be able to check for validity before
// overwriting/resetting the current configuration
MapConfiguration oTmp(_ddl_ref);
// IF is failed, map-file is corrupted
if (isFailed(MapConfiguration::loadMappingFromDOM(oDom, oTmp)))
{
// preserve errors
std::swap(_errors, oTmp._errors);
return ERR_FAILED;
}
a_util::result::Result nResult = a_util::result::SUCCESS;
if (bLoad)
{
// check for consistency
if (isFailed(oTmp.checkMappingConsistency()))
{
std::swap(_errors, oTmp._errors);
return ERR_FAILED;
}
//Check DDL consistency only to set the validity booleans
nResult = oTmp.checkDDLConsistency();
// the config should replace the current one -> swap
swap(oTmp);
}
else if (bMerge)
{
// since we allow partial mapping configurations,
// we need to merge before checking consistency
MapConfiguration oCopy(*this);
nResult = oCopy.merge(oTmp);
if (isOk(nResult))
{
nResult = oCopy.checkMappingConsistency();
}
if (isFailed(nResult))
{
// preserve errors
std::swap(_errors, oCopy._errors);
return ERR_FAILED;
}
//Check DDL consistency only to set the validity booleans
nResult = oCopy.checkDDLConsistency();
// all ok? now we can swap
swap(oCopy);
}
return nResult;
}
a_util::result::Result MapConfiguration::writeToFile(const std::string& strFilePath)
{
a_util::xml::DOM oDom;
oDom.fromString("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>");
a_util::result::Result nRes = writeToDOM(oDom);
if(isOk(nRes))
{
if(!oDom.save(strFilePath))
{
appendError(oDom.getLastError());
nRes = ERR_INVALID_FILE;
}
}
return nRes;
}
a_util::result::Result MapConfiguration::writeToDOM(a_util::xml::DOM& oDom)
{
resetErrors();
// Verify consistency
RETURN_IF_FAILED(checkMappingConsistency());
RETURN_IF_FAILED(checkDDLConsistency());
oDom.reset();
a_util::xml::DOMElement oRoot = oDom.getRoot();
// set <header>
a_util::xml::DOMElement oHeader = oRoot.createChild("header");
RETURN_IF_FAILED(_header.writeToDOM(oHeader));
// set <sources>
a_util::xml::DOMElement oSourcesElement = oRoot.createChild("sources");
for(MapSourceList::const_iterator itSrc = _sources.begin(); itSrc != _sources.end(); itSrc++)
{
a_util::xml::DOMElement oSourceElement = oSourcesElement.createChild("source");
RETURN_IF_FAILED(itSrc->writeToDOM(oSourceElement));
}
// set <targets>
a_util::xml::DOMElement oTargetsElement = oRoot.createChild("targets");
for(MapTargetList::const_iterator itTrg = _targets.begin(); itTrg != _targets.end(); itTrg++)
{
a_util::xml::DOMElement oTargetElement = oTargetsElement.createChild("target");
RETURN_IF_FAILED(itTrg->writeToDOM(oTargetElement));
}
// set <transformations>
a_util::xml::DOMElement oTransformationsElement = oRoot.createChild("transformations");
for(MapTransformationList::const_iterator itTransform = _transforms.begin(); itTransform != _transforms.end(); itTransform++)
{
a_util::xml::DOMElement oTransformationElement = oTransformationsElement.createChild("");
RETURN_IF_FAILED((*itTransform)->writeToDOM(oTransformationElement));
}
// the root <mapping> element
oRoot.setName("mapping");
return a_util::result::SUCCESS;
}
const MapHeader& MapConfiguration::getHeader() const
{
return _header;
}
a_util::result::Result MapConfiguration::setHeaderDescription(const std::string& desc)
{
return _header.setDescription(desc);
}
a_util::result::Result MapConfiguration::setHeaderDdlPaths(const std::string& strDdl)
{
return _header.setDdlPaths(strDdl);
}
const std::string& MapConfiguration::getHeaderDdlPaths() const
{
return _header.getDllPaths();
}
const MapTransformationList& MapConfiguration::getTransformationList() const
{
return _transforms;
}
const MapTransformationBase* MapConfiguration::
getTransformation(const std::string& strTransformationName) const
{
for (MapTransformationList::const_iterator it = _transforms.begin();
it != _transforms.end(); ++it)
{
if ((*it)->getName() == strTransformationName)
{
return *it;
}
}
return NULL;
}
MapTransformationBase* MapConfiguration::getTransformation(const std::string& strTransformationName)
{
for (MapTransformationList::iterator it = _transforms.begin();
it != _transforms.end(); ++it)
{
if ((*it)->getName() == strTransformationName)
{
return *it;
}
}
return NULL;
}
a_util::result::Result MapConfiguration::addTransformation(const std::string& strTransformationName, const std::string& strTransformationType)
{
if(getTransformation(strTransformationName))
{
appendError("A transformation with this name already exists");
return ERR_INVALID_ARG;
}
MapTransformationBase* pTrans = NULL;
RETURN_IF_FAILED(MapTransformationBase::create(this, strTransformationName, strTransformationType, pTrans));
_transforms.push_back(pTrans);
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::removeTransformation(const std::string& strTransformationName)
{
_errors.clear();
if(strTransformationName.empty())
{
return a_util::result::SUCCESS;
}
for(MapTransformationList::iterator itTrf = _transforms.begin(); itTrf != _transforms.end(); itTrf++)
{
if((*itTrf)->getName() == strTransformationName)
{
// Remove all assignments that use this transformation
for (MapTargetList::iterator it = _targets.begin();
it != _targets.end(); ++it)
{
// Copy from list to remove assignments form original list
// while iterating through the copy
MapAssignmentList oAssignList = it->getAssignmentList();
for (MapAssignmentList::iterator itA = oAssignList.begin();
itA != oAssignList.end(); ++itA)
{
if(itA->getTransformation() == strTransformationName)
{
RETURN_IF_FAILED(it->removeAssignmentWithoutClear(itA->getTo()));
}
}
}
delete *itTrf;
_transforms.erase(itTrf);
return a_util::result::SUCCESS;
}
}
return ERR_NOT_FOUND;
}
const MapSource* MapConfiguration::getSource(const std::string& strSourceName) const
{
for (MapSourceList::const_iterator it = _sources.begin();
it != _sources.end(); ++it)
{
if (it->getName() == strSourceName)
{
return &(*it);
}
}
return NULL;
}
MapSource* MapConfiguration::getSource(const std::string& strSourceName)
{
for (MapSourceList::iterator it = _sources.begin();
it != _sources.end(); ++it)
{
if (it->getName() == strSourceName)
{
return &(*it);
}
}
return NULL;
}
a_util::result::Result MapConfiguration::addSource(const std::string& name, const std::string& strType)
{
RETURN_IF_FAILED(resetErrors());
RETURN_IF_FAILED(checkSignalType(strType));
MapSource oSource(this, name, strType);
return addSource(oSource);
}
a_util::result::Result MapConfiguration::removeSource(const std::string& name)
{
_errors.clear();
for (MapTargetList::iterator it = _targets.begin();
it != _targets.end(); ++it)
{
// Copy from list to remove assignments form original list
// while iterating through the copy
MapAssignmentList oAssignList = it->getAssignmentList();
for (MapAssignmentList::iterator itA = oAssignList.begin();
itA != oAssignList.end(); ++itA)
{
if(itA->getSource() == name)
{
RETURN_IF_FAILED(it->removeAssignmentWithoutClear(itA->getTo()));
}
}
// Copy from list to remove triggers form original list
// while iterating through the copy
MapTriggerList oTriggerList = it->getTriggerList();
for (MapTriggerList::iterator itTrigger = oTriggerList.begin();
itTrigger != oTriggerList.end(); ++itTrigger)
{
if((*itTrigger)->getSourceDependency() == name)
{
RETURN_IF_FAILED(it->removeTrigger(*itTrigger));
}
}
}
for (MapSourceList::iterator it = _sources.begin();
it != _sources.end(); ++it)
{
if (it->getName() == name)
{
_sources.erase(it);
return a_util::result::SUCCESS;
}
}
return ERR_NOT_FOUND;
}
const MapSourceList& MapConfiguration::getSourceList() const
{
return _sources;
}
const MapTarget* MapConfiguration::getTarget(const std::string& strTargetName) const
{
for (MapTargetList::const_iterator it = _targets.begin();
it != _targets.end(); ++it)
{
if (it->getName() == strTargetName)
{
return &(*it);
}
}
return NULL;
}
MapTarget* MapConfiguration::getTarget(const std::string& strTargetName)
{
for (MapTargetList::iterator it = _targets.begin();
it != _targets.end(); ++it)
{
if (it->getName() == strTargetName)
{
return &(*it);
}
}
return NULL;
}
a_util::result::Result MapConfiguration::addTarget(const std::string& name, const std::string& strType)
{
RETURN_IF_FAILED(resetErrors());
RETURN_IF_FAILED(checkSignalType(strType));
MapTarget oTarget(this, name, strType);
return addTarget(oTarget);
}
a_util::result::Result MapConfiguration::removeTarget(const std::string& _name)
{
_errors.clear();
for (MapTargetList::iterator it = _targets.begin();
it != _targets.end(); ++it)
{
if (it->getName() == _name)
{
_targets.erase(it);
return a_util::result::SUCCESS;
}
}
return ERR_NOT_FOUND;
}
const MapTargetList& MapConfiguration::getTargetList() const
{
return _targets;
}
a_util::result::Result MapConfiguration::setDescription(const ddl::DDLDescription* pDDL)
{
_ddl_ref = pDDL;
MapConfiguration oCopy = *this;
oCopy._ddl_ref = pDDL;
// reset mapping configuration if we got a ddl that doesn't fit to the current mapping config
if (isFailed(oCopy.checkDDLConsistency()))
{
reset();
}
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::setDescriptionWithoutConsistency(const ddl::DDLDescription* pDDL)
{
_ddl_ref = pDDL;
_checked_for_consistency = false;
_is_consistent = false;
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::modifyDescription(const ddl::DDLDescription* pDDL)
{
_ddl_ref = pDDL;
_errors.clear();
return checkDDLConsistency();
}
const ddl::DDLDescription* MapConfiguration::getDescription() const
{
return _ddl_ref;
}
const MapErrorList& MapConfiguration::getErrorList() const
{
return _errors;
}
a_util::result::Result MapConfiguration::resetErrors()
{
_errors.clear();
if (!_ddl_ref)
{
appendError("No Description found");
return ERR_INVALID_STATE;
}
return a_util::result::SUCCESS;
}
void MapConfiguration::swap(MapConfiguration& oOther)
{
using std::swap;
swap(_ddl_ref, oOther._ddl_ref);
swap(_header, oOther._header);
swap(_sources, oOther._sources);
swap(_targets, oOther._targets);
swap(_transforms, oOther._transforms);
swap(_errors, oOther._errors);
repairConfigReferences(*this);
repairConfigReferences(oOther);
}
void MapConfiguration::repairConfigReferences(MapConfiguration& oConfig)
{
// Sources
for(MapSourceList::iterator itSrc = oConfig._sources.begin(); itSrc != oConfig._sources.end(); itSrc++)
{
itSrc->_config = &oConfig;
}
// Targets
for(MapTargetList::iterator itTrg = oConfig._targets.begin(); itTrg != oConfig._targets.end(); itTrg++)
{
itTrg->_config = &oConfig;
for(MapTriggerList::iterator itTrigger = itTrg->_triggers.begin(); itTrigger != itTrg->_triggers.end(); itTrigger++)
{
(*itTrigger)->_config = &oConfig;
}
}
// Transformations
for(MapTransformationList::iterator itTrf = oConfig._transforms.begin(); itTrf != oConfig._transforms.end(); itTrf++)
{
(*itTrf)->_config = &oConfig;
}
}
a_util::result::Result MapConfiguration::addTarget(const MapTarget& oTarget)
{
RETURN_IF_FAILED(checkSignalName(oTarget.getName()));
_targets.push_back(oTarget);
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::addSource(const MapSource& oSource)
{
RETURN_IF_FAILED(checkSignalName(oSource.getName()));
_sources.push_back(oSource);
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::merge(const MapConfiguration& oOther)
{
MapConfiguration oCopy(*this);
const MapSourceList& lstSources = oOther.getSourceList();
for (MapSourceList::const_iterator it = lstSources.begin();
it != lstSources.end(); ++it)
{
const MapSource* pSrc = getSource(it->getName());
if (pSrc)
{
if (*pSrc != *it)
{
appendError(a_util::strings::format(
"Trying to merge conflicting source definition for '%s'",
it->getName().c_str()));
return ERR_INVALID_ARG;
}
}
else
{
RETURN_IF_FAILED(oCopy.addSource(*it));
}
}
const MapTargetList& lstTargets = oOther.getTargetList();
for (MapTargetList::const_iterator it = lstTargets.begin();
it != lstTargets.end(); ++it)
{
const MapTarget* pTarget = getTarget(it->getName());
if (pTarget)
{
if (*pTarget != *it)
{
appendError(a_util::strings::format(
"Trying to merge conflicting target definition for '%s'",
it->getName().c_str()));
return ERR_INVALID_ARG;
}
}
else
{
RETURN_IF_FAILED(oCopy.addTarget(*it));
}
}
const MapTransformationList& lstTrafos = oOther.getTransformationList();
for (MapTransformationList::const_iterator it = lstTrafos.begin();
it != lstTrafos.end(); ++it)
{
const MapTransformationBase* pSrc = getTransformation((*it)->getName());
if (pSrc)
{
if (!pSrc->isEqual(*(*it)))
{
appendError(a_util::strings::format(
"Trying to merge conflicting transformation definition for '%s'",
(*it)->getName().c_str()));
return ERR_INVALID_ARG;
}
}
else
{
oCopy._transforms.push_back((*it)->clone());
}
}
swap(oCopy);
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::loadMappingFromDOM(a_util::xml::DOM& oDom, MapConfiguration& oTmpConfig)
{
a_util::result::Result nResult = a_util::result::SUCCESS;
// the root <mapping> element
a_util::xml::DOMElement oMapping = oDom.getRoot();
if (oMapping.getName() != "mapping")
{
oTmpConfig.appendError("Missing <mapping> root element");
return ERR_INVALID_ARG; // no need to continue
}
// parse <header>
a_util::xml::DOMElement oElement = oMapping.getChild("header");
if (!oElement.isNull())
{
nResult = oTmpConfig._header.loadFromDOM(oElement, oTmpConfig._errors);
}
else
{
oTmpConfig.appendError("Missing <header> element");
nResult = ERR_INVALID_ARG;
}
// parse <sources>
oElement = oMapping.getChild("sources");
if (!oElement.isNull())
{
const a_util::xml::DOMElementList lstSources = oElement.getChildren();
for (a_util::xml::DOMElementList::const_iterator it = lstSources.begin();
it != lstSources.end(); ++it)
{
if (it->getName() == "source")
{
MapSource oSrc(&oTmpConfig);
a_util::result::Result nRes = oSrc.loadFromDOM(*it);
if (isOk(nRes))
{
nRes = oTmpConfig.addSource(oSrc);
}
if (isFailed(nRes))
{
nResult = nRes;
}
}
}
}
else
{
// optional
}
// parse <targets>
oElement = oMapping.getChild("targets");
if (!oElement.isNull())
{
const a_util::xml::DOMElementList lstTargets = oElement.getChildren();
for (a_util::xml::DOMElementList::const_iterator it = lstTargets.begin();
it != lstTargets.end(); ++it)
{
MapTarget oTarget(&oTmpConfig);
a_util::result::Result nRes = oTarget.loadFromDOM(*it);
if (isOk(nRes))
{
nRes = oTmpConfig.addTarget(oTarget);
}
if (isFailed(nRes))
{
nResult = nRes;
}
}
}
else
{
// optional
}
// parse <transformations>
oElement = oMapping.getChild("transformations");
if (!oElement.isNull())
{
const a_util::xml::DOMElementList lstTrans = oElement.getChildren();
for (a_util::xml::DOMElementList::const_iterator it = lstTrans.begin();
it != lstTrans.end(); ++it)
{
MapTransformationBase* pTrans = NULL;
a_util::result::Result nRes = MapTransformationBase::createFromDOM(&oTmpConfig,
*it, pTrans);
if(isOk(nRes))
{
oTmpConfig._transforms.push_back(pTrans);
}
else
{
nResult = nRes;
}
}
}
else
{
// optional
}
return nResult;
}
a_util::result::Result MapConfiguration::checkMappingConsistency()
{
a_util::result::Result nResult =a_util::result::SUCCESS;
// If import was succesful, check if the mapping is consistent
// All referenced Sources and Transformations must exist in Mapping
if(isOk(nResult))
{
for(MapTargetList::const_iterator itTrg = _targets.begin();
itTrg != _targets.end(); itTrg++)
{
for(MapTriggerList::const_iterator itTrigger = itTrg->getTriggerList().begin();
itTrigger != itTrg->getTriggerList().end(); itTrigger++)
{
if(isFailed((*itTrigger)->checkTriggerReferences()))
{
nResult = ERR_INVALID_ARG;
}
}
for(MapAssignmentList::const_iterator itAssign = itTrg->getAssignmentList().begin();
itAssign != itTrg->getAssignmentList().end(); itAssign++)
{
if(isFailed(checkAssignmentReferences(*itAssign)))
{
nResult = ERR_INVALID_ARG;
}
}
}
}
return nResult;
}
a_util::result::Result MapConfiguration::checkDDLConsistency()
{
a_util::result::Result nRes = a_util::result::SUCCESS;
// Sources
for (MapSourceList::iterator itSource = _sources.begin();
itSource != _sources.end(); ++itSource)
{
if(isOk(checkSignalType(itSource->getType())))
{
itSource->_is_valid = true;
}
else
{
itSource->_is_valid = false;
nRes = ERR_INVALID_TYPE;
}
}
// Targets
for (MapTargetList::iterator itTarget = _targets.begin();
itTarget != _targets.end(); ++itTarget)
{
if(isOk(checkSignalType(itTarget->getType())))
{
itTarget->_is_valid = true;
// Check Assignments type
const ddl::DDLComplex* pTargetStruct =
_ddl_ref->getStructByName(itTarget->getType());
for (MapAssignmentList::iterator itAssign = itTarget->_assignments.begin();
itAssign != itTarget->_assignments.end(); ++itAssign)
{
// Signal type was checked before, so pTargetStruct can be derefenrenced
if(isOk(checkAssignmentType(itTarget->getName(), *pTargetStruct, *itAssign)))
{
itAssign->_is_valid = true;
}
else
{
itAssign->_is_valid = false;
nRes = ERR_INVALID_TYPE;
}
}
// Set overlapping assignments to invalid
a_util::result::Result nResDouble = itTarget->checkDoubleAssignments();
if(isFailed(nResDouble))
{
nRes = nResDouble;
}
// Triggers
MapTriggerList& lstTrg = itTarget->_triggers;
for (MapTriggerList::iterator itTriggers = lstTrg.begin();
itTriggers != lstTrg.end(); ++itTriggers)
{
if(isOk(checkTriggerType(*itTriggers)))
{
(*itTriggers)->_is_valid = true;
}
else
{
(*itTriggers)->_is_valid = false;
nRes = ERR_INVALID_TYPE;
}
}
}
else
{
itTarget->_is_valid = false;
nRes = ERR_INVALID_TYPE;
}
}
// Transformations
for(MapTransformationList::iterator itTrf = _transforms.begin(); itTrf != _transforms.end(); itTrf++)
{
a_util::result::Result nResTrf = (*itTrf)->setTypeFromDDL();
if(isOk(nResTrf))
{
(*itTrf)->_is_valid = true;
}
else
{
(*itTrf)->_is_valid = false;
nRes = nResTrf;
}
}
if (isOk(nRes))
{
_is_consistent = true;
}
_checked_for_consistency = true;
return nRes;
}
a_util::result::Result MapConfiguration::findTypeObject(const std::string& strStruct,
const std::string& strPath, const ddl::IDDLDataType*& pType,
int& nArraySize) const
{
const ddl::DDLComplex* pStruct = _ddl_ref->getStructByName(strStruct);
if (pStruct)
{
return findTypeObject(*pStruct, strPath, pType, nArraySize);
}
return ERR_NOT_FOUND;
}
a_util::result::Result MapConfiguration::findTypeObject(const ddl::DDLComplex& oStruct,
const std::string& strPath, const ddl::IDDLDataType*& pType,
int& nArraySize) const
{
const ddl::DDLElement* pElem = NULL;
bool bIsArrayElement = false;
if (isFailed(DDLHelper::LookupElement(oStruct, strPath, pElem, bIsArrayElement)))
{
return ERR_NOT_FOUND;
}
if (pElem->isDynamic())
{
return ERR_INVALID_TYPE;
}
pType = pElem->getTypeObject();
nArraySize = pElem->getArraysize();
if (bIsArrayElement)
{
nArraySize = 1;
}
return a_util::result::SUCCESS;
}
bool MapConfiguration::checkTypeCompatibility(const ddl::IDDLDataType& oSource,
int nSourceArrSize, const ddl::IDDLDataType& oTarget, int nTargetArrSize) const
{
const ddl::DDLComplex* pSourceStruct = dynamic_cast<const ddl::DDLComplex*>(&oSource);
const ddl::DDLComplex* pTargetStruct = dynamic_cast<const ddl::DDLComplex*>(&oTarget);
if (pSourceStruct)
{
if (!pTargetStruct || pSourceStruct->getName() != pTargetStruct->getName())
{
return false;
}
}
if (pTargetStruct && !pSourceStruct)
{
return false;
}
if (nSourceArrSize != nTargetArrSize)
{
return false;
}
return true;
}
a_util::result::Result MapConfiguration::checkSignalName(const std::string& name) const
{
if(name.empty())
{
return ERR_INVALID_ARG;
}
std::set<std::string> lstSignalName;
for(MapSourceList::const_iterator it = _sources.begin(); it != _sources.end(); it++)
{
lstSignalName.insert(it->getName());
}
for(MapTargetList::const_iterator it = _targets.begin(); it != _targets.end(); it++)
{
lstSignalName.insert(it->getName());
}
if(lstSignalName.find(name) != lstSignalName.end())
{
appendError(a_util::strings::format("A signal with the name '%s' already exists",
name.c_str()));
return ERR_INVALID_ARG;
}
return a_util::result::SUCCESS;
}
a_util::result::Result MapConfiguration::checkSignalType(const std::string& strType) const
{
a_util::result::Result nRes= a_util::result::SUCCESS;
// Is the type defined in DDL
if (!_ddl_ref||!_ddl_ref->getStructByName(strType))
{
appendError(
a_util::strings::format("Unknown type '%s'",
strType.c_str()));
nRes = ERR_INVALID_TYPE;
}
return nRes;
}
a_util::result::Result MapConfiguration::checkAssignmentReferences(const MapAssignment& oAssignment) const
{
a_util::result::Result nRes = a_util::result::SUCCESS;
// Is the transformation known?
if (!oAssignment.getTransformation().empty() &&
!getTransformation(oAssignment.getTransformation()))
{
appendError(a_util::strings::format(
"Unknown <transformation> '%s' in <assignment> '%s'",
oAssignment.getTransformation().c_str(), oAssignment.getTo().c_str()));
nRes = ERR_INVALID_ARG;
}
// Is the source known?
if (!oAssignment.getSource().empty()&&!getSource(oAssignment.getSource()))
{
appendError(
a_util::strings::format("Unknown <source> '%s' in <assignment> '%s'",
oAssignment.getSource().c_str(), oAssignment.getTo().c_str()));
nRes = ERR_INVALID_ARG;
}
return nRes;
}
a_util::result::Result MapConfiguration::checkAssignmentType(const std::string& strSignalName, const ddl::DDLComplex& oSignalStruct, const MapAssignment& oAssignment) const
{
a_util::result::Result nRes= a_util::result::SUCCESS;
const std::string& strTo = oAssignment.getTo();
// Are From&To known in DDL and not dynamic?
int nArrSizeTo = 1;
const ddl::IDDLDataType* pTypeTo = NULL;
a_util::result::Result res = findTypeObject(oSignalStruct, strTo, pTypeTo, nArrSizeTo);
if (res == ERR_NOT_FOUND)
{
appendError(
a_util::strings::format("Target element '%s' unknown or invalid in <target> '%s'",
strTo.c_str(), strSignalName.c_str()));
nRes = ERR_INVALID_TYPE;
}
if (res == ERR_INVALID_TYPE)
{
appendError(
a_util::strings::format("Dynamic target elements are not allowed: '%s' in <target> '%s'",
strTo.c_str(), strSignalName.c_str()));
nRes = ERR_INVALID_TYPE;
}
// find Type for assigned value
const ddl::IDDLDataType* pTypeFrom = NULL;
int nArrSizeFrom = 1;
// If it is a received function, type must be bool
if(oAssignment.getFunction() == "received")
{
pTypeFrom = _ddl_ref->getDataTypeByName("tBool");
}
else if (!oAssignment.getSource().empty())
{
const MapSource* pSrcInstance = getSource(oAssignment.getSource());
const std::string& strFrom = oAssignment.getFrom();
if (!strFrom.empty()) // its a regular field assignment
{
if (isFailed(findTypeObject(pSrcInstance->getType(), strFrom,
pTypeFrom, nArrSizeFrom)))
{
appendError(a_util::strings::format(
"Source element '%s' unknown or invalid for <assignment> to '%s' in <target> '%s'",
strFrom.c_str(), strTo.c_str(), strSignalName.c_str()));
nRes = ERR_INVALID_TYPE;
}
}
else // its a whole signal assignment
{
// use source type for whole signal assignment
pTypeFrom = _ddl_ref->getStructByName(pSrcInstance->getType());
}
}
else // its a constant, a simulation_time or a trigger_counter
{
pTypeFrom = _ddl_ref->getDataTypeByName("tUInt64");
}
// Are From/Constant -> To type-compatible?
if (!checkTypeCompatibility(*pTypeFrom, nArrSizeFrom, *pTypeTo, nArrSizeTo))
{
appendError(a_util::strings::format("Incompatible types for <assignment> to '%s' in <target> '%s'",
strTo.c_str(), strSignalName.c_str()));
nRes = ERR_INVALID_TYPE;
}
return nRes;
}
a_util::result::Result MapConfiguration::checkTriggerType(const MapTriggerBase* pTrigger) const
{
const oo::MapDataTrigger* pMapDTrigger =
dynamic_cast<const oo::MapDataTrigger*>(pTrigger);
if(pMapDTrigger)
{
const MapSource* pSrcInstance = getSource(pMapDTrigger->getSource());
const ddl::IDDLDataType* pTypeVar = NULL;
int nArrSizeVar = 1;
if (isFailed(findTypeObject(pSrcInstance->getType(), pMapDTrigger->getVariable(),
pTypeVar, nArrSizeVar)))
{
appendError(a_util::strings::format(
"Source element '%s' type unknown or invalid for data <trigger> source '%s'",
pMapDTrigger->getVariable().c_str(), pMapDTrigger->getSource().c_str()));
return ERR_INVALID_TYPE;
}
const ddl::IDDLDataType* pTypeFrom = _ddl_ref->getDataTypeByName("tFloat64");
// Are Value -> Variable type-compatible?
if (!checkTypeCompatibility(*pTypeFrom, 1, *pTypeVar, nArrSizeVar))
{
appendError(a_util::strings::format("Data <trigger> variable '%s' in <source> '%s' should be comparable to a float value",
pMapDTrigger->getVariable().c_str(), pMapDTrigger->getSource().c_str()));
return ERR_INVALID_TYPE;
}
}
return a_util::result::SUCCESS;
}
void MapConfiguration::appendError(const std::string& m_strError) const
{
_errors.push_back(m_strError);
}
bool MapConfiguration::isConsistencyChecked()
{
return _checked_for_consistency;
}
bool MapConfiguration::isConsistent()
{
return _is_consistent;
}