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.
1223 lines
40 KiB
1223 lines
40 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 "ConfigurableDomain.h"
|
|
#include "DomainConfiguration.h"
|
|
#include "ConfigurableElement.h"
|
|
#include "ConfigurationAccessContext.h"
|
|
#include "XmlDomainSerializingContext.h"
|
|
#include "XmlDomainImportContext.h"
|
|
#include "XmlDomainExportContext.h"
|
|
#include "Utility.h"
|
|
#include "AlwaysAssert.hpp"
|
|
#include <cassert>
|
|
|
|
#define base CElement
|
|
|
|
using std::string;
|
|
|
|
CConfigurableDomain::CConfigurableDomain(const string &strName) : base(strName)
|
|
{
|
|
}
|
|
|
|
CConfigurableDomain::~CConfigurableDomain()
|
|
{
|
|
// Remove all configurable elements
|
|
ConfigurableElementListIterator it;
|
|
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
CConfigurableElement *pConfigurableElement = *it;
|
|
|
|
// Remove from configurable element
|
|
pConfigurableElement->removeAttachedConfigurableDomain(this);
|
|
}
|
|
|
|
// Remove all associated syncer sets
|
|
ConfigurableElementToSyncerSetMapIterator mapIt;
|
|
|
|
for (mapIt = _configurableElementToSyncerSetMap.begin();
|
|
mapIt != _configurableElementToSyncerSetMap.end(); ++mapIt) {
|
|
|
|
delete mapIt->second;
|
|
}
|
|
}
|
|
|
|
string CConfigurableDomain::getKind() const
|
|
{
|
|
return "ConfigurableDomain";
|
|
}
|
|
|
|
bool CConfigurableDomain::childrenAreDynamic() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Content dumping
|
|
string CConfigurableDomain::logValue(utility::ErrorContext & /*ctx*/) const
|
|
{
|
|
return string("{") +
|
|
|
|
"Sequence aware: " + (_bSequenceAware ? "yes" : "no") +
|
|
|
|
", Last applied configuration: " +
|
|
(_pLastAppliedConfiguration ? _pLastAppliedConfiguration->getName() : "<none>") +
|
|
|
|
"}";
|
|
}
|
|
|
|
// Sequence awareness
|
|
void CConfigurableDomain::setSequenceAwareness(bool bSequenceAware)
|
|
{
|
|
if (_bSequenceAware != bSequenceAware) {
|
|
|
|
_bSequenceAware = bSequenceAware;
|
|
}
|
|
}
|
|
|
|
bool CConfigurableDomain::getSequenceAwareness() const
|
|
{
|
|
return _bSequenceAware;
|
|
}
|
|
|
|
// From IXmlSource
|
|
void CConfigurableDomain::toXml(CXmlElement &xmlElement,
|
|
CXmlSerializingContext &serializingContext) const
|
|
{
|
|
base::toXml(xmlElement, serializingContext);
|
|
|
|
// Sequence awareness
|
|
xmlElement.setAttribute("SequenceAware", _bSequenceAware);
|
|
}
|
|
|
|
void CConfigurableDomain::childrenToXml(CXmlElement &xmlElement,
|
|
CXmlSerializingContext &serializingContext) const
|
|
{
|
|
// Configurations
|
|
composeDomainConfigurations(xmlElement, serializingContext);
|
|
|
|
// Configurable Elements
|
|
composeConfigurableElements(xmlElement);
|
|
|
|
// Settings
|
|
composeSettings(xmlElement, static_cast<CXmlDomainExportContext &>(serializingContext));
|
|
}
|
|
|
|
// XML composing
|
|
void CConfigurableDomain::composeDomainConfigurations(
|
|
CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const
|
|
{
|
|
// Create Configurations element
|
|
CXmlElement xmlConfigurationsElement;
|
|
|
|
xmlElement.createChild(xmlConfigurationsElement, "Configurations");
|
|
|
|
// Delegate to base
|
|
base::childrenToXml(xmlConfigurationsElement, serializingContext);
|
|
}
|
|
|
|
void CConfigurableDomain::composeConfigurableElements(CXmlElement &xmlElement) const
|
|
{
|
|
// Create ConfigurableElements element
|
|
CXmlElement xmlConfigurableElementsElement;
|
|
|
|
xmlElement.createChild(xmlConfigurableElementsElement, "ConfigurableElements");
|
|
|
|
// Serialize out all configurable elements settings
|
|
ConfigurableElementListIterator it;
|
|
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
const CConfigurableElement *pConfigurableElement = *it;
|
|
|
|
// Create corresponding XML child element
|
|
CXmlElement xmlChildConfigurableElement;
|
|
|
|
xmlConfigurableElementsElement.createChild(xmlChildConfigurableElement,
|
|
"ConfigurableElement");
|
|
|
|
// Set Path attribute
|
|
xmlChildConfigurableElement.setAttribute("Path", pConfigurableElement->getPath());
|
|
}
|
|
}
|
|
|
|
void CConfigurableDomain::composeSettings(CXmlElement &xmlElement,
|
|
CXmlDomainExportContext &context) const
|
|
{
|
|
if (!context.withSettings()) {
|
|
|
|
return;
|
|
}
|
|
|
|
// Create Settings element
|
|
CXmlElement xmlSettingsElement;
|
|
|
|
xmlElement.createChild(xmlSettingsElement, "Settings");
|
|
|
|
// Serialize out all configurations settings
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
size_t uiChildConfiguration;
|
|
|
|
for (uiChildConfiguration = 0; uiChildConfiguration < uiNbConfigurations;
|
|
uiChildConfiguration++) {
|
|
|
|
const CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<const CDomainConfiguration *>(getChild(uiChildConfiguration));
|
|
|
|
// Create child xml element for that configuration
|
|
CXmlElement xmlConfigurationSettingsElement;
|
|
|
|
xmlSettingsElement.createChild(xmlConfigurationSettingsElement,
|
|
pDomainConfiguration->getXmlElementName());
|
|
|
|
// Set its name attribute
|
|
xmlConfigurationSettingsElement.setNameAttribute(pDomainConfiguration->getName());
|
|
|
|
// Serialize out configuration settings
|
|
pDomainConfiguration->composeSettings(xmlConfigurationSettingsElement, context);
|
|
}
|
|
}
|
|
|
|
// From IXmlSink
|
|
bool CConfigurableDomain::fromXml(const CXmlElement &xmlElement,
|
|
CXmlSerializingContext &serializingContext)
|
|
{
|
|
// Context
|
|
CXmlDomainImportContext &xmlDomainImportContext =
|
|
static_cast<CXmlDomainImportContext &>(serializingContext);
|
|
|
|
// Sequence awareness (optional)
|
|
xmlElement.getAttribute("SequenceAware", _bSequenceAware);
|
|
|
|
std::string name;
|
|
xmlElement.getAttribute("Name", name);
|
|
setName(name);
|
|
|
|
// Local parsing. Do not dig
|
|
if (!parseDomainConfigurations(xmlElement, xmlDomainImportContext) ||
|
|
!parseConfigurableElements(xmlElement, xmlDomainImportContext) ||
|
|
!parseSettings(xmlElement, xmlDomainImportContext)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// All provided configurations are parsed
|
|
// Attempt validation on areas of non provided configurations for all configurable elements if
|
|
// required
|
|
if (xmlDomainImportContext.autoValidationRequired()) {
|
|
|
|
autoValidateAll();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// XML parsing
|
|
bool CConfigurableDomain::parseDomainConfigurations(const CXmlElement &xmlElement,
|
|
CXmlDomainImportContext &serializingContext)
|
|
{
|
|
// We're supposedly clean
|
|
assert(_configurableElementList.empty());
|
|
|
|
// Get Configurations element
|
|
CXmlElement xmlConfigurationsElement;
|
|
|
|
xmlElement.getChildElement("Configurations", xmlConfigurationsElement);
|
|
|
|
// Parse it and create domain configuration objects
|
|
return base::fromXml(xmlConfigurationsElement, serializingContext);
|
|
}
|
|
|
|
// Parse configurable elements
|
|
bool CConfigurableDomain::parseConfigurableElements(const CXmlElement &xmlElement,
|
|
CXmlDomainImportContext &serializingContext)
|
|
{
|
|
CSystemClass &systemClass = serializingContext.getSystemClass();
|
|
|
|
// Get ConfigurableElements element
|
|
CXmlElement xmlConfigurableElementsElement;
|
|
xmlElement.getChildElement("ConfigurableElements", xmlConfigurableElementsElement);
|
|
|
|
// Parse it and associate found configurable elements to it
|
|
CXmlElement::CChildIterator it(xmlConfigurableElementsElement);
|
|
|
|
CXmlElement xmlConfigurableElementElement;
|
|
|
|
while (it.next(xmlConfigurableElementElement)) {
|
|
|
|
// Locate configurable element
|
|
string strConfigurableElementPath;
|
|
xmlConfigurableElementElement.getAttribute("Path", strConfigurableElementPath);
|
|
|
|
CPathNavigator pathNavigator(strConfigurableElementPath);
|
|
string strError;
|
|
|
|
// Is there an element and does it match system class name?
|
|
if (!pathNavigator.navigateThrough(systemClass.getName(), strError)) {
|
|
|
|
serializingContext.setError(
|
|
"Could not find configurable element of path " + strConfigurableElementPath +
|
|
" from ConfigurableDomain description " + getName() + " (" + strError + ")");
|
|
|
|
return false;
|
|
}
|
|
// Browse system class for configurable element
|
|
CConfigurableElement *pConfigurableElement =
|
|
static_cast<CConfigurableElement *>(systemClass.findDescendant(pathNavigator));
|
|
|
|
if (!pConfigurableElement) {
|
|
|
|
serializingContext.setError("Could not find configurable element of path " +
|
|
strConfigurableElementPath +
|
|
" from ConfigurableDomain description " + getName());
|
|
|
|
return false;
|
|
}
|
|
// Add found element to domain
|
|
core::Results infos;
|
|
if (!addConfigurableElement(pConfigurableElement, nullptr, infos)) {
|
|
|
|
strError = utility::asString(infos);
|
|
serializingContext.setError(strError);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Parse settings
|
|
bool CConfigurableDomain::parseSettings(const CXmlElement &xmlElement,
|
|
CXmlDomainImportContext &serializingContext)
|
|
{
|
|
// Check we actually need to parse configuration settings
|
|
if (!serializingContext.withSettings()) {
|
|
|
|
// No parsing required
|
|
return true;
|
|
}
|
|
|
|
// Get Settings element
|
|
CXmlElement xmlSettingsElement;
|
|
if (!xmlElement.getChildElement("Settings", xmlSettingsElement)) {
|
|
|
|
// No settings, bail out successfully
|
|
return true;
|
|
}
|
|
|
|
// Parse configuration settings
|
|
CXmlElement::CChildIterator it(xmlSettingsElement);
|
|
|
|
CXmlElement xmlConfigurationSettingsElement;
|
|
|
|
while (it.next(xmlConfigurationSettingsElement)) {
|
|
// Get domain configuration
|
|
CDomainConfiguration *pDomainConfiguration = static_cast<CDomainConfiguration *>(
|
|
findChild(xmlConfigurationSettingsElement.getNameAttribute()));
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
serializingContext.setError("Could not find domain configuration referred to by"
|
|
" configurable domain \"" +
|
|
getName() + "\".");
|
|
|
|
return false;
|
|
}
|
|
// Have domain configuration parse settings for all configurable elements
|
|
if (!pDomainConfiguration->parseSettings(xmlConfigurationSettingsElement,
|
|
serializingContext)) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
// Configurable elements association
|
|
bool CConfigurableDomain::addConfigurableElement(CConfigurableElement *pConfigurableElement,
|
|
const CParameterBlackboard *pMainBlackboard,
|
|
core::Results &infos)
|
|
{
|
|
// Already associated?
|
|
if (containsConfigurableElement(pConfigurableElement)) {
|
|
|
|
infos.push_back("Configurable element " + pConfigurableElement->getPath() +
|
|
" already associated to configuration domain " + getName());
|
|
|
|
return false;
|
|
}
|
|
|
|
// Already owned?
|
|
if (pConfigurableElement->belongsTo(this)) {
|
|
|
|
infos.push_back("Configurable element " + pConfigurableElement->getPath() +
|
|
" already owned by configuration domain " + getName());
|
|
|
|
return false;
|
|
}
|
|
|
|
// Do add
|
|
doAddConfigurableElement(pConfigurableElement, infos, pMainBlackboard);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CConfigurableDomain::removeConfigurableElement(CConfigurableElement *pConfigurableElement,
|
|
string &strError)
|
|
{
|
|
// Not associated?
|
|
if (!containsConfigurableElement(pConfigurableElement)) {
|
|
|
|
strError = "Configurable element " + pConfigurableElement->getPath() +
|
|
" not associated to configuration domain " + getName();
|
|
|
|
return false;
|
|
}
|
|
|
|
// Do remove
|
|
doRemoveConfigurableElement(pConfigurableElement, true);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Blackboard Configuration and Base Offset retrieval.
|
|
*
|
|
* This method fetches the Blackboard associated to the ConfigurableElement
|
|
* given in parameter, for a specific Configuration. The ConfigurableElement
|
|
* must belong to the Domain. If a Blackboard is found, the base offset of
|
|
* the ConfigurableElement is returned as well. This base offset corresponds to
|
|
* the offset of the ancestor of the ConfigurableElement associated to the Configuration.
|
|
*
|
|
* @param[in] strConfiguration Name of the Configuration.
|
|
* @param[in] pCandidateDescendantConfigurableElement Pointer to a CConfigurableElement that
|
|
* belongs to the Domain.
|
|
* @param[out] baseOffset The base offset of the CConfigurableElement.
|
|
* @param[out] bIsLastApplied Boolean indicating that the Configuration is
|
|
* the last one applied of the Domain.
|
|
* @param[out] strError Error message
|
|
*
|
|
* return Pointer to the Blackboard of the Configuration.
|
|
*/
|
|
CParameterBlackboard *CConfigurableDomain::findConfigurationBlackboard(
|
|
const string &strConfiguration,
|
|
const CConfigurableElement *pCandidateDescendantConfigurableElement, size_t &baseOffset,
|
|
bool &bIsLastApplied, string &strError) const
|
|
{
|
|
// Find Configuration
|
|
const CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<const CDomainConfiguration *>(findChild(strConfiguration));
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
strError = "Domain configuration " + strConfiguration + " not found";
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Parse all configurable elements
|
|
ConfigurableElementListIterator it;
|
|
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
const CConfigurableElement *pAssociatedConfigurableElement = *it;
|
|
|
|
// Check if the the associated element is the configurable element or one of its ancestors
|
|
if ((pCandidateDescendantConfigurableElement == pAssociatedConfigurableElement) ||
|
|
(pCandidateDescendantConfigurableElement->isDescendantOf(
|
|
pAssociatedConfigurableElement))) {
|
|
|
|
baseOffset = pAssociatedConfigurableElement->getOffset();
|
|
bIsLastApplied = (pDomainConfiguration == _pLastAppliedConfiguration);
|
|
|
|
return pDomainConfiguration->getBlackboard(pAssociatedConfigurableElement);
|
|
}
|
|
}
|
|
|
|
strError = "Element not associated to the Domain";
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Domain splitting
|
|
bool CConfigurableDomain::split(CConfigurableElement *pConfigurableElement, core::Results &infos)
|
|
{
|
|
// Not associated?
|
|
if (!containsConfigurableElement(pConfigurableElement)) {
|
|
|
|
std::string strError = "Configurable element " + pConfigurableElement->getPath() +
|
|
" not associated to configuration domain " + getName();
|
|
infos.push_back(strError);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Create sub domain areas for all configurable element's children
|
|
size_t uiNbConfigurableElementChildren = pConfigurableElement->getNbChildren();
|
|
|
|
if (!uiNbConfigurableElementChildren) {
|
|
|
|
std::string strError = "Configurable element " + pConfigurableElement->getPath() +
|
|
" has no children to split configurable domain to";
|
|
infos.push_back(strError);
|
|
|
|
return false;
|
|
}
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) {
|
|
|
|
CConfigurableElement *pChildConfigurableElement =
|
|
static_cast<CConfigurableElement *>(pConfigurableElement->getChild(uiChild));
|
|
|
|
doAddConfigurableElement(pChildConfigurableElement, infos);
|
|
}
|
|
|
|
// Delegate to configurations
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
pDomainConfiguration->split(pConfigurableElement);
|
|
}
|
|
|
|
// Remove given configurable element from this domain
|
|
// Note: we shouldn't need to recompute the sync set in that case, as the splitted element
|
|
// should include the syncers of its children elements
|
|
doRemoveConfigurableElement(pConfigurableElement, false);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Check if there is a pending configuration for this domain: i.e. an applicable configuration
|
|
// different from the last applied configuration
|
|
const CDomainConfiguration *CConfigurableDomain::getPendingConfiguration() const
|
|
{
|
|
const CDomainConfiguration *pApplicableDomainConfiguration =
|
|
findApplicableDomainConfiguration();
|
|
|
|
if (pApplicableDomainConfiguration) {
|
|
|
|
// Check not the last one before applying
|
|
if (!_pLastAppliedConfiguration ||
|
|
(_pLastAppliedConfiguration != pApplicableDomainConfiguration)) {
|
|
|
|
return pApplicableDomainConfiguration;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Configuration application if required
|
|
void CConfigurableDomain::apply(CParameterBlackboard *pParameterBlackboard, CSyncerSet *pSyncerSet,
|
|
bool bForce, std::string &strInfo) const
|
|
{
|
|
// Apply configuration only if the blackboard will
|
|
// be synchronized either now or by syncerSet.
|
|
if (!pSyncerSet ^ _bSequenceAware) {
|
|
// The configuration can not be syncronised
|
|
return;
|
|
}
|
|
|
|
if (bForce) {
|
|
// Force a configuration restore by forgetting about last applied configuration
|
|
_pLastAppliedConfiguration = nullptr;
|
|
}
|
|
const CDomainConfiguration *pApplicableDomainConfiguration =
|
|
findApplicableDomainConfiguration();
|
|
|
|
if (pApplicableDomainConfiguration) {
|
|
|
|
// Check not the last one before applying
|
|
if (!_pLastAppliedConfiguration ||
|
|
_pLastAppliedConfiguration != pApplicableDomainConfiguration) {
|
|
|
|
strInfo = "Applying configuration '" + pApplicableDomainConfiguration->getName() +
|
|
"' from domain '" + getName() + "'";
|
|
|
|
// Check if we need to synchronize during restore
|
|
bool bSync = !pSyncerSet && _bSequenceAware;
|
|
|
|
// Do the restore
|
|
pApplicableDomainConfiguration->restore(pParameterBlackboard, bSync, nullptr);
|
|
|
|
// Record last applied configuration
|
|
_pLastAppliedConfiguration = pApplicableDomainConfiguration;
|
|
|
|
// Check we need to provide syncer set to caller
|
|
if (pSyncerSet && !_bSequenceAware) {
|
|
|
|
// Since we applied changes, add our own sync set to the given one
|
|
*pSyncerSet += _syncerSet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return applicable configuration validity for given configurable element
|
|
bool CConfigurableDomain::isApplicableConfigurationValid(
|
|
const CConfigurableElement *pConfigurableElement) const
|
|
{
|
|
const CDomainConfiguration *pApplicableDomainConfiguration =
|
|
findApplicableDomainConfiguration();
|
|
|
|
return pApplicableDomainConfiguration &&
|
|
pApplicableDomainConfiguration->isValid(pConfigurableElement);
|
|
}
|
|
|
|
// In case configurable element was removed
|
|
void CConfigurableDomain::computeSyncSet()
|
|
{
|
|
// Clean sync set first
|
|
_syncerSet.clear();
|
|
|
|
// Add syncer sets for all associated configurable elements
|
|
ConfigurableElementToSyncerSetMapIterator mapIt;
|
|
|
|
for (mapIt = _configurableElementToSyncerSetMap.begin();
|
|
mapIt != _configurableElementToSyncerSetMap.end(); ++mapIt) {
|
|
|
|
const CSyncerSet *pSyncerSet = mapIt->second;
|
|
|
|
_syncerSet += *pSyncerSet;
|
|
}
|
|
}
|
|
|
|
// Configuration Management
|
|
bool CConfigurableDomain::createConfiguration(const string &strName,
|
|
const CParameterBlackboard *pMainBlackboard,
|
|
string &strError)
|
|
{
|
|
// Already exists?
|
|
if (findChild(strName)) {
|
|
|
|
strError = "Already existing configuration";
|
|
|
|
return false;
|
|
}
|
|
|
|
// Creation
|
|
auto pDomainConfiguration = new CDomainConfiguration(strName);
|
|
|
|
// Configurable elements association
|
|
ConfigurableElementListIterator it;
|
|
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
const CConfigurableElement *pConfigurableElement = *it;
|
|
;
|
|
|
|
// Retrieve associated syncer set
|
|
CSyncerSet *pSyncerSet = getSyncerSet(pConfigurableElement);
|
|
|
|
// Associate to configuration
|
|
pDomainConfiguration->addConfigurableElement(pConfigurableElement, pSyncerSet);
|
|
}
|
|
|
|
// Hierarchy
|
|
addChild(pDomainConfiguration);
|
|
|
|
// Ensure validity of fresh new domain configuration
|
|
// Attempt auto validation, so that the user gets his/her own settings by defaults
|
|
if (!autoValidateConfiguration(pDomainConfiguration)) {
|
|
|
|
// No valid configuration found to copy in from, validate againt main blackboard (will
|
|
// concerned remaining invalid parts)
|
|
pDomainConfiguration->validate(pMainBlackboard);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CConfigurableDomain::deleteConfiguration(const string &strName, string &strError)
|
|
{
|
|
CDomainConfiguration *pDomainConfiguration = findConfiguration(strName, strError);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Was the last applied?
|
|
if (pDomainConfiguration == _pLastAppliedConfiguration) {
|
|
|
|
// Forget about it
|
|
_pLastAppliedConfiguration = nullptr;
|
|
}
|
|
|
|
// Hierarchy
|
|
removeChild(pDomainConfiguration);
|
|
|
|
// Destroy
|
|
delete pDomainConfiguration;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CConfigurableDomain::listAssociatedToElements(string &strResult) const
|
|
{
|
|
ConfigurableElementListIterator it;
|
|
|
|
// Browse all configurable elements
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
const CConfigurableElement *pConfigurableElement = *it;
|
|
|
|
strResult += pConfigurableElement->getPath() + "\n";
|
|
}
|
|
}
|
|
|
|
bool CConfigurableDomain::renameConfiguration(const string &strName, const string &strNewName,
|
|
string &strError)
|
|
{
|
|
CDomainConfiguration *pDomainConfiguration = findConfiguration(strName, strError);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Rename
|
|
return pDomainConfiguration->rename(strNewName, strError);
|
|
}
|
|
|
|
bool CConfigurableDomain::restoreConfiguration(const string &configurationName,
|
|
CParameterBlackboard *mainBlackboard, bool autoSync,
|
|
core::Results &errors) const
|
|
{
|
|
string error;
|
|
|
|
const CDomainConfiguration *configuration = findConfiguration(configurationName, error);
|
|
|
|
if (configuration == nullptr) {
|
|
|
|
errors.push_back(error);
|
|
return false;
|
|
}
|
|
|
|
// Delegate
|
|
bool bSuccess = configuration->restore(mainBlackboard, autoSync && _bSequenceAware, &errors);
|
|
|
|
// Record last applied configuration
|
|
_pLastAppliedConfiguration = configuration;
|
|
|
|
// Synchronize
|
|
if (autoSync && !_bSequenceAware) {
|
|
|
|
bSuccess &= _syncerSet.sync(*mainBlackboard, false, &errors);
|
|
}
|
|
return bSuccess;
|
|
}
|
|
|
|
bool CConfigurableDomain::saveConfiguration(const string &strName,
|
|
const CParameterBlackboard *pMainBlackboard,
|
|
string &strError)
|
|
{
|
|
// Find Domain configuration
|
|
CDomainConfiguration *pDomainConfiguration = findConfiguration(strName, strError);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Delegate
|
|
pDomainConfiguration->save(pMainBlackboard);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CConfigurableDomain::setElementSequence(const string &strConfiguration,
|
|
const std::vector<string> &astrNewElementSequence,
|
|
string &strError)
|
|
{
|
|
// Find Domain configuration
|
|
CDomainConfiguration *pDomainConfiguration = findConfiguration(strConfiguration, strError);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Delegate to configuration
|
|
return pDomainConfiguration->setElementSequence(astrNewElementSequence, strError);
|
|
}
|
|
|
|
bool CConfigurableDomain::getElementSequence(const string &strConfiguration,
|
|
string &strResult) const
|
|
{
|
|
// Find Domain configuration
|
|
const CDomainConfiguration *pDomainConfiguration =
|
|
findConfiguration(strConfiguration, strResult);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Delegate to configuration
|
|
pDomainConfiguration->getElementSequence(strResult);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CConfigurableDomain::setApplicationRule(
|
|
const string &strConfiguration, const string &strApplicationRule,
|
|
const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition, string &strError)
|
|
{
|
|
// Find Domain configuration
|
|
CDomainConfiguration *pDomainConfiguration = findConfiguration(strConfiguration, strError);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Delegate to configuration
|
|
return pDomainConfiguration->setApplicationRule(strApplicationRule,
|
|
pSelectionCriteriaDefinition, strError);
|
|
}
|
|
|
|
bool CConfigurableDomain::clearApplicationRule(const string &strConfiguration, string &strError)
|
|
{
|
|
// Find Domain configuration
|
|
CDomainConfiguration *pDomainConfiguration = findConfiguration(strConfiguration, strError);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Delegate to configuration
|
|
pDomainConfiguration->clearApplicationRule();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CConfigurableDomain::getApplicationRule(const string &strConfiguration,
|
|
string &strResult) const
|
|
{
|
|
// Find Domain configuration
|
|
const CDomainConfiguration *pDomainConfiguration =
|
|
findConfiguration(strConfiguration, strResult);
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Delegate to configuration
|
|
strResult = pDomainConfiguration->getApplicationRule();
|
|
|
|
return true;
|
|
}
|
|
|
|
// Last applied configuration
|
|
string CConfigurableDomain::getLastAppliedConfigurationName() const
|
|
{
|
|
if (_pLastAppliedConfiguration) {
|
|
|
|
return _pLastAppliedConfiguration->getName();
|
|
}
|
|
return "<none>";
|
|
}
|
|
|
|
// Pending configuration
|
|
string CConfigurableDomain::getPendingConfigurationName() const
|
|
{
|
|
const CDomainConfiguration *pApplicableDomainConfiguration =
|
|
findApplicableDomainConfiguration();
|
|
|
|
if (!pApplicableDomainConfiguration) {
|
|
|
|
// No configuration is pending
|
|
return "<none>";
|
|
}
|
|
|
|
// Check it will be applied
|
|
if (pApplicableDomainConfiguration != _pLastAppliedConfiguration) {
|
|
|
|
// Found config will get applied
|
|
return pApplicableDomainConfiguration->getName();
|
|
} else {
|
|
|
|
// Same configuration as current
|
|
return "";
|
|
}
|
|
}
|
|
|
|
// Ensure validity on whole domain from main blackboard
|
|
void CConfigurableDomain::validate(const CParameterBlackboard *pMainBlackboard)
|
|
{
|
|
|
|
// Propagate
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
pDomainConfiguration->validate(pMainBlackboard);
|
|
}
|
|
}
|
|
|
|
// Ensure validity on areas related to configurable element
|
|
void CConfigurableDomain::validateAreas(const CConfigurableElement *pConfigurableElement,
|
|
const CParameterBlackboard *pMainBlackboard)
|
|
{
|
|
// Propagate
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
pDomainConfiguration->validate(pConfigurableElement, pMainBlackboard);
|
|
}
|
|
}
|
|
|
|
// Attempt validation for all configurable element's areas, relying on already existing valid
|
|
// configuration inside domain
|
|
void CConfigurableDomain::autoValidateAll()
|
|
{
|
|
// Validate
|
|
ConfigurableElementListIterator it;
|
|
|
|
// Browse all configurable elements for configuration validation
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
const CConfigurableElement *pConfigurableElement = *it;
|
|
|
|
// Auto validate element
|
|
autoValidateAreas(pConfigurableElement);
|
|
}
|
|
}
|
|
|
|
// Attempt validation for configurable element's areas, relying on already existing valid
|
|
// configuration inside domain
|
|
void CConfigurableDomain::autoValidateAreas(const CConfigurableElement *pConfigurableElement)
|
|
{
|
|
// Find first valid configuration for given configurable element
|
|
const CDomainConfiguration *pValidDomainConfiguration =
|
|
findValidDomainConfiguration(pConfigurableElement);
|
|
|
|
// No valid configuration found, give up
|
|
if (!pValidDomainConfiguration) {
|
|
|
|
return;
|
|
}
|
|
|
|
// Validate all other configurations against found one, if any
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
if (pDomainConfiguration != pValidDomainConfiguration &&
|
|
!pDomainConfiguration->isValid(pConfigurableElement)) {
|
|
// Validate
|
|
pDomainConfiguration->validateAgainst(pValidDomainConfiguration, pConfigurableElement);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Attempt configuration validation for all configurable elements' areas, relying on already
|
|
// existing valid configuration inside domain
|
|
bool CConfigurableDomain::autoValidateConfiguration(CDomainConfiguration *pDomainConfiguration)
|
|
{
|
|
// Find another configuration than this one, that ought to be valid!
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
const CDomainConfiguration *pPotententialValidDomainConfiguration =
|
|
static_cast<const CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
if (pPotententialValidDomainConfiguration != pDomainConfiguration) {
|
|
|
|
// Validate against it
|
|
pDomainConfiguration->validateAgainst(pPotententialValidDomainConfiguration);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Search for a valid configuration for given configurable element
|
|
const CDomainConfiguration *CConfigurableDomain::findValidDomainConfiguration(
|
|
const CConfigurableElement *pConfigurableElement) const
|
|
{
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
const CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<const CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
if (pDomainConfiguration->isValid(pConfigurableElement)) {
|
|
|
|
return pDomainConfiguration;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Search for an applicable configuration
|
|
const CDomainConfiguration *CConfigurableDomain::findApplicableDomainConfiguration() const
|
|
{
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
const CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<const CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
if (pDomainConfiguration->isApplicable()) {
|
|
|
|
return pDomainConfiguration;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Gather set of configurable elements
|
|
void CConfigurableDomain::gatherConfigurableElements(
|
|
std::set<const CConfigurableElement *> &configurableElementSet) const
|
|
{
|
|
// Insert all configurable elements
|
|
configurableElementSet.insert(_configurableElementList.begin(), _configurableElementList.end());
|
|
}
|
|
|
|
// Check configurable element already attached
|
|
bool CConfigurableDomain::containsConfigurableElement(
|
|
const CConfigurableElement *pConfigurableCandidateElement) const
|
|
{
|
|
ConfigurableElementListIterator it;
|
|
|
|
// Browse all configurable elements for comparison
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
if (pConfigurableCandidateElement == *it) {
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Merge any descended configurable element to this one with this one
|
|
void CConfigurableDomain::mergeAlreadyAssociatedDescendantConfigurableElements(
|
|
CConfigurableElement *newElement, core::Results &infos)
|
|
{
|
|
std::list<CConfigurableElement *> mergedConfigurableElementList;
|
|
|
|
ConfigurableElementListIterator it;
|
|
|
|
// Browse all configurable elements (new one not yet in the list!)
|
|
for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
|
|
|
|
CConfigurableElement *pConfigurablePotentialDescendantElement = *it;
|
|
|
|
if (pConfigurablePotentialDescendantElement->isDescendantOf(newElement)) {
|
|
|
|
infos.push_back("In domain '" + getName() +
|
|
"', merging descendant configurable element's configurations '" +
|
|
pConfigurablePotentialDescendantElement->getName() +
|
|
"' into its ascendant '" + newElement->getName() + "' ones");
|
|
|
|
// Merge configuration data
|
|
mergeConfigurations(newElement, pConfigurablePotentialDescendantElement);
|
|
|
|
// Keep track for removal
|
|
mergedConfigurableElementList.push_back(pConfigurablePotentialDescendantElement);
|
|
}
|
|
}
|
|
|
|
// Remove all merged elements (new one not yet in the list!)
|
|
for (it = mergedConfigurableElementList.begin(); it != mergedConfigurableElementList.end();
|
|
++it) {
|
|
|
|
CConfigurableElement *pMergedConfigurableElement = *it;
|
|
|
|
// Remove merged from configurable element from internal tracking list
|
|
// Note: we shouldn't need to recompute the sync set in that case, as the merged to element
|
|
// should include the syncers of merged from elements
|
|
doRemoveConfigurableElement(pMergedConfigurableElement, false);
|
|
}
|
|
}
|
|
|
|
void CConfigurableDomain::mergeConfigurations(CConfigurableElement *pToConfigurableElement,
|
|
CConfigurableElement *pFromConfigurableElement)
|
|
{
|
|
// Propagate to domain configurations
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
// Do the merge.
|
|
pDomainConfiguration->merge(pToConfigurableElement, pFromConfigurableElement);
|
|
}
|
|
}
|
|
|
|
// Configurable elements association
|
|
void CConfigurableDomain::doAddConfigurableElement(CConfigurableElement *pConfigurableElement,
|
|
core::Results &infos,
|
|
const CParameterBlackboard *pMainBlackboard)
|
|
{
|
|
// Inform configurable element
|
|
pConfigurableElement->addAttachedConfigurableDomain(this);
|
|
|
|
// Create associated syncer set
|
|
auto pSyncerSet = new CSyncerSet;
|
|
|
|
// Add to sync set the configurable element one
|
|
pConfigurableElement->fillSyncerSet(*pSyncerSet);
|
|
|
|
// Store it
|
|
_configurableElementToSyncerSetMap[pConfigurableElement] = pSyncerSet;
|
|
|
|
// Add it to global one
|
|
_syncerSet += *pSyncerSet;
|
|
|
|
// Inform configurations
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
pDomainConfiguration->addConfigurableElement(pConfigurableElement, pSyncerSet);
|
|
}
|
|
|
|
// Ensure area validity for that configurable element (if main blackboard provided)
|
|
if (pMainBlackboard) {
|
|
|
|
infos.push_back("Validating domain '" + getName() +
|
|
"' against main blackboard for configurable element '" +
|
|
pConfigurableElement->getPath() + "'");
|
|
// Need to validate against main blackboard
|
|
validateAreas(pConfigurableElement, pMainBlackboard);
|
|
}
|
|
|
|
// Already associated descendend configurable elements need a merge of their configuration data
|
|
mergeAlreadyAssociatedDescendantConfigurableElements(pConfigurableElement, infos);
|
|
|
|
// Add to list
|
|
_configurableElementList.push_back(pConfigurableElement);
|
|
}
|
|
|
|
void CConfigurableDomain::doRemoveConfigurableElement(CConfigurableElement *pConfigurableElement,
|
|
bool bRecomputeSyncSet)
|
|
{
|
|
// Remove from list
|
|
_configurableElementList.remove(pConfigurableElement);
|
|
|
|
// Remove associated syncer set
|
|
CSyncerSet *pSyncerSet = getSyncerSet(pConfigurableElement);
|
|
|
|
_configurableElementToSyncerSetMap.erase(pConfigurableElement);
|
|
|
|
delete pSyncerSet;
|
|
|
|
// Inform configurable element
|
|
pConfigurableElement->removeAttachedConfigurableDomain(this);
|
|
|
|
// Inform configurations
|
|
size_t uiNbConfigurations = getNbChildren();
|
|
|
|
for (size_t uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
|
|
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(getChild(uiChild));
|
|
|
|
pDomainConfiguration->removeConfigurableElement(pConfigurableElement);
|
|
}
|
|
// Recompute our sync set if needed
|
|
if (bRecomputeSyncSet) {
|
|
|
|
computeSyncSet();
|
|
}
|
|
}
|
|
|
|
// Syncer set retrieval from configurable element
|
|
CSyncerSet *CConfigurableDomain::getSyncerSet(
|
|
const CConfigurableElement *pConfigurableElement) const
|
|
{
|
|
auto mapIt = _configurableElementToSyncerSetMap.find(pConfigurableElement);
|
|
|
|
ALWAYS_ASSERT(mapIt != _configurableElementToSyncerSetMap.end(),
|
|
"Could not find syncer set for " << getName() << " configurable domain");
|
|
|
|
return mapIt->second;
|
|
}
|
|
|
|
// Configuration retrieval
|
|
CDomainConfiguration *CConfigurableDomain::findConfiguration(const string &strConfiguration,
|
|
string &strError)
|
|
{
|
|
CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<CDomainConfiguration *>(findChild(strConfiguration));
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
strError = "Domain configuration " + strConfiguration + " not found";
|
|
|
|
return nullptr;
|
|
}
|
|
return pDomainConfiguration;
|
|
}
|
|
|
|
const CDomainConfiguration *CConfigurableDomain::findConfiguration(const string &strConfiguration,
|
|
string &strError) const
|
|
{
|
|
const CDomainConfiguration *pDomainConfiguration =
|
|
static_cast<const CDomainConfiguration *>(findChild(strConfiguration));
|
|
|
|
if (!pDomainConfiguration) {
|
|
|
|
strError = "Domain configuration " + strConfiguration + " not found";
|
|
|
|
return nullptr;
|
|
}
|
|
return pDomainConfiguration;
|
|
}
|