ESPWorkunit.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /*##############################################################################
  2. # HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. ############################################################################## */
  16. define([
  17. "dojo/_base/declare",
  18. "dojo/_base/array",
  19. "dojo/_base/lang",
  20. "dojo/_base/Deferred",
  21. "dojo/data/ObjectStore",
  22. "dojo/store/util/QueryResults",
  23. "dojo/store/Observable",
  24. "dojo/Stateful",
  25. "hpcc/ESPResult",
  26. "hpcc/WsWorkunits"
  27. ], function (declare, arrayUtil, lang, Deferred, ObjectStore, QueryResults, Observable, Stateful,
  28. ESPResult, WsWorkunits) {
  29. _workunits = {};
  30. var Store = declare(null, {
  31. idProperty: "Wuid",
  32. _watched: {},
  33. constructor: function (options) {
  34. declare.safeMixin(this, options);
  35. },
  36. getIdentity: function (object) {
  37. return object[this.idProperty];
  38. },
  39. get: function (id) {
  40. if (!_workunits[id]) {
  41. _workunits[id] = new Workunit({
  42. Wuid: id
  43. });
  44. }
  45. return _workunits[id];
  46. },
  47. remove: function (item) {
  48. if (_workunits[this.getIdentity(item)]) {
  49. _workunits[this.getIdentity(item)].killTimer();
  50. delete _workunits[this.getIdentity(item)];
  51. }
  52. },
  53. query: function (query, options) {
  54. var request = {};
  55. lang.mixin(request, options.query);
  56. if (options.start)
  57. request['PageStartFrom'] = options.start;
  58. if (options.count)
  59. request['Count'] = options.count;
  60. if (options.sort) {
  61. request['Sortby'] = options.sort[0].attribute;
  62. request['Descending'] = options.sort[0].descending;
  63. }
  64. var results = WsWorkunits.WUQuery({
  65. request: request
  66. });
  67. var deferredResults = new Deferred();
  68. deferredResults.total = results.then(function (response) {
  69. if (lang.exists("WUQueryResponse.NumWUs", response)) {
  70. return response.WUQueryResponse.NumWUs;
  71. }
  72. return 0;
  73. });
  74. var context = this;
  75. Deferred.when(results, function (response) {
  76. var workunits = [];
  77. for (key in context._watched) {
  78. context._watched[key].unwatch();
  79. }
  80. this._watched = {};
  81. if (lang.exists("WUQueryResponse.Workunits.ECLWorkunit", response)) {
  82. arrayUtil.forEach(response.WUQueryResponse.Workunits.ECLWorkunit, function (item, index) {
  83. var wu = context.get(item.Wuid);
  84. wu.updateData(item);
  85. workunits.push(wu);
  86. context._watched[wu.Wuid] = wu.watch("changedCount", function (name, oldValue, newValue) {
  87. if (oldValue !== newValue) {
  88. context.notify(wu, wu.Wuid);
  89. }
  90. });
  91. });
  92. }
  93. deferredResults.resolve(workunits);
  94. });
  95. return QueryResults(deferredResults);
  96. }
  97. });
  98. var WorkunitData = declare([Stateful], {
  99. Wuid: "",
  100. changedCount: 0,
  101. _StateIDSetter: function (StateID) {
  102. if (this.StateID !== StateID) {
  103. this.StateID = StateID;
  104. var actionEx = lang.exists("ActionEx", this) ? this.ActionEx : null;
  105. this.set("hasCompleted", WsWorkunits.isComplete(this.StateID, actionEx));
  106. }
  107. },
  108. _VariablesSetter: function (Variables) {
  109. var variables = [];
  110. for (var i = 0; i < Variables.ECLResult.length; ++i) {
  111. context.variables.push(lang.mixin({
  112. ColumnType: Variables.ECLResult[i].ECLSchemas && Variables.ECLResult[i].ECLSchemas.ECLSchemaItem.length ? Variables.ECLResult[i].ECLSchemas.ECLSchemaItem[0].ColumnType : "unknown"
  113. }, variables[i]));
  114. }
  115. this.set("variables", variables);
  116. },
  117. _ResultsSetter: function (Results) {
  118. var results = [];
  119. for (var i = 0; i < Results.ECLResult.length; ++i) {
  120. results.push(ESPResult.Get(lang.mixin({ wu: this.wu, Wuid: this.Wuid }, Results.ECLResult[i])));
  121. }
  122. this.set("results", results);
  123. },
  124. _SourceFilesSetter: function (SourceFiles) {
  125. var sourceFiles = [];
  126. for (var i = 0; i < SourceFiles.ECLSourceFile.length; ++i) {
  127. sourceFiles.push(ESPResult.Get(lang.mixin({ wu: this.wu, Wuid: this.Wuid }, SourceFiles.ECLSourceFile[i])));
  128. }
  129. this.set("sourceFiles", sourceFiles);
  130. },
  131. _TimersSetter: function(Timers) {
  132. var timers = [];
  133. for (var i = 0; i < Timers.ECLTimer.length; ++i) {
  134. var timeParts = Timers.ECLTimer[i].Value.split(":");
  135. var secs = 0;
  136. for (var j = 0; j < timeParts.length; ++j) {
  137. secs = secs * 60 + timeParts[j] * 1;
  138. }
  139. timers.push(lang.mixin(Timers.ECLTimer[i], {
  140. Seconds: Math.round(secs * 1000) / 1000,
  141. HasSubGraphId: Timers.ECLTimer[i].SubGraphId && Timers.ECLTimer[i].SubGraphId != "" ? true : false
  142. }));
  143. }
  144. this.set("timers", timers);
  145. },
  146. _GraphsSetter: function(Graphs) {
  147. this.set("graphs", Graphs.ECLGraph);
  148. },
  149. getData: function () {
  150. if (this instanceof WorkunitData) {
  151. return (WorkunitData)(this);
  152. }
  153. return {};
  154. },
  155. updateData: function (response) {
  156. var changed = false;
  157. for (var key in response) {
  158. if (this.get(key) !== response[key]) {
  159. changed = true;
  160. this.set(key, response[key]);
  161. }
  162. }
  163. if (changed) {
  164. this.set("changedCount", this.get("changedCount") + 1);
  165. }
  166. }
  167. });
  168. var Workunit = declare([WorkunitData], {
  169. results: [],
  170. graphs: [],
  171. timers: [],
  172. _assertHasWuid: function () {
  173. if (!this.Wuid) {
  174. throw new Error("Wuid cannot be empty.");
  175. }
  176. },
  177. onCreate: function () {
  178. },
  179. onUpdate: function () {
  180. },
  181. onSubmit: function () {
  182. },
  183. constructor: function (args) {
  184. this.inherited(arguments);
  185. declare.safeMixin(this, args);
  186. this.wu = this;
  187. },
  188. isComplete: function () {
  189. return this.hasCompleted;
  190. },
  191. setTimer: function (timer) {
  192. this._timerTickCount = 0;
  193. this._timer = timer;
  194. this.onTimer();
  195. },
  196. killTimer: function () {
  197. this._timerTickCount = 0;
  198. this._timer = 0;
  199. },
  200. onTimer: function () {
  201. this._timerTickCount++;
  202. if (this.hasCompleted) {
  203. this.killTimer();
  204. return;
  205. } else {
  206. if (this._timerTickCount < 5 && this._timerTickCount % 1 === 0) {
  207. this.refresh();
  208. } else if (this._timerTickCount < 30 && this._timerTickCount % 5 === 0) {
  209. this.refresh();
  210. } else if (this._timerTickCount < 60 && this._timerTickCount % 10 === 0) {
  211. this.refresh();
  212. } else if (this._timerTickCount < 120 && this._timerTickCount % 30 === 0) {
  213. this.refresh();
  214. } else if (this._timerTickCount % 60 === 0) {
  215. this.refresh();
  216. }
  217. }
  218. var context = this;
  219. if (this._timer) {
  220. setTimeout(function () {
  221. context.onTimer();
  222. }, this._timer);
  223. } else {
  224. this_timerTickCount = 0;
  225. }
  226. },
  227. monitor: function (callback) {
  228. if (this.hasCompleted) {
  229. if (callback) {
  230. callback(this);
  231. }
  232. } else {
  233. this.setTimer(1000);
  234. var context = this;
  235. this.watch("changedCount", function (name, oldValue, newValue) {
  236. if (oldValue !== newValue && newValue) {
  237. if (callback) {
  238. callback(context);
  239. }
  240. }
  241. });
  242. }
  243. },
  244. create: function (ecl) {
  245. var context = this;
  246. WsWorkunits.WUCreate({
  247. load: function (response) {
  248. _workunits[response.WUCreateResponse.Workunit.Wuid] = context
  249. context.updateData(response.WUCreateResponse.Workunit);
  250. context.onCreate();
  251. }
  252. });
  253. },
  254. update: function (request, appData) {
  255. this._assertHasWuid();
  256. lang.mixin(request, {
  257. Wuid: this.Wuid
  258. });
  259. lang.mixin(request, {
  260. StateOrig: this.State,
  261. JobnameOrig: this.Jobname,
  262. DescriptionOrig: this.Description,
  263. ProtectedOrig: this.Protected,
  264. ScopeOrig: this.Scope,
  265. ClusterOrig: this.Cluster,
  266. ApplicationValues: appData
  267. });
  268. var context = this;
  269. WsWorkunits.WUUpdate({
  270. request: request,
  271. load: function (response) {
  272. context.updateData(response.WUUpdateResponse.Workunit);
  273. context.onUpdate();
  274. }
  275. });
  276. },
  277. submit: function (target) {
  278. this._assertHasWuid();
  279. var context = this;
  280. WsWorkunits.WUSubmit({
  281. request: {
  282. Wuid: this.Wuid,
  283. Cluster: target
  284. },
  285. load: function (response) {
  286. context.onSubmit();
  287. }
  288. });
  289. },
  290. _resubmit: function (clone, resetWorkflow) {
  291. this._assertHasWuid();
  292. var context = this;
  293. WsWorkunits.WUResubmit({
  294. request: {
  295. Wuids: this.Wuid,
  296. CloneWorkunit: clone,
  297. ResetWorkflow: resetWorkflow
  298. },
  299. load: function (response) {
  300. context.refresh();
  301. }
  302. });
  303. },
  304. clone: function () {
  305. this._resubmit(true, false);
  306. },
  307. resubmit: function () {
  308. this._resubmit(false, false);
  309. },
  310. restart: function () {
  311. this._resubmit(false, true);
  312. },
  313. _action: function (action) {
  314. this._assertHasWuid();
  315. var context = this;
  316. WsWorkunits.WUAction([{ Wuid: this.Wuid }], action, {
  317. load: function (response) {
  318. context.refresh();
  319. }
  320. });
  321. },
  322. setToFailed: function () {
  323. this._action("setToFailed");
  324. },
  325. abort: function () {
  326. this._action("Abort");
  327. },
  328. doDelete: function () {
  329. this._action("Delete");
  330. },
  331. publish: function (jobName) {
  332. this._assertHasWuid();
  333. var context = this;
  334. WsWorkunits.WUPublishWorkunit({
  335. request: {
  336. Wuid: this.Wuid,
  337. JobName: jobName,
  338. Activate: 1,
  339. UpdateWorkUnitName: 1,
  340. Wait: 5000
  341. },
  342. load: function (response) {
  343. context.updateData(response.WUPublishWorkunitResponse);
  344. }
  345. });
  346. },
  347. refresh: function (full) {
  348. if (full) {
  349. this.getInfo({
  350. onGetText: function () {
  351. },
  352. onGetWUExceptions: function () {
  353. },
  354. onGetGraphs: function () {
  355. },
  356. onGetSourceFiles: function () {
  357. },
  358. onGetResults: function () {
  359. },
  360. onGetVariables: function () {
  361. },
  362. onGetTimers: function () {
  363. },
  364. onGetApplicationValues: function () {
  365. }
  366. });
  367. } else {
  368. this.getQuery();
  369. }
  370. },
  371. getQuery: function () {
  372. this._assertHasWuid();
  373. var context = this;
  374. WsWorkunits.WUQuery({
  375. request: {
  376. Wuid: this.Wuid,
  377. },
  378. load: function (response) {
  379. if (lang.exists("WUQueryResponse.Workunits.ECLWorkunit", response)) {
  380. arrayUtil.forEach(response.WUQueryResponse.Workunits.ECLWorkunit, function (item, index) {
  381. context.updateData(item);
  382. });
  383. }
  384. }
  385. });
  386. },
  387. getInfo: function (args) {
  388. this._assertHasWuid();
  389. var context = this;
  390. WsWorkunits.WUInfo({
  391. request: {
  392. Wuid: this.Wuid,
  393. TruncateEclTo64k: args.onGetText ? false : true,
  394. IncludeExceptions: args.onGetWUExceptions ? true : false,
  395. IncludeGraphs: args.onGetGraphs ? true : false,
  396. IncludeSourceFiles: args.onGetSourceFiles ? true : false,
  397. IncludeResults: args.onGetResults ? true : false,
  398. IncludeResultsViewNames: false,
  399. IncludeVariables: args.onGetVariables ? true : false,
  400. IncludeTimers: args.onGetTimers ? true : false,
  401. IncludeDebugValues: false,
  402. IncludeApplicationValues: args.onGetApplicationValues ? true : false,
  403. IncludeWorkflows: false,
  404. IncludeXmlSchemas: args.onGetResults ? true : false,
  405. SuppressResultSchemas: args.onGetResults ? false : true
  406. },
  407. load: function (response) {
  408. if (lang.exists("WUInfoResponse.Workunit", response)) {
  409. context.updateData(response.WUInfoResponse.Workunit);
  410. if (args.onGetText && lang.exists("Query.Text", context)) {
  411. args.onGetText(context.Query.Text);
  412. }
  413. if (args.onGetWUExceptions && lang.exists("Exceptions.ECLException", context)) {
  414. args.onGetWUExceptions(context.Exceptions.ECLException);
  415. }
  416. if (args.onGetApplicationValues && lang.exists("ApplicationValues.ApplicationValue", context)) {
  417. args.onGetApplicationValues(context.ApplicationValues.ApplicationValue)
  418. }
  419. if (args.onGetVariables && lang.exists("variables", context)) {
  420. args.onGetVariables(context.variables);
  421. }
  422. if (args.onGetResults && lang.exists("results", context)) {
  423. args.onGetResults(context.results);
  424. }
  425. if (args.onGetSourceFiles && lang.exists("sourceFiles", context)) {
  426. args.onGetSourceFiles(context.sourceFiles);
  427. }
  428. if (args.onGetTimers && lang.exists("timers", context)) {
  429. args.onGetTimers(context.timers);
  430. }
  431. if (args.onGetGraphs && lang.exists("graphs", context)) {
  432. if (context.timers || lang.exists("ApplicationValues.ApplicationValue", context)) {
  433. for (var i = 0; i < context.graphs.length; ++i) {
  434. if (context.timers) {
  435. context.graphs[i].Time = 0;
  436. for (var j = 0; j < context.timers.length; ++j) {
  437. if (context.timers[j].GraphName == context.graphs[i].Name) {
  438. context.graphs[i].Time += context.timers[j].Seconds;
  439. }
  440. context.graphs[i].Time = Math.round(context.graphs[i].Time * 1000) / 1000;
  441. }
  442. }
  443. if (lang.exists("ApplicationValues.ApplicationValue", context)) {
  444. var idx = context.getApplicationValueIndex("ESPWorkunit.js", context.graphs[i].Name + "_SVG");
  445. if (idx >= 0) {
  446. context.graphs[i].svg = context.ApplicationValues.ApplicationValue[idx].Value;
  447. }
  448. }
  449. }
  450. }
  451. args.onGetGraphs(context.graphs)
  452. }
  453. if (args.onAfterSend) {
  454. args.onAfterSend(context);
  455. }
  456. }
  457. }
  458. });
  459. },
  460. getGraphIndex: function (name) {
  461. for (var i = 0; i < this.graphs.length; ++i) {
  462. if (this.graphs[i].Name == name) {
  463. return i;
  464. }
  465. }
  466. return -1;
  467. },
  468. getApplicationValueIndex: function (application, name) {
  469. if (lang.exists("ApplicationValues.ApplicationValue", this)) {
  470. for (var i = 0; i < this.ApplicationValues.ApplicationValue.length; ++i) {
  471. if (this.ApplicationValues.ApplicationValue[i].Application == application && this.ApplicationValues.ApplicationValue[i].Name == name) {
  472. return i;
  473. }
  474. }
  475. }
  476. return -1;
  477. },
  478. getState: function () {
  479. return this.State;
  480. },
  481. getStateIconClass: function () {
  482. switch (this.StateID) {
  483. case 1:
  484. case 3:
  485. return "iconCompleted";
  486. case 2:
  487. case 11:
  488. case 15:
  489. return "iconRunning";
  490. case 4:
  491. case 7:
  492. return "iconFailed";
  493. case 5:
  494. case 8:
  495. case 10:
  496. case 12:
  497. case 13:
  498. case 14:
  499. case 16:
  500. return "iconArchived";
  501. case 6:
  502. return "iconAborting";
  503. case 9:
  504. return "iconSubmitted";
  505. case 999:
  506. return "iconDeleted";
  507. }
  508. return "iconWorkunit";
  509. },
  510. getStateImage: function () {
  511. switch (this.StateID) {
  512. case 1:
  513. return "img/workunit_completed.png";
  514. case 2:
  515. return "img/workunit_running.png";
  516. case 3:
  517. return "img/workunit_completed.png";
  518. case 4:
  519. return "img/workunit_failed.png";
  520. case 5:
  521. return "img/workunit_warning.png";
  522. case 6:
  523. return "img/workunit_aborting.png";
  524. case 7:
  525. return "img/workunit_failed.png";
  526. case 8:
  527. return "img/workunit_warning.png";
  528. case 9:
  529. return "img/workunit_submitted.png";
  530. case 10:
  531. return "img/workunit_warning.png";
  532. case 11:
  533. return "img/workunit_running.png";
  534. case 12:
  535. return "img/workunit_warning.png";
  536. case 13:
  537. return "img/workunit_warning.png";
  538. case 14:
  539. return "img/workunit_warning.png";
  540. case 15:
  541. return "img/workunit_running.png";
  542. case 16:
  543. return "img/workunit_warning.png";
  544. case 999:
  545. return "img/workunit_deleted.png";
  546. }
  547. return "img/workunit.png";
  548. },
  549. getProtectedImage: function () {
  550. if (this.Protected) {
  551. return "img/locked.png"
  552. }
  553. return "img/unlocked.png"
  554. },
  555. fetchText: function (onFetchText) {
  556. var context = this;
  557. if (lang.exists("Query.Text", context)) {
  558. onFetchText(this.Query.Text);
  559. return;
  560. }
  561. this.getInfo({
  562. onGetText: onFetchText
  563. });
  564. },
  565. fetchXML: function (onFetchXML) {
  566. if (this.xml) {
  567. onFetchXML(this.xml);
  568. return;
  569. }
  570. this._assertHasWuid();
  571. var context = this;
  572. WsWorkunits.WUFile({
  573. request: {
  574. Wuid: this.Wuid,
  575. Type: "XML"
  576. },
  577. load: function (response) {
  578. context.xml = response;
  579. onFetchXML(response);
  580. }
  581. });
  582. },
  583. fetchResults: function (onFetchResults) {
  584. if (this.results && this.results.length) {
  585. onFetchResults(this.results);
  586. return;
  587. }
  588. this.getInfo({
  589. onGetResults: onFetchResults
  590. });
  591. },
  592. fetchTimers: function (onFetchTimers) {
  593. if (this.timers && this.timers.length) {
  594. onFetchTimers(this.timers);
  595. return;
  596. }
  597. this.getInfo({
  598. onGetTimers: onFetchTimers
  599. });
  600. },
  601. fetchGraphs: function (onFetchGraphs) {
  602. if (this.graphs && this.graphs.length) {
  603. onFetchGraphs(this.graphs);
  604. return;
  605. }
  606. this.getInfo({
  607. onGetGraphs: onFetchGraphs
  608. });
  609. },
  610. fetchGraphXgmmlByName: function (name, onFetchGraphXgmml) {
  611. var idx = this.getGraphIndex(name);
  612. if (idx >= 0) {
  613. this.fetchGraphXgmml(idx, onFetchGraphXgmml);
  614. }
  615. },
  616. fetchGraphXgmml: function (idx, onFetchGraphXgmml) {
  617. this._assertHasWuid();
  618. var context = this;
  619. WsWorkunits.WUGetGraph({
  620. request: {
  621. Wuid: this.Wuid,
  622. GraphName: this.graphs[idx].Name
  623. },
  624. load: function (response) {
  625. context.graphs[idx].xgmml = response.WUGetGraphResponse.Graphs.ECLGraphEx[0].Graph;
  626. onFetchGraphXgmml(context.graphs[idx].xgmml, context.graphs[idx].svg);
  627. }
  628. });
  629. },
  630. setGraphSvg: function (graphName, svg) {
  631. var idx = this.getGraphIndex(graphName);
  632. if (idx >= 0) {
  633. this.graphs[idx].svg = svg;
  634. var appData = [];
  635. appData[graphName + "_SVG"] = svg;
  636. this.update({}, appData);
  637. }
  638. }
  639. });
  640. return {
  641. Create: function (params) {
  642. retVal = new Workunit(params);
  643. retVal.create();
  644. return retVal;
  645. },
  646. Get: function (wuid) {
  647. var store = new Store();
  648. return store.get(wuid);
  649. },
  650. CreateWUQueryObjectStore: function (options) {
  651. var store = new Store(options);
  652. store = Observable(store);
  653. var objStore = new ObjectStore({ objectStore: store });
  654. return objStore;
  655. }
  656. };
  657. });