SchemaItem.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2017 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "SchemaItem.hpp"
  14. #include "Exceptions.hpp"
  15. #include "SchemaTypeStringLimits.hpp"
  16. #include "SchemaTypeIntegerLimits.hpp"
  17. #include <algorithm>
  18. // static class variables
  19. //std::map<std::string, std::vector<std::shared_ptr<SchemaValue>>> SchemaItem::m_uniqueAttributeValueSets;
  20. SchemaItem::SchemaItem(const std::string &name, const std::string &className, const std::shared_ptr<SchemaItem> &pParent) :
  21. m_pParent(pParent),
  22. m_hidden(false),
  23. m_minInstances(1),
  24. m_maxInstances(1)
  25. {
  26. //
  27. // Set property defaults
  28. m_properties["name"] = name;
  29. m_properties["displayName"] = name;
  30. m_properties["className"] = className;
  31. //
  32. // If this is a root node (no parent), then do some additional init
  33. if (m_pParent.expired())
  34. {
  35. //
  36. // Create a default type so that all values have a type
  37. std::shared_ptr<SchemaType> pDefaultType = std::make_shared<SchemaType>("default");
  38. std::shared_ptr<SchemaTypeLimits> pDefaultLimits = std::make_shared<SchemaTypeLimits>();
  39. pDefaultType->setLimits(pDefaultLimits);
  40. addSchemaValueType(pDefaultType);
  41. }
  42. }
  43. void SchemaItem::addSchemaValueType(const std::shared_ptr<SchemaType> &pType)
  44. {
  45. m_types[pType->getName()] = pType;
  46. }
  47. std::shared_ptr<SchemaType> SchemaItem::getSchemaValueType(const std::string &typeName, bool throwIfNotPresent) const
  48. {
  49. std::shared_ptr<SchemaType> pType;
  50. auto it = m_types.find(typeName);
  51. if (it != m_types.end())
  52. {
  53. return it->second;
  54. }
  55. else
  56. {
  57. std::shared_ptr<SchemaItem> pParent = m_pParent.lock();
  58. if (pParent)
  59. {
  60. return pParent->getSchemaValueType(typeName, throwIfNotPresent);
  61. }
  62. }
  63. //
  64. // Did not find the type
  65. if (throwIfNotPresent)
  66. {
  67. std::string msg = "Unable to find type: " + typeName;
  68. throw(ParseException(msg));
  69. }
  70. return pType;
  71. }
  72. bool SchemaItem::addUniqueName(const std::string keyName)
  73. {
  74. auto result = m_keys.insert(keyName);
  75. return result.second; // true if keyName did not already exist
  76. }
  77. void SchemaItem::addSchemaType(const std::shared_ptr<SchemaItem> &pItem, const std::string &typeName)
  78. {
  79. auto it = m_schemaTypes.find(typeName);
  80. if (it == m_schemaTypes.end())
  81. {
  82. m_schemaTypes[typeName] = pItem;
  83. }
  84. else
  85. {
  86. throw(ParseException("Duplicate config type found: " + m_properties["name"]));
  87. }
  88. }
  89. std::shared_ptr<SchemaItem> SchemaItem::getSchemaType(const std::string &name, bool throwIfNotPresent) const
  90. {
  91. std::shared_ptr<SchemaItem> pItem;
  92. auto it = m_schemaTypes.find(name);
  93. if (it != m_schemaTypes.end())
  94. {
  95. return it->second;
  96. }
  97. else
  98. {
  99. std::shared_ptr<SchemaItem> pParent = m_pParent.lock();
  100. if (pParent)
  101. {
  102. return pParent->getSchemaType(name, throwIfNotPresent);
  103. }
  104. }
  105. //
  106. // Did not find the type
  107. if (throwIfNotPresent)
  108. {
  109. std::string msg = "Unable to find config type: " + name;
  110. throw(ParseException(msg));
  111. }
  112. return pItem;
  113. }
  114. //
  115. // This method is used to insert a named type into the current schema item. This is done by making copies
  116. // of the relevant members and inserting them into this instance
  117. void SchemaItem::insertSchemaType(const std::shared_ptr<SchemaItem> pTypeItem)
  118. {
  119. //
  120. // To insert a schema type (for example a previously defined complexType name="" XSD definition)
  121. // loop through each set of configurable pieces of the input type, make a copy of each, and add it to
  122. // this element.
  123. //
  124. // Children
  125. std::vector<std::shared_ptr<SchemaItem>> typeChildren;
  126. pTypeItem->getChildren(typeChildren);
  127. for (auto childIt = typeChildren.begin(); childIt != typeChildren.end(); ++childIt)
  128. {
  129. std::shared_ptr<SchemaItem> pNewItem = std::make_shared<SchemaItem>(*(*childIt));
  130. addChild(pNewItem);
  131. }
  132. //
  133. // Attributes
  134. std::vector< std::shared_ptr<SchemaValue>> typeAttributes;
  135. pTypeItem->getAttributes(typeAttributes);
  136. for (auto attrIt = typeAttributes.begin(); attrIt != typeAttributes.end(); ++attrIt)
  137. {
  138. std::shared_ptr<SchemaValue> pNewAttr = std::make_shared<SchemaValue>(*(*attrIt));
  139. addAttribute(pNewAttr);
  140. }
  141. //
  142. // Type main value
  143. if (pTypeItem->getItemSchemaValue() != nullptr)
  144. {
  145. std::shared_ptr<SchemaValue> pNewItemCfgValue = std::make_shared<SchemaValue>(*(pTypeItem->getItemSchemaValue()));
  146. setItemSchemaValue(pNewItemCfgValue);
  147. }
  148. //
  149. // Unique attribute sets
  150. for (auto setIt = pTypeItem->m_uniqueAttributeValueSetDefs.begin(); setIt != pTypeItem->m_uniqueAttributeValueSetDefs.end(); ++setIt)
  151. {
  152. m_uniqueAttributeValueSetDefs.insert({ setIt->first, setIt->second });
  153. }
  154. //
  155. // Unique attribute reference sets
  156. for (auto it = pTypeItem->m_uniqueAttributeValueSetReferences.begin(); it != pTypeItem->m_uniqueAttributeValueSetReferences.end(); ++it)
  157. {
  158. m_uniqueAttributeValueSetReferences.insert({ it->first, it->second });
  159. }
  160. }
  161. void SchemaItem::addAttribute(const std::shared_ptr<SchemaValue> &pCfgValue)
  162. {
  163. auto retVal = m_attributes.insert({ pCfgValue->getName(), pCfgValue });
  164. if (!retVal.second)
  165. {
  166. throw(ParseException("Duplicate attribute (" + pCfgValue->getName() + ") found for element " + m_properties["name"]));
  167. }
  168. }
  169. void SchemaItem::addAttribute(const std::map<std::string, std::shared_ptr<SchemaValue>> &attributes)
  170. {
  171. for (auto it = attributes.begin(); it != attributes.end(); ++it)
  172. addAttribute(it->second);
  173. }
  174. void SchemaItem::addAttribute(const std::vector<std::shared_ptr<SchemaValue>> &attributes)
  175. {
  176. for (auto it=attributes.begin(); it!=attributes.end(); ++it)
  177. addAttribute(*it);
  178. }
  179. void SchemaItem::getAttributes(std::vector<std::shared_ptr<SchemaValue>> &attributes) const
  180. {
  181. for (auto it = m_attributes.begin(); it != m_attributes.end(); ++it)
  182. attributes.push_back(it->second);
  183. }
  184. std::shared_ptr<SchemaValue> SchemaItem::getAttribute(const std::string &name, bool createIfDoesNotExist) const
  185. {
  186. std::shared_ptr<SchemaValue> pCfgValue;
  187. auto it = m_attributes.find(name);
  188. if (it != m_attributes.end())
  189. {
  190. pCfgValue = it->second;
  191. }
  192. else if (createIfDoesNotExist)
  193. {
  194. // not found, build a default cfg value for the undefined attribute
  195. pCfgValue = std::make_shared<SchemaValue>(name, false);
  196. pCfgValue->setType(getSchemaValueType("default"));
  197. }
  198. return pCfgValue;
  199. }
  200. void SchemaItem::addUniqueAttributeValueSetDefinition(const std::string &setName, const std::string &elementPath, const std::string &attributeName, bool duplicateOk)
  201. {
  202. m_uniqueAttributeValueSetDefs.insert({ setName, SetInfo(setName, elementPath, attributeName, duplicateOk) }); // these are processed later
  203. }
  204. void SchemaItem::addReferenceToUniqueAttributeValueSet(const std::string &setName, const std::string &elementPath, const std::string &attributeName)
  205. {
  206. m_uniqueAttributeValueSetReferences.insert({ setName, SetInfo(setName, elementPath, attributeName) }); // these are processed later
  207. }
  208. void SchemaItem::processUniqueAttributeValueSetReferences(const std::map<std::string, std::vector<std::shared_ptr<SchemaValue>>> &uniqueAttributeValueSets)
  209. {
  210. for (auto setRefIt = m_uniqueAttributeValueSetReferences.begin(); setRefIt != m_uniqueAttributeValueSetReferences.end(); ++setRefIt)
  211. {
  212. auto keyIt = uniqueAttributeValueSets.find(setRefIt->second.m_setName);
  213. if (keyIt != uniqueAttributeValueSets.end())
  214. {
  215. for (auto cfgIt = keyIt->second.begin(); cfgIt != keyIt->second.end(); ++cfgIt)
  216. {
  217. std::shared_ptr<SchemaValue> pKeyRefAttribute = *cfgIt; // this is the reference attribute from which attributeName must be a member
  218. std::string cfgValuePath = ((setRefIt->second.m_elementPath != ".") ? setRefIt->second.m_elementPath : "") + "@" + setRefIt->second.m_attributeName;
  219. std::vector<std::shared_ptr<SchemaValue>> cfgValues;
  220. findSchemaValues(cfgValuePath, cfgValues);
  221. if (!cfgValues.empty())
  222. {
  223. for (auto attrIt = cfgValues.begin(); attrIt != cfgValues.end(); ++attrIt)
  224. {
  225. (*attrIt)->setUniqueValueSetRef(pKeyRefAttribute);
  226. }
  227. }
  228. else
  229. {
  230. throw(ParseException("Attribute " + (setRefIt->second.m_attributeName + " not found when adding keyRef for key " + (setRefIt->second.m_setName))));
  231. }
  232. }
  233. }
  234. else
  235. {
  236. throw(ParseException("Keyref to key '" + (setRefIt->second.m_setName + "' was not found")));
  237. }
  238. }
  239. }
  240. void SchemaItem::getChildren(std::vector<std::shared_ptr<SchemaItem>> &children)
  241. {
  242. for (auto it = m_children.begin(); it != m_children.end(); ++it)
  243. {
  244. children.push_back(it->second);
  245. }
  246. }
  247. std::shared_ptr<SchemaItem> SchemaItem::getChild(const std::string &name)
  248. {
  249. std::shared_ptr<SchemaItem> pItem = std::make_shared<SchemaItem>(name, "default", shared_from_this());
  250. auto it = m_children.find(name); // only return the first one
  251. if (it != m_children.end())
  252. {
  253. pItem = it->second;
  254. }
  255. return pItem;
  256. }
  257. std::shared_ptr<SchemaItem> SchemaItem::getChildByComponent(const std::string &name, std::string &componentName)
  258. {
  259. std::shared_ptr<SchemaItem> pItem = std::make_shared<SchemaItem>(name, "default", shared_from_this());
  260. auto childItRange = m_children.equal_range(name);
  261. for (auto childIt = childItRange.first; childIt != childItRange.second; ++childIt)
  262. {
  263. if (childIt->second->getProperty("componentName") == componentName)
  264. {
  265. pItem = childIt->second;
  266. break;
  267. }
  268. }
  269. return pItem;
  270. }
  271. void SchemaItem::resetEnvironment()
  272. {
  273. for (auto it = m_attributes.begin(); it != m_attributes.end(); ++it)
  274. {
  275. it->second->resetEnvironment();
  276. }
  277. }
  278. void SchemaItem::findSchemaValues(const std::string &path, std::vector<std::shared_ptr<SchemaValue>> &schemaValues)
  279. {
  280. bool rootPath = path[0] == '/';
  281. //
  282. // If path is from the root, and we aren't the root, pass the request to our parent
  283. if (rootPath && !m_pParent.expired())
  284. {
  285. std::shared_ptr<SchemaItem> pParent = m_pParent.lock();
  286. if (pParent)
  287. {
  288. return pParent->findSchemaValues(path, schemaValues);
  289. }
  290. }
  291. //
  292. // Break the path down and process it
  293. size_t start = rootPath ? 1 : 0; // skip leading slash if we are at the root
  294. size_t end = path.find_first_of("/@", start);
  295. if (end != std::string::npos)
  296. {
  297. std::string elem = path.substr(start, end - start);
  298. if (rootPath)
  299. {
  300. if (m_properties["name"] == elem)
  301. {
  302. return findSchemaValues(path.substr(end + 1), schemaValues);
  303. }
  304. else
  305. {
  306. throw(ParseException("Unable to find root element '" + elem + "' when searching path '" + path + "'"));
  307. }
  308. }
  309. if (path[0] == '@')
  310. {
  311. std::string attrName = path.substr(1);
  312. auto rangeIt = m_attributes.equal_range(attrName);
  313. for (auto it = rangeIt.first; it != rangeIt.second; ++it)
  314. {
  315. schemaValues.push_back(it->second);
  316. }
  317. }
  318. else
  319. {
  320. auto rangeIt = m_children.equal_range(elem);
  321. for (auto it = rangeIt.first; it != rangeIt.second; ++it)
  322. {
  323. it->second->findSchemaValues(path.substr(end + ((path[end] == '/') ? 1 : 0)), schemaValues);
  324. }
  325. }
  326. }
  327. return;
  328. }
  329. void SchemaItem::processDefinedUniqueAttributeValueSets(std::map<std::string, std::vector<std::shared_ptr<SchemaValue>>> &uniqueAttributeValueSets)
  330. {
  331. for (auto setIt = m_uniqueAttributeValueSetDefs.begin(); setIt != m_uniqueAttributeValueSetDefs.end(); ++setIt)
  332. {
  333. auto it = uniqueAttributeValueSets.find(setIt->first);
  334. bool keyDefExists = it != uniqueAttributeValueSets.end();
  335. if (!keyDefExists || setIt->second.m_duplicateOk)
  336. {
  337. std::string cfgValuePath = ((setIt->second.m_elementPath != ".") ? setIt->second.m_elementPath : "") + "@" + setIt->second.m_attributeName;
  338. std::vector<std::shared_ptr<SchemaValue>> cfgValues;
  339. findSchemaValues(cfgValuePath, cfgValues);
  340. if (!cfgValues.empty())
  341. {
  342. //
  343. // For each attribute, if it does not already exist in the list of attributes making up this
  344. // key value, add it.
  345. for (auto attrIt = cfgValues.begin(); attrIt != cfgValues.end(); ++attrIt)
  346. {
  347. (*attrIt)->setUniqueValue(true);
  348. if (!keyDefExists)
  349. {
  350. std::vector<std::shared_ptr<SchemaValue>> values;
  351. values.push_back(*attrIt);
  352. it = uniqueAttributeValueSets.insert({ setIt->second.m_setName, values }).first; // so the else condition will work
  353. keyDefExists = true; // Now, it does exist
  354. }
  355. else
  356. {
  357. std::vector<std::shared_ptr<SchemaValue>> &values = it->second;
  358. bool found = false;
  359. for (auto cfgIt = values.begin(); cfgIt != values.end() && !found; ++cfgIt)
  360. {
  361. found = (*cfgIt) == (*attrIt);
  362. }
  363. if (!found)
  364. values.push_back(*attrIt);
  365. }
  366. }
  367. }
  368. else
  369. {
  370. throw(ParseException("Attribute " + setIt->second.m_attributeName + " not found for key " + setIt->second.m_setName));
  371. }
  372. }
  373. else
  374. {
  375. throw(ParseException("Duplicate key (" + setIt->second.m_setName + ") found for element " + m_properties["name"]));
  376. }
  377. }
  378. //
  379. // Post process all of our children now
  380. for (auto it = m_children.begin(); it != m_children.end(); ++it)
  381. {
  382. it->second->processDefinedUniqueAttributeValueSets(uniqueAttributeValueSets);
  383. }
  384. }
  385. void SchemaItem::postProcessConfig(const std::map<std::string, std::vector<std::shared_ptr<SchemaValue>>> &uniqueAttributeValueSets)
  386. {
  387. //
  388. // Make sure that the item type value for all children that are insertable (minRequired = 0 or maxAllowed > minRequired)
  389. std::set<std::string> itemTypes;
  390. for (auto it = m_children.begin(); it != m_children.end(); ++it)
  391. {
  392. if (it->second->isInsertable())
  393. {
  394. auto rc = itemTypes.insert(it->second->getItemType());
  395. if (!rc.second)
  396. {
  397. throw(ParseException("Duplicate itemType(" + it->second->getItemType() + ") found for element " + m_properties["name"]));
  398. }
  399. }
  400. }
  401. processUniqueAttributeValueSetReferences(uniqueAttributeValueSets);
  402. //
  403. // Post process the attributes
  404. for (auto it = m_attributes.begin(); it != m_attributes.end(); ++it)
  405. {
  406. //
  407. // If this is a mirroed value, go find the source and attach ourselves so that if that value changes,
  408. // it is replicated to us.
  409. if (it->second->isMirroredValue())
  410. {
  411. std::vector<std::shared_ptr<SchemaValue>> cfgValues;
  412. findSchemaValues(it->second->getMirrorFromPath(), cfgValues);
  413. if (!cfgValues.empty() && cfgValues.size() == 1)
  414. {
  415. if (cfgValues.size() == 1)
  416. {
  417. it->second->addMirroredSchemaValue(cfgValues[0]);
  418. }
  419. else
  420. {
  421. throw(ParseException("Multiple sources found for mirror from path for attribute " + it->second->getName() + " (path=" + it->second->getMirrorFromPath()));
  422. }
  423. }
  424. else
  425. {
  426. throw(ParseException("Mirrored from source not found for attribute " + it->second->getName() + " path=" + it->second->getMirrorFromPath()));
  427. }
  428. }
  429. }
  430. //
  431. // Post process all of our children now
  432. for (auto it = m_children.begin(); it!= m_children.end(); ++it)
  433. {
  434. it->second->postProcessConfig(uniqueAttributeValueSets);
  435. }
  436. }
  437. std::string SchemaItem::getItemType() const
  438. {
  439. //
  440. // Return itemType based on this set of rules
  441. if (!getProperty("itemType").empty())
  442. return getProperty("itemType");
  443. else if (!getProperty("componentName").empty())
  444. return getProperty("componentName");
  445. return getProperty("name");
  446. }
  447. std::string SchemaItem::getProperty(const std::string &name, const std::string &dflt) const
  448. {
  449. std::string retVal = dflt;
  450. auto it = m_properties.find(name);
  451. if (it != m_properties.end())
  452. {
  453. retVal = it->second;
  454. }
  455. return retVal;
  456. }