You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
510 lines
20 KiB
510 lines
20 KiB
/*
|
|
* Copyright (c) 2011-2015, Intel Corporation
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include "DomainConfiguration.h"
|
|
#include "ConfigurableElement.h"
|
|
#include "CompoundRule.h"
|
|
#include "Subsystem.h"
|
|
#include "XmlDomainSerializingContext.h"
|
|
#include "XmlDomainImportContext.h"
|
|
#include "XmlDomainExportContext.h"
|
|
#include "ConfigurationAccessContext.h"
|
|
#include "AlwaysAssert.hpp"
|
|
#include <assert.h>
|
|
#include <cstdlib>
|
|
#include <algorithm>
|
|
#include <numeric>
|
|
#include "RuleParser.h"
|
|
|
|
#define base CElement
|
|
|
|
using std::string;
|
|
|
|
CDomainConfiguration::CDomainConfiguration(const string &strName) : base(strName)
|
|
{
|
|
}
|
|
|
|
// Class kind
|
|
string CDomainConfiguration::getKind() const
|
|
{
|
|
return "Configuration";
|
|
}
|
|
|
|
// Child dynamic creation
|
|
bool CDomainConfiguration::childrenAreDynamic() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// XML configuration settings parsing
|
|
bool CDomainConfiguration::parseSettings(CXmlElement &xmlConfigurationSettingsElement,
|
|
CXmlDomainImportContext &context)
|
|
{
|
|
// Parse configurable element's configuration settings
|
|
CXmlElement::CChildIterator it(xmlConfigurationSettingsElement);
|
|
|
|
CXmlElement xmlConfigurableElementSettingsElement;
|
|
auto insertLocation = begin(mAreaConfigurationList);
|
|
|
|
while (it.next(xmlConfigurableElementSettingsElement)) {
|
|
|
|
// Retrieve area configuration
|
|
string configurableElementPath;
|
|
xmlConfigurableElementSettingsElement.getAttribute("Path", configurableElementPath);
|
|
|
|
auto areaConfiguration = findAreaConfigurationByPath(configurableElementPath);
|
|
if (areaConfiguration == end(mAreaConfigurationList)) {
|
|
|
|
context.setError("Configurable Element " + configurableElementPath +
|
|
" referred to by Configuration " + getPath() +
|
|
" not associated to Domain");
|
|
|
|
return false;
|
|
}
|
|
// Parse
|
|
if (!importOneConfigurableElementSettings(areaConfiguration->get(),
|
|
xmlConfigurableElementSettingsElement, context)) {
|
|
|
|
return false;
|
|
}
|
|
// Take into account the new configuration order by moving the configuration associated to
|
|
// the element to the n-th position of the configuration list.
|
|
// It will result in prepending to the configuration list wit the configuration of all
|
|
// elements found in XML, keeping the order of the processing of the XML file.
|
|
mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration);
|
|
// areaConfiguration is still valid, but now refer to the reorderer list
|
|
insertLocation = std::next(areaConfiguration);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// XML configuration settings composing
|
|
void CDomainConfiguration::composeSettings(CXmlElement &xmlConfigurationSettingsElement,
|
|
CXmlDomainExportContext &context) const
|
|
{
|
|
// Go through all are configurations
|
|
for (auto &areaConfiguration : mAreaConfigurationList) {
|
|
|
|
// Retrieve configurable element
|
|
const CConfigurableElement *pConfigurableElement =
|
|
areaConfiguration->getConfigurableElement();
|
|
|
|
// Create configurable element child element
|
|
CXmlElement xmlConfigurableElementSettingsElement;
|
|
|
|
xmlConfigurationSettingsElement.createChild(xmlConfigurableElementSettingsElement,
|
|
"ConfigurableElement");
|
|
|
|
// Set Path attribute
|
|
xmlConfigurableElementSettingsElement.setAttribute("Path", pConfigurableElement->getPath());
|
|
|
|
// Delegate composing to area configuration
|
|
exportOneConfigurableElementSettings(areaConfiguration.get(),
|
|
xmlConfigurableElementSettingsElement, context);
|
|
}
|
|
}
|
|
|
|
// Serialize one configuration for one configurable element
|
|
bool CDomainConfiguration::importOneConfigurableElementSettings(
|
|
CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement,
|
|
CXmlDomainImportContext &context)
|
|
{
|
|
const CConfigurableElement *destination = areaConfiguration->getConfigurableElement();
|
|
|
|
// Check structure
|
|
if (xmlConfigurableElementSettingsElement.getNbChildElements() != 1) {
|
|
|
|
// Structure error
|
|
context.setError("Struture error encountered while parsing settings of " +
|
|
destination->getKind() + " " + destination->getName() +
|
|
" in Configuration " + getPath());
|
|
|
|
return false;
|
|
}
|
|
|
|
// Element content
|
|
CXmlElement xmlConfigurableElementSettingsElementContent;
|
|
// Check name and kind
|
|
if (!xmlConfigurableElementSettingsElement.getChildElement(
|
|
destination->getXmlElementName(), destination->getName(),
|
|
xmlConfigurableElementSettingsElementContent)) {
|
|
|
|
// "Component" tag has been renamed to "ParameterBlock", but retro-compatibility shall
|
|
// be ensured.
|
|
//
|
|
// So checking if this case occurs, i.e. element name is "ParameterBlock"
|
|
// but found xml setting name is "Component".
|
|
bool compatibilityCase =
|
|
(destination->getXmlElementName() == "ParameterBlock") &&
|
|
xmlConfigurableElementSettingsElement.getChildElement(
|
|
"Component", destination->getName(), xmlConfigurableElementSettingsElementContent);
|
|
|
|
// Error if the compatibility case does not occur.
|
|
if (!compatibilityCase) {
|
|
context.setError("Couldn't find settings for " + destination->getXmlElementName() +
|
|
" " + destination->getName() + " for Configuration " + getPath());
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Create configuration access context
|
|
string error;
|
|
CConfigurationAccessContext configurationAccessContext(error, false);
|
|
|
|
// Have domain configuration parse settings for configurable element
|
|
bool success = areaConfiguration->serializeXmlSettings(
|
|
xmlConfigurableElementSettingsElementContent, configurationAccessContext);
|
|
|
|
context.appendToError(error);
|
|
return success;
|
|
}
|
|
|
|
bool CDomainConfiguration::exportOneConfigurableElementSettings(
|
|
CAreaConfiguration *areaConfiguration, CXmlElement &xmlConfigurableElementSettingsElement,
|
|
CXmlDomainExportContext &context) const
|
|
{
|
|
const CConfigurableElement *source = areaConfiguration->getConfigurableElement();
|
|
|
|
// Create child XML element
|
|
CXmlElement xmlConfigurableElementSettingsElementContent;
|
|
xmlConfigurableElementSettingsElement.createChild(xmlConfigurableElementSettingsElementContent,
|
|
source->getXmlElementName());
|
|
|
|
// Create configuration access context
|
|
string error;
|
|
CConfigurationAccessContext configurationAccessContext(error, true);
|
|
configurationAccessContext.setValueSpaceRaw(context.valueSpaceIsRaw());
|
|
configurationAccessContext.setOutputRawFormat(context.outputRawFormatIsHex());
|
|
|
|
// Have domain configuration parse settings for configurable element
|
|
bool success = areaConfiguration->serializeXmlSettings(
|
|
xmlConfigurableElementSettingsElementContent, configurationAccessContext);
|
|
|
|
context.appendToError(error);
|
|
return success;
|
|
}
|
|
|
|
void CDomainConfiguration::addConfigurableElement(const CConfigurableElement *configurableElement,
|
|
const CSyncerSet *syncerSet)
|
|
{
|
|
mAreaConfigurationList.emplace_back(configurableElement->createAreaConfiguration(syncerSet));
|
|
}
|
|
|
|
void CDomainConfiguration::removeConfigurableElement(
|
|
const CConfigurableElement *pConfigurableElement)
|
|
{
|
|
auto &areaConfigurationToRemove = getAreaConfiguration(pConfigurableElement);
|
|
|
|
mAreaConfigurationList.remove(areaConfigurationToRemove);
|
|
}
|
|
|
|
bool CDomainConfiguration::setElementSequence(const std::vector<string> &newElementSequence,
|
|
string &error)
|
|
{
|
|
std::vector<string> elementSequenceSet;
|
|
auto insertLocation = begin(mAreaConfigurationList);
|
|
|
|
for (const std::string &elementPath : newElementSequence) {
|
|
|
|
auto areaConfiguration = findAreaConfigurationByPath(elementPath);
|
|
if (areaConfiguration == end(mAreaConfigurationList)) {
|
|
|
|
error = "Element " + elementPath + " not found in domain";
|
|
|
|
return false;
|
|
}
|
|
auto it = find(begin(elementSequenceSet), end(elementSequenceSet), elementPath);
|
|
if (it != end(elementSequenceSet)) {
|
|
error = "Element " + elementPath + " provided more than once";
|
|
return false;
|
|
}
|
|
elementSequenceSet.push_back(elementPath);
|
|
// Take into account the new configuration order by moving the configuration associated to
|
|
// the element to the n-th position of the configuration list.
|
|
// It will result in prepending to the configuration list wit the configuration of all
|
|
// elements found in XML, keeping the order of the processing of the XML file.
|
|
mAreaConfigurationList.splice(insertLocation, mAreaConfigurationList, areaConfiguration);
|
|
// areaConfiguration is still valid, but now refer to the reorderer list
|
|
insertLocation = std::next(areaConfiguration);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CDomainConfiguration::getElementSequence(string &strResult) const
|
|
{
|
|
// List configurable element paths out of ordered area configuration list
|
|
strResult = accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), string("\n"),
|
|
[](const string &a, const AreaConfiguration &conf) {
|
|
return a + conf->getConfigurableElement()->getPath() + "\n";
|
|
});
|
|
}
|
|
|
|
// Application rule
|
|
bool CDomainConfiguration::setApplicationRule(
|
|
const string &strApplicationRule,
|
|
const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition, string &strError)
|
|
{
|
|
// Parser
|
|
CRuleParser ruleParser(strApplicationRule, pSelectionCriteriaDefinition);
|
|
|
|
// Attempt to parse it
|
|
if (!ruleParser.parse(nullptr, strError)) {
|
|
|
|
return false;
|
|
}
|
|
// Replace compound rule
|
|
setRule(ruleParser.grabRootRule());
|
|
|
|
return true;
|
|
}
|
|
|
|
void CDomainConfiguration::clearApplicationRule()
|
|
{
|
|
// Replace compound rule
|
|
setRule(nullptr);
|
|
}
|
|
|
|
string CDomainConfiguration::getApplicationRule() const
|
|
{
|
|
const CCompoundRule *pRule = getRule();
|
|
return pRule ? pRule->dump() : "<none>";
|
|
}
|
|
|
|
/**
|
|
* Get the Configuration Blackboard.
|
|
*
|
|
* Fetch the Configuration Blackboard related to the ConfigurableElement given in parameter. This
|
|
* Element is used to retrieve the correct AreaConfiguration where the Blackboard is stored.
|
|
*
|
|
* @param[in] pConfigurableElement A pointer to a ConfigurableElement that is part of the
|
|
* Domain. This must have been checked previously, as an
|
|
* assertion is performed.
|
|
*
|
|
* return Pointer to the Blackboard of the Configuration.
|
|
*/
|
|
CParameterBlackboard *CDomainConfiguration::getBlackboard(
|
|
const CConfigurableElement *pConfigurableElement) const
|
|
{
|
|
const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
|
|
[&](const AreaConfiguration &conf) {
|
|
return conf != nullptr &&
|
|
conf->getConfigurableElement() == pConfigurableElement;
|
|
});
|
|
ALWAYS_ASSERT(it != end(mAreaConfigurationList), "Configurable Element "
|
|
<< pConfigurableElement->getName()
|
|
<< " not found in any area Configuration");
|
|
return &(*it)->getBlackboard();
|
|
}
|
|
|
|
// Save data from current
|
|
void CDomainConfiguration::save(const CParameterBlackboard *pMainBlackboard)
|
|
{
|
|
// Just propagate to areas
|
|
for (auto &areaConfiguration : mAreaConfigurationList) {
|
|
areaConfiguration->save(pMainBlackboard);
|
|
}
|
|
}
|
|
|
|
// Apply data to current
|
|
bool CDomainConfiguration::restore(CParameterBlackboard *pMainBlackboard, bool bSync,
|
|
core::Results *errors) const
|
|
{
|
|
return std::accumulate(begin(mAreaConfigurationList), end(mAreaConfigurationList), true,
|
|
[&](bool accumulator, const AreaConfiguration &conf) {
|
|
return conf->restore(pMainBlackboard, bSync, errors) && accumulator;
|
|
});
|
|
}
|
|
|
|
// Ensure validity for configurable element area configuration
|
|
void CDomainConfiguration::validate(const CConfigurableElement *pConfigurableElement,
|
|
const CParameterBlackboard *pMainBlackboard)
|
|
{
|
|
auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement);
|
|
|
|
// Delegate
|
|
areaConfigurationToValidate->validate(pMainBlackboard);
|
|
}
|
|
|
|
// Ensure validity of all area configurations
|
|
void CDomainConfiguration::validate(const CParameterBlackboard *pMainBlackboard)
|
|
{
|
|
for (auto &areaConfiguration : mAreaConfigurationList) {
|
|
areaConfiguration->validate(pMainBlackboard);
|
|
}
|
|
}
|
|
|
|
// Return configuration validity for given configurable element
|
|
bool CDomainConfiguration::isValid(const CConfigurableElement *pConfigurableElement) const
|
|
{
|
|
// Get child configurable elemnt's area configuration
|
|
auto &areaConfiguration = getAreaConfiguration(pConfigurableElement);
|
|
|
|
ALWAYS_ASSERT(areaConfiguration != nullptr, "Configurable Element "
|
|
<< pConfigurableElement->getName()
|
|
<< " not found in any area Configuration");
|
|
|
|
return areaConfiguration->isValid();
|
|
}
|
|
|
|
// Ensure validity of configurable element's area configuration by copying in from a valid one
|
|
void CDomainConfiguration::validateAgainst(const CDomainConfiguration *pValidDomainConfiguration,
|
|
const CConfigurableElement *pConfigurableElement)
|
|
{
|
|
// Retrieve related area configurations
|
|
auto &areaConfigurationToValidate = getAreaConfiguration(pConfigurableElement);
|
|
const auto &areaConfigurationToValidateAgainst =
|
|
pValidDomainConfiguration->getAreaConfiguration(pConfigurableElement);
|
|
|
|
// Delegate to area
|
|
areaConfigurationToValidate->validateAgainst(areaConfigurationToValidateAgainst.get());
|
|
}
|
|
|
|
void CDomainConfiguration::validateAgainst(const CDomainConfiguration *validDomainConfiguration)
|
|
{
|
|
ALWAYS_ASSERT(mAreaConfigurationList.size() ==
|
|
validDomainConfiguration->mAreaConfigurationList.size(),
|
|
"Cannot validate domain configuration "
|
|
<< getPath() << " since area configuration list does not have the same size"
|
|
"than the configuration list to check against");
|
|
for (const auto &configurationToValidateAgainst :
|
|
validDomainConfiguration->mAreaConfigurationList) {
|
|
// Get the area configuration associated to the configurable element of the
|
|
// valid area configuration, it will assert if none found.
|
|
auto configurableElement = configurationToValidateAgainst->getConfigurableElement();
|
|
auto &configurationToValidate = getAreaConfiguration(configurableElement);
|
|
// Delegate to area
|
|
configurationToValidate->validateAgainst(configurationToValidateAgainst.get());
|
|
}
|
|
}
|
|
|
|
// Dynamic data application
|
|
bool CDomainConfiguration::isApplicable() const
|
|
{
|
|
const CCompoundRule *pRule = getRule();
|
|
|
|
return pRule && pRule->matches();
|
|
}
|
|
|
|
// Merge existing configurations to given configurable element ones
|
|
void CDomainConfiguration::merge(CConfigurableElement *pToConfigurableElement,
|
|
CConfigurableElement *pFromConfigurableElement)
|
|
{
|
|
// Retrieve related area configurations
|
|
auto &areaConfigurationToMergeTo = getAreaConfiguration(pToConfigurableElement);
|
|
const auto &areaConfigurationToMergeFrom = getAreaConfiguration(pFromConfigurableElement);
|
|
|
|
// Do the merge
|
|
areaConfigurationToMergeFrom->copyToOuter(areaConfigurationToMergeTo.get());
|
|
}
|
|
|
|
// Domain splitting
|
|
void CDomainConfiguration::split(CConfigurableElement *pFromConfigurableElement)
|
|
{
|
|
// Retrieve related area configuration
|
|
const auto &areaConfigurationToSplitFrom = getAreaConfiguration(pFromConfigurableElement);
|
|
|
|
// Go through children areas to copy configuration data to them
|
|
size_t uiNbConfigurableElementChildren = pFromConfigurableElement->getNbChildren();
|
|
size_t uiChild;
|
|
|
|
for (uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) {
|
|
|
|
CConfigurableElement *pToChildConfigurableElement =
|
|
static_cast<CConfigurableElement *>(pFromConfigurableElement->getChild(uiChild));
|
|
|
|
// Get child configurable elemnt's area configuration
|
|
auto &childAreaConfiguration = getAreaConfiguration(pToChildConfigurableElement);
|
|
|
|
// Do the copy
|
|
childAreaConfiguration->copyFromOuter(areaConfigurationToSplitFrom.get());
|
|
}
|
|
}
|
|
|
|
const CDomainConfiguration::AreaConfiguration &CDomainConfiguration::getAreaConfiguration(
|
|
const CConfigurableElement *pConfigurableElement) const
|
|
{
|
|
const auto &it = find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
|
|
[&](const AreaConfiguration &conf) {
|
|
return conf->getConfigurableElement() == pConfigurableElement;
|
|
});
|
|
ALWAYS_ASSERT(it != end(mAreaConfigurationList),
|
|
"Configurable Element " << pConfigurableElement->getName()
|
|
<< " not found in Domain Configuration list");
|
|
return *it;
|
|
}
|
|
|
|
CDomainConfiguration::AreaConfigurations::iterator CDomainConfiguration::
|
|
findAreaConfigurationByPath(const std::string &configurableElementPath)
|
|
{
|
|
auto areaConfiguration =
|
|
find_if(begin(mAreaConfigurationList), end(mAreaConfigurationList),
|
|
[&](const AreaConfiguration &conf) {
|
|
return conf->getConfigurableElement()->getPath() == configurableElementPath;
|
|
});
|
|
return areaConfiguration;
|
|
}
|
|
|
|
// Rule
|
|
const CCompoundRule *CDomainConfiguration::getRule() const
|
|
{
|
|
if (getNbChildren()) {
|
|
// Rule created
|
|
return static_cast<const CCompoundRule *>(getChild(ECompoundRule));
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
CCompoundRule *CDomainConfiguration::getRule()
|
|
{
|
|
if (getNbChildren()) {
|
|
// Rule created
|
|
return static_cast<CCompoundRule *>(getChild(ECompoundRule));
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void CDomainConfiguration::setRule(CCompoundRule *pRule)
|
|
{
|
|
CCompoundRule *pOldRule = getRule();
|
|
|
|
if (pOldRule) {
|
|
// Remove previous rule
|
|
removeChild(pOldRule);
|
|
|
|
delete pOldRule;
|
|
}
|
|
|
|
// Set new one
|
|
if (pRule) {
|
|
// Chain
|
|
addChild(pRule);
|
|
}
|
|
}
|