ws_config2Service.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  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 "ws_config2Service.hpp"
  14. #include "jfile.hpp"
  15. #include "SchemaItem.hpp"
  16. #include "InsertableItem.hpp"
  17. #include "jexcept.hpp"
  18. #include "ws_config2Error.hpp"
  19. static const std::string CFG2_MASTER_CONFIG_FILE = "environment.xsd";
  20. static const std::string CFG2_CONFIG_DIR = COMPONENTFILES_DIR PATHSEPSTR "config2xml" PATHSEPSTR;
  21. static const std::string CFG2_SOURCE_DIR = CONFIG_SOURCE_DIR;
  22. static const std::string ACTIVE_ENVIRONMENT_FILE = CONFIG_DIR PATHSEPSTR ENV_XML_FILE;
  23. Cws_config2Ex::Cws_config2Ex()
  24. {
  25. m_sessionKey = 0;
  26. }
  27. Cws_config2Ex::~Cws_config2Ex()
  28. {
  29. }
  30. bool Cws_config2Ex::onOpenSession(IEspContext &context, IEspOpenSessionRequest &req, IEspOpenSessionResponse &resp)
  31. {
  32. bool loaded = false;
  33. ConfigMgrSession *pNewSession = new ConfigMgrSession();
  34. std::string inputMasterFile = req.getMasterSchemaFile();
  35. std::string inputSchemaPath = req.getSchemaPath();
  36. std::string inputSourcePath = req.getSourcePath();
  37. std::string inputActivePath = req.getSourcePath();
  38. pNewSession->masterConfigFile = (inputMasterFile != "") ? inputMasterFile : CFG2_MASTER_CONFIG_FILE;
  39. pNewSession->username = req.getUsername();
  40. pNewSession->schemaPath = !inputSchemaPath.empty() ? inputSchemaPath : CFG2_CONFIG_DIR;
  41. pNewSession->sourcePath = !inputSourcePath.empty() ? inputSourcePath : CFG2_SOURCE_DIR;
  42. pNewSession->activePath = !inputActivePath.empty() ? inputActivePath : ACTIVE_ENVIRONMENT_FILE;
  43. //
  44. // Only XML supported at this time
  45. pNewSession->configType = XML;
  46. //
  47. // Open the session by loading the schema, which is done during session init
  48. std::vector<std::string> cfgParms;
  49. cfgParms.push_back("buildset.xml"); // Note that this is hardcoded for now, when other types suppored, must be passed in
  50. if (pNewSession->initializeSession(cfgParms))
  51. {
  52. std::string sessionId = std::to_string(m_sessionKey);
  53. resp.setSessionId(sessionId.c_str());
  54. m_sessions[sessionId] = pNewSession;
  55. m_sessionKey++;
  56. }
  57. else
  58. {
  59. std::string errMsg = pNewSession->getLastMsg();
  60. delete pNewSession;
  61. throw MakeStringException(CFGMGR_ERROR_SESSION_NOT_CREATED, "Error creating session, error: %s", errMsg.c_str());
  62. }
  63. return true;
  64. }
  65. bool Cws_config2Ex::onCloseSession(IEspContext &context, IEspCloseSessionRequest &req, IEspEmptyResponse &resp)
  66. {
  67. std::string sessionId = req.getSessionId();
  68. ConfigMgrSession *pSession = getConfigSession(sessionId);
  69. if (pSession->modified)
  70. {
  71. if (!req.getForceClose())
  72. {
  73. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_MODIFIED, "Current environment is modified, either save or close it first");
  74. }
  75. }
  76. deleteConfigSession(sessionId);
  77. return true;
  78. }
  79. bool Cws_config2Ex::onGetOpenSessions(IEspContext &context, IEspListOpenSessionsRequest &req, IEspListOpenSessionsResponse &resp)
  80. {
  81. IArrayOf<IEspOpenSessionInfo> openSessions;
  82. for (auto sessionIt=m_sessions.begin(); sessionIt != m_sessions.end(); ++sessionIt)
  83. {
  84. ConfigMgrSession *pSession = sessionIt->second;
  85. Owned<IEspOpenSessionInfo> pSessionInfo = createOpenSessionInfo();
  86. pSessionInfo->setUsername(pSession->username.c_str());
  87. pSessionInfo->setCurEnvironmentFile(pSession->curEnvironmentFile.c_str());
  88. pSessionInfo->setLocked(pSession->locked);
  89. pSessionInfo->setModified(pSession->modified);
  90. openSessions.append(*pSessionInfo.getLink());
  91. }
  92. resp.setOpenSessions(openSessions);
  93. return true;
  94. }
  95. bool Cws_config2Ex::onGetEnvironmentFileList(IEspContext &context, IEspCommonSessionRequest &req, IEspGetEnvironmentListResponse &resp)
  96. {
  97. std::string sessionId = req.getSessionId();
  98. ConfigMgrSession *pSession = getConfigSession(sessionId);
  99. //
  100. // Calculate md5 checksum of the current active environment for use in comparing against the available list
  101. // of environments so the active environment is identified in the returned list
  102. StringBuffer activeConfig_md5sum;
  103. md5_filesum(pSession->activePath.c_str(), activeConfig_md5sum);
  104. IArrayOf<IEspEnvironmentFileType> environmentFiles;
  105. Owned<IFile> pDir = createIFile(CFG2_SOURCE_DIR.c_str());
  106. if (pDir->exists())
  107. {
  108. Owned<IDirectoryIterator> it = pDir->directoryFiles(NULL, false, true);
  109. ForEach(*it)
  110. {
  111. StringBuffer filename;
  112. it->getName(filename);
  113. String str(filename);
  114. str.toLowerCase();
  115. if (str.endsWith(pSession->getEnvironmentFileExtension().c_str()))
  116. {
  117. Owned<IEspEnvironmentFileType> pEnvFile = createEnvironmentFileType();
  118. pEnvFile->setFilename(filename.str());
  119. //
  120. // See if active
  121. StringBuffer curEnvFile_md5sum;
  122. std::string fullPath;
  123. std::string fname = filename.str();
  124. pSession->getEnvironmentFullyQualifiedPath(fname, fullPath);
  125. md5_filesum(fullPath.c_str(), curEnvFile_md5sum);
  126. if (strcmp(curEnvFile_md5sum.str(),activeConfig_md5sum.str()) == 0)
  127. {
  128. pEnvFile->setIsActive(true);
  129. }
  130. environmentFiles.append(*pEnvFile.getLink());
  131. }
  132. }
  133. resp.setEnvironmentFiles(environmentFiles);
  134. }
  135. return true;
  136. }
  137. bool Cws_config2Ex::onOpenEnvironmentFile(IEspContext &context, IEspOpenEnvironmentFileRequest &req, IEspOpenEnvironmentFileResponse &resp)
  138. {
  139. bool doOpen = false;
  140. ConfigMgrSession *pSession = getConfigSession(req.getSessionId());
  141. //
  142. // See if modified (which can only be true if an environment is currently loaded)
  143. if (pSession->modified)
  144. {
  145. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_MODIFIED, "Current environment is modified, either save or close it first");
  146. }
  147. std::string newEnvFile = req.getFilename();
  148. if (!pSession->loadEnvironment(newEnvFile))
  149. {
  150. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_NOT_LOADED, "Unable to load environment, error = %s", pSession->getLastMsg().c_str());
  151. }
  152. resp.setRootNodeId(pSession->m_pEnvMgr->getRootNodeId().c_str());
  153. return true;
  154. }
  155. bool Cws_config2Ex::onCloseEnvironmentFile(IEspContext &context, IEspCloseEnvironmentFileRequest &req, IEspEmptyResponse &resp)
  156. {
  157. bool doClose = false;
  158. ConfigMgrSession *pSession = getConfigSession(req.getSessionId());
  159. if (pSession->modified)
  160. {
  161. pSession = getConfigSessionForUpdate(req.getSessionId(), req.getSessionLockKey()); // forces the lock key check
  162. //
  163. // Since modified, only allow close if discard changes is set
  164. if (!req.getDiscardChanges())
  165. {
  166. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_MODIFIED, "Current environment is modified, either save, close, or set discardChanges");
  167. }
  168. }
  169. pSession->closeEnvironment();
  170. return true;
  171. }
  172. bool Cws_config2Ex::onSaveEnvironmentFile(IEspContext &context, IEspSaveEnvironmentFileRequest &req, IEspEmptyResponse &resp)
  173. {
  174. // todo: If this envronment file is loaded by any other session, go mark that session that the environment has changed
  175. // and don't allow a save w/o reloading first. maybe add a reload request. Add relevant errors.
  176. // also make sure if filename is specified that it
  177. // 1. does not match the current loaded environment if current environment is modified and lock key is missing or does not match
  178. // 2. does not match the name of any other open session's loaded and locked environment.
  179. std::string sessionId = req.getSessionId();
  180. ConfigMgrSession *pSession = getConfigSession(sessionId); // only verify session ID, lock key verified below
  181. std::string saveFilename = req.getFilename();
  182. bool doSave = true;
  183. bool wasSaved = false;
  184. //
  185. // If a new filename is given, then search existing sessions to see if the filename matches any open
  186. // environments that have locked it. If so, prevent the save.
  187. if (!saveFilename.empty())
  188. {
  189. for (auto sessionIt = m_sessions.begin(); sessionIt != m_sessions.end(); ++sessionIt)
  190. {
  191. if (sessionIt->second->curEnvironmentFile == saveFilename && sessionIt->second->locked)
  192. {
  193. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_LOCKED, "Target environment is currently locked by another session");
  194. }
  195. }
  196. }
  197. //
  198. // If session if modified and saving over exiting environment, check lock key
  199. if (saveFilename.empty() && pSession->modified)
  200. {
  201. pSession = getConfigSessionForUpdate(req.getSessionLockKey(), req.getSessionLockKey());
  202. }
  203. if (!pSession->saveEnvironment(saveFilename))
  204. {
  205. throw MakeStringException(CFGMGR_ERROR_SAVE_ENVIRONMENT, "There was a problem saving the environment");
  206. }
  207. //
  208. // Save was completed, if a new filename was given, then search existing sessions to see if the filename
  209. // matches any open environments. If so, mark the session as having the environment externally modified
  210. // which prevents that session from locking the environment. Note that another session having the
  211. // environment locked would have prevented this session from locking the same environment.
  212. if (!saveFilename.empty())
  213. {
  214. for (auto sessionIt = m_sessions.begin(); sessionIt != m_sessions.end(); ++sessionIt)
  215. {
  216. if (sessionIt->second->curEnvironmentFile == saveFilename)
  217. {
  218. sessionIt->second->externallyModified = true;
  219. }
  220. }
  221. }
  222. return true;
  223. }
  224. bool Cws_config2Ex::onLockSession(IEspContext &context, IEspCommonSessionRequest &req, IEspLockSessionResponse &resp)
  225. {
  226. std::string sessionId = req.getSessionId();
  227. ConfigMgrSession *pSession = getConfigSession(sessionId);
  228. if (pSession->locked)
  229. {
  230. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_LOCKED, "Current enironment already locked");
  231. }
  232. if (pSession->curEnvironmentFile.empty())
  233. {
  234. throw MakeStringException(CFGMGR_ERROR_NO_ENVIRONMENT, "No environment loaded");
  235. }
  236. if (pSession->externallyModified)
  237. {
  238. throw MakeStringException(CFGMGR_ERROR_ENV_EXTERNAL_CHANGE, "No environment loaded");
  239. }
  240. //
  241. // Search existing sessions to see if any currently have this environment file locked
  242. for (auto sessionIt = m_sessions.begin(); sessionIt != m_sessions.end(); ++sessionIt)
  243. {
  244. if (sessionIt->second != pSession && sessionIt->second->locked && pSession->curEnvironmentFile == sessionIt->second->curEnvironmentFile)
  245. {
  246. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_LOCKED, "Environment is locked by another session");
  247. }
  248. }
  249. if (pSession->lock())
  250. {
  251. resp.setSessionLockKey(pSession->lockKey.c_str());
  252. }
  253. else
  254. {
  255. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_LOCKING, "Error locking the session");
  256. }
  257. return true;
  258. }
  259. bool Cws_config2Ex::onUnlockSession(IEspContext &context, IEspUnlockSessionRequest &req, IEspEmptyResponse &resp)
  260. {
  261. ConfigMgrSession *pSession = getConfigSessionForUpdate(req.getSessionId(), req.getSessionLockKey());
  262. if (!pSession->unlock(req.getSessionLockKey()))
  263. {
  264. throw MakeStringException(CFGMGR_ERROR_ENVIRONMENT_LOCKING, "Error unlocking the session");
  265. }
  266. return true;
  267. }
  268. bool Cws_config2Ex::onGetNode(IEspContext &context, IEspNodeRequest &req, IEspGetNodeResponse &resp)
  269. {
  270. std::string sessionId = req.getSessionId();
  271. std::string id = req.getNodeId();
  272. ConfigMgrSession *pSession = getConfigSession(sessionId);
  273. Status status;
  274. EnvironmentMgr *pEnvMgr = pSession->m_pEnvMgr;
  275. std::shared_ptr<EnvironmentNode> pNode = pEnvMgr->getEnvironmentNode(id);
  276. if (pNode == nullptr)
  277. {
  278. throw MakeStringException(CFGMGR_ERROR_NODE_INVALID, "Environment node ID is not valid");
  279. }
  280. getNodeResponse(pNode, resp);
  281. pNode->validate(status, false); // validate this node only
  282. addStatusToResponse(status, pSession, reinterpret_cast<IEspStatusResponse &>(resp));
  283. //
  284. // Finalize the response
  285. resp.setNodeId(id.c_str());
  286. return true;
  287. }
  288. bool Cws_config2Ex::onInsertNode(IEspContext &context, IEspInsertNodeRequest &req, IEspGetNodeResponse &resp)
  289. {
  290. ConfigMgrSession *pSession = getConfigSessionForUpdate(req.getSessionId(), req.getSessionLockKey());
  291. Status status;
  292. std::string parentNodeId = req.getParentNodeId();
  293. std::shared_ptr<EnvironmentNode> pNode = pSession->m_pEnvMgr->getEnvironmentNode(parentNodeId);
  294. if (pNode)
  295. {
  296. std::shared_ptr<EnvironmentNode> pNewNode = pSession->m_pEnvMgr->addNewEnvironmentNode(parentNodeId, req.getNodeType(), status);
  297. if (pNewNode)
  298. {
  299. getNodeResponse(pNewNode, resp);
  300. resp.setNodeId(pNewNode->getId().c_str());
  301. pSession->modified = true;
  302. }
  303. }
  304. else
  305. {
  306. throw MakeStringException(CFGMGR_ERROR_NODE_INVALID, "Environment node ID is not valid");
  307. }
  308. addStatusToResponse(status, pSession, reinterpret_cast<IEspStatusResponse &>(resp));
  309. return true;
  310. }
  311. bool Cws_config2Ex::onRemoveNode(IEspContext &context, IEspRemoveNodeRequest &req, IEspStatusResponse &resp)
  312. {
  313. std::string sessionId = req.getSessionId();
  314. std::string key = req.getSessionLockKey();
  315. ConfigMgrSession *pSession = getConfigSessionForUpdate(sessionId, key);
  316. Status status;
  317. std::string nodeId = req.getNodeId();
  318. if (!pSession->m_pEnvMgr->removeEnvironmentNode(nodeId))
  319. {
  320. throw MakeStringException(CFGMGR_ERROR_NODE_INVALID, "Environment node ID is not valid");
  321. }
  322. pSession->modified = true;
  323. pSession->m_pEnvMgr->validate(status, false);
  324. addStatusToResponse(status, pSession, resp);
  325. return true;
  326. }
  327. bool Cws_config2Ex::onValidateEnvironment(IEspContext &context, IEspValidateEnvironmentRequest &req, IEspStatusResponse &resp)
  328. {
  329. Status status;
  330. std::string sessionId = req.getSessionId();
  331. ConfigMgrSession *pSession = getConfigSession(sessionId);
  332. pSession->m_pEnvMgr->validate(status, req.getIncludeHiddenNodes());
  333. addStatusToResponse(status, pSession, resp);
  334. return true;
  335. }
  336. bool Cws_config2Ex::onSetValues(IEspContext &context, IEspSetValuesRequest &req, IEspStatusResponse &resp)
  337. {
  338. Status status;
  339. std::string sessionId = req.getSessionId();
  340. std::string key = req.getSessionLockKey();
  341. ConfigMgrSession *pSession = getConfigSessionForUpdate(sessionId, key);
  342. std::string id = req.getNodeId();
  343. std::shared_ptr<EnvironmentNode> pNode = pSession->m_pEnvMgr->getEnvironmentNode(id);
  344. if (pNode == nullptr)
  345. {
  346. throw MakeStringException(CFGMGR_ERROR_NODE_INVALID, "Environment node ID is not valid");
  347. }
  348. bool forceCreate = req.getForceCreate();
  349. bool allowInvalid = req.getAllowInvalid();
  350. IArrayOf<IConstAttributeValueType> &attrbuteValues = req.getAttributeValues();
  351. std::vector<NameValue> values;
  352. ForEachItemIn(i, attrbuteValues)
  353. {
  354. IConstAttributeValueType& attrVal = attrbuteValues.item(i);
  355. NameValue value;
  356. value.name = attrVal.getName();
  357. value.value = attrVal.getValue();
  358. values.push_back(value);
  359. }
  360. pNode->setAttributeValues(values, status, allowInvalid, forceCreate);
  361. pSession->modified = true;
  362. addStatusToResponse(status, pSession, resp);
  363. return true;
  364. }
  365. bool Cws_config2Ex::onGetParents(IEspContext &context, IEspNodeRequest &req, IEspGetParentsResponse &resp)
  366. {
  367. std::string nodeId = req.getNodeId();
  368. std::string sessionId = req.getSessionId();
  369. ConfigMgrSession *pSession = getConfigSession(sessionId);
  370. StringArray ids;
  371. std::shared_ptr<EnvironmentNode> pNode = pSession->m_pEnvMgr->getEnvironmentNode(nodeId);
  372. if (pNode == nullptr)
  373. {
  374. throw MakeStringException(CFGMGR_ERROR_NODE_INVALID, "Environment node ID is not valid");
  375. }
  376. while (pNode)
  377. {
  378. pNode = pNode->getParent();
  379. if (pNode)
  380. {
  381. ids.append(pNode->getId().c_str());
  382. }
  383. }
  384. resp.setParentIdList(ids);
  385. return true;
  386. }
  387. bool Cws_config2Ex::onGetNodeTree(IEspContext &context, IEspGetTreeRequest &req, IEspGetTreeResponse &resp)
  388. {
  389. std::string nodeId = req.getNodeId();
  390. std::string sessionId = req.getSessionId();
  391. ConfigMgrSession *pSession = getConfigSession(sessionId);
  392. std::shared_ptr<EnvironmentNode> pNode = pSession->m_pEnvMgr->getEnvironmentNode(nodeId);
  393. if (pNode)
  394. {
  395. getNodeTree(pNode, resp.updateTree(), req.getNumLevels(), req.getIncludeAttributes());
  396. }
  397. return true;
  398. }
  399. bool Cws_config2Ex::onFetchNodes(IEspContext &context, IEspFetchNodesRequest &req, IEspFetchNodesResponse &resp)
  400. {
  401. std::string sessionId = req.getSessionId();
  402. std::string path = req.getPath();
  403. std::string startingNodeId = req.getStartingNodeId();
  404. std::shared_ptr<EnvironmentNode> pStartingNode;
  405. ConfigMgrSession *pSession = getConfigSession(sessionId);
  406. if (startingNodeId != "")
  407. {
  408. if (path[0] == '/')
  409. {
  410. throw MakeStringException(CDGMGR_ERROR_PATH_INVALID, "Path may not begin at root if starting node specified");
  411. }
  412. pStartingNode = pSession->m_pEnvMgr->getEnvironmentNode(startingNodeId);
  413. if (!pStartingNode)
  414. {
  415. throw MakeStringException(CFGMGR_ERROR_NODE_INVALID, "The starting node ID is not valid");
  416. }
  417. }
  418. else if (path[0] != '/')
  419. {
  420. throw MakeStringException(CDGMGR_ERROR_PATH_INVALID, "Path must begin at root (/) if no starting node is specified");
  421. }
  422. std::vector<std::shared_ptr<EnvironmentNode>> nodes;
  423. pSession->m_pEnvMgr->fetchNodes(path, nodes, pStartingNode);
  424. StringArray ids;
  425. for ( auto &&pNode : nodes)
  426. {
  427. if (!pNode->getSchemaItem()->isHidden())
  428. {
  429. ids.append(pNode->getId().c_str());
  430. }
  431. }
  432. resp.setNodeIds(ids);
  433. return true;
  434. }
  435. void Cws_config2Ex::addStatusToResponse(const Status &status, ConfigMgrSession *pSession, IEspStatusResponse &resp) const
  436. {
  437. std::vector<statusMsg> statusMsgs = status.getMessages();
  438. IArrayOf<IEspStatusMsgType> msgs;
  439. for (auto msgIt=statusMsgs.begin(); msgIt!=statusMsgs.end(); ++msgIt)
  440. {
  441. Owned<IEspStatusMsgType> pStatusMsg = createStatusMsgType();
  442. pStatusMsg->setNodeId((*msgIt).nodeId.c_str());
  443. pStatusMsg->setMsg((*msgIt).msg.c_str());
  444. pStatusMsg->setMsgLevel(status.getStatusTypeString((*msgIt).msgLevel).c_str());
  445. pStatusMsg->setAttribute((*msgIt).attribute.c_str());
  446. if (!(*msgIt).nodeId.empty() && pSession != nullptr)
  447. {
  448. StringArray ids;
  449. getNodeParents((*msgIt).nodeId, pSession, ids);
  450. std::shared_ptr<EnvironmentNode> pNode = pSession->m_pEnvMgr->getEnvironmentNode((*msgIt).nodeId);
  451. pStatusMsg->setNodeName(pNode->getName().c_str());
  452. pStatusMsg->setParentIdList(ids);
  453. }
  454. msgs.append(*pStatusMsg.getLink());
  455. }
  456. resp.updateStatus().setStatus(msgs);
  457. resp.updateStatus().setError(status.isError());
  458. }
  459. ConfigMgrSession *Cws_config2Ex::getConfigSession(const std::string &sessionId)
  460. {
  461. ConfigMgrSession *pSession = nullptr;
  462. if (sessionId.empty())
  463. throw MakeStringException(CFGMGR_ERROR_MISSING_SESSION_ID, "Session ID required");
  464. auto it = m_sessions.find(sessionId);
  465. if (it != m_sessions.end())
  466. {
  467. pSession = (it->second);
  468. }
  469. if (pSession == nullptr)
  470. throw MakeStringException(CFGMGR_ERROR_INVALID_SESSION_ID, "Session ID not valid");
  471. return pSession;
  472. }
  473. ConfigMgrSession *Cws_config2Ex::getConfigSessionForUpdate(const std::string &sessionId, const std::string &lockKey)
  474. {
  475. ConfigMgrSession *pSession = getConfigSession(sessionId);
  476. if (!pSession->doesKeyFit(lockKey))
  477. {
  478. throw MakeStringException(CFGMGR_ERROR_LOCK_KEY_INVALID, "Session lock key is missing or invalid");
  479. }
  480. return pSession;
  481. }
  482. bool Cws_config2Ex::deleteConfigSession(const std::string &sessionId)
  483. {
  484. bool rc = false;
  485. ConfigMgrSession *pSession = getConfigSession(sessionId);
  486. if (pSession)
  487. {
  488. m_sessions.erase(sessionId);
  489. delete pSession;
  490. rc = true;
  491. }
  492. return rc;
  493. }
  494. void Cws_config2Ex::getNodeResponse(const std::shared_ptr<EnvironmentNode> &pNode, IEspGetNodeResponse &resp) const
  495. {
  496. const std::shared_ptr<SchemaItem> &pNodeSchemaItem = pNode->getSchemaItem();
  497. std::string nodeDisplayName;
  498. resp.setNodeId(pNode->getId().c_str());
  499. //
  500. // Fill in base node info struct
  501. getNodeInfo(pNode, resp.updateNodeInfo());
  502. //
  503. // Handle the attributes
  504. IArrayOf<IEspAttributeType> nodeAttributes;
  505. if (pNode->hasAttributes())
  506. {
  507. std::vector<std::shared_ptr<EnvironmentValue>> attributes;
  508. pNode->getAttributes(attributes);
  509. getAttributes(attributes, nodeAttributes);
  510. }
  511. resp.setAttributes(nodeAttributes);
  512. //
  513. // Now the children
  514. IArrayOf<IEspNodeType> childNodes;
  515. if (pNode->hasChildren())
  516. {
  517. std::vector<std::shared_ptr<EnvironmentNode>> children;
  518. pNode->getChildren(children);
  519. for (auto it=children.begin(); it!=children.end(); ++it)
  520. {
  521. std::shared_ptr<EnvironmentNode> pChildEnvNode = *it;
  522. const std::shared_ptr<SchemaItem> pSchemaItem = pChildEnvNode->getSchemaItem();
  523. Owned<IEspNodeType> pChildNode = createNodeType();
  524. getNodeInfo(pChildEnvNode, pChildNode->updateNodeInfo());
  525. pChildNode->setNodeId(pChildEnvNode->getId().c_str());
  526. pChildNode->setNumChildren(pChildEnvNode->getNumChildren());
  527. childNodes.append(*pChildNode.getLink());
  528. }
  529. }
  530. resp.setChildren(childNodes);
  531. //
  532. // Build a list of items that can be inserted under this node
  533. IArrayOf<IEspInsertItemType> newNodes;
  534. std::vector<InsertableItem> insertableList;
  535. pNode->getInsertableItems(insertableList);
  536. for (auto it=insertableList.begin(); it!=insertableList.end(); ++it)
  537. {
  538. bool addItem = true;
  539. std::shared_ptr<SchemaItem> pSchemaItem = (*it).m_pSchemaItem;
  540. Owned<IEspInsertItemType> pInsertInfo = createInsertItemType();
  541. pInsertInfo->setName(pSchemaItem->getProperty("displayName").c_str());
  542. pInsertInfo->setNodeType(pSchemaItem->getItemType().c_str());
  543. pInsertInfo->setClass(pSchemaItem->getProperty("className").c_str());
  544. pInsertInfo->setCategory(pSchemaItem->getProperty("category").c_str());
  545. pInsertInfo->setRequired(pSchemaItem->isRequired());
  546. pInsertInfo->setTooltip(pSchemaItem->getProperty("tooltip").c_str());
  547. if (it->m_limitChoices)
  548. {
  549. pInsertInfo->setFixedChoices(true);
  550. IArrayOf<IEspChoiceLimitType> fixedChoices;
  551. for (auto &fc : (*it).m_itemLimits)
  552. {
  553. Owned<IEspChoiceLimitType> pChoice = createChoiceLimitType();
  554. pChoice->setDisplayName(fc.itemName.c_str());
  555. std::string itemType = pSchemaItem->getItemType() + "@" + fc.attributeName + "=" + fc.attributeValue;
  556. pChoice->setItemType(itemType.c_str());
  557. fixedChoices.append(*pChoice.getLink());
  558. }
  559. pInsertInfo->setChoiceList(fixedChoices);
  560. addItem = fixedChoices.ordinality() != 0;
  561. }
  562. if (addItem)
  563. {
  564. newNodes.append(*pInsertInfo.getLink());
  565. }
  566. }
  567. resp.setInsertable(newNodes);
  568. if (pNodeSchemaItem->isItemValueDefined())
  569. {
  570. resp.setLocalValueDefined(true);
  571. const std::shared_ptr<SchemaValue> &pNodeSchemaValue = pNodeSchemaItem->getItemSchemaValue();
  572. const std::shared_ptr<SchemaType> &pType = pNodeSchemaValue->getType();
  573. resp.updateValue().updateType().setName(pType->getName().c_str());
  574. if (pType->getLimits()->isMaxSet())
  575. {
  576. resp.updateValue().updateType().updateLimits().setMaxValid(true);
  577. resp.updateValue().updateType().updateLimits().setMax(pType->getLimits()->getMax());
  578. }
  579. if (pType->getLimits()->isMinSet())
  580. {
  581. resp.updateValue().updateType().updateLimits().setMinValid(true);
  582. resp.updateValue().updateType().updateLimits().setMin(pType->getLimits()->getMin());
  583. }
  584. if (pNode->isLocalValueSet())
  585. {
  586. const std::shared_ptr<EnvironmentValue> &pLocalValue = pNode->getLocalEnvValue();
  587. resp.updateValue().setCurrentValue(pLocalValue->getValue().c_str());
  588. //
  589. // Type information
  590. const std::shared_ptr<SchemaValue> pLocalSchemaValue = pLocalValue->getSchemaValue();
  591. const std::shared_ptr<SchemaType> &pLocalType = pLocalSchemaValue->getType();
  592. std::shared_ptr<SchemaTypeLimits> &pLimits = pLocalType->getLimits();
  593. resp.updateValue().updateType().setName(pLocalType->getName().c_str());
  594. if (pLocalType->getLimits()->isMaxSet())
  595. {
  596. resp.updateValue().updateType().updateLimits().setMaxValid(true);
  597. resp.updateValue().updateType().updateLimits().setMax(pLocalType->getLimits()->getMax());
  598. }
  599. if (pLocalType->getLimits()->isMinSet())
  600. {
  601. resp.updateValue().updateType().updateLimits().setMinValid(true);
  602. resp.updateValue().updateType().updateLimits().setMin(pLocalType->getLimits()->getMin());
  603. }
  604. resp.updateValue().setRequired(pLocalSchemaValue->isRequired());
  605. resp.updateValue().setReadOnly(pLocalSchemaValue->isReadOnly());
  606. resp.updateValue().setHidden(pLocalSchemaValue->isHidden());
  607. }
  608. }
  609. }
  610. void Cws_config2Ex::getNodeInfo(const std::shared_ptr<EnvironmentNode> &pNode, IEspNodeInfoType &nodeInfo) const
  611. {
  612. const std::shared_ptr<SchemaItem> &pNodeSchemaItem = pNode->getSchemaItem();
  613. std::string nodeDisplayName;
  614. //
  615. // Fill in base node info struct
  616. getNodeInfo(pNodeSchemaItem, nodeInfo); // fill it in based on schema
  617. getNodeDisplayName(pNode, nodeDisplayName); // possibly override the displayname
  618. nodeInfo.setName(nodeDisplayName.c_str());
  619. }
  620. void Cws_config2Ex::getNodeInfo(const std::shared_ptr<SchemaItem> &pNodeSchemaItem, IEspNodeInfoType &nodeInfo) const
  621. {
  622. //
  623. // Fill in base node info struct
  624. nodeInfo.setName(pNodeSchemaItem->getProperty("displayName").c_str());
  625. nodeInfo.setNodeType(pNodeSchemaItem->getItemType().c_str());
  626. nodeInfo.setClass(pNodeSchemaItem->getProperty("className").c_str());
  627. nodeInfo.setCategory(pNodeSchemaItem->getProperty("category").c_str());
  628. nodeInfo.setTooltip(pNodeSchemaItem->getProperty("tooltip").c_str());
  629. nodeInfo.setHidden(pNodeSchemaItem->isHidden());
  630. }
  631. void Cws_config2Ex::getAttributes(const std::vector<std::shared_ptr<EnvironmentValue>> &attributes, IArrayOf<IEspAttributeType> &nodeAttributes) const
  632. {
  633. for (auto it=attributes.begin(); it!=attributes.end(); ++it)
  634. {
  635. std::shared_ptr<EnvironmentValue> pAttr = *it;
  636. Owned<IEspAttributeType> pAttribute = createAttributeType();
  637. const std::shared_ptr<SchemaValue> &pSchemaValue = pAttr->getSchemaValue();
  638. std::string attributeName = pAttr->getName();
  639. pAttribute->setName(attributeName.c_str());
  640. pAttribute->setDisplayName(pSchemaValue->getDisplayName().c_str());
  641. pAttribute->setTooltip(pSchemaValue->getTooltip().c_str());
  642. const std::shared_ptr<SchemaType> &pType = pSchemaValue->getType();
  643. std::shared_ptr<SchemaTypeLimits> &pLimits = pType->getLimits();
  644. pAttribute->updateType().setName(pType->getName().c_str());
  645. if (pType->getLimits()->isMaxSet())
  646. {
  647. pAttribute->updateType().updateLimits().setMaxValid(true);
  648. pAttribute->updateType().updateLimits().setMax(pType->getLimits()->getMax());
  649. }
  650. if (pType->getLimits()->isMinSet())
  651. {
  652. pAttribute->updateType().updateLimits().setMinValid(true);
  653. pAttribute->updateType().updateLimits().setMin(pType->getLimits()->getMin());
  654. }
  655. pAttribute->setRequired(pSchemaValue->isRequired());
  656. pAttribute->setReadOnly(pSchemaValue->isReadOnly());
  657. pAttribute->setHidden(pSchemaValue->isHidden());
  658. pAttribute->setDeprecated(pSchemaValue->isDeprecated());
  659. pAttribute->setGroup(pSchemaValue->getGroup().c_str());
  660. std::vector<AllowedValue> allowedValues;
  661. pSchemaValue->getAllowedValues(allowedValues, pAttr->getEnvironmentNode());
  662. if (!allowedValues.empty())
  663. {
  664. IArrayOf<IEspChoiceType> choices;
  665. for (auto valueIt=allowedValues.begin(); valueIt!=allowedValues.end(); ++valueIt)
  666. {
  667. Owned<IEspChoiceType> pChoice = createChoiceType();
  668. pChoice->setDisplayName((*valueIt).m_displayName.c_str());
  669. pChoice->setValue((*valueIt).m_value.c_str());
  670. pChoice->setDesc((*valueIt).m_description.c_str());
  671. pChoice->setMsg((*valueIt).m_userMessage.c_str());
  672. pChoice->setMsgType((*valueIt).m_userMessageType.c_str());
  673. //
  674. // Add dependencies
  675. if ((*valueIt).hasDependencies())
  676. {
  677. IArrayOf<IEspDependentValueType> dependencies;
  678. for (auto &depIt: (*valueIt).getDependencies())
  679. {
  680. Owned<IEspDependentValueType> pDep = createDependentValueType();
  681. pDep->setAttributeName(depIt.m_attribute.c_str());
  682. pDep->setAttributeValue(depIt.m_value.c_str());
  683. dependencies.append(*pDep.getLink());
  684. }
  685. pChoice->setDependencies(dependencies);
  686. }
  687. choices.append(*pChoice.getLink());
  688. }
  689. pAttribute->updateType().updateLimits().setChoiceList(choices);
  690. }
  691. pAttribute->setCurrentValue(pAttr->getValue().c_str());
  692. pAttribute->setDefaultValue(pSchemaValue->getDefaultValue().c_str());
  693. nodeAttributes.append(*pAttribute.getLink());
  694. }
  695. }
  696. void Cws_config2Ex::getNodeDisplayName(const std::shared_ptr<EnvironmentNode> &pNode, std::string &nodeDisplayName) const
  697. {
  698. const std::shared_ptr<SchemaItem> &pNodeSchemaItem = pNode->getSchemaItem();
  699. nodeDisplayName = pNodeSchemaItem->getProperty("displayName");
  700. if (pNode->hasAttributes())
  701. {
  702. std::shared_ptr<EnvironmentValue> pAttr = pNode->getAttribute("name");
  703. if (pAttr && pAttr->isValueSet())
  704. {
  705. nodeDisplayName = pAttr->getValue(); // better usability value
  706. }
  707. }
  708. }
  709. void Cws_config2Ex::getNodeParents(const std::string &nodeId, ConfigMgrSession *pSession, StringArray &parentNodeIds) const
  710. {
  711. std::shared_ptr<EnvironmentNode> pNode = pSession->m_pEnvMgr->getEnvironmentNode(nodeId);
  712. if (pNode)
  713. {
  714. while (pNode)
  715. {
  716. pNode = pNode->getParent();
  717. if (pNode)
  718. {
  719. parentNodeIds.append(pNode->getId().c_str());
  720. }
  721. }
  722. }
  723. }
  724. void Cws_config2Ex::getNodeTree(const std::shared_ptr<EnvironmentNode> &pNode, IEspTreeElementType &treeElement, int levels, bool includeAttributes) const
  725. {
  726. //
  727. // Fill in this element
  728. treeElement.setNodeId(pNode->getId().c_str());
  729. getNodeInfo(pNode, treeElement.updateNodeInfo());
  730. if (includeAttributes && pNode->hasAttributes())
  731. {
  732. IArrayOf<IEspAttributeType> nodeAttributes;
  733. std::vector<std::shared_ptr<EnvironmentValue>> attributes;
  734. pNode->getAttributes(attributes);
  735. getAttributes(attributes, nodeAttributes);
  736. treeElement.setAttributes(nodeAttributes);
  737. }
  738. //
  739. // If we need to descend more levels, do so
  740. if (levels > 0)
  741. {
  742. --levels;
  743. IArrayOf<IEspTreeElementType> childNodes;
  744. if (pNode->hasChildren())
  745. {
  746. std::vector<std::shared_ptr<EnvironmentNode>> children;
  747. pNode->getChildren(children);
  748. for (auto it=children.begin(); it!=children.end(); ++it)
  749. {
  750. Owned<IEspTreeElementType> pTreeElement = createTreeElementType();
  751. getNodeTree(*it, *pTreeElement, levels, includeAttributes);
  752. childNodes.append(*pTreeElement.getLink());
  753. }
  754. }
  755. treeElement.setChildren(childNodes);
  756. }
  757. }