wuwebview.cpp 34 KB

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