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 "Element.h"
     31 #include "XmlElementSerializingContext.h"
     32 #include "ElementLibrary.h"
     33 #include "ErrorContext.hpp"
     34 #include "PfError.hpp"
     35 #include <algorithm>
     36 #include <assert.h>
     37 #include <stdio.h>
     38 #include <stdarg.h>
     39 #include <stdlib.h>
     40 
     41 using std::string;
     42 
     43 const std::string CElement::gDescriptionPropertyName = "Description";
     44 
     45 CElement::CElement(const string &strName) : _strName(strName)
     46 {
     47 }
     48 
     49 CElement::~CElement()
     50 {
     51     removeChildren();
     52 }
     53 
     54 void CElement::setDescription(const string &strDescription)
     55 {
     56     _strDescription = strDescription;
     57 }
     58 
     59 const string &CElement::getDescription() const
     60 {
     61     return _strDescription;
     62 }
     63 
     64 bool CElement::childrenAreDynamic() const
     65 {
     66     // By default, children are searched and not created during xml parsing
     67     return false;
     68 }
     69 
     70 bool CElement::init(string &strError)
     71 {
     72 
     73     for (CElement *child : _childArray) {
     74 
     75         if (!child->init(strError)) {
     76 
     77             return false;
     78         }
     79     }
     80 
     81     return true;
     82 }
     83 
     84 string CElement::dumpContent(utility::ErrorContext &errorContext, const size_t depth) const
     85 {
     86     string output;
     87     string strIndent;
     88 
     89     // Level
     90     size_t indents = depth;
     91 
     92     while (indents--) {
     93 
     94         strIndent += "    ";
     95     }
     96     // Type
     97     output += strIndent + "- " + getKind();
     98 
     99     // Name
    100     if (!_strName.empty()) {
    101 
    102         output += ": " + getName();
    103     }
    104 
    105     // Value
    106     string strValue = logValue(errorContext);
    107 
    108     if (!strValue.empty()) {
    109 
    110         output += " = " + strValue;
    111     }
    112 
    113     output += "\n";
    114 
    115     for (CElement *pChild : _childArray) {
    116 
    117         output += pChild->dumpContent(errorContext, depth + 1);
    118     }
    119 
    120     return output;
    121 }
    122 
    123 // Element properties
    124 void CElement::showProperties(string &strResult) const
    125 {
    126     strResult += "Kind: " + getKind() + "\n";
    127     showDescriptionProperty(strResult);
    128 }
    129 
    130 void CElement::showDescriptionProperty(std::string &strResult) const
    131 {
    132     if (!getDescription().empty()) {
    133         strResult += gDescriptionPropertyName + ": " + getDescription() + "\n";
    134     }
    135 }
    136 
    137 // Content dumping
    138 string CElement::logValue(utility::ErrorContext & /*ctx*/) const
    139 {
    140     return "";
    141 }
    142 
    143 // From IXmlSink
    144 bool CElement::fromXml(const CXmlElement &xmlElement,
    145                        CXmlSerializingContext &serializingContext) try {
    146     xmlElement.getAttribute(gDescriptionPropertyName, _strDescription);
    147 
    148     // Propagate through children
    149     CXmlElement::CChildIterator childIterator(xmlElement);
    150 
    151     CXmlElement childElement;
    152 
    153     while (childIterator.next(childElement)) {
    154 
    155         CElement *pChild;
    156 
    157         if (!childrenAreDynamic()) {
    158 
    159             pChild = findChildOfKind(childElement.getType());
    160 
    161             if (!pChild) {
    162 
    163                 serializingContext.setError("Unable to handle XML element: " +
    164                                             childElement.getPath());
    165 
    166                 return false;
    167             }
    168 
    169         } else {
    170             // Child needs creation
    171             pChild = createChild(childElement, serializingContext);
    172 
    173             if (!pChild) {
    174 
    175                 return false;
    176             }
    177         }
    178 
    179         // Dig
    180         if (!pChild->fromXml(childElement, serializingContext)) {
    181 
    182             return false;
    183         }
    184     }
    185 
    186     return true;
    187 } catch (const PfError &e) {
    188     serializingContext.appendLineToError(e.what());
    189     return false;
    190 }
    191 
    192 void CElement::childrenToXml(CXmlElement &xmlElement,
    193                              CXmlSerializingContext &serializingContext) const
    194 {
    195     // Browse children and propagate
    196     for (CElement *pChild : _childArray) {
    197 
    198         // Create corresponding child element
    199         CXmlElement xmlChildElement;
    200 
    201         xmlElement.createChild(xmlChildElement, pChild->getXmlElementName());
    202 
    203         // Propagate
    204         pChild->toXml(xmlChildElement, serializingContext);
    205     }
    206 }
    207 
    208 void CElement::toXml(CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const
    209 {
    210     setXmlNameAttribute(xmlElement);
    211     setXmlDescriptionAttribute(xmlElement);
    212     childrenToXml(xmlElement, serializingContext);
    213 }
    214 
    215 void CElement::setXmlDescriptionAttribute(CXmlElement &xmlElement) const
    216 {
    217     const string &description = getDescription();
    218     if (!description.empty()) {
    219         xmlElement.setAttribute(gDescriptionPropertyName, description);
    220     }
    221 }
    222 
    223 void CElement::setXmlNameAttribute(CXmlElement &xmlElement) const
    224 {
    225     // By default, set Name attribute if any
    226     string strName = getName();
    227 
    228     if (!strName.empty()) {
    229 
    230         xmlElement.setNameAttribute(strName);
    231     }
    232 }
    233 
    234 // Name
    235 void CElement::setName(const string &strName)
    236 {
    237     _strName = strName;
    238 }
    239 
    240 const string &CElement::getName() const
    241 {
    242     return _strName;
    243 }
    244 
    245 bool CElement::rename(const string &strName, string &strError)
    246 {
    247     // Check for conflict with brotherhood if relevant
    248     if (_pParent && _pParent->childrenAreDynamic()) {
    249 
    250         for (CElement *pParentChild : _pParent->_childArray) {
    251 
    252             if (pParentChild != this && pParentChild->getName() == strName) {
    253 
    254                 // Conflict
    255                 strError = "Name conflicts with brother element";
    256 
    257                 return false;
    258             }
    259         }
    260     }
    261     // Change name
    262     setName(strName);
    263 
    264     return true;
    265 }
    266 
    267 string CElement::getPathName() const
    268 {
    269     if (!_strName.empty()) {
    270 
    271         return _strName;
    272     } else {
    273 
    274         return getKind();
    275     }
    276 }
    277 
    278 // Hierarchy
    279 void CElement::addChild(CElement *pChild)
    280 {
    281     _childArray.push_back(pChild);
    282 
    283     pChild->_pParent = this;
    284 }
    285 
    286 CElement *CElement::getChild(size_t index)
    287 {
    288     assert(index <= _childArray.size());
    289 
    290     return _childArray[index];
    291 }
    292 
    293 const CElement *CElement::getChild(size_t index) const
    294 {
    295     assert(index <= _childArray.size());
    296 
    297     return _childArray[index];
    298 }
    299 
    300 CElement *CElement::createChild(const CXmlElement &childElement,
    301                                 CXmlSerializingContext &serializingContext)
    302 {
    303     // Context
    304     CXmlElementSerializingContext &elementSerializingContext =
    305         static_cast<CXmlElementSerializingContext &>(serializingContext);
    306 
    307     // Child needs creation
    308     CElement *pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
    309 
    310     if (!pChild) {
    311 
    312         elementSerializingContext.setError("Unable to create XML element " +
    313                                            childElement.getPath());
    314 
    315         return nullptr;
    316     }
    317     // Store created child!
    318     addChild(pChild);
    319 
    320     return pChild;
    321 }
    322 
    323 bool CElement::removeChild(CElement *pChild)
    324 {
    325     auto childIt = find(begin(_childArray), end(_childArray), pChild);
    326     if (childIt != end(_childArray)) {
    327 
    328         _childArray.erase(childIt);
    329         return true;
    330     }
    331     return false;
    332 }
    333 
    334 void CElement::listChildren(string &strChildList) const
    335 {
    336     // Get list of children names
    337     for (CElement *pChild : _childArray) {
    338 
    339         strChildList += pChild->getName() + "\n";
    340     }
    341 }
    342 
    343 string CElement::listQualifiedPaths(bool bDive, size_t level) const
    344 {
    345     string strResult;
    346 
    347     // Dive Will cause only leaf nodes to be printed
    348     if (!bDive || !getNbChildren()) {
    349 
    350         strResult = getQualifiedPath() + "\n";
    351     }
    352 
    353     if (bDive || !level) {
    354         // Get list of children paths
    355         for (CElement *pChild : _childArray) {
    356 
    357             strResult += pChild->listQualifiedPaths(bDive, level + 1);
    358         }
    359     }
    360     return strResult;
    361 }
    362 
    363 void CElement::listChildrenPaths(string &strChildList) const
    364 {
    365     // Get list of children paths
    366     for (CElement *pChild : _childArray) {
    367 
    368         strChildList += pChild->getPath() + "\n";
    369     }
    370 }
    371 
    372 size_t CElement::getNbChildren() const
    373 {
    374     return _childArray.size();
    375 }
    376 
    377 const CElement *CElement::getParent() const
    378 {
    379     return _pParent;
    380 }
    381 
    382 CElement *CElement::getParent()
    383 {
    384     return _pParent;
    385 }
    386 
    387 void CElement::clean()
    388 {
    389     if (childrenAreDynamic()) {
    390 
    391         removeChildren();
    392     } else {
    393         // Just propagate
    394         for (CElement *pChild : _childArray) {
    395 
    396             pChild->clean();
    397         }
    398     }
    399 }
    400 
    401 void CElement::removeChildren()
    402 {
    403     // Delete in reverse order
    404     ChildArrayReverseIterator it;
    405 
    406     for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
    407 
    408         delete *it;
    409     }
    410     _childArray.clear();
    411 }
    412 
    413 const CElement *CElement::findDescendant(CPathNavigator &pathNavigator) const
    414 {
    415     string *pStrChildName = pathNavigator.next();
    416 
    417     if (!pStrChildName) {
    418 
    419         return this;
    420     }
    421 
    422     const CElement *pChild = findChild(*pStrChildName);
    423 
    424     if (!pChild) {
    425 
    426         return nullptr;
    427     }
    428 
    429     return pChild->findDescendant(pathNavigator);
    430 }
    431 
    432 CElement *CElement::findDescendant(CPathNavigator &pathNavigator)
    433 {
    434     string *pStrChildName = pathNavigator.next();
    435 
    436     if (!pStrChildName) {
    437 
    438         return this;
    439     }
    440 
    441     CElement *pChild = findChild(*pStrChildName);
    442 
    443     if (!pChild) {
    444 
    445         return nullptr;
    446     }
    447 
    448     return pChild->findDescendant(pathNavigator);
    449 }
    450 
    451 bool CElement::isDescendantOf(const CElement *pCandidateAscendant) const
    452 {
    453     if (!_pParent) {
    454 
    455         return false;
    456     }
    457     if (_pParent == pCandidateAscendant) {
    458 
    459         return true;
    460     }
    461     return _pParent->isDescendantOf(pCandidateAscendant);
    462 }
    463 
    464 CElement *CElement::findChild(const string &strName)
    465 {
    466     for (CElement *pChild : _childArray) {
    467 
    468         if (pChild->getPathName() == strName) {
    469 
    470             return pChild;
    471         }
    472     }
    473 
    474     return nullptr;
    475 }
    476 
    477 const CElement *CElement::findChild(const string &strName) const
    478 {
    479     for (CElement *pChild : _childArray) {
    480 
    481         if (pChild->getPathName() == strName) {
    482 
    483             return pChild;
    484         }
    485     }
    486 
    487     return nullptr;
    488 }
    489 
    490 CElement *CElement::findChildOfKind(const string &strKind)
    491 {
    492     for (CElement *pChild : _childArray) {
    493 
    494         if (pChild->getKind() == strKind) {
    495 
    496             return pChild;
    497         }
    498     }
    499 
    500     return nullptr;
    501 }
    502 
    503 const CElement *CElement::findChildOfKind(const string &strKind) const
    504 {
    505     for (CElement *pChild : _childArray) {
    506 
    507         if (pChild->getKind() == strKind) {
    508 
    509             return pChild;
    510         }
    511     }
    512 
    513     return nullptr;
    514 }
    515 
    516 string CElement::getPath() const
    517 {
    518     // Take out root element from the path
    519     if (_pParent && _pParent->_pParent) {
    520 
    521         return _pParent->getPath() + "/" + getPathName();
    522     }
    523     return "/" + getPathName();
    524 }
    525 
    526 string CElement::getQualifiedPath() const
    527 {
    528     return getPath() + " [" + getKind() + "]";
    529 }
    530 
    531 string CElement::getXmlElementName() const
    532 {
    533     // Default to element kind
    534     return getKind();
    535 }
    536