123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- 'use strict';
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- /**
- * Licensed Materials - Property of IBM
- * IBM Business Analytics (C) Copyright IBM Corp. 2019, 2020
- * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
- */
- /**
- * @class TransactionAPI
- * @hideconstructor
- * @classdesc API class that is used to control transactional operations across API calls
- */
- define(['underscore', '../../../../../lib/@waca/dashboard-common/dist/core/APIFactory', '../TransactionAPI'], function (_, APIFactory, TransactionAPI) {
- var Transaction = function () {
- function Transaction() {
- _classCallCheck(this, Transaction);
- this._transactions = new Map();
- this._handlers = new Map();
- }
- Transaction.prototype.getAPI = function getAPI() {
- return APIFactory.createAPI(this, [TransactionAPI]);
- };
- Transaction.prototype.startTransaction = function startTransaction(parentToken) {
- if (!(parentToken && parentToken.transactionId)) {
- // create a new transaction entry
- var entry = this._createTransactionEntry(_.uniqueId('__transaction__'));
- if (parentToken && parentToken.source) {
- entry.token.source = parentToken.source;
- entry.token.eventGenerated = parentToken.eventGenerated;
- }
- return entry.token;
- } else {
- var _entry = this._get(parentToken.transactionId);
- if (_entry) {
- // add a sub-transaction to an existing transaction entry
- var subTransactionIdx = this._addSubTransaction(_entry);
- var res = _.extend({ subTransaction: subTransactionIdx }, _entry.token);
- if (parentToken && parentToken.source) {
- res.source = parentToken.source;
- res.eventGenerated = parentToken.eventGenerated;
- }
- return res;
- }
- console.warn('Invalid transactionId: ' + parentToken.transactionId);
- return parentToken;
- }
- };
- Transaction.prototype.startTransactionById = function startTransactionById(transactionId) {
- var entry = this._get(transactionId);
- if (entry) {
- return this.startTransaction(entry.token);
- }
- entry = this._createTransactionEntry(transactionId);
- return entry.token;
- };
- Transaction.prototype.endTransaction = function endTransaction(token) {
- var transactionId = token && token.transactionId;
- var entry = this._get(transactionId);
- if (entry && Number.isInteger(token.subTransaction)) {
- entry = entry.children[token.subTransaction];
- }
- if (entry) {
- entry.timestamp.end = Date.now();
- entry.end();
- } else {
- console.warn('Invalid transactionId: ' + transactionId);
- }
- return token;
- };
- Transaction.prototype.getTransactionById = function getTransactionById(id) {
- var entry = this._get(id);
- return entry ? entry.token : {};
- };
- Transaction.prototype.registerTransactionHandler = function registerTransactionHandler(token, handlerId, handler, args) {
- var isValid = this.isValidTransaction(token);
- if (isValid) {
- // register and invoke the handler
- this._register(handlerId, handler, token.transactionId, args);
- return this._invoke(handlerId);
- } else {
- // directly invoke the handler and move on
- var rv = handler([args]);
- return rv instanceof Promise ? rv : Promise.resolve();
- }
- };
- Transaction.prototype.whenTransactionComplete = function whenTransactionComplete(token) {
- // we only need wait for the root promise to complete
- var entry = this._get(token.transactionId);
- // return the transaction promise which disposes the transaction at the end
- return entry._promise.then(this._dispose.bind(this, token.transactionId));
- };
- Transaction.prototype.isValidTransaction = function isValidTransaction(token) {
- return !!this._get(token.transactionId);
- };
- Transaction.prototype.getActiveTransactionList = function getActiveTransactionList() {
- return _.map(this._getAll(), function (entry) {
- return entry.token;
- });
- };
- /**
- * @private
- * Create a new transaction entry
- * @param {String} uniqueId unique transaction identifier
- * {
- * token: {
- * transactionId: 'xyz'
- * },
- * end: function() { ... },
- * timestamp: {
- * start: 1551142727899,
- * end: 1551142741757
- * }
- * }
- */
- Transaction.prototype._createTransactionEntry = function _createTransactionEntry(uniqueId) {
- var entry = {
- 'token': {
- 'transactionId': uniqueId
- },
- 'timestamp': {
- 'start': Date.now()
- }
- };
- entry._promise = new Promise(function (resolve) {
- this.end = function () {
- if (this.children && this.children.length > 0) {
- this.children[0]._promise.then(resolve);
- } else {
- resolve();
- }
- }.bind(this);
- }.bind(entry));
- this._set(uniqueId, entry);
- return entry;
- };
- /**
- * @private
- * Add a sub-transcation to an existing transaction
- * @param {Object} entry parent transaction entry object
- * {
- * token: {
- * transactionId: 'xyz'
- * },
- * children: [{
- * end: function() { ... },
- * next: { ... }
- * timestamp: {
- * start: 1551142727899,
- * end: 1551142741757
- * }
- * }, {
- * end: function() { ... },
- * timestamp: {
- * start: 1551142727899,
- * end: 1551142741757
- * }
- * }]
- * end: function() { ... },
- * timestamp: {
- * start: 1551142727899
- * }
- * }
- */
- Transaction.prototype._addSubTransaction = function _addSubTransaction(entry) {
- // prepare the subtransactions list
- if (!entry.children) {
- entry.children = [];
- }
- var subTransactionEntry = {
- timestamp: {
- start: Date.now()
- }
- };
- var transactionIndex = entry.children.length;
- var lastItem = entry.children && entry.children[entry.children.length - 1];
- // link the current transaction as the next transaction for the previous transaction
- if (lastItem) {
- lastItem.next = subTransactionEntry;
- }
- subTransactionEntry._promise = new Promise(function (resolve) {
- this.end = function () {
- if (this.next) {
- // resolve the my promise once the next promise is resolved
- this.next._promise.then(resolve);
- } else {
- resolve();
- }
- }.bind(this);
- }.bind(subTransactionEntry));
- // add the subtransaction to the existing entry
- entry.children.push(subTransactionEntry);
- return transactionIndex;
- };
- Transaction.prototype._getAll = function _getAll() {
- var all = [];
- this._transactions.forEach(function (tranaction) {
- all.push(tranaction);
- });
- return all;
- };
- Transaction.prototype._get = function _get(transactionId) {
- return this._transactions.get(transactionId);
- };
- Transaction.prototype._set = function _set(transactionId, entry) {
- this._transactions.set(transactionId, entry);
- };
- Transaction.prototype._dispose = function _dispose(transactionId) {
- this._transactions.delete(transactionId);
- };
- Transaction.prototype._register = function _register(handlerId, handler, transactionId, args) {
- var entry = this._handlers.get(handlerId);
- if (entry) {
- // update the transactions related to current handler
- if (entry.transactionIds.indexOf(transactionId) < 0) {
- entry.transactionIds.push(transactionId);
- }
- entry.args.push(args);
- } else {
- // register the handler
- this._handlers.set(handlerId, {
- 'transactionIds': [transactionId],
- 'handler': handler,
- 'args': [args]
- });
- }
- };
- Transaction.prototype._isRegistered = function _isRegistered(handlerId) {
- return !!this._handlers.get(handlerId);
- };
- /**
- * This is an enhancement to replace Promise.all to handle cases
- * which the array of transactions can grow asynchronously.
- * Once the initial handler waits for all transactions complete,
- * transactions that are added afterwards may result the handler
- * to be invoked prematurely.
- */
- Transaction.prototype._waitForAllTransactions = function _waitForAllTransactions(transactionIds) {
- var _this = this;
- var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
- if (transactionIds.length > index) {
- // We can not rely on Promise.all since a new transaction can be added
- // after the handler was initially register and invoked
- var transaction = this._get(transactionIds[index]);
- if (transaction) {
- // wait for the current transaction to complete
- return transaction._promise.then(function () {
- // seek for the next transaction during the runtime
- return _this._waitForAllTransactions(transactionIds, index + 1);
- });
- } else {
- // continue with the next transaction
- return this._waitForAllTransactions(transactionIds, index + 1);
- }
- }
- return Promise.resolve();
- };
- Transaction.prototype._invoke = function _invoke(handlerId) {
- var _this2 = this;
- var entry = this._handlers.get(handlerId);
- if (!entry._promise) {
- // @todo Use Transaction._waitForAllTransactions to support optimized rendering
- var transactions = _.map(entry.transactionIds, function (id) {
- return _this2._get(id)._promise;
- });
- // invoke the handler once all related transactions are complete
- entry._promise = Promise.all(transactions).then(function () {
- // entry._promise = this._waitForAllTransactions(entry.transactionIds).then(() => {
- // dispose all transactions that are registered for this handler
- _.each(entry.transactionIds, _this2._dispose.bind(_this2));
- try {
- return entry.handler(entry.args);
- } finally {
- // clean up the handler
- _this2._handlers.delete(handlerId);
- }
- });
- }
- return entry._promise;
- };
- return Transaction;
- }();
- return Transaction;
- });
- //# sourceMappingURL=Transaction.js.map
|