wuwebview.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  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. class WuExpandedResultBuffer : public CInterface, implements IPTreeNotifyEvent
  25. {
  26. public:
  27. IMPLEMENT_IINTERFACE;
  28. WuExpandedResultBuffer(const char *queryname, unsigned _flags=0) :
  29. name(queryname), datasetLevel(0), finalized(false), flags(_flags), hasXmlns(false)
  30. {
  31. if (flags & (WWV_INCL_NAMESPACES | WWV_INCL_GENERATED_NAMESPACES))
  32. {
  33. StringBuffer lower(name);
  34. ns.append("urn:hpccsystems:ecl:").append(lower.toLowerCase());
  35. }
  36. if (!(flags & WWV_OMIT_XML_DECLARATION))
  37. buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  38. if (flags & WWV_USE_DISPLAY_XSLT)
  39. buffer.append("<?xml-stylesheet type=\"text/xsl\" href=\"/esp/xslt/xmlformatter.xsl\"?>");
  40. if (flags & WWV_ADD_SOAP)
  41. buffer.append(
  42. "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
  43. " xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\">"
  44. " <soap:Body>"
  45. );
  46. if (flags & WWV_ADD_RESPONSE_TAG)
  47. {
  48. buffer.append('<');
  49. if (queryname)
  50. buffer.append(queryname);
  51. buffer.append("Response");
  52. if (flags & WWV_INCL_NAMESPACES && ns.length())
  53. buffer.append(" xmlns=\"").append(ns.str()).append('\"');
  54. buffer.append('>');
  55. }
  56. if (flags & WWV_ADD_RESULTS_TAG)
  57. buffer.append("<Results>");
  58. if (!(flags & WWV_OMIT_RESULT_TAG))
  59. buffer.append("<Result>");
  60. }
  61. void appendResults(IConstWorkUnit *wu, const char *username, const char *pw)
  62. {
  63. StringBufferAdaptor resultXML(buffer);
  64. getFullWorkUnitResultsXML(username, pw, wu, resultXML, WorkUnitXML_NoRoot, ExceptionSeverityError);
  65. }
  66. void appendSingleResult(IConstWorkUnit *wu, const char *resultname, const char *username, const char *pw)
  67. {
  68. SCMStringBuffer wuid;
  69. StringBufferAdaptor resultXML(buffer);
  70. Owned<IResultSetFactory> factory = getResultSetFactory(username, pw);
  71. Owned<INewResultSet> nr = factory->createNewResultSet(wu->getWuid(wuid).str(), 0, resultname);
  72. getResultXml(resultXML, nr.get(), resultname, 0, 0, NULL);
  73. }
  74. void appendDatasetsFromXML(const char *xml)
  75. {
  76. assertex(!finalized);
  77. Owned<IPullPTreeReader> reader = createPullXMLStringReader(xml, *this);
  78. reader->load();
  79. }
  80. void append(const char *value)
  81. {
  82. assertex(!finalized);
  83. buffer.append(value);
  84. }
  85. void appendSchemaResource(IPropertyTree &res, ILoadedDllEntry *dll)
  86. {
  87. if (!dll || (flags & WWV_OMIT_SCHEMAS))
  88. return;
  89. if (res.getPropInt("@seq", -1)>=0 && res.hasProp("@id"))
  90. {
  91. int id = res.getPropInt("@id");
  92. size32_t len = 0;
  93. const void *data = NULL;
  94. if (dll->getResource(len, data, "RESULT_XSD", (unsigned) id) && len>0)
  95. {
  96. buffer.append("<XmlSchema name=\"").append(res.queryProp("@name")).append("\">");
  97. if (res.getPropBool("@compressed"))
  98. {
  99. StringBuffer decompressed;
  100. decompressResource(len, data, decompressed);
  101. if (flags & WWV_CDATA_SCHEMAS)
  102. buffer.append("<![CDATA[");
  103. buffer.append(decompressed.str());
  104. if (flags & WWV_CDATA_SCHEMAS)
  105. buffer.append("]]>");
  106. }
  107. else
  108. buffer.append(len, (const char *)data);
  109. buffer.append("</XmlSchema>");
  110. }
  111. }
  112. }
  113. void appendManifestSchemas(IPropertyTree &manifest, ILoadedDllEntry *dll)
  114. {
  115. assertex(!finalized);
  116. if (!dll)
  117. return;
  118. Owned<IPropertyTreeIterator> iter = manifest.getElements("Resource[@type='RESULT_XSD']");
  119. ForEach(*iter)
  120. appendSchemaResource(iter->query(), dll);
  121. }
  122. void appendManifestResultSchema(IPropertyTree &manifest, const char *resultname, ILoadedDllEntry *dll)
  123. {
  124. assertex(!finalized);
  125. if (!dll)
  126. return;
  127. VStringBuffer xpath("Resource[@name='%s'][@type='RESULT_XSD']", resultname);
  128. IPropertyTree *res=manifest.queryPropTree(xpath.str());
  129. if (res)
  130. appendSchemaResource(*res, dll);
  131. }
  132. void appendXML(IPropertyTree *xml, const char *tag=NULL)
  133. {
  134. assertex(!finalized);
  135. if (tag)
  136. buffer.append('<').append(tag).append('>');
  137. if (xml)
  138. toXML(xml, buffer);
  139. if (tag)
  140. buffer.append("</").append(tag).append('>');
  141. }
  142. virtual void beginNode(const char *tag, offset_t startOffset)
  143. {
  144. if (streq("Dataset", tag) || streq("Exception", tag))
  145. datasetLevel++;
  146. if (datasetLevel)
  147. buffer.append('<').append(tag);
  148. }
  149. virtual void newAttribute(const char *name, const char *value)
  150. {
  151. if (datasetLevel)
  152. {
  153. if (streq(name, "@xmlns"))
  154. {
  155. if (!(flags & WWV_INCL_NAMESPACES))
  156. return;
  157. if (datasetLevel==1)
  158. hasXmlns=true;
  159. }
  160. if (datasetLevel==1 && streq(name, "@name"))
  161. dsname.set(value).toLowerCase().replace(' ', '_');;
  162. buffer.append(' ').append(name+1).append("=\"");
  163. encodeUtf8XML(value, buffer);
  164. buffer.append('\"');
  165. }
  166. }
  167. virtual void beginNodeContent(const char *tag)
  168. {
  169. if (datasetLevel==1 && streq("Dataset", tag))
  170. {
  171. if (!hasXmlns && dsname.length() && (flags & WWV_INCL_GENERATED_NAMESPACES))
  172. {
  173. StringBuffer s(ns);
  174. s.append(":result:").append(dsname.str());
  175. buffer.append(" xmlns=\"").append(s).append('\"');
  176. }
  177. dsname.clear();
  178. hasXmlns=false;
  179. }
  180. if (datasetLevel)
  181. buffer.append('>');
  182. }
  183. virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset)
  184. {
  185. if (datasetLevel)
  186. {
  187. if (length)
  188. {
  189. if (binary)
  190. JBASE64_Encode(value, length, buffer);
  191. else
  192. encodeUtf8XML((const char *)value, buffer);
  193. }
  194. buffer.append("</").append(tag).append('>');
  195. if (streq("Dataset", tag) || streq("Exception", tag))
  196. datasetLevel--;
  197. }
  198. }
  199. StringBuffer &finalize()
  200. {
  201. if (!finalized)
  202. {
  203. if (!(flags & WWV_OMIT_RESULT_TAG))
  204. buffer.append("</Result>");
  205. if (flags & WWV_ADD_RESULTS_TAG)
  206. buffer.append("</Results>");
  207. if (flags & WWV_ADD_RESPONSE_TAG)
  208. buffer.appendf("</%sResponse>", name.sget());
  209. if (flags & WWV_ADD_SOAP)
  210. buffer.append("</soap:Body></soap:Envelope>");
  211. finalized=true;
  212. }
  213. return buffer;
  214. }
  215. const char *str()
  216. {
  217. finalize();
  218. return buffer.str();
  219. }
  220. size32_t length()
  221. {
  222. finalize();
  223. return buffer.length();
  224. }
  225. public:
  226. StringBuffer buffer;
  227. StringAttr name;
  228. StringBuffer dsname;
  229. StringBuffer ns;
  230. bool hasXmlns;
  231. bool finalized;
  232. unsigned flags;
  233. private:
  234. int datasetLevel;
  235. };
  236. class WuWebView : public CInterface,
  237. implements IWuWebView,
  238. implements IIncludeHandler
  239. {
  240. public:
  241. IMPLEMENT_IINTERFACE;
  242. WuWebView(IConstWorkUnit &wu, const char *queryname, const char *wdir, bool mapEspDir, bool delay=true) :
  243. manifestIncludePathsSet(false), dir(wdir), mapEspDirectories(mapEspDir), delayedDll(delay)
  244. {
  245. name.set(queryname);
  246. setWorkunit(wu);
  247. }
  248. WuWebView(const char *wuid, const char *queryname, const char *wdir, bool mapEspDir, bool delay=true) :
  249. manifestIncludePathsSet(false), dir(wdir), mapEspDirectories(mapEspDir), delayedDll(delay)
  250. {
  251. name.set(queryname);
  252. setWorkunit(wuid);
  253. }
  254. void setWorkunit(IConstWorkUnit &wu);
  255. void setWorkunit(const char *wuid);
  256. ILoadedDllEntry *loadDll(bool force=false);
  257. IPropertyTree *ensureManifest();
  258. virtual void getResultViewNames(StringArray &names);
  259. virtual void renderResults(const char *viewName, const char *xml, StringBuffer &html);
  260. virtual void renderResults(const char *viewName, StringBuffer &html);
  261. virtual void renderSingleResult(const char *viewName, const char *resultname, StringBuffer &html);
  262. virtual void expandResults(const char *xml, StringBuffer &out, unsigned flags);
  263. virtual void expandResults(StringBuffer &out, unsigned flags);
  264. virtual void applyResultsXSLT(const char *filename, const char *xml, StringBuffer &out);
  265. virtual void applyResultsXSLT(const char *filename, StringBuffer &out);
  266. virtual StringBuffer &aggregateResources(const char *type, StringBuffer &content);
  267. void renderExpandedResults(const char *viewName, WuExpandedResultBuffer &expanded, StringBuffer &out);
  268. void appendResultSchemas(WuExpandedResultBuffer &buffer);
  269. void getResultXSLT(const char *viewName, StringBuffer &xslt, StringBuffer &abspath);
  270. void getResource(IPropertyTree *res, StringBuffer &content);
  271. void getResource(const char *name, StringBuffer &content, StringBuffer &abspath, const char *type);
  272. void calculateResourceIncludePaths();
  273. virtual bool getInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly);
  274. bool getEspInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly);
  275. void addVariableFromPTree(IWorkUnit *w, IConstWUResult &vardef, IResultSetMetaData &metadef, const char *varname, IPropertyTree *valtree);
  276. void addInputsFromPTree(IPropertyTree *pt);
  277. void addInputsFromXml(const char *xml);
  278. protected:
  279. SCMStringBuffer dllname;
  280. Owned<IConstWorkUnit> cw;
  281. Owned<ILoadedDllEntry> dll;
  282. bool delayedDll;
  283. Owned<IPropertyTree> manifest;
  284. SCMStringBuffer name;
  285. bool mapEspDirectories;
  286. bool manifestIncludePathsSet;
  287. StringAttr dir;
  288. StringAttr username;
  289. StringAttr pw;
  290. };
  291. IPropertyTree *WuWebView::ensureManifest()
  292. {
  293. if (!manifest)
  294. {
  295. StringBuffer xml;
  296. manifest.setown((loadDll() && getEmbeddedManifestXML(dll, xml)) ? createPTreeFromXMLString(xml.str()) : createPTree());
  297. }
  298. return manifest.get();
  299. }
  300. void WuWebView::calculateResourceIncludePaths()
  301. {
  302. if (!manifestIncludePathsSet)
  303. {
  304. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements("Resource[@filename]");
  305. ForEach(*iter)
  306. {
  307. if (!iter->query().hasProp("@resourcePath")) //backward compatible
  308. {
  309. StringBuffer abspath;
  310. makeAbsolutePath(iter->query().queryProp("@filename"), dir.get(), abspath);
  311. StringBuffer respath;
  312. makePathUniversal(abspath.str(), respath);
  313. iter->query().setProp("@resourcePath", respath.str());
  314. }
  315. }
  316. manifestIncludePathsSet=true;
  317. }
  318. }
  319. bool WuWebView::getEspInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly)
  320. {
  321. StringBuffer absPath;
  322. makeAbsolutePath(includename, dir.get(), absPath);
  323. if (checkFileExists(absPath.str()))
  324. {
  325. Owned <IFile> f = createIFile(absPath.str());
  326. Owned <IFileIO> fio = f->open(IFOread);
  327. read(fio, 0, (size32_t) f->size(), includebuf);
  328. }
  329. //esp looks in two places for path starting with "xslt/"
  330. else if (mapEspDirectories && !strncmp(includename, "xslt/", 5))
  331. {
  332. absPath.clear().append(dir.get());
  333. absPath.append("smc_").append(includename);;
  334. makeAbsolutePath(absPath);
  335. if (checkFileExists(absPath.str()))
  336. {
  337. Owned <IFile> f = createIFile(absPath.str());
  338. Owned <IFileIO> fio = f->open(IFOread);
  339. read(fio, 0, (size32_t) f->size(), includebuf);
  340. }
  341. }
  342. return true;
  343. }
  344. bool WuWebView::getInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly)
  345. {
  346. int len=strlen(includename);
  347. if (len<8)
  348. return false;
  349. //eliminate "file://"
  350. if (strncmp(includename, "file://", 7)==0)
  351. includename+=7;
  352. //eliminate extra '/' for windows absolute paths
  353. if (len>9 && includename[2]==':')
  354. includename++;
  355. if (mapEspDirectories && !strnicmp(includename, "/esp/", 5))
  356. return getEspInclude(includename+5, includebuf, pathOnly);
  357. IPropertyTree *res = NULL;
  358. if (manifest)
  359. {
  360. if (strieq(includename, "/EmbeddedView"))
  361. res = manifest->queryPropTree("Resource[@name='Results'][@type='XSLT']");
  362. else
  363. {
  364. VStringBuffer xpath("Resource[@resourcePath='%s']", includename);
  365. res = manifest->queryPropTree(xpath.str());
  366. }
  367. }
  368. if (res)
  369. {
  370. StringBuffer xslt;
  371. getResource(res, xslt);
  372. includebuf.append(xslt.str());
  373. }
  374. else if (checkFileExists(includename))
  375. {
  376. Owned <IFile> f = createIFile(includename);
  377. Owned <IFileIO> fio = f->open(IFOread);
  378. read(fio, 0, (size32_t) f->size(), includebuf);
  379. }
  380. return true;
  381. }
  382. void WuWebView::getResultViewNames(StringArray &names)
  383. {
  384. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements("Views/Results[@name]");
  385. ForEach(*iter)
  386. names.append(iter->query().queryProp("@name"));
  387. if (manifest->hasProp("Views/XSLT/RESULTS[@resource='Results']"))
  388. names.append("EmbeddedView");
  389. }
  390. void WuWebView::getResource(IPropertyTree *res, StringBuffer &content)
  391. {
  392. if (!loadDll())
  393. return;
  394. if (res->hasProp("@id"))
  395. {
  396. int id = res->getPropInt("@id");
  397. size32_t len = 0;
  398. const void *data = NULL;
  399. if (dll->getResource(len, data, res->queryProp("@type"), (unsigned) id) && len>0)
  400. {
  401. if (res->getPropBool("@compressed"))
  402. {
  403. StringBuffer decompressed;
  404. decompressResource(len, data, content);
  405. content.append(decompressed.str());
  406. }
  407. else
  408. content.append(len, (const char *)data);
  409. }
  410. }
  411. }
  412. void WuWebView::getResource(const char *name, StringBuffer &content, StringBuffer &includepath, const char *type)
  413. {
  414. VStringBuffer xpath("Resource[@name='%s']", name);
  415. if (type)
  416. xpath.append("[@type='").append(type).append("']");
  417. IPropertyTree *res = ensureManifest()->queryPropTree(xpath.str());
  418. calculateResourceIncludePaths();
  419. includepath.append(res->queryProp("@resourcePath"));
  420. if (res)
  421. getResource(res, content);
  422. }
  423. StringBuffer &WuWebView::aggregateResources(const char *type, StringBuffer &content)
  424. {
  425. VStringBuffer xpath("Resource[@type='%s']", type);
  426. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements(xpath.str());
  427. ForEach(*iter)
  428. getResource(&iter->query(), content);
  429. return content;
  430. }
  431. void WuWebView::getResultXSLT(const char *viewName, StringBuffer &xslt, StringBuffer &abspath)
  432. {
  433. if (!viewName || !*viewName)
  434. return;
  435. if (strieq("EmbeddedView", viewName))
  436. {
  437. getResource("Results", xslt, abspath, "XSLT");
  438. return;
  439. }
  440. VStringBuffer xpath("Views/Results[@name='%s']/@resource", viewName);
  441. const char *resource = ensureManifest()->queryProp(xpath.str());
  442. if (resource)
  443. getResource(resource, xslt, abspath, "XSLT");
  444. }
  445. void WuWebView::renderExpandedResults(const char *viewName, WuExpandedResultBuffer &expanded, StringBuffer &out)
  446. {
  447. IPropertyTree *mf = ensureManifest();
  448. calculateResourceIncludePaths();
  449. IPropertyTree *view;
  450. const char *type = NULL;
  451. const char *respath = NULL;
  452. if (strieq("EmbeddedView", viewName))
  453. {
  454. view = mf->queryPropTree("Views/XSLT/RESULTS[@resource='Results']");
  455. if (!view)
  456. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "EmbeddedView not found");
  457. type="xslt";
  458. respath="/EmbeddedView";
  459. }
  460. else
  461. {
  462. VStringBuffer xpath("Views/Results[@name='%s']", viewName);
  463. view = mf->queryPropTree(xpath.str());
  464. if (!view)
  465. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "Result view %s not found", viewName);
  466. type=view->queryProp("@type");
  467. if (!type)
  468. throw MakeStringException(WUWEBERR_UnknownViewType, "No type defined for view %s", viewName);
  469. if (strieq(type, "xslt"))
  470. {
  471. const char *resname = view->queryProp("@resource");
  472. if (!resname || !*resname)
  473. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "resource for %s view not defined", viewName);
  474. xpath.set("Resource[@name='").append(resname).append("']/@resourcePath");
  475. respath = mf->queryProp(xpath.str());
  476. if (!respath || !*respath)
  477. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "resource %s not resolved", resname);
  478. }
  479. else if (!strieq(type, "xml"))
  480. throw MakeStringException(WUWEBERR_UnknownViewType, "View %s has an unknown type of %s", viewName, type);
  481. }
  482. expanded.appendXML(view, "view");
  483. expanded.appendManifestSchemas(*mf, loadDll());
  484. expanded.finalize();
  485. if (strieq(type, "xml"))
  486. return out.swapWith(expanded.buffer);
  487. Owned<IXslTransform> t = getXslProcessor()->createXslTransform();
  488. StringBuffer cacheId(viewName);
  489. cacheId.append('@').append(dllname.str()); //using dllname, cloned workunits can share cache entry
  490. t->setIncludeHandler(this);
  491. t->loadXslFromEmbedded(respath, cacheId.str());
  492. t->setXmlSource(expanded.buffer.str(), expanded.buffer.length());
  493. t->transform(out);
  494. }
  495. void WuWebView::renderResults(const char *viewName, const char *xml, StringBuffer &out)
  496. {
  497. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  498. buffer.appendDatasetsFromXML(xml);
  499. renderExpandedResults(viewName, buffer, out);
  500. }
  501. void WuWebView::renderResults(const char *viewName, StringBuffer &out)
  502. {
  503. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  504. buffer.appendResults(cw, username.get(), pw.get());
  505. renderExpandedResults(viewName, buffer, out);
  506. }
  507. void WuWebView::renderSingleResult(const char *viewName, const char *resultname, StringBuffer &out)
  508. {
  509. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  510. buffer.appendSingleResult(cw, resultname, username.get(), pw.get());
  511. renderExpandedResults(viewName, buffer, out);
  512. }
  513. void WuWebView::expandResults(const char *xml, StringBuffer &out, unsigned flags)
  514. {
  515. WuExpandedResultBuffer expander(name.str(), flags);
  516. expander.appendDatasetsFromXML(xml);
  517. expander.appendManifestSchemas(*ensureManifest(), loadDll());
  518. expander.finalize();
  519. out.append(expander.buffer);
  520. }
  521. void WuWebView::expandResults(StringBuffer &out, unsigned flags)
  522. {
  523. SCMStringBuffer xml;
  524. getFullWorkUnitResultsXML(username.get(), pw.get(), cw, xml);
  525. expandResults(xml.str(), out, flags);
  526. }
  527. void WuWebView::applyResultsXSLT(const char *filename, const char *xml, StringBuffer &out)
  528. {
  529. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  530. buffer.appendDatasetsFromXML(xml);
  531. buffer.appendManifestSchemas(*ensureManifest(), loadDll());
  532. Owned<IXslTransform> t = getXslProcessor()->createXslTransform();
  533. t->setIncludeHandler(this);
  534. //override default behavior using filename as cache identifier, there's a chance includes are
  535. //mapped to resources and need to be distinguished in cache
  536. StringBuffer cacheId(filename);
  537. cacheId.append('@').append(dllname.str()); //cloned workunits have same dll and resources
  538. t->loadXslFromFile(filename, cacheId.str());
  539. t->setXmlSource(buffer.str(), buffer.length());
  540. t->transform(out);
  541. }
  542. void WuWebView::applyResultsXSLT(const char *filename, StringBuffer &out)
  543. {
  544. SCMStringBuffer xml;
  545. getFullWorkUnitResultsXML(username.get(), pw.get(), cw, xml);
  546. applyResultsXSLT(filename, xml.str(), out);
  547. }
  548. ILoadedDllEntry *WuWebView::loadDll(bool force)
  549. {
  550. if (!dll && (force || delayedDll))
  551. {
  552. try
  553. {
  554. dll.setown(queryDllServer().loadDll(dllname.str(), DllLocationAnywhere));
  555. }
  556. catch(...)
  557. {
  558. DBGLOG("Failed to load %s", dllname.str());
  559. }
  560. delayedDll=false;
  561. }
  562. return dll.get();
  563. }
  564. void WuWebView::setWorkunit(IConstWorkUnit &_cw)
  565. {
  566. cw.set(&_cw);
  567. if (!name.length())
  568. {
  569. cw->getJobName(name);
  570. name.s.replace(' ','_');
  571. }
  572. Owned<IConstWUQuery> q = cw->getQuery();
  573. q->getQueryDllName(dllname);
  574. if (!delayedDll)
  575. loadDll(true);
  576. }
  577. void WuWebView::setWorkunit(const char *wuid)
  578. {
  579. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  580. Owned<IConstWorkUnit> wu = factory->openWorkUnit(wuid, false);
  581. if (!wu)
  582. throw MakeStringException(WUWEBERR_WorkUnitNotFound, "Workunit not found %s", wuid);
  583. setWorkunit(*wu);
  584. }
  585. void WuWebView::addVariableFromPTree(IWorkUnit *w, IConstWUResult &vardef, IResultSetMetaData &metadef, const char *varname, IPropertyTree *valtree)
  586. {
  587. if (!varname || !*varname)
  588. return;
  589. Owned<IWUResult> var = w->updateVariableByName(varname);
  590. if (!vardef.isResultScalar())
  591. {
  592. StringBuffer ds;
  593. if (valtree->hasChildren())
  594. toXML(valtree, ds);
  595. else
  596. {
  597. const char *val = valtree->queryProp(NULL);
  598. if (val)
  599. decodeXML(val, ds);
  600. }
  601. if (ds.length())
  602. var->setResultRaw(ds.length(), ds.str(), ResultFormatXml);
  603. }
  604. else
  605. {
  606. const char *val = valtree->queryProp(NULL);
  607. if (val && *val)
  608. {
  609. switch (metadef.getColumnDisplayType(0))
  610. {
  611. case TypeBoolean:
  612. var->setResultBool(strieq(val, "1") || strieq(val, "true") || strieq(val, "on"));
  613. break;
  614. case TypeInteger:
  615. var->setResultInt(_atoi64(val));
  616. break;
  617. case TypeUnsignedInteger:
  618. var->setResultInt(_atoi64(val));
  619. break;
  620. case TypeReal:
  621. var->setResultReal(atof(val));
  622. break;
  623. case TypeSet:
  624. case TypeDataset:
  625. case TypeData:
  626. var->setResultRaw(strlen(val), val, ResultFormatRaw);
  627. break;
  628. case TypeUnicode: {
  629. MemoryBuffer target;
  630. convertUtf(target, UtfReader::Utf16le, strlen(val), val, UtfReader::Utf8);
  631. var->setResultUnicode(target.toByteArray(), (target.length()>1) ? target.length()/2 : 0);
  632. }
  633. break;
  634. case TypeString:
  635. case TypeUnknown:
  636. default:
  637. var->setResultString(val, strlen(val));
  638. break;
  639. break;
  640. }
  641. var->setResultStatus(ResultStatusSupplied);
  642. }
  643. }
  644. }
  645. void WuWebView::addInputsFromPTree(IPropertyTree *pt)
  646. {
  647. IPropertyTree *start = pt;
  648. if (start->hasProp("Envelope"))
  649. start=start->queryPropTree("Envelope");
  650. if (start->hasProp("Body"))
  651. start=start->queryPropTree("Body/*[1]");
  652. Owned<IResultSetFactory> resultSetFactory(getResultSetFactory(username.get(), pw.get()));
  653. Owned<IPropertyTreeIterator> it = start->getElements("*");
  654. WorkunitUpdate wu(&cw->lock());
  655. ForEach(*it)
  656. {
  657. IPropertyTree &eclparm=it->query();
  658. const char *varname = eclparm.queryName();
  659. IConstWUResult *vardef = wu->getVariableByName(varname);
  660. if (vardef)
  661. {
  662. Owned<IResultSetMetaData> metadef = resultSetFactory->createResultSetMeta(vardef);
  663. if (metadef)
  664. addVariableFromPTree(wu.get(), *vardef, *metadef, varname, &eclparm);
  665. }
  666. }
  667. }
  668. void WuWebView::addInputsFromXml(const char *xml)
  669. {
  670. Owned<IPropertyTree> pt = createPTreeFromXMLString(xml, ipt_none, (PTreeReaderOptions)(ptr_ignoreWhiteSpace|ptr_ignoreNameSpaces));
  671. addInputsFromPTree(pt.get());
  672. }
  673. extern WUWEBVIEW_API IWuWebView *createWuWebView(IConstWorkUnit &wu, const char *queryname, const char *dir, bool mapEspDirectories)
  674. {
  675. try
  676. {
  677. return new WuWebView(wu, queryname, dir, mapEspDirectories);
  678. }
  679. catch (...)
  680. {
  681. SCMStringBuffer wuid;
  682. DBGLOG("ERROR loading workunit %s shared object.", wu.getWuid(wuid).str());
  683. }
  684. return NULL;
  685. }
  686. extern WUWEBVIEW_API IWuWebView *createWuWebView(const char *wuid, const char *queryname, const char *dir, bool mapEspDirectories)
  687. {
  688. try
  689. {
  690. return new WuWebView(wuid, queryname, dir, mapEspDirectories);
  691. }
  692. catch (...)
  693. {
  694. DBGLOG("ERROR loading workunit %s shared object.", wuid);
  695. }
  696. return NULL;
  697. }