wuwebview.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "jlib.hpp"
  15. #include "jexcept.hpp"
  16. #include "jptree.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, false, ExceptionSeverityError, true);
  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<IPullXMLReader> 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 &loadedDll)
  86. {
  87. if (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 (loadedDll.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 &loadedDll)
  114. {
  115. assertex(!finalized);
  116. Owned<IPropertyTreeIterator> iter = manifest.getElements("Resource[@type='RESULT_XSD']");
  117. ForEach(*iter)
  118. appendSchemaResource(iter->query(), loadedDll);
  119. }
  120. void appendManifestResultSchema(IPropertyTree &manifest, const char *resultname, ILoadedDllEntry &loadedDll)
  121. {
  122. assertex(!finalized);
  123. VStringBuffer xpath("Resource[@name='%s'][@type='RESULT_XSD']", resultname);
  124. IPropertyTree *res=manifest.queryPropTree(xpath.str());
  125. if (res)
  126. appendSchemaResource(*res, loadedDll);
  127. }
  128. void appendXML(IPropertyTree *xml, const char *tag=NULL)
  129. {
  130. assertex(!finalized);
  131. if (tag)
  132. buffer.append('<').append(tag).append('>');
  133. if (xml)
  134. toXML(xml, buffer);
  135. if (tag)
  136. buffer.append("</").append(tag).append('>');
  137. }
  138. virtual void beginNode(const char *tag, offset_t startOffset)
  139. {
  140. if (streq("Dataset", tag) || streq("Exception", tag))
  141. datasetLevel++;
  142. if (datasetLevel)
  143. buffer.append('<').append(tag);
  144. }
  145. virtual void newAttribute(const char *name, const char *value)
  146. {
  147. if (datasetLevel)
  148. {
  149. if (streq(name, "@xmlns"))
  150. {
  151. if (!(flags & WWV_INCL_NAMESPACES))
  152. return;
  153. if (datasetLevel==1)
  154. hasXmlns=true;
  155. }
  156. if (datasetLevel==1 && streq(name, "@name"))
  157. dsname.set(value).toLowerCase().replace(' ', '_');;
  158. buffer.append(' ').append(name+1).append("=\"");
  159. encodeUtf8XML(value, buffer);
  160. buffer.append('\"');
  161. }
  162. }
  163. virtual void beginNodeContent(const char *tag)
  164. {
  165. if (datasetLevel==1 && streq("Dataset", tag))
  166. {
  167. if (!hasXmlns && dsname.length() && (flags & WWV_INCL_GENERATED_NAMESPACES))
  168. {
  169. StringBuffer s(ns);
  170. s.append(":result:").append(dsname.str());
  171. buffer.append(" xmlns=\"").append(s).append('\"');
  172. }
  173. dsname.clear();
  174. hasXmlns=false;
  175. }
  176. if (datasetLevel)
  177. buffer.append('>');
  178. }
  179. virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset)
  180. {
  181. if (datasetLevel)
  182. {
  183. if (length)
  184. {
  185. if (binary)
  186. JBASE64_Encode(value, length, buffer);
  187. else
  188. encodeUtf8XML((const char *)value, buffer);
  189. }
  190. buffer.append("</").append(tag).append('>');
  191. if (streq("Dataset", tag) || streq("Exception", tag))
  192. datasetLevel--;
  193. }
  194. }
  195. StringBuffer &finalize()
  196. {
  197. if (!finalized)
  198. {
  199. if (!(flags & WWV_OMIT_RESULT_TAG))
  200. buffer.append("</Result>");
  201. if (flags & WWV_ADD_RESULTS_TAG)
  202. buffer.append("</Results>");
  203. if (flags & WWV_ADD_RESPONSE_TAG)
  204. buffer.appendf("</%sResponse>", name.sget());
  205. if (flags & WWV_ADD_SOAP)
  206. buffer.append("</soap:Body></soap:Envelope>");
  207. finalized=true;
  208. }
  209. return buffer;
  210. }
  211. const char *str()
  212. {
  213. finalize();
  214. return buffer.str();
  215. }
  216. size32_t length()
  217. {
  218. finalize();
  219. return buffer.length();
  220. }
  221. public:
  222. StringBuffer buffer;
  223. StringAttr name;
  224. StringBuffer dsname;
  225. StringBuffer ns;
  226. bool hasXmlns;
  227. bool finalized;
  228. unsigned flags;
  229. private:
  230. int datasetLevel;
  231. };
  232. class WuWebView : public CInterface,
  233. implements IWuWebView,
  234. implements IIncludeHandler
  235. {
  236. public:
  237. IMPLEMENT_IINTERFACE;
  238. WuWebView(IConstWorkUnit &wu, const char *queryname, const char *wdir, bool mapEspDir) :
  239. manifestIncludePathsSet(false), dir(wdir), mapEspDirectories(mapEspDir)
  240. {
  241. name.set(queryname);
  242. load(wu);
  243. }
  244. WuWebView(const char *wuid, const char *queryname, const char *wdir, bool mapEspDir) :
  245. manifestIncludePathsSet(false), dir(wdir), mapEspDirectories(mapEspDir)
  246. {
  247. name.set(queryname);
  248. load(wuid);
  249. }
  250. void load(IConstWorkUnit &wu);
  251. void load(const char *wuid);
  252. IPropertyTree *ensureManifest();
  253. virtual void getResultViewNames(StringArray &names);
  254. virtual void renderResults(const char *viewName, const char *xml, StringBuffer &html);
  255. virtual void renderResults(const char *viewName, StringBuffer &html);
  256. virtual void renderSingleResult(const char *viewName, const char *resultname, StringBuffer &html);
  257. virtual void expandResults(const char *xml, StringBuffer &out, unsigned flags);
  258. virtual void expandResults(StringBuffer &out, unsigned flags);
  259. virtual void applyResultsXSLT(const char *filename, const char *xml, StringBuffer &out);
  260. virtual void applyResultsXSLT(const char *filename, StringBuffer &out);
  261. virtual StringBuffer &aggregateResources(const char *type, StringBuffer &content);
  262. void renderExpandedResults(const char *viewName, WuExpandedResultBuffer &expanded, StringBuffer &out);
  263. void appendResultSchemas(WuExpandedResultBuffer &buffer);
  264. void getResultXSLT(const char *viewName, StringBuffer &xslt, StringBuffer &abspath);
  265. void getResource(IPropertyTree *res, StringBuffer &content);
  266. void getResource(const char *name, StringBuffer &content, StringBuffer &abspath, const char *type);
  267. void calculateResourceIncludePaths();
  268. virtual bool getInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly);
  269. protected:
  270. SCMStringBuffer dllname;
  271. Owned<IConstWorkUnit> wu;
  272. Owned<ILoadedDllEntry> loadedDll;
  273. Owned<IPropertyTree> manifest;
  274. SCMStringBuffer name;
  275. bool mapEspDirectories;
  276. bool manifestIncludePathsSet;
  277. StringAttr dir;
  278. StringAttr username;
  279. StringAttr pw;
  280. };
  281. IPropertyTree *WuWebView::ensureManifest()
  282. {
  283. if (!manifest)
  284. {
  285. StringBuffer xml;
  286. manifest.setown((loadedDll && getEmbeddedManifestXML(loadedDll, xml)) ? createPTreeFromXMLString(xml.str()) : createPTree());
  287. }
  288. return manifest.get();
  289. }
  290. void WuWebView::calculateResourceIncludePaths()
  291. {
  292. if (!manifestIncludePathsSet)
  293. {
  294. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements("Resource[@filename]");
  295. ForEach(*iter)
  296. {
  297. StringBuffer abspath;
  298. iter->query().setProp("@res_include_path", makeAbsolutePath(iter->query().queryProp("@filename"), dir.get(), abspath).str());
  299. }
  300. manifestIncludePathsSet=true;
  301. }
  302. }
  303. bool WuWebView::getInclude(const char *includename, MemoryBuffer &includebuf, bool &pathOnly)
  304. {
  305. int len=strlen(includename);
  306. if (len<8)
  307. return false;
  308. //eliminate "file://"
  309. if (strncmp(includename, "file://", 7)==0)
  310. includename+=7;
  311. //eliminate extra '/' for windows absolute paths
  312. if (len>9 && includename[2]==':')
  313. includename++;
  314. StringBuffer relpath;
  315. if (mapEspDirectories && !strnicmp(includename, "/esp/", 5))
  316. relpath.append(includename+=5);
  317. else
  318. relpath.append(includename); //still correct for OS
  319. StringBuffer abspath;
  320. makeAbsolutePath(relpath.str(), dir.get(), abspath);
  321. IPropertyTree *res = NULL;
  322. if (manifest)
  323. {
  324. VStringBuffer xpath("Resource[@res_include_path='%s']", abspath.str());
  325. res = manifest->queryPropTree(xpath.str());
  326. }
  327. if (res)
  328. {
  329. StringBuffer xslt;
  330. getResource(res, xslt);
  331. includebuf.append(xslt.str());
  332. }
  333. else if (checkFileExists(abspath.str()))
  334. {
  335. Owned <IFile> f = createIFile(abspath.str());
  336. Owned <IFileIO> fio = f->open(IFOread);
  337. read(fio, 0, (size32_t) f->size(), includebuf);
  338. }
  339. //esp looks in two places for path starting with "xslt/"
  340. else if (mapEspDirectories && !strncmp(includename, "xslt/", 5))
  341. {
  342. StringBuffer relpath(dir.get());
  343. relpath.append("smc_").append(includename);;
  344. makeAbsolutePath(relpath.str(), abspath.clear());
  345. if (checkFileExists(abspath.str()))
  346. {
  347. Owned <IFile> f = createIFile(abspath.str());
  348. Owned <IFileIO> fio = f->open(IFOread);
  349. read(fio, 0, (size32_t) f->size(), includebuf);
  350. }
  351. }
  352. return true;
  353. }
  354. void WuWebView::getResultViewNames(StringArray &names)
  355. {
  356. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements("Views/Results[@name]");
  357. ForEach(*iter)
  358. names.append(iter->query().queryProp("@name"));
  359. }
  360. void WuWebView::getResource(IPropertyTree *res, StringBuffer &content)
  361. {
  362. if (!loadedDll)
  363. return;
  364. if (res->hasProp("@id"))
  365. {
  366. int id = res->getPropInt("@id");
  367. size32_t len = 0;
  368. const void *data = NULL;
  369. if (loadedDll->getResource(len, data, res->queryProp("@type"), (unsigned) id) && len>0)
  370. {
  371. if (res->getPropBool("@compressed"))
  372. {
  373. StringBuffer decompressed;
  374. decompressResource(len, data, content);
  375. content.append(decompressed.str());
  376. }
  377. else
  378. content.append(len, (const char *)data);
  379. }
  380. }
  381. }
  382. void WuWebView::getResource(const char *name, StringBuffer &content, StringBuffer &includepath, const char *type)
  383. {
  384. VStringBuffer xpath("Resource[@name='%s']", name);
  385. if (type)
  386. xpath.append("[@type='").append(type).append("']");
  387. IPropertyTree *res = ensureManifest()->queryPropTree(xpath.str());
  388. calculateResourceIncludePaths();
  389. includepath.append(res->queryProp("@res_include_path"));
  390. if (res)
  391. getResource(res, content);
  392. }
  393. StringBuffer &WuWebView::aggregateResources(const char *type, StringBuffer &content)
  394. {
  395. VStringBuffer xpath("Resource[@type='%s']", type);
  396. Owned<IPropertyTreeIterator> iter = ensureManifest()->getElements(xpath.str());
  397. ForEach(*iter)
  398. getResource(&iter->query(), content);
  399. return content;
  400. }
  401. void WuWebView::getResultXSLT(const char *viewName, StringBuffer &xslt, StringBuffer &abspath)
  402. {
  403. VStringBuffer xpath("Views/Results[@name='%s']/@resource", viewName);
  404. const char *resource = ensureManifest()->queryProp(xpath.str());
  405. if (resource)
  406. getResource(resource, xslt, abspath, "XSLT");
  407. }
  408. void WuWebView::renderExpandedResults(const char *viewName, WuExpandedResultBuffer &expanded, StringBuffer &out)
  409. {
  410. IPropertyTree *mf = ensureManifest();
  411. VStringBuffer xpath("Views/Results[@name='%s']", viewName);
  412. IPropertyTree *view = mf->queryPropTree(xpath.str());
  413. if (!view)
  414. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "Result view %s not found", viewName);
  415. expanded.appendXML(view, "view");
  416. if (loadedDll)
  417. expanded.appendManifestSchemas(*mf, *loadedDll);
  418. expanded.finalize();
  419. const char *type=view->queryProp("@type");
  420. if (!type)
  421. throw MakeStringException(WUWEBERR_UnknownViewType, "No type defined for view %s", viewName);
  422. else if (strieq(type, "xml"))
  423. {
  424. out.swapWith(expanded.buffer);
  425. return;
  426. }
  427. else if (!strieq(type, "xslt"))
  428. throw MakeStringException(WUWEBERR_UnknownViewType, "View %s has an unknown type of %s", viewName, type);
  429. StringBuffer xslt;
  430. StringBuffer rootpath;
  431. getResultXSLT(viewName, xslt, rootpath);
  432. if (!xslt.length())
  433. throw MakeStringException(WUWEBERR_ViewResourceNotFound, "XSLT for %s view not found", viewName);
  434. Owned<IXslTransform> t = getXslProcessor()->createXslTransform();
  435. t->setIncludeHandler(this);
  436. StringBuffer cacheId(viewName);
  437. cacheId.append('@').append(dllname.str()); //using dllname, cloned workunits can share cache entry
  438. t->setXslSource(xslt.str(), xslt.length(), cacheId.str(), rootpath.str());
  439. t->setXmlSource(expanded.buffer.str(), expanded.buffer.length());
  440. t->transform(out);
  441. }
  442. void WuWebView::renderResults(const char *viewName, const char *xml, StringBuffer &out)
  443. {
  444. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  445. buffer.appendDatasetsFromXML(xml);
  446. renderExpandedResults(viewName, buffer, out);
  447. }
  448. void WuWebView::renderResults(const char *viewName, StringBuffer &out)
  449. {
  450. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  451. buffer.appendResults(wu, username.get(), pw.get());
  452. renderExpandedResults(viewName, buffer, out);
  453. }
  454. void WuWebView::renderSingleResult(const char *viewName, const char *resultname, StringBuffer &out)
  455. {
  456. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  457. buffer.appendSingleResult(wu, resultname, username.get(), pw.get());
  458. renderExpandedResults(viewName, buffer, out);
  459. }
  460. void WuWebView::expandResults(const char *xml, StringBuffer &out, unsigned flags)
  461. {
  462. WuExpandedResultBuffer expander(name.str(), flags);
  463. expander.appendDatasetsFromXML(xml);
  464. if (loadedDll)
  465. expander.appendManifestSchemas(*ensureManifest(), *loadedDll);
  466. expander.finalize();
  467. out.append(expander.buffer);
  468. }
  469. void WuWebView::expandResults(StringBuffer &out, unsigned flags)
  470. {
  471. SCMStringBuffer xml;
  472. getFullWorkUnitResultsXML(username.get(), pw.get(), wu, xml, false, ExceptionSeverityInformation);
  473. expandResults(xml.str(), out, flags);
  474. }
  475. void WuWebView::applyResultsXSLT(const char *filename, const char *xml, StringBuffer &out)
  476. {
  477. WuExpandedResultBuffer buffer(name.str(), WWV_ADD_RESPONSE_TAG | WWV_ADD_RESULTS_TAG);
  478. buffer.appendDatasetsFromXML(xml);
  479. if (loadedDll)
  480. buffer.appendManifestSchemas(*ensureManifest(), *loadedDll);
  481. Owned<IXslTransform> t = getXslProcessor()->createXslTransform();
  482. t->setIncludeHandler(this);
  483. //override default behavior using filename as cache identifier, there's a chance includes are
  484. //mapped to resources and need to be distinguished in cache
  485. StringBuffer cacheId(filename);
  486. cacheId.append('@').append(dllname.str()); //cloned workunits have same dll and resources
  487. t->loadXslFromFile(filename, cacheId.str());
  488. t->setXmlSource(buffer.str(), buffer.length());
  489. t->transform(out);
  490. }
  491. void WuWebView::applyResultsXSLT(const char *filename, StringBuffer &out)
  492. {
  493. SCMStringBuffer xml;
  494. getFullWorkUnitResultsXML(username.get(), pw.get(), wu, xml, false, ExceptionSeverityInformation);
  495. applyResultsXSLT(filename, xml.str(), out);
  496. }
  497. void WuWebView::load(IConstWorkUnit &cwu)
  498. {
  499. wu.set(&cwu);
  500. if (!name.length())
  501. {
  502. wu->getJobName(name);
  503. name.s.replace(' ','_');
  504. }
  505. Owned<IConstWUQuery> q = wu->getQuery();
  506. q->getQueryDllName(dllname);
  507. try
  508. {
  509. loadedDll.setown(queryDllServer().loadDll(dllname.str(), DllLocationAnywhere));
  510. }
  511. catch(...)
  512. {
  513. DBGLOG("Failed to load %s", dllname.str());
  514. }
  515. }
  516. void WuWebView::load(const char *wuid)
  517. {
  518. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  519. Owned<IConstWorkUnit> wu = factory->openWorkUnit(wuid, false);
  520. if (!wu)
  521. throw MakeStringException(WUWEBERR_WorkUnitNotFound, "Workunit not found %s", wuid);
  522. load(*wu);
  523. }
  524. extern WUWEBVIEW_API IWuWebView *createWuWebView(IConstWorkUnit &wu, const char *queryname, const char *dir, bool mapEspDirectories)
  525. {
  526. try
  527. {
  528. return new WuWebView(wu, queryname, dir, mapEspDirectories);
  529. }
  530. catch (...)
  531. {
  532. SCMStringBuffer wuid;
  533. DBGLOG("ERROR loading workunit %s shared object.", wu.getWuid(wuid).str());
  534. }
  535. return NULL;
  536. }
  537. extern WUWEBVIEW_API IWuWebView *createWuWebView(const char *wuid, const char *queryname, const char *dir, bool mapEspDirectories)
  538. {
  539. try
  540. {
  541. return new WuWebView(wuid, queryname, dir, mapEspDirectories);
  542. }
  543. catch (...)
  544. {
  545. DBGLOG("ERROR loading workunit %s shared object.", wuid);
  546. }
  547. return NULL;
  548. }