Home | History | Annotate | Download | only in parameter
      1 /*
      2  * Copyright (c) 2011-2015, Intel Corporation
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright notice, this
      9  * list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright notice,
     12  * this list of conditions and the following disclaimer in the documentation and/or
     13  * other materials provided with the distribution.
     14  *
     15  * 3. Neither the name of the copyright holder nor the names of its contributors
     16  * may be used to endorse or promote products derived from this software without
     17  * specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 #include "Subsystem.h"
     31 #include "ComponentLibrary.h"
     32 #include "InstanceDefinition.h"
     33 #include "XmlParameterSerializingContext.h"
     34 #include "ParameterAccessContext.h"
     35 #include "ConfigurationAccessContext.h"
     36 #include "SubsystemObjectCreator.h"
     37 #include "MappingData.h"
     38 #include <assert.h>
     39 #include <sstream>
     40 
     41 #define base CConfigurableElement
     42 
     43 using std::string;
     44 using std::list;
     45 
     46 CSubsystem::CSubsystem(const string &strName, core::log::Logger &logger)
     47     : base(strName), _pComponentLibrary(new CComponentLibrary),
     48       _pInstanceDefinition(new CInstanceDefinition), _logger(logger)
     49 {
     50     // Note: A subsystem contains instance components
     51     // InstanceDefintion and ComponentLibrary objects are then not chosen to be children
     52     // They'll be delt with locally
     53 }
     54 
     55 CSubsystem::~CSubsystem()
     56 {
     57     // FIXME use unique_ptr, would make this method empty
     58 
     59     for (auto *subsystemObject : _subsystemObjectList) {
     60 
     61         delete subsystemObject;
     62     }
     63 
     64     // Remove susbsystem creators
     65     for (auto *subsystemObjectCreator : _subsystemObjectCreatorArray) {
     66 
     67         delete subsystemObjectCreator;
     68     }
     69 
     70     // Order matters!
     71     delete _pInstanceDefinition;
     72     delete _pComponentLibrary;
     73 
     74     delete _pMappingData;
     75 }
     76 
     77 string CSubsystem::getKind() const
     78 {
     79     return "Subsystem";
     80 }
     81 
     82 // Susbsystem sanity
     83 bool CSubsystem::isAlive() const
     84 {
     85     return true;
     86 }
     87 
     88 // Resynchronization after subsystem restart needed
     89 bool CSubsystem::needResync(bool /*bClear*/)
     90 {
     91     return false;
     92 }
     93 
     94 bool CSubsystem::structureFromXml(const CXmlElement &xmlElement,
     95                                   CXmlSerializingContext &serializingContext)
     96 {
     97     // Subsystem class does not rely on generic fromXml algorithm of Element class.
     98     // So, setting here the description if found as XML attribute.
     99     string description;
    100     xmlElement.getAttribute(gDescriptionPropertyName, description);
    101     setDescription(description);
    102 
    103     // Context
    104     CXmlParameterSerializingContext &parameterBuildContext =
    105         static_cast<CXmlParameterSerializingContext &>(serializingContext);
    106 
    107     // Install temporary component library for further component creation
    108     parameterBuildContext.setComponentLibrary(_pComponentLibrary);
    109 
    110     CXmlElement childElement;
    111 
    112     // Manage mapping attribute
    113     string rawMapping;
    114     xmlElement.getAttribute("Mapping", rawMapping);
    115     if (!rawMapping.empty()) {
    116 
    117         std::string error;
    118         _pMappingData = new CMappingData;
    119         if (!_pMappingData->init(rawMapping, error)) {
    120 
    121             serializingContext.setError("Invalid Mapping data from XML element '" +
    122                                         xmlElement.getPath() + "': " + error);
    123             return false;
    124         }
    125     }
    126 
    127     // XML populate ComponentLibrary
    128     xmlElement.getChildElement("ComponentLibrary", childElement);
    129 
    130     if (!_pComponentLibrary->fromXml(childElement, serializingContext)) {
    131 
    132         return false;
    133     }
    134 
    135     // XML populate InstanceDefintion
    136     xmlElement.getChildElement("InstanceDefintion", childElement);
    137     if (!_pInstanceDefinition->fromXml(childElement, serializingContext)) {
    138 
    139         return false;
    140     }
    141 
    142     // Create components
    143     _pInstanceDefinition->createInstances(this);
    144 
    145     // Execute mapping to create subsystem mapping entities
    146     string strError;
    147     if (!mapSubsystemElements(strError)) {
    148 
    149         serializingContext.setError(strError);
    150 
    151         return false;
    152     }
    153 
    154     return true;
    155 }
    156 
    157 bool CSubsystem::mapSubsystemElements(string &strError)
    158 {
    159     // Default mapping context
    160     CMappingContext context(_contextMappingKeyArray.size());
    161     // Add Subsystem-level mapping data, which will be propagated to all children
    162     handleMappingContext(this, context, strError);
    163 
    164     _contextStack.push(context);
    165 
    166     // Map all instantiated subelements in subsystem
    167     size_t nbChildren = getNbChildren();
    168 
    169     for (size_t child = 0; child < nbChildren; child++) {
    170 
    171         CInstanceConfigurableElement *pInstanceConfigurableChildElement =
    172             static_cast<CInstanceConfigurableElement *>(getChild(child));
    173 
    174         if (!pInstanceConfigurableChildElement->map(*this, strError)) {
    175 
    176             return false;
    177         }
    178     }
    179     return true;
    180 }
    181 
    182 // Formats the mapping of the ConfigurableElements
    183 string CSubsystem::formatMappingDataList(
    184     const list<const CConfigurableElement *> &configurableElementPath) const
    185 {
    186     // The list is parsed in reverse order because it has been filled from the leaf to the trunk
    187     // of the tree. When formatting the mapping, we want to start from the subsystem level
    188     std::list<string> mappings;
    189     list<const CConfigurableElement *>::const_reverse_iterator it;
    190     for (it = configurableElementPath.rbegin(); it != configurableElementPath.rend(); ++it) {
    191 
    192         auto maybeMapping = (*it)->getFormattedMapping();
    193         if (not maybeMapping.empty()) {
    194             mappings.push_back(maybeMapping);
    195         }
    196     }
    197 
    198     return utility::asString(mappings, ", ");
    199 }
    200 
    201 // Find the CSubystemObject containing a specific CInstanceConfigurableElement
    202 const CSubsystemObject *CSubsystem::findSubsystemObjectFromConfigurableElement(
    203     const CInstanceConfigurableElement *pInstanceConfigurableElement) const
    204 {
    205 
    206     list<CSubsystemObject *>::const_iterator it;
    207     for (it = _subsystemObjectList.begin(); it != _subsystemObjectList.end(); ++it) {
    208 
    209         // Check if one of the SubsystemObjects is associated with a ConfigurableElement
    210         // corresponding to the expected one
    211         const CSubsystemObject *pSubsystemObject = *it;
    212 
    213         if (pSubsystemObject->getConfigurableElement() == pInstanceConfigurableElement) {
    214 
    215             return pSubsystemObject;
    216         }
    217     }
    218 
    219     return nullptr;
    220 }
    221 
    222 void CSubsystem::findSubsystemLevelMappingKeyValue(
    223     const CInstanceConfigurableElement *pInstanceConfigurableElement, string &strMappingKey,
    224     string &strMappingValue) const
    225 {
    226     // Find creator to get key name
    227     std::vector<CSubsystemObjectCreator *>::const_iterator it;
    228     for (it = _subsystemObjectCreatorArray.begin(); it != _subsystemObjectCreatorArray.end();
    229          ++it) {
    230 
    231         const CSubsystemObjectCreator *pSubsystemObjectCreator = *it;
    232 
    233         strMappingKey = pSubsystemObjectCreator->getMappingKey();
    234 
    235         // Check if the ObjectCreator MappingKey corresponds to the element mapping data
    236         const string *pStrValue;
    237         if (pInstanceConfigurableElement->getMappingData(strMappingKey, pStrValue)) {
    238 
    239             strMappingValue = *pStrValue;
    240             return;
    241         }
    242     }
    243     assert(0);
    244 }
    245 
    246 // Formats the mapping data as a comma separated list of key value pairs
    247 string CSubsystem::getFormattedSubsystemMappingData(
    248     const CInstanceConfigurableElement *pInstanceConfigurableElement) const
    249 {
    250     // Find the SubsystemObject related to pInstanceConfigurableElement
    251     const CSubsystemObject *pSubsystemObject =
    252         findSubsystemObjectFromConfigurableElement(pInstanceConfigurableElement);
    253 
    254     // Exit if node does not correspond to a SubsystemObject
    255     if (pSubsystemObject == NULL) {
    256 
    257         return "";
    258     }
    259 
    260     // Find SubsystemCreator mapping key
    261     string strMappingKey;
    262     string strMappingValue; // mapping value where amends are not replaced by their value
    263     findSubsystemLevelMappingKeyValue(pInstanceConfigurableElement, strMappingKey, strMappingValue);
    264 
    265     // Find SubSystemObject mapping value (with amends replaced by their value)
    266     return strMappingKey + ":" + pSubsystemObject->getFormattedMappingValue();
    267 }
    268 
    269 string CSubsystem::getMapping(list<const CConfigurableElement *> &configurableElementPath) const
    270 {
    271     if (configurableElementPath.empty()) {
    272 
    273         return "";
    274     }
    275 
    276     // Get the first element, which is the element containing the amended mapping
    277     const CInstanceConfigurableElement *pInstanceConfigurableElement =
    278         static_cast<const CInstanceConfigurableElement *>(configurableElementPath.front());
    279 
    280     // Format context mapping data
    281     string strValue = formatMappingDataList(configurableElementPath);
    282 
    283     // Print the mapping of the first node, which corresponds to a SubsystemObject
    284     auto subsystemObjectAmendedMapping =
    285         getFormattedSubsystemMappingData(pInstanceConfigurableElement);
    286     if (not subsystemObjectAmendedMapping.empty()) {
    287         strValue += ", " + subsystemObjectAmendedMapping;
    288     }
    289 
    290     return strValue;
    291 }
    292 
    293 // Used for simulation and virtual subsystems
    294 void CSubsystem::setDefaultValues(CParameterAccessContext &parameterAccessContext) const
    295 {
    296     base::setDefaultValues(parameterAccessContext);
    297 }
    298 
    299 // Belonging subsystem
    300 const CSubsystem *CSubsystem::getBelongingSubsystem() const
    301 {
    302     return this;
    303 }
    304 
    305 // Subsystem context mapping keys publication
    306 void CSubsystem::addContextMappingKey(const string &strMappingKey)
    307 {
    308     _contextMappingKeyArray.push_back(strMappingKey);
    309 }
    310 
    311 // Subsystem object creator publication (strong reference)
    312 void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator *pSubsystemObjectCreator)
    313 {
    314     _subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator);
    315 }
    316 
    317 // Generic error handling from derived subsystem classes
    318 string CSubsystem::getMappingError(const string &strKey, const string &strMessage,
    319                                    const CConfigurableElement *pConfigurableElement) const
    320 {
    321     return getName() + " " + getKind() + " " + "mapping:\n" + strKey + " " + "error: \"" +
    322            strMessage + "\" " + "for element " + pConfigurableElement->getPath();
    323 }
    324 
    325 bool CSubsystem::getMappingData(const std::string &strKey, const std::string *&pStrValue) const
    326 {
    327     if (_pMappingData) {
    328 
    329         return _pMappingData->getValue(strKey, pStrValue);
    330     }
    331     return false;
    332 }
    333 
    334 // Returns the formatted mapping
    335 std::string CSubsystem::getFormattedMapping() const
    336 {
    337     if (!_pMappingData) {
    338         return "";
    339     }
    340     return _pMappingData->asString();
    341 }
    342 
    343 // Mapping generic context handling
    344 bool CSubsystem::handleMappingContext(const CConfigurableElement *pConfigurableElement,
    345                                       CMappingContext &context, string &strError) const
    346 {
    347     // Feed context with found mapping data
    348     for (size_t item = 0; item < _contextMappingKeyArray.size(); item++) {
    349 
    350         const string &strKey = _contextMappingKeyArray[item];
    351         const string *pStrValue;
    352 
    353         if (pConfigurableElement->getMappingData(strKey, pStrValue)) {
    354             // Assign item to context
    355             if (!context.setItem(item, &strKey, pStrValue)) {
    356 
    357                 strError = getMappingError(strKey, "Already set", pConfigurableElement);
    358 
    359                 return false;
    360             }
    361         }
    362     }
    363     return true;
    364 }
    365 
    366 // Subsystem object creation handling
    367 bool CSubsystem::handleSubsystemObjectCreation(
    368     CInstanceConfigurableElement *pInstanceConfigurableElement, CMappingContext &context,
    369     bool &bHasCreatedSubsystemObject, string &strError)
    370 {
    371     bHasCreatedSubsystemObject = false;
    372 
    373     for (const auto *pSubsystemObjectCreator : _subsystemObjectCreatorArray) {
    374 
    375         // Mapping key
    376         string strKey = pSubsystemObjectCreator->getMappingKey();
    377         // Object id
    378         const string *pStrValue;
    379 
    380         if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
    381 
    382             // First check context consistency
    383             // (required ancestors must have been set prior to object creation)
    384             uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask();
    385 
    386             for (size_t uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size();
    387                  uiAncestorKey++) {
    388 
    389                 if (!((1 << uiAncestorKey) & uiAncestorMask)) {
    390                     // Ancestor not required
    391                     continue;
    392                 }
    393                 // Check ancestor was provided
    394                 if (!context.iSet(uiAncestorKey)) {
    395 
    396                     strError =
    397                         getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] + " not set",
    398                                         pInstanceConfigurableElement);
    399 
    400                     return false;
    401                 }
    402             }
    403 
    404             // Then check configurable element size is correct
    405             if (pInstanceConfigurableElement->getFootPrint() >
    406                 pSubsystemObjectCreator->getMaxConfigurableElementSize()) {
    407 
    408                 string strSizeError =
    409                     "Size should not exceed " +
    410                     std::to_string(pSubsystemObjectCreator->getMaxConfigurableElementSize());
    411 
    412                 strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement);
    413 
    414                 return false;
    415             }
    416 
    417             // Do create object and keep its track
    418             _subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate(
    419                 *pStrValue, pInstanceConfigurableElement, context, _logger));
    420 
    421             // Indicate subsytem creation to caller
    422             bHasCreatedSubsystemObject = true;
    423 
    424             // The subsystem Object has been instantiated, no need to continue looking for an
    425             // instantiation mapping
    426             break;
    427         }
    428     }
    429 
    430     return true;
    431 }
    432 
    433 // From IMapper
    434 // Handle a configurable element mapping
    435 bool CSubsystem::mapBegin(CInstanceConfigurableElement *pInstanceConfigurableElement,
    436                           bool &bKeepDiving, string &strError)
    437 {
    438     // Get current context
    439     CMappingContext context = _contextStack.top();
    440 
    441     // Add mapping in context
    442     if (!handleMappingContext(pInstanceConfigurableElement, context, strError)) {
    443 
    444         return false;
    445     }
    446 
    447     // Push context
    448     _contextStack.push(context);
    449 
    450     // Assume diving by default
    451     bKeepDiving = true;
    452 
    453     // Deal with ambiguous usage of parameter blocks
    454     bool bShouldCreateSubsystemObject = true;
    455 
    456     switch (pInstanceConfigurableElement->getType()) {
    457 
    458     case CInstanceConfigurableElement::EComponent:
    459     case CInstanceConfigurableElement::EParameterBlock:
    460         // Subsystem object creation is optional in parameter blocks
    461         bShouldCreateSubsystemObject = false;
    462     // No break
    463     case CInstanceConfigurableElement::EBitParameterBlock:
    464     case CInstanceConfigurableElement::EParameter:
    465     case CInstanceConfigurableElement::EStringParameter:
    466 
    467         bool bHasCreatedSubsystemObject;
    468 
    469         if (!handleSubsystemObjectCreation(pInstanceConfigurableElement, context,
    470                                            bHasCreatedSubsystemObject, strError)) {
    471 
    472             return false;
    473         }
    474         // Check for creation error
    475         if (bShouldCreateSubsystemObject && !bHasCreatedSubsystemObject) {
    476 
    477             strError = getMappingError("Not found", "Subsystem object mapping key is missing",
    478                                        pInstanceConfigurableElement);
    479             return false;
    480         }
    481         // Not created and no error, keep diving
    482         bKeepDiving = !bHasCreatedSubsystemObject;
    483 
    484         return true;
    485 
    486     default:
    487         assert(0);
    488         return false;
    489     }
    490 }
    491 
    492 void CSubsystem::mapEnd()
    493 {
    494     // Unstack context
    495     _contextStack.pop();
    496 }
    497