pkgimpl.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 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. #ifndef WUPACKAGE_IMPL_HPP
  14. #define WUPACKAGE_IMPL_HPP
  15. #include "platform.h"
  16. #include "jprop.hpp"
  17. #include "jptree.hpp"
  18. #include "jregexp.hpp"
  19. #include "package.h"
  20. #include "referencedfilelist.hpp"
  21. class CPackageSuperFileArray : public CInterface, implements ISimpleSuperFileEnquiry
  22. {
  23. IArrayOf<IPropertyTree> subFiles;
  24. public:
  25. IMPLEMENT_IINTERFACE;
  26. CPackageSuperFileArray(IPropertyTreeIterator &_subs)
  27. {
  28. ForEach(_subs)
  29. {
  30. IPropertyTree &sub = _subs.query();
  31. sub.Link();
  32. subFiles.append(sub);
  33. }
  34. }
  35. virtual unsigned numSubFiles() const
  36. {
  37. return subFiles.length();
  38. }
  39. virtual bool getSubFileName(unsigned num, StringBuffer &name) const
  40. {
  41. if (subFiles.isItem(num))
  42. {
  43. name.append(subFiles.item(num).queryProp("@value"));
  44. return true;
  45. }
  46. else
  47. return false;
  48. }
  49. virtual unsigned findSubName(const char *subname) const
  50. {
  51. ForEachItemIn(idx, subFiles)
  52. {
  53. if (stricmp(subFiles.item(idx).queryProp("@value"), subname))
  54. return idx;
  55. }
  56. return NotFound;
  57. }
  58. virtual unsigned getContents(StringArray &contents) const
  59. {
  60. ForEachItemIn(idx, subFiles)
  61. {
  62. contents.append(subFiles.item(idx).queryProp("@value"));
  63. }
  64. return subFiles.length();
  65. }
  66. };
  67. class WORKUNIT_API CPackageNode : extends CInterface, implements IHpccPackage
  68. {
  69. protected:
  70. Owned<IPropertyTree> node;
  71. Owned<IProperties> mergedEnvironment;
  72. hash64_t hash;
  73. void mergeEnvironment(const CPackageNode *base);
  74. virtual IPropertyTreeIterator *lookupElements(const char *xpath1, const char *xpath2) const = 0;
  75. inline StringBuffer makeSuperFileXPath(StringBuffer &xpath, const char *superFileName) const
  76. {
  77. superFileName = skipForeign(superFileName);
  78. return xpath.append("SuperFile[@id='").appendLower(strlen(superFileName), superFileName).append("']");
  79. }
  80. ISimpleSuperFileEnquiry *resolveSuperFile(const char *superFileName) const;
  81. inline bool hasProp(const char *xpath) const
  82. {
  83. return (node) ? node->hasProp(xpath) : false;
  84. }
  85. virtual bool getSysFieldTranslationEnabled() const {return false;}
  86. virtual bool getEnableFieldTranslation() const
  87. {
  88. const char *val = queryEnv("control:enableFieldTranslation");
  89. if (val)
  90. return strToBool(val);
  91. else
  92. return getSysFieldTranslationEnabled();
  93. }
  94. CPackageNode()
  95. {
  96. hash = 0;
  97. }
  98. virtual const IHpccPackage *queryRootPackage()
  99. {
  100. return NULL;
  101. }
  102. public:
  103. IMPLEMENT_IINTERFACE;
  104. CPackageNode(IPropertyTree *p);
  105. ~CPackageNode()
  106. {
  107. }
  108. // Load mergedEnvironment from local XML node
  109. void loadEnvironment();
  110. virtual const char *queryEnv(const char *varname) const
  111. {
  112. return mergedEnvironment->queryProp(varname);
  113. }
  114. virtual hash64_t queryHash() const
  115. {
  116. return hash;
  117. }
  118. virtual const IPropertyTree *queryTree() const
  119. {
  120. return node;
  121. }
  122. virtual IPropertyTree *getQuerySets() const
  123. {
  124. if (!node)
  125. return NULL;
  126. return node->getPropTree("QuerySets");
  127. }
  128. virtual bool validate(StringArray &warn, StringArray &err) const;
  129. };
  130. enum baseResolutionState
  131. {
  132. basesUnresolved=0,
  133. basesResolving=1,
  134. basesResolved=2
  135. };
  136. template <class TYPE>
  137. class CResolvedPackage : public TYPE
  138. {
  139. public:
  140. typedef CResolvedPackage<TYPE> self;
  141. CIArrayOf<self> bases;
  142. baseResolutionState baseResolution;
  143. CResolvedPackage<TYPE>(IPropertyTree *p) : TYPE(p), baseResolution(basesUnresolved) {}
  144. virtual aindex_t getBaseCount() const {return bases.length();}
  145. const self *getResolvedBase(aindex_t pos) const
  146. {
  147. if (pos < getBaseCount())
  148. return &bases.item(pos);
  149. return NULL;
  150. }
  151. virtual const TYPE *getBaseNode(aindex_t pos) const {return (const TYPE *) getResolvedBase(pos);}
  152. void appendBase(const IHpccPackage *base)
  153. {
  154. if (base)
  155. {
  156. const self *p = dynamic_cast<const self *>(base);
  157. bases.append(const_cast<self &>(*LINK(p))); // should really be an arrayof<const base> but that would require some fixing in jlib
  158. TYPE::hash = pkgHash64Data(sizeof(p->hash), &p->hash, TYPE::hash);
  159. TYPE::mergeEnvironment(p);
  160. }
  161. }
  162. void resolveBases(const IHpccPackageMap *packages)
  163. {
  164. if (baseResolution==basesResolved)
  165. return;
  166. if (baseResolution==basesResolving)
  167. throw MakeStringExceptionDirect(0, "PACKAGE_ERROR: circular or invalid base package definition");
  168. TYPE::loadEnvironment();
  169. if (packages)
  170. {
  171. Owned<IPropertyTreeIterator> baseIterator = TYPE::node->getElements("Base");
  172. if (!baseIterator->first())
  173. appendBase(TYPE::queryRootPackage());
  174. else
  175. {
  176. baseResolution=basesResolving;
  177. do
  178. {
  179. IPropertyTree &baseElem = baseIterator->query();
  180. const char *baseId = baseElem.queryProp("@id");
  181. if (!baseId)
  182. throw MakeStringException(PACKAGE_MISSING_ID, "PACKAGE_ERROR: base element missing id attribute");
  183. const IHpccPackage *base = packages->queryPackage(baseId);
  184. if (!base)
  185. throw MakeStringException(PACKAGE_NOT_FOUND, "PACKAGE_ERROR: base package %s not found", baseId);
  186. CResolvedPackage<TYPE> *rebase = dynamic_cast<CResolvedPackage<TYPE> *>(const_cast<IHpccPackage *>(base));
  187. rebase->resolveBases(packages);
  188. appendBase(base);
  189. }
  190. while(baseIterator->next());
  191. }
  192. baseResolution=basesResolved;
  193. }
  194. }
  195. // Search this package and any bases for an element matching xpath1, then return iterator for its children that match xpath2
  196. IPropertyTreeIterator *lookupElements(const char *xpath1, const char *xpath2) const
  197. {
  198. IPropertyTree *parentNode = TYPE::node->queryPropTree(xpath1);
  199. if (parentNode)
  200. return parentNode->getElements(xpath2);
  201. ForEachItemIn(idx, bases)
  202. {
  203. const self &basePackage = bases.item(idx);
  204. IPropertyTreeIterator *it = basePackage.lookupElements(xpath1, xpath2);
  205. if (it)
  206. return it;
  207. }
  208. return NULL;
  209. }
  210. bool hasSuperFile(const char *superFileName) const
  211. {
  212. if (!superFileName || !*superFileName || !TYPE::node)
  213. return false;
  214. StringBuffer xpath;
  215. if (TYPE::hasProp(TYPE::makeSuperFileXPath(xpath, superFileName)))
  216. return true;
  217. ForEachItemIn(idx, bases)
  218. {
  219. if (bases.item(idx).hasProp(xpath))
  220. return true;
  221. }
  222. return false;
  223. }
  224. virtual bool validate(StringArray &warn, StringArray &err) const
  225. {
  226. return TYPE::validate(warn, err);
  227. }
  228. };
  229. typedef CResolvedPackage<CPackageNode> CHpccPackage;
  230. //================================================================================================
  231. // CPackageMap - an implementation of IPackageMap using a string map
  232. //================================================================================================
  233. template <class TYPE, class IFACE>
  234. class CPackageMapOf : public CInterface, implements IHpccPackageMap
  235. {
  236. public:
  237. typedef CResolvedPackage<TYPE> packageType;
  238. MapStringToMyClassViaBase<packageType, IFACE> packages;
  239. StringAttr packageId;
  240. StringAttr querySet;
  241. bool active;
  242. StringArray wildMatches, wildIds;
  243. public:
  244. IMPLEMENT_IINTERFACE;
  245. CPackageMapOf(const char *_packageId, const char *_querySet, bool _active)
  246. : packageId(_packageId), querySet(_querySet), active(_active), packages(true)
  247. {
  248. }
  249. // IPackageMap interface
  250. virtual bool isActive() const
  251. {
  252. return active;
  253. }
  254. virtual const packageType *queryResolvedPackage(const char *name) const
  255. {
  256. return name ? packages.getValue(name) : NULL;
  257. }
  258. virtual const IHpccPackage *queryPackage(const char *name) const
  259. {
  260. return name ? (IFACE*)packages.getValue(name) : NULL;
  261. }
  262. virtual const char *queryPackageId() const
  263. {
  264. return packageId;
  265. }
  266. virtual const packageType *matchResolvedPackage(const char *name) const
  267. {
  268. if (name && *name)
  269. {
  270. const packageType *pkg = queryResolvedPackage(name);
  271. if (pkg)
  272. return pkg;
  273. const char *tail = name + strlen(name)-1;
  274. while (tail>name && isdigit(*tail))
  275. tail--;
  276. if (*tail=='.' && tail>name)
  277. {
  278. StringAttr notail(name, tail-name);
  279. pkg = queryResolvedPackage(notail);
  280. if (pkg)
  281. return pkg;
  282. }
  283. ForEachItemIn(idx, wildMatches)
  284. {
  285. if (WildMatch(name, wildMatches.item(idx), true))
  286. return queryResolvedPackage(wildIds.item(idx));
  287. }
  288. }
  289. return NULL;
  290. }
  291. const IHpccPackage *matchPackage(const char *name) const
  292. {
  293. return (IFACE *) matchResolvedPackage(name);
  294. }
  295. void load(IPropertyTree *xml)
  296. {
  297. if (!xml)
  298. return;
  299. Owned<IPropertyTreeIterator> allpackages = xml->getElements("Package");
  300. ForEach(*allpackages)
  301. {
  302. IPropertyTree &packageTree = allpackages->query();
  303. const char *id = packageTree.queryProp("@id");
  304. if (!id || !*id)
  305. throw MakeStringException(PACKAGE_MISSING_ID, "Invalid package map - Package element missing id attribute");
  306. Owned<packageType> package = new packageType(&packageTree);
  307. packages.setValue(id, package.get());
  308. const char *queries = packageTree.queryProp("@queries");
  309. if (queries && *queries)
  310. {
  311. wildMatches.append(queries);
  312. wildIds.append(id);
  313. }
  314. }
  315. HashIterator it(packages);
  316. ForEach (it)
  317. {
  318. packageType *pkg = packages.getValue((const char *)it.query().getKey());
  319. if (pkg)
  320. pkg->resolveBases(this);
  321. }
  322. }
  323. void load(const char *id)
  324. {
  325. load(getPackageMapById(id, true));
  326. }
  327. virtual bool validate(const char *queryToCheck, StringArray &warn, StringArray &err,
  328. StringArray &unmatchedQueries, StringArray &unusedPackages, StringArray &unmatchedFiles) const
  329. {
  330. bool isValid = true;
  331. MapStringTo<bool> referencedPackages;
  332. Owned<IPropertyTree> qs = getQueryRegistry(querySet, true);
  333. if (!qs)
  334. throw MakeStringException(PACKAGE_TARGET_NOT_FOUND, "Target %s not found", querySet.sget());
  335. HashIterator it(packages);
  336. ForEach (it)
  337. {
  338. const char *packageId = (const char *)it.query().getKey();
  339. packageType *pkg = packages.getValue(packageId);
  340. if (!pkg)
  341. continue;
  342. if (!pkg->validate(warn, err))
  343. isValid = false;
  344. Owned<IPropertyTreeIterator> baseNodes = pkg->queryTree()->getElements("Base");
  345. ForEach(*baseNodes)
  346. {
  347. const char *baseId = baseNodes->query().queryProp("@id");
  348. if (!baseId || !*baseId)
  349. {
  350. VStringBuffer msg("Package '%s' contains Base element with no id attribute", packageId);
  351. err.append(msg.str());
  352. continue;
  353. }
  354. if (!referencedPackages.getValue(baseId))
  355. referencedPackages.setValue(baseId, true);
  356. }
  357. }
  358. StringBuffer xpath("Query");
  359. if (queryToCheck && *queryToCheck)
  360. xpath.appendf("[@id='%s']", queryToCheck);
  361. Owned<IPropertyTreeIterator> queries = qs->getElements(xpath);
  362. if (!queries->first())
  363. {
  364. warn.append("No Queries found");
  365. return isValid;
  366. }
  367. Owned<IWorkUnitFactory> wufactory = getWorkUnitFactory(NULL, NULL);
  368. ForEach(*queries)
  369. {
  370. const char *queryid = queries->query().queryProp("@id");
  371. if (queryid && *queryid)
  372. {
  373. Owned<IReferencedFileList> filelist = createReferencedFileList(NULL, NULL);
  374. Owned<IConstWorkUnit> cw = wufactory->openWorkUnit(queries->query().queryProp("@wuid"), false);
  375. filelist->addFilesFromQuery(cw, this, queryid);
  376. Owned<IReferencedFileIterator> refFiles = filelist->getFiles();
  377. ForEach(*refFiles)
  378. {
  379. VStringBuffer fullname("%s/%s", queryid, refFiles->query().getLogicalName());
  380. unmatchedFiles.append(fullname);
  381. }
  382. const IHpccPackage *matched = matchPackage(queryid);
  383. if (matched)
  384. {
  385. const char *matchId = matched->queryTree()->queryProp("@id");
  386. if (!referencedPackages.getValue(matchId))
  387. referencedPackages.setValue(matchId, true);
  388. }
  389. else
  390. unmatchedQueries.append(queryid);
  391. }
  392. }
  393. ForEach (it)
  394. {
  395. const char *packageId = (const char *)it.query().getKey();
  396. if (!referencedPackages.getValue(packageId))
  397. unusedPackages.append(packageId);
  398. }
  399. return isValid;
  400. }
  401. };
  402. typedef CPackageMapOf<CPackageNode, IHpccPackage> CHpccPackageMap;
  403. //================================================================================================
  404. // CHpccPackageSet - an implementation of IHpccPackageSet
  405. //================================================================================================
  406. class WORKUNIT_API CHpccPackageSet : public CInterface, implements IHpccPackageSet
  407. {
  408. IArrayOf<CHpccPackageMap> packageMaps;
  409. StringAttr process;
  410. public:
  411. IMPLEMENT_IINTERFACE;
  412. CHpccPackageSet(const char *_process);
  413. void load(IPropertyTree *xml);
  414. virtual const IHpccPackageMap *queryActiveMap(const char *queryset) const;
  415. };
  416. #endif