wuwebview.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  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. #include "jlib.hpp"
  14. #include "jexcept.hpp"
  15. #include "jptree.hpp"
  16. #include "junicode.hpp"
  17. #include "workunit.hpp"
  18. #include "dllserver.hpp"
  19. #include "thorplugin.hpp"
  20. #include "xslprocessor.hpp"
  21. #include "fileview.hpp"
  22. #include "wuwebview.hpp"
  23. #include "wuweberror.hpp"
  24. typedef MapStringTo<bool> BoolHash;
  25. class WuExpandedResultBuffer : implements IPTreeNotifyEvent, public CInterface
  26. {
  27. public:
  28. IMPLEMENT_IINTERFACE;
  29. WuExpandedResultBuffer(const char *queryname, unsigned _flags=0) :
  30. name(queryname), resultlevel(0), finalized(false), flags(_flags), hasXmlns(false)
  31. {
  32. if (flags & (WWV_INCL_NAMESPACES | WWV_INCL_GENERATED_NAMESPACES))
  33. {
  34. StringBuffer lower(name);
  35. ns.append("urn:hpccsystems:ecl:").append(lower.toLowerCase());
  36. }
  37. if (!(flags & WWV_OMIT_XML_DECLARATION))
  38. buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  39. if (flags & WWV_USE_DISPLAY_XSLT)
  40. buffer.append("<?xml-stylesheet type=\"text/xsl\" href=\"/esp/xslt/xmlformatter.xsl\"?>");
  41. if (flags & WWV_ADD_SOAP)
  42. buffer.append(
  43. "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
  44. " xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\">"
  45. " <soap:Body>"
  46. );
  47. if (flags & WWV_ADD_RESPONSE_TAG)
  48. {
  49. buffer.append('<');
  50. if (queryname)
  51. buffer.append(queryname);
  52. buffer.append("Response");
  53. if ((flags & WWV_INCL_NAMESPACES) && ns.length())
  54. buffer.append(" xmlns=\"").append(ns.str()).append('\"');
  55. buffer.append('>');
  56. }
  57. if (flags & WWV_ADD_RESULTS_TAG)
  58. buffer.append("<Results>");
  59. if (!(flags & WWV_OMIT_RESULT_TAG))
  60. buffer.append("<Result>");
  61. initResultChildTags();
  62. }
  63. void initResultChildTags()
  64. {
  65. resultChildTags.setValue("Dataset", true);
  66. resultChildTags.setValue("Exception", true);
  67. resultChildTags.setValue("Warning", true);
  68. resultChildTags.setValue("Alert", true);
  69. resultChildTags.setValue("Info", true);
  70. }
  71. void appendResults(IConstWorkUnit *wu, const char *username, const char *pw)
  72. {
  73. StringBufferAdaptor resultXML(buffer);
  74. getFullWorkUnitResultsXML(username, pw, wu, resultXML, WorkUnitXML_NoRoot, SeverityError);
  75. }
  76. void appendSingleResult(IConstWorkUnit *wu, const char *resultname, const char *username, const char *pw)
  77. {
  78. StringBufferAdaptor resultXML(buffer);
  79. Owned<IResultSetFactory> factory = getResultSetFactory(username, pw);
  80. Owned<INewResultSet> nr = factory->createNewResultSet(wu->queryWuid(), 0, resultname);
  81. getResultXml(resultXML, nr.get(), resultname, 0, 0, NULL);
  82. }
  83. void appendDatasetsFromXML(const char *xml)
  84. {
  85. assertex(!finalized);
  86. Owned<IPullPTreeReader> reader = createPullXMLStringReader(xml, *this);
  87. reader->load();
  88. }
  89. void append(const char *value)
  90. {
  91. assertex(!finalized);
  92. buffer.append(value);
  93. }
  94. void appendSchemaResource(IPropertyTree &res, ILoadedDllEntry *dll)
  95. {
  96. if (!dll || (flags & WWV_OMIT_SCHEMAS))
  97. return;
  98. if (res.getPropInt("@seq", -1)>=0 && res.hasProp("@id"))
  99. {
  100. int id = res.getPropInt("@id");
  101. size32_t len = 0;
  102. const void *data = NULL;
  103. if (dll->getResource(len, data, "RESULT_XSD", (unsigned) id) && len>0)
  104. {
  105. buffer.append("<XmlSchema name=\"").append(res.queryProp("@name")).append("\">");
  106. if (res.getPropBool("@compressed"))
  107. {
  108. StringBuffer decompressed;
  109. decompressResource(len, data, decompressed);
  110. if (flags & WWV_CDATA_SCHEMAS)
  111. buffer.append("<![CDATA[");
  112. buffer.append(decompressed.str());
  113. if (flags & WWV_CDATA_SCHEMAS)
  114. buffer.append("]]>");
  115. }
  116. else
  117. buffer.append(len, (const char *)data);
  118. buffer.append("</XmlSchema>");
  119. }
  120. }
  121. }
  122. void appendManifestSchemas(IPropertyTree &manifest, ILoadedDllEntry *dll)
  123. {
  124. if (flags & WWV_OMIT_SCHEMAS)
  125. return;
  126. assertex(!finalized);
  127. if (!dll)
  128. return;
  129. BoolHash uniqueResultNames;
  130. Owned<IPropertyTreeIterator> iter = manifest.getElements("Resource[@type='RESULT_XSD']");
  131. ForEach(*iter)
  132. {
  133. IPropertyTree& res = iter->query();
  134. const char* name = res.queryProp("@name");
  135. if (name && *name)
  136. {
  137. bool* found = uniqueResultNames.getValue(name);
  138. if (found && *found)
  139. continue;
  140. uniqueResultNames.setValue(name, true);
  141. }
  142. appendSchemaResource(res, dll);
  143. }
  144. }
  145. void appendManifestResultSchema(IPropertyTree &manifest, const char *resultname, ILoadedDllEntry *dll)
  146. {
  147. assertex(!finalized);
  148. if (!dll)
  149. return;
  150. VStringBuffer xpath("Resource[@name='%s'][@type='RESULT_XSD']", resultname);
  151. IPropertyTree *res=manifest.queryPropTree(xpath.str());
  152. if (res)
  153. appendSchemaResource(*res, dll);
  154. }
  155. void appendXML(IPropertyTree *xml, const char *tag=NULL)
  156. {
  157. assertex(!finalized);
  158. if (tag)
  159. buffer.append('<').append(tag).append('>');
  160. if (xml)
  161. toXML(xml, buffer);
  162. if (tag)
  163. buffer.append("</").append(tag).append('>');
  164. }
  165. virtual void beginNode(const char *tag, offset_t startOffset)
  166. {
  167. bool *pIsResultTag = resultChildTags.getValue(tag);
  168. if (pIsResultTag && *pIsResultTag)
  169. resultlevel++;
  170. if (resultlevel)
  171. buffer.append('<').append(tag);
  172. }
  173. virtual void newAttribute(const char *name, const char *value)
  174. {
  175. if (resultlevel)
  176. {
  177. if (streq(name, "@xmlns"))
  178. {
  179. if (!(flags & WWV_INCL_NAMESPACES))
  180. return;
  181. if (resultlevel==1)
  182. hasXmlns=true;
  183. }
  184. if (resultlevel==1 && streq(name, "@name"))
  185. dsname.set(value).toLowerCase().replace(' ', '_');;
  186. buffer.append(' ').append(name+1).append("=\"");
  187. encodeUtf8XML(value, buffer);
  188. buffer.append('\"');
  189. }
  190. }
  191. virtual void beginNodeContent(const char *tag)
  192. {
  193. if (resultlevel==1 && streq("Dataset", tag))
  194. {
  195. if (!hasXmlns && dsname.length() && (flags & WWV_INCL_GENERATED_NAMESPACES))
  196. {
  197. StringBuffer s(ns);
  198. s.append(":result:").append(dsname.str());
  199. buffer.append(" xmlns=\"").append(s).append('\"');
  200. }
  201. dsname.clear();
  202. hasXmlns=false;
  203. }
  204. if (resultlevel)
  205. buffer.append('>');
  206. }
  207. virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset)
  208. {
  209. if (resultlevel)
  210. {
  211. if (length)
  212. {
  213. if (binary)
  214. JBASE64_Encode(value, length, buffer);
  215. else
  216. encodeUtf8XML((const char *)value, buffer);
  217. }
  218. buffer.append("</").append(tag).append('>');
  219. bool *pIsResultTag = resultChildTags.getValue(tag);
  220. if (pIsResultTag && *pIsResultTag)
  221. resultlevel--;
  222. }
  223. }
  224. StringBuffer &finalize()
  225. {
  226. if (!finalized)
  227. {
  228. if (!(flags & WWV_OMIT_RESULT_TAG))
  229. buffer.append("</Result>");
  230. if (flags & WWV_ADD_RESULTS_TAG)
  231. buffer.append("</Results>");
  232. if (flags & WWV_ADD_RESPONSE_TAG)
  233. buffer.appendf("</%sResponse>", name.str());
  234. if (flags & WWV_ADD_SOAP)
  235. buffer.append("</soap:Body></soap:Envelope>");
  236. finalized=true;
  237. }
  238. return buffer;
  239. }
  240. const char *str()
  241. {
  242. finalize();
  243. return buffer.str();
  244. }
  245. size32_t length()
  246. {
  247. finalize();
  248. return buffer.length();
  249. }
  250. public:
  251. StringBuffer buffer;
  252. StringAttr name;
  253. StringBuffer dsname;
  254. StringBuffer ns;
  255. bool hasXmlns;
  256. bool finalized;
  257. unsigned flags;
  258. MapStringTo<bool> resultChildTags;
  259. private:
  260. int resultlevel;
  261. };
  262. class WuWebView : public CInterface,
  263. implements IWuWebView,
  264. implements IIncludeHandler
  265. {
  266. public:
  267. IMPLEMENT_IINTERFACE
  268. WuWebView(IConstWorkUnit &wu, const char *_target, const char *queryname, const char *wdir, bool mapEspDir, bool delay=true) :
  269. manifestIncludePathsSet(false), dir(wdir), mapEspDirectories(mapEspDir), delayedDll(delay), target(_target)
  270. {
  271. name.set(queryname);
  272. setWorkunit(wu);
  273. }
  274. WuWebView(const char *wuid, const char *_target, const char *queryname, const char *wdir, bool mapEspDir, bool delay=true) :
  275. manifestIncludePathsSet(false), dir(wdir), mapEspDirectories(mapEspDir), delayedDll(delay), target(_target)
  276. {
  277. name.set(queryname);
  278. setWorkunit(wuid);
  279. }
  280. void setWorkunit(IConstWorkUnit &wu);
  281. void setWorkunit(const char *wuid);
  282. ILoadedDllEntry *loadDll(bool force=false);
  283. IPropertyTree *ensureManifest();
  284. virtual void getResultViewNames(StringArray &names);
  285. virtual void getResourceURLs(StringArray &urls, const char *prefix);
  286. virtual unsigned getResourceURLCount();
  287. virtual void renderResults(const char *viewName, const char *xml, StringBuffer &html);
  288. virtual void renderResults(const char *viewName, StringBuffer &html);
  289. virtual void renderSingleResult(const char *viewName, const char *resultname, StringBuffer &html);
  290. virtual void renderResultsJSON(StringBuffer &out, const char *jsonp);
  291. virtual void expandResults(const char *xml, StringBuffer &out, unsigned flags);
  292. virtual void expandResults(StringBuffer &out, unsigned flags);
  293. virtual void createWuidResponse(StringBuffer &out, unsigned flags);
  294. virtual void applyResultsXSLT(const char *filename, const char *xml, StringBuffer &out);
  295. virtual void applyResultsXSLT(const char *filename, StringBuffer &out);
  296. virtual StringBuffer &aggregateResources(const char *type, StringBuffer &content);
  297. void renderExpandedResults(const char *viewName, WuExpandedResultBuffer &expanded, StringBuffer &out);
  298. void appendResultSchemas(WuExpandedResultBuffer &buffer);
  299. void getResultXSLT(const char *viewName, StringBuffer &xslt, StringBuffer &abspath);
  300. bool getResource(IPropertyTree *res, StringBuffer &content);
  301. bool getResource(IPropertyTree *res, MemoryBuffer &content);
  302. bool getResource(IPropertyTree *res, size32_t & len, const void * & data);
  303. void getResource(const char *name, StringBuffer &content, StringBuffer &abspath, const char *type);
  304. bool getResourceByPath(const char *path, MemoryBuffer &mb);
  305. StringBuffer &getManifest(StringBuffer &mf){return toXML(ensureManifest(), mf);}
  306. IConstWUQuery* getEmbeddedQuery();
  307. void calculateResourceIncludePaths();
  308. virtual bool getInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly);
  309. bool getEspInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly);
  310. void addVariableFromPTree(IWorkUnit *w, IConstWUResult &vardef, IResultSetMetaData &metadef, const char *varname, IPropertyTree *valtree);
  311. void addInputsFromPTree(IPropertyTree *pt);
  312. void addInputsFromXml(const char *xml);
  313. protected:
  314. SCMStringBuffer dllname;
  315. StringBuffer name;
  316. StringBuffer manifestDir;
  317. Owned<IConstWorkUnit> cw;
  318. Owned<ILoadedDllEntry> dll;
  319. Owned<IPropertyTree> manifest;
  320. StringAttr target;
  321. StringAttr dir;
  322. StringAttr username;
  323. StringAttr pw;
  324. bool mapEspDirectories;
  325. bool manifestIncludePathsSet;
  326. bool delayedDll;
  327. };
  328. IPropertyTree *WuWebView::ensureManifest()
  329. {
  330. if (!manifest)
  331. {
  332. StringBuffer xml;
  333. manifest.setown((loadDll() && getEmbeddedManifestXML(dll, xml)) ? createPTreeFromXMLString(xml.str()) : createPTree());
  334. }
  335. return manifest.get();
  336. }
  337. StringBuffer &makeResourcePath(const char *path, const char *basedir, StringBuffer &respath)
  338. {
  339. StringBuffer abspath;
  340. makeAbsolutePath(path, basedir, abspath);
  341. return makePathUniversal(abspath, respath);
  342. }
  343. void WuWebView::calculateResourceIncludePaths()
  344. {
  345. if (!manifestIncludePathsSet)
  346. {
  347. manifestDir.set(ensureManifest()->queryProp("@manifestDir"));
  348. Owned<IPropertyTreeIterator> iter = manifest->getElements("Resource[@filename]");
  349. ForEach(*iter)
  350. {
  351. if (!iter->query().hasProp("@resourcePath")) //backward compatible
  352. {
  353. StringBuffer respath;
  354. makeResourcePath(iter->query().queryProp("@filename"), dir.get(), respath);
  355. iter->query().setProp("@resourcePath", respath.str());
  356. }
  357. }
  358. manifestIncludePathsSet=true;
  359. }
  360. }
  361. bool WuWebView::getEspInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly)
  362. {
  363. StringBuffer absPath;
  364. makeAbsolutePath(includename, dir.get(), absPath);
  365. if (checkFileExists(absPath.str()))
  366. {
  367. Owned <IFile> f = createIFile(absPath.str());
  368. Owned <IFileIO> fio = f->open(IFOread);
  369. read(fio, 0, (size32_t) f->size(), includebuf);
  370. }
  371. //esp looks in two places for path starting with "xslt/"
  372. else if (mapEspDirectories && !strncmp(includename, "xslt/", 5))
  373. {
  374. absPath.clear().append(dir.get());
  375. absPath.append("smc_").append(includename);;
  376. makeAbsolutePath(absPath);
  377. if (checkFileExists(absPath.str()))
  378. {
  379. Owned <IFile> f = createIFile(absPath.str());
  380. Owned <IFileIO> fio = f->open(IFOread);
  381. read(fio, 0, (size32_t) f->size(), includebuf);
  382. }
  383. }
  384. return true;
  385. }
  386. bool WuWebView::getInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly)
  387. {
  388. //eliminate "file://"
  389. if (strncmp(includename, "file:", 5)==0)
  390. includename+=5;
  391. if (*includename=='/')
  392. {
  393. while (includename[1]=='/')
  394. includename++;
  395. //eliminate extra '/' for windows absolute paths
  396. if (includename[1] && includename[2]==':')
  397. includename++;
  398. }
  399. if (mapEspDirectories && !strnicmp(includename, "/esp/", 5))
  400. return getEspInclude(includename+5, includebuf, pathOnly);
  401. IPropertyTree *res = NULL;
  402. if (manifest)
  403. {
  404. if (strieq(includename, "/EmbeddedView"))
  405. res = manifest->queryPropTree("Resource[@name='Results'][@type='XSLT']");
  406. else
  407. {
  408. VStringBuffer xpath("Resource[@resourcePath='%s']", includename);
  409. res = manifest->queryPropTree(xpath.str());
  410. }
  411. }
  412. if (res)
  413. {
  414. StringBuffer xslt;
  415. getResource(res, xslt);
  416. includebuf.append(xslt.str());
  417. }
  418. else if (checkFileExists(includename))
  419. {
  420. Owned <IFile> f = createIFile(includename);
  421. Owned <IFileIO> fio = f->open(IFOread);
  422. read(fio, 0, (size32_t) f->size(), includebuf);
  423. }
  424. return true;
  425. }
  426. bool WuWebView::getResourceByPath(const char *path, MemoryBuffer &mb)
  427. {
  428. calculateResourceIncludePaths();
  429. StringBuffer xpath;
  430. if (!manifestDir.length())
  431. xpath.setf("Resource[@filename='%s'][1]", path);
  432. else
  433. {
  434. StringBuffer respath;
  435. makeResourcePath(path, manifestDir.str(), respath);
  436. xpath.setf("Resource[@resourcePath='%s'][1]", respath.str());
  437. }
  438. IPropertyTree *res = ensureManifest()->queryPropTree(xpath.str());
  439. if (!res)
  440. return false;
  441. return getResource(res, mb);
  442. }
  443. unsigned WuWebView::getResourceURLCount()
  444. {
  445. unsigned urlCount = 1;
  446. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements("Resource");
  447. ForEach(*iter)
  448. {
  449. IPropertyTree &res = iter->query();
  450. if (res.hasProp("@ResourcePath") || res.hasProp("@filename"))
  451. urlCount++;
  452. }
  453. return urlCount;
  454. }
  455. void WuWebView::getResourceURLs(StringArray &urls, const char *prefix)
  456. {
  457. const char *wuid = cw->queryWuid();
  458. StringBuffer url(prefix);
  459. url.append("manifest/");
  460. if (target.length() && name.length())
  461. url.appendf("query/%s/%s", target.get(), name.str());
  462. else
  463. url.append(wuid);
  464. urls.append(url);
  465. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements("Resource");
  466. ForEach(*iter)
  467. {
  468. IPropertyTree &res = iter->query();
  469. url.set(prefix).append("res/");
  470. if (target.length() && name.length())
  471. url.appendf("query/%s/%s", target.get(), name.str());
  472. else
  473. url.append(wuid);
  474. if (res.hasProp("@ResourcePath"))
  475. urls.append(url.append(res.queryProp("@ResourcePath")));
  476. else if (res.hasProp("@filename"))
  477. urls.append(url.append('/').append(res.queryProp("@filename")));
  478. }
  479. }
  480. void WuWebView::getResultViewNames(StringArray &names)
  481. {
  482. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements("Views/Results[@name]");
  483. ForEach(*iter)
  484. names.append(iter->query().queryProp("@name"));
  485. if (manifest->hasProp("Views/XSLT/RESULTS[@resource='Results']"))
  486. names.append("EmbeddedView");
  487. }
  488. bool WuWebView::getResource(IPropertyTree *res, size32_t & len, const void * & data)
  489. {
  490. if (!loadDll())
  491. return false;
  492. if (res->hasProp("@id") && (res->hasProp("@header")||res->hasProp("@compressed")))
  493. {
  494. int id = res->getPropInt("@id");
  495. return (dll->getResource(len, data, res->queryProp("@type"), (unsigned) id) && len>0);
  496. }
  497. return false;
  498. }
  499. bool WuWebView::getResource(IPropertyTree *res, MemoryBuffer &content)
  500. {
  501. size32_t len = 0;
  502. const void *data = NULL;
  503. if (getResource(res, len, data))
  504. {
  505. if (res->getPropBool("@compressed"))
  506. decompressResource(len, data, content);
  507. else
  508. content.append(len, (const char *)data);
  509. return true;
  510. }
  511. return false;
  512. }
  513. bool WuWebView::getResource(IPropertyTree *res, StringBuffer &content)
  514. {
  515. size32_t len = 0;
  516. const void *data = NULL;
  517. if (getResource(res, len, data))
  518. {
  519. if (res->getPropBool("@compressed"))
  520. decompressResource(len, data, content);
  521. else
  522. content.append(len, (const char *)data);
  523. return true;
  524. }
  525. return false;
  526. }
  527. void WuWebView::getResource(const char *name, StringBuffer &content, StringBuffer &includepath, const char *type)
  528. {
  529. VStringBuffer xpath("Resource[@name='%s']", name);
  530. if (type)
  531. xpath.append("[@type='").append(type).append("']");
  532. IPropertyTree *res = ensureManifest()->queryPropTree(xpath.str());
  533. calculateResourceIncludePaths();
  534. includepath.append(res->queryProp("@resourcePath"));
  535. if (res)
  536. getResource(res, content);
  537. }
  538. StringBuffer &WuWebView::aggregateResources(const char *type, StringBuffer &content)
  539. {
  540. VStringBuffer xpath("Resource[@type='%s']", type);
  541. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements(xpath.str());
  542. ForEach(*iter)
  543. getResource(&iter->query(), content);
  544. return content;
  545. }
  546. void WuWebView::getResultXSLT(const char *viewName, StringBuffer &xslt, StringBuffer &abspath)
  547. {
  548. if (!viewName || !*viewName)
  549. return;
  550. if (strieq("EmbeddedView", viewName))
  551. {
  552. getResource("Results", xslt, abspath, "XSLT");
  553. return;
  554. }
  555. VStringBuffer xpath("Views/Results[@name='%s']/@resource", viewName);
  556. const char *resource = ensureManifest()->queryProp(xpath.str());
  557. if (resource)
  558. getResource(resource, xslt, abspath, "XSLT");
  559. }
  560. void WuWebView::renderExpandedResults(const char *viewName, WuExpandedResultBuffer &expanded, StringBuffer &out)
  561. {
  562. IPropertyTree *mf = ensureManifest();
  563. calculateResourceIncludePaths();
  564. IPropertyTree *view;
  565. const char *type = NULL;
  566. const char *respath = NULL;
  567. if (strieq("EmbeddedView", viewName))
  568. {
  569. view = mf->queryPropTree("Views/XSLT/RESULTS[@resource='Results']");
  570. if (!view)
  571. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "EmbeddedView not found");
  572. type="xslt";
  573. respath="/EmbeddedView";
  574. }
  575. else
  576. {
  577. VStringBuffer xpath("Views/Results[@name='%s']", viewName);
  578. view = mf->queryPropTree(xpath.str());
  579. if (!view)
  580. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "Result view %s not found", viewName);
  581. type=view->queryProp("@type");
  582. if (!type)
  583. throw MakeStringException(WUWEBERR_UnknownViewType, "No type defined for view %s", viewName);
  584. if (strieq(type, "xslt"))
  585. {
  586. const char *resname = view->queryProp("@resource");
  587. if (!resname || !*resname)
  588. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "resource for %s view not defined", viewName);
  589. xpath.set("Resource[@name='").append(resname).append("']/@resourcePath");
  590. respath = mf->queryProp(xpath.str());
  591. if (!respath || !*respath)
  592. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "resource %s not resolved", resname);
  593. }
  594. else if (!strieq(type, "xml"))
  595. throw MakeStringException(WUWEBERR_UnknownViewType, "View %s has an unknown type of %s", viewName, type);
  596. }
  597. expanded.appendXML(view, "view");
  598. expanded.appendManifestSchemas(*mf, loadDll());
  599. expanded.finalize();
  600. if (strieq(type, "xml"))
  601. return out.swapWith(expanded.buffer);
  602. Owned<IXslTransform> t = getXslProcessor()->createXslTransform();
  603. StringBuffer cacheId(viewName);
  604. cacheId.append('@').append(dllname.str()); //using dllname, cloned workunits can share cache entry
  605. t->setIncludeHandler(this);
  606. t->loadXslFromEmbedded(respath, cacheId.str());
  607. t->setXmlSource(expanded.buffer.str(), expanded.buffer.length());
  608. t->transform(out);
  609. }
  610. void WuWebView::renderResults(const char *viewName, const char *xml, StringBuffer &out)
  611. {
  612. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  613. buffer.appendDatasetsFromXML(xml);
  614. renderExpandedResults(viewName, buffer, out);
  615. }
  616. void WuWebView::renderResults(const char *viewName, StringBuffer &out)
  617. {
  618. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  619. buffer.appendResults(cw, username.get(), pw.get());
  620. renderExpandedResults(viewName, buffer, out);
  621. }
  622. void WuWebView::renderResultsJSON(StringBuffer &out, const char *jsonp)
  623. {
  624. if (jsonp && *jsonp)
  625. out.append(jsonp).append('(');
  626. out.append('{');
  627. StringBuffer responseName(name.str());
  628. responseName.append("Response");
  629. appendJSONName(out, responseName);
  630. StringBufferAdaptor json(out);
  631. getFullWorkUnitResultsJSON(username, pw, cw, json, 0, SeverityError);
  632. out.append("}");
  633. if (jsonp && *jsonp)
  634. out.append(");");
  635. }
  636. void WuWebView::renderSingleResult(const char *viewName, const char *resultname, StringBuffer &out)
  637. {
  638. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  639. buffer.appendSingleResult(cw, resultname, username.get(), pw.get());
  640. renderExpandedResults(viewName, buffer, out);
  641. }
  642. void expandWuXmlResults(StringBuffer &out, const char *name, const char *xml, unsigned flags, IPropertyTree *manifest, ILoadedDllEntry *dll)
  643. {
  644. WuExpandedResultBuffer expander(name, flags);
  645. expander.appendDatasetsFromXML(xml);
  646. if (!(flags & WWV_OMIT_SCHEMAS) && manifest && dll)
  647. expander.appendManifestSchemas(*manifest, dll);
  648. expander.finalize();
  649. out.append(expander.buffer);
  650. }
  651. extern WUWEBVIEW_API void expandWuXmlResults(StringBuffer &out, const char *name, const char *xml, unsigned flags)
  652. {
  653. expandWuXmlResults(out, name, xml, flags, NULL, NULL);
  654. }
  655. void WuWebView::expandResults(const char *xml, StringBuffer &out, unsigned flags)
  656. {
  657. IPropertyTree *manifest = NULL;
  658. ILoadedDllEntry *dll = NULL;
  659. if (!(flags & WWV_OMIT_SCHEMAS))
  660. {
  661. manifest = ensureManifest();
  662. dll = loadDll();
  663. }
  664. expandWuXmlResults(out, name.str(), xml, flags, manifest, dll);
  665. }
  666. void WuWebView::createWuidResponse(StringBuffer &out, unsigned flags)
  667. {
  668. flags &= ~WWV_ADD_RESULTS_TAG;
  669. flags |= WWV_OMIT_RESULT_TAG;
  670. WuExpandedResultBuffer expander(name.str(), flags);
  671. appendXMLTag(expander.buffer, "Wuid", cw->queryWuid());
  672. expander.finalize();
  673. out.append(expander.buffer);
  674. }
  675. void WuWebView::expandResults(StringBuffer &out, unsigned flags)
  676. {
  677. SCMStringBuffer xml;
  678. getFullWorkUnitResultsXML(username.get(), pw.get(), cw, xml, WorkUnitXML_SeverityTags, SeverityInformation);
  679. expandResults(xml.str(), out, flags);
  680. }
  681. void WuWebView::applyResultsXSLT(const char *filename, const char *xml, StringBuffer &out)
  682. {
  683. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  684. buffer.appendDatasetsFromXML(xml);
  685. buffer.appendManifestSchemas(*ensureManifest(), loadDll());
  686. Owned<IXslTransform> t = getXslProcessor()->createXslTransform();
  687. t->setIncludeHandler(this);
  688. //override default behavior using filename as cache identifier, there's a chance includes are
  689. //mapped to resources and need to be distinguished in cache
  690. StringBuffer cacheId(filename);
  691. cacheId.append('@').append(dllname.str()); //cloned workunits have same dll and resources
  692. t->loadXslFromFile(filename, cacheId.str());
  693. t->setXmlSource(buffer.str(), buffer.length());
  694. t->transform(out);
  695. }
  696. void WuWebView::applyResultsXSLT(const char *filename, StringBuffer &out)
  697. {
  698. SCMStringBuffer xml;
  699. getFullWorkUnitResultsXML(username.get(), pw.get(), cw, xml);
  700. applyResultsXSLT(filename, xml.str(), out);
  701. }
  702. ILoadedDllEntry *WuWebView::loadDll(bool force)
  703. {
  704. if (!dll && dllname.length() && (force || delayedDll))
  705. {
  706. try
  707. {
  708. dll.setown(queryDllServer().loadDll(dllname.str(), DllLocationAnywhere));
  709. }
  710. catch (IException *e)
  711. {
  712. VStringBuffer msg("Failed to load %s", dllname.str());
  713. EXCLOG(e, msg.str());
  714. e->Release();
  715. }
  716. catch(...)
  717. {
  718. DBGLOG("Failed to load %s", dllname.str());
  719. }
  720. delayedDll=false;
  721. }
  722. return dll.get();
  723. }
  724. void WuWebView::setWorkunit(IConstWorkUnit &_cw)
  725. {
  726. cw.set(&_cw);
  727. if (!name.length())
  728. {
  729. name.set(cw->queryJobName());
  730. name.replace(' ','_');
  731. }
  732. Owned<IConstWUQuery> q = cw->getQuery();
  733. if (q)
  734. {
  735. q->getQueryDllName(dllname);
  736. if (!delayedDll)
  737. loadDll(true);
  738. }
  739. }
  740. void WuWebView::setWorkunit(const char *wuid)
  741. {
  742. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  743. Owned<IConstWorkUnit> wu = factory->openWorkUnit(wuid);
  744. if (!wu)
  745. throw MakeStringException(WUWEBERR_WorkUnitNotFound, "Workunit not found %s", wuid);
  746. setWorkunit(*wu);
  747. }
  748. void WuWebView::addVariableFromPTree(IWorkUnit *w, IConstWUResult &vardef, IResultSetMetaData &metadef, const char *varname, IPropertyTree *valtree)
  749. {
  750. if (!varname || !*varname)
  751. return;
  752. Owned<IWUResult> var = w->updateVariableByName(varname);
  753. if (!vardef.isResultScalar())
  754. {
  755. StringBuffer ds;
  756. if (valtree->hasChildren())
  757. toXML(valtree, ds);
  758. else
  759. {
  760. const char *val = valtree->queryProp(NULL);
  761. if (val)
  762. decodeXML(val, ds);
  763. }
  764. if (ds.length())
  765. var->setResultRaw(ds.length(), ds.str(), ResultFormatXml);
  766. }
  767. else
  768. {
  769. const char *val = valtree->queryProp(NULL);
  770. if (val && *val)
  771. {
  772. switch (metadef.getColumnDisplayType(0))
  773. {
  774. case TypeBoolean:
  775. var->setResultBool(strieq(val, "1") || strieq(val, "true") || strieq(val, "on"));
  776. break;
  777. case TypeInteger:
  778. var->setResultInt(_atoi64(val));
  779. break;
  780. case TypeUnsignedInteger:
  781. var->setResultInt(_atoi64(val));
  782. break;
  783. case TypeReal:
  784. var->setResultReal(atof(val));
  785. break;
  786. case TypeSet:
  787. case TypeDataset:
  788. case TypeData:
  789. var->setResultRaw(strlen(val), val, ResultFormatRaw);
  790. break;
  791. case TypeUnicode: {
  792. MemoryBuffer target;
  793. convertUtf(target, UtfReader::Utf16le, strlen(val), val, UtfReader::Utf8);
  794. var->setResultUnicode(target.toByteArray(), (target.length()>1) ? target.length()/2 : 0);
  795. }
  796. break;
  797. case TypeString:
  798. case TypeUnknown:
  799. default:
  800. var->setResultString(val, strlen(val));
  801. break;
  802. break;
  803. }
  804. var->setResultStatus(ResultStatusSupplied);
  805. }
  806. }
  807. }
  808. void WuWebView::addInputsFromPTree(IPropertyTree *pt)
  809. {
  810. IPropertyTree *start = pt;
  811. if (start->hasProp("Envelope"))
  812. start=start->queryPropTree("Envelope");
  813. if (start->hasProp("Body"))
  814. start=start->queryPropTree("Body/*[1]");
  815. Owned<IResultSetFactory> resultSetFactory(getResultSetFactory(username.get(), pw.get()));
  816. Owned<IPropertyTreeIterator> it = start->getElements("*");
  817. WorkunitUpdate wu(&cw->lock());
  818. ForEach(*it)
  819. {
  820. IPropertyTree &eclparm=it->query();
  821. const char *varname = eclparm.queryName();
  822. IConstWUResult *vardef = wu->getVariableByName(varname);
  823. if (vardef)
  824. {
  825. Owned<IResultSetMetaData> metadef = resultSetFactory->createResultSetMeta(vardef);
  826. if (metadef)
  827. addVariableFromPTree(wu.get(), *vardef, *metadef, varname, &eclparm);
  828. }
  829. }
  830. }
  831. void WuWebView::addInputsFromXml(const char *xml)
  832. {
  833. Owned<IPropertyTree> pt = createPTreeFromXMLString(xml, ipt_none, (PTreeReaderOptions)(ptr_ignoreWhiteSpace|ptr_ignoreNameSpaces));
  834. addInputsFromPTree(pt.get());
  835. }
  836. IConstWUQuery* WuWebView::getEmbeddedQuery()
  837. {
  838. if (!loadDll())
  839. return NULL;
  840. StringBuffer dllXML;
  841. if (!getEmbeddedWorkUnitXML(dll, dllXML))
  842. return NULL;
  843. Owned<ILocalWorkUnit> embeddedWU = createLocalWorkUnit(dllXML.str());
  844. return embeddedWU->getQuery();
  845. }
  846. extern WUWEBVIEW_API IWuWebView *createWuWebView(IConstWorkUnit &wu, const char *target, const char *queryname, const char *dir, bool mapEspDirectories)
  847. {
  848. try
  849. {
  850. return new WuWebView(wu, target, queryname, dir, mapEspDirectories);
  851. }
  852. catch (IException *e)
  853. {
  854. VStringBuffer msg("ERROR loading workunit %s shared object.", wu.queryWuid());
  855. EXCLOG(e, msg.str());
  856. e->Release();
  857. }
  858. catch (...)
  859. {
  860. DBGLOG("ERROR loading workunit %s shared object.", wu.queryWuid());
  861. }
  862. return NULL;
  863. }
  864. extern WUWEBVIEW_API IWuWebView *createWuWebView(const char *wuid, const char *target, const char *queryname, const char *dir, bool mapEspDirectories)
  865. {
  866. try
  867. {
  868. return new WuWebView(wuid, target, queryname, dir, mapEspDirectories);
  869. }
  870. catch (IException *e)
  871. {
  872. VStringBuffer msg("ERROR loading workunit %s shared object.", wuid);
  873. EXCLOG(e, msg.str());
  874. e->Release();
  875. }
  876. catch (...)
  877. {
  878. DBGLOG("ERROR loading workunit %s shared object.", wuid);
  879. }
  880. return NULL;
  881. }
  882. const char *mimeTypeFromFileExt(const char *ext)
  883. {
  884. if (!ext)
  885. return "application/octet-stream";
  886. if (*ext=='.')
  887. ext++;
  888. if (strieq(ext, "html") || strieq(ext, "htm"))
  889. return "text/html";
  890. if (strieq(ext, "xml") || strieq(ext, "xsl") || strieq(ext, "xslt"))
  891. return "application/xml";
  892. if (strieq(ext, "js"))
  893. return "text/javascript";
  894. if (strieq(ext, "css"))
  895. return "text/css";
  896. if (strieq(ext, "jpeg") || strieq(ext, "jpg"))
  897. return "image/jpeg";
  898. if (strieq(ext, "gif"))
  899. return "image/gif";
  900. if (strieq(ext, "png"))
  901. return "image/png";
  902. if (strieq(ext, "svg"))
  903. return "image/svg+xml";
  904. if (strieq(ext, "txt") || strieq(ext, "text"))
  905. return "text/plain";
  906. if (strieq(ext, "zip"))
  907. return "application/zip";
  908. if (strieq(ext, "pdf"))
  909. return "application/pdf";
  910. if (strieq(ext, "xpi"))
  911. return "application/x-xpinstall";
  912. if (strieq(ext, "exe") || strieq(ext, "class"))
  913. return "application/octet-stream";
  914. return "application/octet-stream";
  915. }
  916. static void getQueryInfoFromPath(const char *&path, const char *op, StringBuffer &target, StringBuffer &queryname, StringBuffer &wuid)
  917. {
  918. StringBuffer s;
  919. nextPathNode(path, s);
  920. if (op && strieq(s, op))
  921. nextPathNode(path, s.clear());
  922. if (strieq(s, "query"))
  923. {
  924. nextPathNode(path, target);
  925. if (!target.length())
  926. throw MakeStringException(WUWEBERR_TargetNotFound, "Target cluster required");
  927. nextPathNode(path, queryname);
  928. Owned<IPropertyTree> query = resolveQueryAlias(target, queryname, true);
  929. if (!query)
  930. throw MakeStringException(WUWEBERR_QueryNotFound, "Query not found");
  931. wuid.set(query->queryProp("@wuid"));
  932. }
  933. else
  934. wuid.swapWith(s);
  935. }
  936. extern WUWEBVIEW_API void getWuResourceByPath(const char *path, MemoryBuffer &mb, StringBuffer &mimetype)
  937. {
  938. StringBuffer wuid, target, queryname;
  939. getQueryInfoFromPath(path, "res", target, queryname, wuid);
  940. Owned<IWuWebView> web = createWuWebView(wuid, target, queryname, NULL, true);
  941. if (!web)
  942. throw MakeStringException(WUWEBERR_WorkUnitNotFound, "Cannot open workunit");
  943. mimetype.append(mimeTypeFromFileExt(strrchr(path, '.')));
  944. if (!web->getResourceByPath(path, mb))
  945. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "Cannot open resource");
  946. }
  947. extern WUWEBVIEW_API void getWuManifestByPath(const char *path, StringBuffer &mf)
  948. {
  949. StringBuffer wuid, target, queryname;
  950. getQueryInfoFromPath(path, "manifest", target, queryname, wuid);
  951. Owned<IWuWebView> web = createWuWebView(wuid, target, queryname, NULL, true);
  952. if (!web)
  953. throw MakeStringException(WUWEBERR_WorkUnitNotFound, "Cannot open workunit");
  954. if (!web->getManifest(mf).length())
  955. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "Cannot open manifest");
  956. }
  957. extern WUWEBVIEW_API void getWuResourceUrlListByPath(const char *path, StringBuffer &fmt, StringBuffer &content, const char *prefix)
  958. {
  959. StringBuffer wuid, target, queryname;
  960. getQueryInfoFromPath(path, "resurls", target, queryname, wuid);
  961. nextPathNode(path, fmt);
  962. if (!fmt.length())
  963. fmt.set("xml");
  964. Owned<IWuWebView> web = createWuWebView(wuid, target, queryname, NULL, true);
  965. if (!web)
  966. throw MakeStringException(WUWEBERR_WorkUnitNotFound, "Cannot open workunit");
  967. StringArray urls;
  968. web->getResourceURLs(urls, prefix);
  969. bool json = strieq(fmt, "json");
  970. content.append(json ? "{\"url\": [" : "<ResourceUrls>");
  971. ForEachItemIn(i, urls)
  972. {
  973. if (json)
  974. appendJSONValue(content, NULL, urls.item(i));
  975. else
  976. appendXMLTag(content, "url", urls.item(i));
  977. }
  978. content.append(json ? "]}" : "</ResourceUrls>");
  979. }