/* * Copyright (c) 2011-2014, 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 #define base CBinarySerializableElement using std::string; CConfigurableDomain::CConfigurableDomain() : _bSequenceAware(false), _pLastAppliedConfiguration(NULL) { } CConfigurableDomain::CConfigurableDomain(const string& strName) : base(strName), _bSequenceAware(false), _pLastAppliedConfiguration(NULL) { } 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 void CConfigurableDomain::logValue(string& strValue, CErrorContext& errorContext) const { (void)errorContext; strValue = "{"; // Sequence awareness strValue += "Sequence aware: "; strValue += _bSequenceAware ? "yes" : "no"; // Last applied configuration strValue += ", Last applied configuration: "; strValue += _pLastAppliedConfiguration ? _pLastAppliedConfiguration->getName() : ""; strValue += "}"; } // Sequence awareness void CConfigurableDomain::setSequenceAwareness(bool bSequenceAware) { if (_bSequenceAware != bSequenceAware) { log_info("Making domain \"%s\" sequence %s", getName().c_str(), bSequenceAware ? "aware" : "unaware"); _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.setAttributeBoolean("SequenceAware", _bSequenceAware); } void CConfigurableDomain::childrenToXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const { // Configurations composeDomainConfigurations(xmlElement, serializingContext); // Configurable Elements composeConfigurableElements(xmlElement); // Settings composeSettings(xmlElement, 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.setAttributeString("Path", pConfigurableElement->getPath()); } } void CConfigurableDomain::composeSettings(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const { // Context const CXmlDomainExportContext& xmlDomainExportContext = static_cast(serializingContext); if (!xmlDomainExportContext.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->getKind()); // Set its name attribute xmlConfigurationSettingsElement.setNameAttribute(pDomainConfiguration->getName()); // Serialize out configuration settings pDomainConfiguration->composeSettings(xmlConfigurationSettingsElement, serializingContext); } } // From IXmlSink bool CConfigurableDomain::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) { // Context CXmlDomainImportContext& xmlDomainImportContext = static_cast(serializingContext); // Sequence awareness (optional) _bSequenceAware = xmlElement.hasAttribute("SequenceAware") && xmlElement.getAttributeBoolean("SequenceAware"); setName(xmlElement.getAttributeString("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.getAttributeString("Path"); 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 if (!addConfigurableElement(pConfigurableElement, NULL, strError)) { 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, string& strError) { // Already associated? if (containsConfigurableElement(pConfigurableElement)) { strError = "Configurable element " + pConfigurableElement->getPath() + " already associated to configuration domain " + getName(); return false; } // Already owned? if (pConfigurableElement->belongsTo(this)) { strError = "Configurable element " + pConfigurableElement->getPath() + " already owned by configuration domain " + getName(); return false; } // Do add doAddConfigurableElement(pConfigurableElement, 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; } log_info("Removing configurable element \"%s\" from domain \"%s\"", pConfigurableElement->getPath().c_str(), getName().c_str()); // 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] uiBaseOffset 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, uint32_t& uiBaseOffset, bool& bIsLastApplied, string& strError) const { // Find Configuration const CDomainConfiguration* pDomainConfiguration = static_cast(findChild(strConfiguration)); if (!pDomainConfiguration) { strError = "Domain configuration " + strConfiguration + " not found"; return NULL; } // 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))) { uiBaseOffset = pAssociatedConfigurableElement->getOffset(); bIsLastApplied = (pDomainConfiguration == _pLastAppliedConfiguration); return pDomainConfiguration->getBlackboard(pAssociatedConfigurableElement); } } strError = "Element not associated to the Domain"; return NULL; } // Domain splitting bool CConfigurableDomain::split(CConfigurableElement* pConfigurableElement, string& strError) { // Not associated? if (!containsConfigurableElement(pConfigurableElement)) { strError = "Configurable element " + pConfigurableElement->getPath() + " not associated to configuration domain " + getName(); return false; } log_info("Splitting configurable element \"%s\" domain \"%s\"", pConfigurableElement->getPath().c_str(), getName().c_str()); // Create sub domain areas for all configurable element's children size_t uiNbConfigurableElementChildren = pConfigurableElement->getNbChildren(); if (!uiNbConfigurableElementChildren) { strError = "Configurable element " + pConfigurableElement->getPath() + " has no children to split configurable domain to"; return false; } size_t uiChild; for (uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) { CConfigurableElement* pChildConfigurableElement = static_cast(pConfigurableElement->getChild(uiChild)); doAddConfigurableElement(pChildConfigurableElement); } // Delegate to configurations size_t uiNbConfigurations = getNbChildren(); for (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 NULL; } // Configuration application if required void CConfigurableDomain::apply(CParameterBlackboard* pParameterBlackboard, CSyncerSet* pSyncerSet, bool bForce) 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 = NULL; } const CDomainConfiguration* pApplicableDomainConfiguration = findApplicableDomainConfiguration(); if (pApplicableDomainConfiguration) { // Check not the last one before applying if (!_pLastAppliedConfiguration || _pLastAppliedConfiguration != pApplicableDomainConfiguration) { log_info("Applying configuration \"%s\" from domain \"%s\"", pApplicableDomainConfiguration->getName().c_str(), getName().c_str()); // Check if we need to synchronize during restore bool bSync = !pSyncerSet && _bSequenceAware; // Do the restore pApplicableDomainConfiguration->restore(pParameterBlackboard, bSync, NULL); // 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; } log_info("Creating domain configuration \"%s\" into domain \"%s\"", strName.c_str(), getName().c_str()); // Creation CDomainConfiguration* 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; } log_info("Deleting configuration \"%s\" from domain \"%s\"", strName.c_str(), getName().c_str()); // Was the last applied? if (pDomainConfiguration == _pLastAppliedConfiguration) { // Forget about it _pLastAppliedConfiguration = NULL; } // Hierarchy removeChild(pDomainConfiguration); // Destroy delete pDomainConfiguration; return true; } void CConfigurableDomain::listAssociatedToElements(string& strResult) const { strResult = "\n"; 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; } log_info("Renaming domain \"%s\"'s configuration \"%s\" to \"%s\"", getName().c_str(), strName.c_str(), strNewName.c_str()); // Rename return pDomainConfiguration->rename(strNewName, strError); } bool CConfigurableDomain::restoreConfiguration(const string& strName, CParameterBlackboard* pMainBlackboard, bool bAutoSync, std::list& lstrError) const { string strError; const CDomainConfiguration* pDomainConfiguration = findConfiguration(strName, strError); if (!pDomainConfiguration) { lstrError.push_back(strError); return false; } log_info("Restoring domain \"%s\"'s configuration \"%s\" to parameter blackboard", getName().c_str(), pDomainConfiguration->getName().c_str()); // Delegate bool bSuccess = pDomainConfiguration->restore(pMainBlackboard, bAutoSync && _bSequenceAware, &lstrError); // Record last applied configuration _pLastAppliedConfiguration = pDomainConfiguration; // Synchronize if (bAutoSync && !_bSequenceAware) { bSuccess &= _syncerSet.sync(*pMainBlackboard, false, &lstrError); } 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; } log_info("Saving domain \"%s\"'s configuration \"%s\" from parameter blackboard", getName().c_str(), pDomainConfiguration->getName().c_str()); // 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 pDomainConfiguration->getApplicationRule(strResult); return true; } // Last applied configuration string CConfigurableDomain::getLastAppliedConfigurationName() const { if (_pLastAppliedConfiguration) { return _pLastAppliedConfiguration->getName(); } return ""; } // Pending configuration string CConfigurableDomain::getPendingConfigurationName() const { const CDomainConfiguration* pPendingConfiguration = getPendingConfiguration(); if (pPendingConfiguration) { return pPendingConfiguration->getName(); } return ""; } // Ensure validity on whole domain from main blackboard void CConfigurableDomain::validate(const CParameterBlackboard* pMainBlackboard) { // Propagate size_t uiNbConfigurations = getNbChildren(); size_t uiChild; for (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) { log_info("Validating domain \"%s\" against main blackboard for configurable element \"%s\"", getName().c_str(), pConfigurableElement->getPath().c_str()); // Propagate size_t uiNbConfigurations = getNbChildren(); size_t uiChild; for (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(); size_t uiChild; for (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(); size_t uiChild; for (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(); size_t uiChild; for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { const CDomainConfiguration* pDomainConfiguration = static_cast(getChild(uiChild)); if (pDomainConfiguration->isValid(pConfigurableElement)) { return pDomainConfiguration; } } return NULL; } // Search for an applicable configuration const CDomainConfiguration* CConfigurableDomain::findApplicableDomainConfiguration() const { size_t uiNbConfigurations = getNbChildren(); size_t uiChild; for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) { const CDomainConfiguration* pDomainConfiguration = static_cast(getChild(uiChild)); if (pDomainConfiguration->isApplicable()) { return pDomainConfiguration; } } return NULL; } // 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* pNewConfigurableElement) { 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(pNewConfigurableElement)) { log_info("In domain \"%s\", merging descendant configurable element's configurations \"%s\" into its ascendant \"%s\" ones", getName().c_str(), pConfigurablePotentialDescendantElement->getName().c_str(), pNewConfigurableElement->getName().c_str()); // Merge configuration data mergeConfigurations(pNewConfigurableElement, 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(); size_t uiChild; for (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, const CParameterBlackboard *pMainBlackboard) { // Inform configurable element pConfigurableElement->addAttachedConfigurableDomain(this); // Create associated syncer set CSyncerSet* 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(); size_t uiChild; for (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) { // Need to validate against main blackboard validateAreas(pConfigurableElement, pMainBlackboard); } // Already associated descendend configurable elements need a merge of their configuration data mergeAlreadyAssociatedDescendantConfigurableElements(pConfigurableElement); // 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(); size_t uiChild; for (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 { ConfigurableElementToSyncerSetMapIterator mapIt = _configurableElementToSyncerSetMap.find(pConfigurableElement); assert(mapIt != _configurableElementToSyncerSetMap.end()); 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 NULL; } 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 NULL; } return pDomainConfiguration; }