DispatcherEntry.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. *+------------------------------------------------------------------------+
  3. *| Licensed Materials - Property of IBM
  4. *| IBM Cognos Products: Viewer
  5. *| (C) Copyright IBM Corp. 2001, 2016
  6. *|
  7. *| US Government Users Restricted Rights - Use, duplication or
  8. *| disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  9. *|
  10. *+------------------------------------------------------------------------+
  11. */
  12. /*
  13. * DispatcherEntry classes are used for sending http requests from the Viewer.
  14. *
  15. * Hierarchy of classes
  16. *
  17. * DispatcherEntry
  18. * AsynchDataDispatcherEntry
  19. * ModifyReportDispatcherEntry
  20. * ReportDispatcherEntry
  21. * ViewerDispatcherEntry
  22. * AsynchJSONDispatcherEntry
  23. * ReportInfoDispatcherEntry
  24. * DataDispatcherEntry
  25. * JSONDispatcherEntry
  26. *
  27. * DispatcherEntry: This is the base class for all requests sent by the Viewer. It provides defaults for handling faults,
  28. * working and passport timeouts. It adds common form fields that ALL requests should have,
  29. * for example b_action=cognosViewer. By default it will use a basic XmlHttpObject to do the request
  30. *
  31. * AsynchDataDispatcherEntry: This class should be used when needing to make an asynch request that returns a DATA resposne.
  32. * It'll create an asynchDATARequest object to make the http request as well as set
  33. * the cv.resposneFormat to data.
  34. *
  35. * ModifyReportDispatcherEntry: This class should be used when performing an action that will modify the report. It requires an
  36. * action object to be set via the initializeAction method.
  37. *
  38. * ReportDispatcherEntry: This is the base class for all secondary requests done to the report (page up, drill, change format, ...).
  39. * It should be treated as an abstract class and never be created directly. It will add common form fields
  40. * needed for secondary requests (tracking, conversation, ...) and it will handle updating UI with the response
  41. *
  42. * ViewerDispatcherEntry: This class can be found under 3 different folders (fragments, iWidget, standalone) depending where
  43. * the Viewer is being used. This is the class you should use/create for all secondary requests. Any formfields
  44. * that are specific to fragments, iWidget or standalone should be added to these classes
  45. *
  46. * AsynchJSONDispatcherEntry: This class should be used when needing to make an asynch request that returns a JSON response. It'll
  47. * create an asynchJSONRequest object to make the http request as well as set the cv.resposneFormat to asynchJSON
  48. *
  49. * ReportInfoDispatcherEntry: This class is used to gather information about the report (collectFilterableItems, collectFilterValues, getInfo)
  50. *
  51. * DataDispatcherEntry: This class should be used when needing to make a request that returns a data response.
  52. *
  53. * JSONDispatcherEntry: This class should be used when needing to make a request that returns a json response.
  54. *
  55. *
  56. * There are a few different ways to modify the default behavior of the dispatcherEntry classes.
  57. *
  58. * 1. Setting your own callback. By default all the callbacks are taken care of and the only one you need to specify
  59. * is the callback for complete. However, you can override the default callbacks by simply calling setCallbacks and specify
  60. * any of the callbacks you wish to override. For example, if I wanted to change the behavior of handling faults so that my function
  61. * would get called, I'd do the following, where this.onFault is a function that I'd implement.
  62. *
  63. * oDispatcherEntry.setCallbacks( {
  64. * "complete" : {"object":this, "method":this.onComplete},
  65. * "fault" : {"object" : this, "method" : this.onFault}
  66. * });
  67. *
  68. * The list of possible callbacks are:
  69. * complete: gets called when the response is complete
  70. * postComplete: last thing that will get called, useful if you want the normal complete
  71. * code execute and get called back when it's all done
  72. * working: gets called if the asynch response has a status of working or stillWorking. Note, the wait request
  73. * will still get sent internally. This callback is simply if you need to do something
  74. * before the wait request is sent.
  75. * error: gets called if an http error happened
  76. * cancel: gets called when a request was canceled
  77. * prompting: gets called when the response has a status of prompting
  78. * passportTimeout: gets called when the response contains a passportTimeout fault
  79. * fault: gets called when the response has a status of fault
  80. * closeErrorDlg: gets called when the user closes the log on dialog without login in or if he hits Ok on a fault dialog
  81. *
  82. * 2. Setting your own dialogs for the request indicator and/or working dialog. By default, only the ModifyReportDispatcherEntry and
  83. * ReportDispatcherEntry classes will show feedback to the user in the UI that a request is executing. You can override that behavior for
  84. * any of the dispatcherEntry classes by calling set setWorkingDialog and/or setRequestIndicator. The dialog you pass to those functions
  85. * needs to extend the IRequestIndicator class.
  86. */
  87. function DispatcherEntry(oCV)
  88. {
  89. this.m_oCV = oCV;
  90. this.m_requestKey = null;
  91. this.m_canBeQueued = false;
  92. this.m_originalFormFields = null;
  93. this.m_bUsePageRequest = false;
  94. if (oCV) {
  95. if (!this.m_request) {
  96. this.m_request = new XmlHttpObject();
  97. this.m_request.init("POST", this.m_oCV.getGateway(), "", true);
  98. }
  99. if (!this.m_requestHandler) {
  100. this.setRequestHandler(new BaseRequestHandler(oCV));
  101. }
  102. DispatcherEntry.prototype.setDefaultFormFields.call(this);
  103. this.setCallbacks( {
  104. "entryComplete" : {"object":this, "method":this.onEntryComplete},
  105. "entryFault" : {"object":this, "method":this.onEntryFault},
  106. "newRequest" : {"object":this, "method": this.onNewRequest},
  107. "fault" : {"object" : this, "method" : this.onFault},
  108. "error" : {"object" : this, "method" : this.onError},
  109. "passportTimeout" : {"object" : this, "method" : this.onPassportTimeout},
  110. "working" : {"object" : this, "method" : this.onWorking },
  111. "prompting" : {"object" : this, "method" : this.onPrompting},
  112. "preHttpRequest" : {"object" : this, "method" : this.onPreHttpRequest},
  113. "postHttpRequest" : {"object" : this, "method" : this.onPostHttpRequest},
  114. "postEntryComplete" : { "object" : this, 'method' : this.onPostEntryComplete}
  115. });
  116. }
  117. }
  118. DispatcherEntry.prototype.setHeaders = function(headers) {
  119. this.m_request.setHeaders(headers);
  120. };
  121. DispatcherEntry.prototype.getHeaders = function() {
  122. return this.m_request.getHeaders();
  123. };
  124. DispatcherEntry.prototype.setOriginalFormFields = function(formFields) {
  125. this.m_originalFormFields = formFields;
  126. };
  127. DispatcherEntry.prototype.getOriginalFormFields = function() {
  128. return this.m_originalFormFields;
  129. };
  130. DispatcherEntry.prototype.setRequestHandler = function(handler) {
  131. // This is the central location where we can override some of the status callbacks
  132. handler.addCallbackHooks();
  133. this.m_requestHandler = handler;
  134. };
  135. DispatcherEntry.prototype.getRequestHandler = function() {
  136. return this.m_requestHandler;
  137. };
  138. DispatcherEntry.prototype.setWorkingDialog = function(workingDialog) {
  139. if (this.getRequestHandler()) {
  140. this.m_requestHandler.setWorkingDialog(workingDialog);
  141. }
  142. };
  143. DispatcherEntry.prototype.setRequestIndicator = function(requestIndicator) {
  144. if (this.getRequestHandler()) {
  145. this.getRequestHandler().setRequestIndicator(requestIndicator);
  146. }
  147. };
  148. DispatcherEntry.prototype.forceSynchronous = function() {
  149. this.getRequest().forceSynchronous();
  150. };
  151. DispatcherEntry.prototype.setUsePageRequest = function(bUsePageRequest) {
  152. this.m_bUsePageRequest = bUsePageRequest;
  153. };
  154. DispatcherEntry.prototype.getUsePageRequest = function() {
  155. return this.m_bUsePageRequest;
  156. };
  157. /**
  158. * Add any form fields that ALL request should have
  159. */
  160. DispatcherEntry.prototype.setDefaultFormFields = function() {
  161. var envParams = this.getViewer().envParams;
  162. this.addFormField("b_action", "cognosViewer");
  163. this.addFormField("cv.catchLogOnFault", "true");
  164. this.addDefinedNonNullFormField("protectParameters", envParams["protectParameters"]);
  165. this.addDefinedNonNullFormField("ui.routingServerGroup", envParams["ui.routingServerGroup"]);
  166. this.addDefinedNonNullFormField("cv.debugDirectory", envParams["cv.debugDirectory"]);
  167. this.addDefinedNonNullFormField("cv.showFaultPage", envParams["cv.showFaultPage"]);
  168. this.addDefinedNonNullFormField("cv.useRAPDrill", envParams["cv.useRAPDrill"]);
  169. this.addDefinedNonNullFormField("container", envParams["container"]);
  170. this.addNonEmptyStringFormField("cv.objectPermissions", envParams["cv.objectPermissions"]);
  171. };
  172. DispatcherEntry.prototype.getViewer = function() {
  173. return this.m_oCV;
  174. };
  175. DispatcherEntry.prototype.prepareRequest = function()
  176. {
  177. // Will get called before the request is executed.
  178. };
  179. DispatcherEntry.addWidgetInfoToFormFields = function(oWidget/*ViewerIWdiget Object*/, oDispatcherEntry/*DispatcherEntry Object*/){
  180. if(oWidget){
  181. var sBUXRTStateInfo = oWidget.getBUXRTStateInfoMap();
  182. if(sBUXRTStateInfo){
  183. oDispatcherEntry.addFormField("cv.buxRTStateInfo",sBUXRTStateInfo);
  184. }
  185. var sDisplayName = oWidget.getDisplayName();
  186. if(sDisplayName && sDisplayName.length >0){
  187. oDispatcherEntry.addFormField("displayTitle", sDisplayName);
  188. }
  189. }
  190. };
  191. DispatcherEntry.prototype.canBeQueued = function() {
  192. return this.m_canBeQueued;
  193. };
  194. DispatcherEntry.prototype.setCanBeQueued = function(canBeQueued) {
  195. this.m_canBeQueued = canBeQueued;
  196. };
  197. DispatcherEntry.prototype.getKey = function() {
  198. return this.m_requestKey;
  199. };
  200. DispatcherEntry.prototype.setKey = function(key) {
  201. this.m_requestKey = key;
  202. };
  203. /**
  204. * The request must be of type XmlHttpObject or extend that class
  205. * @param {Object} request
  206. */
  207. DispatcherEntry.prototype.setRequest = function(request) {
  208. this.m_request = request;
  209. };
  210. DispatcherEntry.prototype.getRequest = function() {
  211. return this.m_request;
  212. };
  213. /**
  214. * JSON structure of the following format
  215. * { customArguments:[arg1, arg2, ...],
  216. * "complete": {"object" : obj, "method": method},
  217. * "prompting": {"object" : obj, "method": method},
  218. * ...
  219. * };
  220. *
  221. * Possible callbacks
  222. * complete - gets called when the response is complete
  223. * working - gets called if the asynch response has a status of working or stillWorking
  224. * error - gets called if an http error happened
  225. * cancel - gets called when a request was canceled
  226. * prompting - gets called when the response has a status of prompting
  227. * passportTimeout - gets called when the response contains a passportTimeout fault
  228. * fault - gets called when the response has a status of fault
  229. * preHttpRequest - gets called right before the http request is sent
  230. * postHttpRequest - gets called right after the http response is received
  231. *
  232. */
  233. DispatcherEntry.prototype.setCallbacks = function(callbacks) {
  234. this.getRequest().setCallbacks(callbacks);
  235. };
  236. DispatcherEntry.prototype.getCallbacks = function() {
  237. return this.getRequest().getCallbacks();
  238. };
  239. /**
  240. * Executes the request. Also adds in our own callbacks so that we're notified for a
  241. * fault or when the entry is complete, that way we can remove the entry from the queue
  242. */
  243. DispatcherEntry.prototype.sendRequest = function() {
  244. this.prepareRequest();
  245. // save the original form fields, in case we have to retry the request
  246. var formFields = this.getRequest().getFormFields();
  247. var formFieldNames = formFields.keys();
  248. if (!this.m_originalFormFields) {
  249. this.m_originalFormFields = new CDictionary();
  250. for (var index = 0; index < formFieldNames.length; index++) {
  251. this.m_originalFormFields.add(formFieldNames[index], formFields.get(formFieldNames[index]));
  252. }
  253. }
  254. this.getRequest().sendRequest();
  255. };
  256. /**
  257. * Callback for when the request object creates a new request internaly so
  258. * that we know about the new request object. This will happen most often
  259. * for waits
  260. * @param {Object} request
  261. */
  262. DispatcherEntry.prototype.onNewRequest = function(request) {
  263. this.setRequest(request);
  264. };
  265. /**
  266. * Will retry the original request
  267. */
  268. DispatcherEntry.prototype.retryRequest = function() {
  269. var oCV = this.getViewer();
  270. oCV.setRetryDispatcherEntry(null);
  271. var request = this.getRequest().newRequest();
  272. request.setHeaders(null);
  273. this.setRequest(request);
  274. var formFieldNames = this.m_originalFormFields.keys();
  275. for (var index = 0; index < formFieldNames.length; index++) {
  276. var formField = formFieldNames[index];
  277. var formFieldValue = this.m_originalFormFields.get(formField);
  278. if (formField == "cv.responseFormat" && formFieldValue == "iWidget") {
  279. this.addFormField("cv.responseFormat", "data");
  280. }
  281. else if (formField == "ui.action" && formFieldValue == "wait") {
  282. this.addFormField("ui.action", this.m_originalFormFields.get("ui.primaryAction"));
  283. }
  284. else if(formField != "m_tracking" && formField != "cv.outputKey") {
  285. this.addFormField(formField, formFieldValue);
  286. }
  287. }
  288. this.addFormField("widget.reloadToolbar", "true");
  289. if (this.m_oCV.getViewerWidget()) {
  290. this.addFormField("cv.buxCurrentUserRole", this.m_oCV.getViewerWidget().getUserRole());
  291. }
  292. this.addNonEmptyStringFormField("cv.objectPermissions", oCV.envParams["cv.objectPermissions"]);
  293. this.addNonEmptyStringFormField("limitedInteractiveMode", oCV.envParams["limitedInteractiveMode"]);
  294. this.m_oCV.getViewerDispatcher().dispatchRequest(this);
  295. };
  296. DispatcherEntry.prototype.abortHttpRequest = function() {
  297. // guard against sending multiple cancel requests
  298. if (!this.m_bCancelCalled) {
  299. if (this.getRequestHandler()) {
  300. this.getRequestHandler().onCancel();
  301. }
  302. this.m_bCancelCalled = true;
  303. this.getRequest().abortHttpRequest();
  304. this.onEntryComplete();
  305. }
  306. };
  307. DispatcherEntry.prototype.cancelRequest = function(forceSynchronous) {
  308. // guard against sending multiple cancel requests
  309. if (!this.m_bCancelCalled) {
  310. this.m_bCancelCalled = true;
  311. if (this.getRequestHandler()) {
  312. this.getRequestHandler().onCancel();
  313. }
  314. if (forceSynchronous) {
  315. this.getRequest().forceSynchronous();
  316. }
  317. this.getRequest().cancel();
  318. this.onEntryComplete();
  319. }
  320. };
  321. DispatcherEntry.prototype.getFormFields = function() {
  322. return this.m_request.getFormFields();
  323. };
  324. DispatcherEntry.prototype.getFormField = function(name) {
  325. if (this.m_request) {
  326. return this.m_request.getFormField(name);
  327. } else {
  328. return "";
  329. }
  330. };
  331. DispatcherEntry.prototype.clearFormFields = function() {
  332. this.m_request.clearFormFields();
  333. };
  334. DispatcherEntry.prototype.formFieldExists = function(name) {
  335. if (this.m_request) {
  336. return this.m_request.getFormFields().exists(name);
  337. }
  338. return false;
  339. };
  340. DispatcherEntry.prototype.removeFormField = function(name) {
  341. if (this.formFieldExists(name)) {
  342. this.m_request.getFormFields().remove(name);
  343. }
  344. };
  345. DispatcherEntry.prototype.addFormField = function(name, value) {
  346. this.m_request.addFormField(name, value);
  347. };
  348. DispatcherEntry.prototype.addDefinedNonNullFormField = function(name, value) {
  349. if (typeof value != "undefined" && value != null) {
  350. this.addFormField(name, value);
  351. }
  352. };
  353. DispatcherEntry.prototype.addDefinedFormField = function(name, value) {
  354. if (typeof value != "undefined") {
  355. this.addFormField(name, value);
  356. }
  357. };
  358. DispatcherEntry.prototype.addNonNullFormField = function(name, value) {
  359. if (value != null) {
  360. this.addFormField(name, value);
  361. }
  362. };
  363. DispatcherEntry.prototype.addNonEmptyStringFormField = function(name, value) {
  364. if (typeof value != "undefined" && value != null && value != "") {
  365. this.addFormField(name, value);
  366. }
  367. };
  368. DispatcherEntry.prototype.onWorking = function(response, arg1) {
  369. if (this.getRequestHandler()) {
  370. this.getRequestHandler().onWorking(response);
  371. }
  372. };
  373. /**
  374. * onFault is called when we got a SOAP fault back
  375. */
  376. DispatcherEntry.prototype.onFault = function(response) {
  377. if (this.getRequestHandler()) {
  378. this.getRequestHandler().onFault(response);
  379. }
  380. };
  381. /**
  382. * onError is called when we got an http error.
  383. */
  384. DispatcherEntry.prototype.onError = function(response) {
  385. // When we abort an http request (cancel) we'll also get an error. Simply ignore it.
  386. if (this.m_bCancelCalled) {
  387. return;
  388. }
  389. if (this.getRequestHandler()) {
  390. this.getRequestHandler().onError(response);
  391. }
  392. };
  393. /**
  394. * We're not a 100% that the user will leave the page but we still need to unhook the http error
  395. * handling in case he does leave the page so that the cancelled http request error doesn't show up in the UI
  396. */
  397. DispatcherEntry.prototype.possibleUnloadEvent = function() {
  398. this.setCallbacks( {"error" : {} });
  399. };
  400. DispatcherEntry.prototype.onPreHttpRequest = function(request) {
  401. if (this.getRequestHandler()) {
  402. this.getRequestHandler().preHttpRequest(request);
  403. }
  404. };
  405. DispatcherEntry.prototype.onPostHttpRequest = function(response) {
  406. if (this.getRequestHandler()) {
  407. this.getRequestHandler().postHttpRequest(response);
  408. }
  409. };
  410. DispatcherEntry.prototype.onPassportTimeout = function(response) {
  411. if (this.getRequestHandler()) {
  412. this.getRequestHandler().onPassportTimeout(response);
  413. }
  414. };
  415. DispatcherEntry.prototype.onPrompting = function(response) {
  416. if (this.getRequestHandler()) {
  417. this.getRequestHandler().onPrompting(response);
  418. }
  419. };
  420. /**
  421. * Callback when the request is complete so that we can remove
  422. * the dispatcher entry from the queue before processing the response
  423. * @param {Object} response
  424. */
  425. DispatcherEntry.prototype.onEntryComplete = function(response) {
  426. if (!this.m_oCV._beingDestroyed) {
  427. this.m_oCV.getViewerDispatcher().requestComplete(this);
  428. }
  429. };
  430. /**
  431. * Callback when the request generates a fault so that we can remove the dispatcher entry
  432. * from the queue before processing the response
  433. * @param {Object} response
  434. */
  435. DispatcherEntry.prototype.onEntryFault = function(response) {
  436. this.m_oCV.setFaultDispatcherEntry(this);
  437. this.m_oCV.resetViewerDispatcher();
  438. if (!this.m_bCancelCalled) {
  439. this.m_oCV.setRetryDispatcherEntry(this);
  440. }
  441. };
  442. /**
  443. * Called when the user closes the log on dialog without login in or closes the fault dialog
  444. */
  445. DispatcherEntry.prototype.onCloseErrorDlg = function() {
  446. var callbacks = this.getCallbacks();
  447. if (callbacks["closeErrorDlg"]) {
  448. var callbackFunc = GUtil.generateCallback(callbacks["closeErrorDlg"].method, [], callbacks["closeErrorDlg"].object);
  449. callbackFunc();
  450. }
  451. };
  452. DispatcherEntry.prototype.onPostEntryComplete = function() {
  453. if (this.getRequestHandler()) {
  454. this.getRequestHandler().onPostEntryComplete();
  455. }
  456. this.executeCallback("postComplete");
  457. };
  458. DispatcherEntry.prototype.executeCallback = function(callback) {
  459. var callbacks = this.getCallbacks();
  460. if (callbacks[callback]) {
  461. var callbackArguments = (callbacks.customArguments)?[this, callbacks.customArguments]: [this];
  462. var callbackFunc = GUtil.generateCallback(callbacks[callback].method, callbackArguments, callbacks[callback].object);
  463. callbackFunc();
  464. return true;
  465. }
  466. return false;
  467. };