/* * 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 #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() : "") + "}"; } // 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(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(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(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(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( 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(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(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(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 &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 ""; } // Pending configuration string CConfigurableDomain::getPendingConfigurationName() const { const CDomainConfiguration *pApplicableDomainConfiguration = findApplicableDomainConfiguration(); if (!pApplicableDomainConfiguration) { // No configuration is pending return ""; } // 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(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(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(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(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(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(getChild(uiChild)); if (pDomainConfiguration->isApplicable()) { return pDomainConfiguration; } } return nullptr; } // Gather set of configurable elements void CConfigurableDomain::gatherConfigurableElements( std::set &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 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(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(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(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(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(findChild(strConfiguration)); if (!pDomainConfiguration) { strError = "Domain configuration " + strConfiguration + " not found"; return nullptr; } return pDomainConfiguration; }