@adobe/acc-js-sdk 1.1.61 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.cursor/commands/opsx-apply.md +152 -0
  2. package/.cursor/commands/opsx-archive.md +157 -0
  3. package/.cursor/commands/opsx-explore.md +173 -0
  4. package/.cursor/commands/opsx-propose.md +106 -0
  5. package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
  6. package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
  7. package/.cursor/skills/openspec-explore/SKILL.md +288 -0
  8. package/.cursor/skills/openspec-propose/SKILL.md +110 -0
  9. package/.eslintrc.js +2 -2
  10. package/.github/prompts/opsx-apply.prompt.md +149 -0
  11. package/.github/prompts/opsx-archive.prompt.md +154 -0
  12. package/.github/prompts/opsx-explore.prompt.md +170 -0
  13. package/.github/prompts/opsx-propose.prompt.md +103 -0
  14. package/.github/skills/openspec-apply-change/SKILL.md +156 -0
  15. package/.github/skills/openspec-archive-change/SKILL.md +114 -0
  16. package/.github/skills/openspec-explore/SKILL.md +288 -0
  17. package/.github/skills/openspec-propose/SKILL.md +110 -0
  18. package/.github/workflows/codeql-analysis.yml +5 -4
  19. package/.github/workflows/npm-publish.yml +3 -3
  20. package/AGENTS.md +117 -0
  21. package/CLAUDE.md +2 -0
  22. package/MIGRATION.md +10 -0
  23. package/README.md +6 -2
  24. package/ai-docs/coding-rules.md +95 -0
  25. package/ai-docs/tech-stack.md +43 -0
  26. package/babel.config.js +5 -0
  27. package/docs/changeLog.html +34 -0
  28. package/docs/checkList.html +2 -2
  29. package/docs/connectionParameters.html +5 -0
  30. package/docs/quickstart.html +2 -1
  31. package/docs/release.html +1 -1
  32. package/openspec/config.yaml +20 -0
  33. package/package-lock.json +7437 -3924
  34. package/package.json +9 -7
  35. package/src/AGENTS.md +98 -0
  36. package/src/CLAUDE.md +2 -0
  37. package/src/application.js +637 -637
  38. package/src/cache.js +133 -133
  39. package/src/cacheRefresher.js +190 -190
  40. package/src/campaign.js +532 -532
  41. package/src/client.js +1539 -1532
  42. package/src/crypto.js +52 -52
  43. package/src/domUtil.js +346 -346
  44. package/src/entityAccessor.js +61 -61
  45. package/src/index.js +83 -83
  46. package/src/methodCache.js +69 -69
  47. package/src/optionCache.js +26 -26
  48. package/src/soap.js +321 -322
  49. package/src/testUtil.js +13 -13
  50. package/src/transport.js +70 -70
  51. package/src/util.js +147 -147
  52. package/src/web/bundler.js +5 -5
  53. package/src/xtkCaster.js +258 -258
  54. package/src/xtkEntityCache.js +34 -34
  55. package/src/xtkJob.js +185 -185
  56. package/test/AGENTS.md +37 -0
  57. package/test/CLAUDE.md +2 -0
  58. package/test/cacheRefresher.test.js +7 -0
  59. package/test/client.test.js +123 -81
  60. package/test/jest.config.js +6 -0
  61. package/test/observability.test.js +6 -1
  62. package/test/xtkJob.test.js +2 -2
package/src/client.js CHANGED
@@ -10,36 +10,35 @@ OF ANY KIND, either express or implied. See the License for the specific languag
10
10
  governing permissions and limitations under the License.
11
11
  */
12
12
  (function() {
13
- "use strict";
14
- /*jshint sub:true*/
13
+ "use strict";
15
14
 
16
- /**********************************************************************************
15
+ /**********************************************************************************
17
16
  *
18
17
  * ACC JavaScript SDK
19
18
  * See README.md for usage
20
19
  *
21
20
  *********************************************************************************/
22
21
 
23
- /**
22
+ /**
24
23
  * Client to ACC instance
25
24
  */
26
- const { SoapMethodCall } = require('./soap.js');
27
- const { CampaignException, makeCampaignException } = require('./campaign.js');
28
- const XtkCaster = require('./xtkCaster.js').XtkCaster;
29
- const XtkEntityCache = require('./xtkEntityCache.js').XtkEntityCache;
30
- const Cipher = require('./crypto.js').Cipher;
31
- const DomUtil = require('./domUtil.js').DomUtil;
32
- const MethodCache = require('./methodCache.js').MethodCache;
33
- const OptionCache = require('./optionCache.js').OptionCache;
34
- const CacheRefresher = require('./cacheRefresher.js').CacheRefresher;
35
- const request = require('./transport.js').request;
36
- const { Application, newSchema } = require('./application.js');
37
- const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
38
- const { Util } = require('./util.js');
39
- const { XtkJobInterface } = require('./xtkJob.js');
40
- const qsStringify = require('qs-stringify');
41
-
42
- /**
25
+ const { SoapMethodCall } = require('./soap.js');
26
+ const { CampaignException, makeCampaignException } = require('./campaign.js');
27
+ const XtkCaster = require('./xtkCaster.js').XtkCaster;
28
+ const XtkEntityCache = require('./xtkEntityCache.js').XtkEntityCache;
29
+ const Cipher = require('./crypto.js').Cipher;
30
+ const DomUtil = require('./domUtil.js').DomUtil;
31
+ const MethodCache = require('./methodCache.js').MethodCache;
32
+ const OptionCache = require('./optionCache.js').OptionCache;
33
+ const CacheRefresher = require('./cacheRefresher.js').CacheRefresher;
34
+ const request = require('./transport.js').request;
35
+ const { Application, newSchema } = require('./application.js');
36
+ const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
37
+ const { Util } = require('./util.js');
38
+ const { XtkJobInterface } = require('./xtkJob.js');
39
+ const qsStringify = require('qs-stringify');
40
+
41
+ /**
43
42
  * @namespace Campaign
44
43
  *
45
44
  * @typedef {Object} SessionInfo
@@ -61,7 +60,7 @@ const qsStringify = require('qs-stringify');
61
60
  * @memberOf Campaign
62
61
  */
63
62
 
64
- /**
63
+ /**
65
64
  * @typedef {Object} XtkMethodParam
66
65
  * @property {string} name - the name of the parameter
67
66
  * @property {string} type - the type of the parameter
@@ -69,7 +68,7 @@ const qsStringify = require('qs-stringify');
69
68
  * @memberOf Campaign
70
69
  */
71
70
 
72
- /**
71
+ /**
73
72
  * Java Script Proxy handler for an XTK object. An XTK object is one constructed with the following syntax:
74
73
  *
75
74
  * <code>
@@ -82,43 +81,44 @@ const qsStringify = require('qs-stringify');
82
81
  * @private
83
82
  * @memberof Campaign
84
83
  */
85
- const xtkObjectHandler = {
84
+ const xtkObjectHandler = {
86
85
  set: function(callContext, prop, value) {
87
- const object = callContext.object;
88
- object[prop] = value;
86
+ const object = callContext.object;
87
+ object[prop] = value;
88
+ return true;
89
89
  },
90
90
 
91
91
  get: function(callContext, methodName) {
92
- if (methodName == ".")
93
- return callContext;
94
- if (methodName === "__xtkProxy")
95
- return true;
96
- if (methodName === "save") {
97
- return async () => {
98
- return callContext.client.NLWS.xtkSession.write(callContext.object);
99
- };
100
- }
101
- if (methodName === "entity") {
102
- return callContext.object;
103
- }
104
-
105
- const caller = function(thisArg, argumentsList) {
106
- const callContext = thisArg["."];
107
- if (methodName == "inspect") return callContext.object;
108
- methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
109
- return callContext.client._callMethod(methodName, callContext, argumentsList);
92
+ if (methodName == ".")
93
+ return callContext;
94
+ if (methodName === "__xtkProxy")
95
+ return true;
96
+ if (methodName === "save") {
97
+ return async () => {
98
+ return callContext.client.NLWS.xtkSession.write(callContext.object);
110
99
  };
100
+ }
101
+ if (methodName === "entity") {
102
+ return callContext.object;
103
+ }
111
104
 
112
- return new Proxy(caller, {
113
- apply: function(target, thisArg, argumentsList) {
114
- return target(thisArg, argumentsList);
115
- }
116
- });
105
+ const caller = function(thisArg, argumentsList) {
106
+ const callContext = thisArg["."];
107
+ if (methodName == "inspect") return callContext.object;
108
+ methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
109
+ return callContext.client._callMethod(methodName, callContext, argumentsList);
110
+ };
111
+
112
+ return new Proxy(caller, {
113
+ apply: function(target, thisArg, argumentsList) {
114
+ return target(thisArg, argumentsList);
115
+ }
116
+ });
117
117
 
118
118
  }
119
- };
119
+ };
120
120
 
121
- /**
121
+ /**
122
122
  * Java Script Proxy handler for NLWS.
123
123
  * The proxy resolves constructs such as
124
124
  *
@@ -134,106 +134,106 @@ const xtkObjectHandler = {
134
134
  * @private
135
135
  * @memberof Campaign
136
136
  */
137
- const clientHandler = (representation, headers, pushDownOptions) => {
137
+ const clientHandler = (representation, headers, pushDownOptions) => {
138
138
  return {
139
- get: function(client, namespace) {
140
-
141
- // Force XML or JSON representation (NLWS.xml or NLWS.json)
142
- if (namespace == "xml") return new Proxy(client, clientHandler("xml", headers, pushDownOptions));
143
- if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson", headers, pushDownOptions));
144
-
145
- // Override HTTP headers (NLWS.headers({...}))
146
- // Unlike NLWS.xml or NLWS.json, NLWS.headers returns a function. This function takes key/value
147
- // pairs of headers, and, when called, returns a proxy object which will remember the headers
148
- // and be able to pass them to subsequent SOAP call context
149
- if (namespace == "headers") return (methodHeaders) => {
150
- // Build of copy of the http headers and append new headers in order to accomodate
151
- // chained calls, such as NLWS.headers(...).headers(...)
152
- const newHeaders = {};
153
- if (headers) for (let h in headers) newHeaders[h] = headers[h];
154
- if (methodHeaders) for (let h in methodHeaders) newHeaders[h] = methodHeaders[h];
155
- return new Proxy(client, clientHandler(representation, newHeaders, pushDownOptions));
156
- };
139
+ get: function(client, namespace) {
140
+
141
+ // Force XML or JSON representation (NLWS.xml or NLWS.json)
142
+ if (namespace == "xml") return new Proxy(client, clientHandler("xml", headers, pushDownOptions));
143
+ if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson", headers, pushDownOptions));
144
+
145
+ // Override HTTP headers (NLWS.headers({...}))
146
+ // Unlike NLWS.xml or NLWS.json, NLWS.headers returns a function. This function takes key/value
147
+ // pairs of headers, and, when called, returns a proxy object which will remember the headers
148
+ // and be able to pass them to subsequent SOAP call context
149
+ if (namespace == "headers") return (methodHeaders) => {
150
+ // Build of copy of the http headers and append new headers in order to accomodate
151
+ // chained calls, such as NLWS.headers(...).headers(...)
152
+ const newHeaders = {};
153
+ if (headers) for (let h in headers) newHeaders[h] = headers[h];
154
+ if (methodHeaders) for (let h in methodHeaders) newHeaders[h] = methodHeaders[h];
155
+ return new Proxy(client, clientHandler(representation, newHeaders, pushDownOptions));
156
+ };
157
157
 
158
- // Pushes down addition options to the SOAP and transport layers
159
- if (namespace == "pushDown") return (methodPushDownOptions) => {
160
- // Build of copy of the pushDownOptions in order to accomodate
161
- // chained calls, such as NLWS.pushDown(...).pushDown(...)
162
- const newPushDownOptions = {};
163
- if (pushDownOptions) for (let h in pushDownOptions) newPushDownOptions[h] = pushDownOptions[h];
164
- if (methodPushDownOptions) for (let h in methodPushDownOptions) newPushDownOptions[h] = methodPushDownOptions[h];
165
- return new Proxy(client, clientHandler(representation, headers, newPushDownOptions));
166
- };
158
+ // Pushes down addition options to the SOAP and transport layers
159
+ if (namespace == "pushDown") return (methodPushDownOptions) => {
160
+ // Build of copy of the pushDownOptions in order to accomodate
161
+ // chained calls, such as NLWS.pushDown(...).pushDown(...)
162
+ const newPushDownOptions = {};
163
+ if (pushDownOptions) for (let h in pushDownOptions) newPushDownOptions[h] = pushDownOptions[h];
164
+ if (methodPushDownOptions) for (let h in methodPushDownOptions) newPushDownOptions[h] = methodPushDownOptions[h];
165
+ return new Proxy(client, clientHandler(representation, headers, newPushDownOptions));
166
+ };
167
167
 
168
- return new Proxy({ client:client, namespace:namespace}, {
169
- get: function(callContext, methodName) {
170
- callContext.representation = representation;
171
- callContext.headers = callContext.headers || client._connectionParameters._options.extraHttpHeaders;
172
- callContext.pushDownOptions = {};
173
- if (headers) {
174
- for (let h in headers) callContext.headers[h] = headers[h];
175
- }
176
- if (pushDownOptions) {
177
- for (let h in pushDownOptions) callContext.pushDownOptions[h] = pushDownOptions[h];
178
- }
168
+ return new Proxy({ client:client, namespace:namespace}, {
169
+ get: function(callContext, methodName) {
170
+ callContext.representation = representation;
171
+ callContext.headers = callContext.headers || client._connectionParameters._options.extraHttpHeaders;
172
+ callContext.pushDownOptions = {};
173
+ if (headers) {
174
+ for (let h in headers) callContext.headers[h] = headers[h];
175
+ }
176
+ if (pushDownOptions) {
177
+ for (let h in pushDownOptions) callContext.pushDownOptions[h] = pushDownOptions[h];
178
+ }
179
179
 
180
- if (methodName == ".")
181
- return callContext;
182
-
183
- // get Schema id from namespace (find first upper case letter)
184
- callContext.schemaId = Util.schemaIdFromNamespace(namespace);
185
-
186
- const caller = function(thisArg, argumentsList) {
187
- const callContext = thisArg["."];
188
- const namespace = callContext.namespace;
189
- const methodNameLC = methodName.toLowerCase();
190
- methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
191
- if (namespace == "xtkSession" && methodNameLC == "logon")
192
- return callContext.client.logon(argumentsList[0]);
193
- else if (namespace == "xtkSession" && methodNameLC == "logoff")
194
- return callContext.client.logoff();
195
- else if (namespace == "xtkSession" && methodNameLC == "getoption") {
196
- var promise = callContext.client._callMethod(methodName, callContext, argumentsList);
197
- return promise.then(function(optionAndValue) {
198
- const optionName = argumentsList[0];
199
- return client._optionCache.put(optionName, optionAndValue).then(() => optionAndValue);
200
- });
201
- }
202
- // static method
203
- var result = callContext.client._callMethod(methodName, callContext, argumentsList);
204
- return result;
205
- };
206
-
207
- if (methodName == "create") {
208
- return function(body) {
209
- callContext.object = body || {}; // supports empty bodies
210
- if (!callContext.object.xtkschema) callContext.object.xtkschema = callContext.schemaId;
211
- return new Proxy(callContext, xtkObjectHandler);
212
- };
213
- }
180
+ if (methodName == ".")
181
+ return callContext;
182
+
183
+ // get Schema id from namespace (find first upper case letter)
184
+ callContext.schemaId = Util.schemaIdFromNamespace(namespace);
185
+
186
+ const caller = function(thisArg, argumentsList) {
187
+ const callContext = thisArg["."];
188
+ const namespace = callContext.namespace;
189
+ const methodNameLC = methodName.toLowerCase();
190
+ methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
191
+ if (namespace == "xtkSession" && methodNameLC == "logon")
192
+ return callContext.client.logon(argumentsList[0]);
193
+ else if (namespace == "xtkSession" && methodNameLC == "logoff")
194
+ return callContext.client.logoff();
195
+ else if (namespace == "xtkSession" && methodNameLC == "getoption") {
196
+ var promise = callContext.client._callMethod(methodName, callContext, argumentsList);
197
+ return promise.then(function(optionAndValue) {
198
+ const optionName = argumentsList[0];
199
+ return client._optionCache.put(optionName, optionAndValue).then(() => optionAndValue);
200
+ });
201
+ }
202
+ // static method
203
+ var result = callContext.client._callMethod(methodName, callContext, argumentsList);
204
+ return result;
205
+ };
214
206
 
215
- return new Proxy(caller, {
216
- apply: function(target, thisArg, argumentsList) {
217
- return target(thisArg, argumentsList);
218
- }
219
- });
220
- }
207
+ if (methodName == "create") {
208
+ return function(body) {
209
+ callContext.object = body || {}; // supports empty bodies
210
+ if (!callContext.object.xtkschema) callContext.object.xtkschema = callContext.schemaId;
211
+ return new Proxy(callContext, xtkObjectHandler);
212
+ };
213
+ }
214
+
215
+ return new Proxy(caller, {
216
+ apply: function(target, thisArg, argumentsList) {
217
+ return target(thisArg, argumentsList);
218
+ }
221
219
  });
222
- }
220
+ }
221
+ });
222
+ }
223
223
  };
224
- };
224
+ };
225
225
 
226
- // ========================================================================================
227
- // Campaign credentials
228
- // ========================================================================================
226
+ // ========================================================================================
227
+ // Campaign credentials
228
+ // ========================================================================================
229
229
 
230
- /**
230
+ /**
231
231
  * @class
232
232
  * @constructor
233
233
  * @private
234
234
  * @memberof Campaign
235
235
  */
236
- class Credentials {
236
+ class Credentials {
237
237
 
238
238
  /**
239
239
  * Credentials to a Campaign instance. Encapsulates the various types of credentials.
@@ -243,16 +243,16 @@ class Credentials {
243
243
  * @param {string} securityToken the security token. Will use an empty token if not specified
244
244
  */
245
245
  constructor(type, sessionToken, securityToken) {
246
- if (type != "UserPassword" && type != "ImsServiceToken" && type != "SessionToken" && type != "SessionAndSecurityToken" &&
246
+ if (type != "UserPassword" && type != "ImsServiceToken" && type != "SessionToken" && type != "SessionAndSecurityToken" &&
247
247
  type != "AnonymousUser" && type != "SecurityToken" && type != "BearerToken" && type != "ImsBearerToken")
248
- throw CampaignException.INVALID_CREDENTIALS_TYPE(type);
249
- this._type = type;
250
- this._sessionToken = sessionToken || "";
251
- this._securityToken = securityToken || "";
252
- if (type == "BearerToken" || type === "ImsBearerToken") {
253
- this._bearerToken = sessionToken || "";
254
- this._sessionToken = "";
255
- }
248
+ throw CampaignException.INVALID_CREDENTIALS_TYPE(type);
249
+ this._type = type;
250
+ this._sessionToken = sessionToken || "";
251
+ this._securityToken = securityToken || "";
252
+ if (type == "BearerToken" || type === "ImsBearerToken") {
253
+ this._bearerToken = sessionToken || "";
254
+ this._sessionToken = "";
255
+ }
256
256
  }
257
257
 
258
258
  /**
@@ -262,11 +262,11 @@ class Credentials {
262
262
  * @returns {string} the user name
263
263
  */
264
264
  _getUser() {
265
- if (this._type != "UserPassword")
266
- throw CampaignException.CANNOT_GET_CREDENTIALS_USER(this._type);
267
- const tokens = this._sessionToken.split("/");
268
- const user = tokens[0];
269
- return user;
265
+ if (this._type != "UserPassword")
266
+ throw CampaignException.CANNOT_GET_CREDENTIALS_USER(this._type);
267
+ const tokens = this._sessionToken.split("/");
268
+ const user = tokens[0];
269
+ return user;
270
270
  }
271
271
 
272
272
  /**
@@ -276,20 +276,20 @@ class Credentials {
276
276
  * @returns {string} the user password
277
277
  */
278
278
  _getPassword() {
279
- if (this._type != "UserPassword")
280
- throw CampaignException.CANNOT_GET_CREDENTIALS_PASSWORD(this._type);
281
- const tokens = this._sessionToken.split("/");
282
- const password = tokens.length > 1 ? tokens[1] : "";
283
- return password;
279
+ if (this._type != "UserPassword")
280
+ throw CampaignException.CANNOT_GET_CREDENTIALS_PASSWORD(this._type);
281
+ const tokens = this._sessionToken.split("/");
282
+ const password = tokens.length > 1 ? tokens[1] : "";
283
+ return password;
284
284
  }
285
- }
285
+ }
286
286
 
287
287
 
288
- // ========================================================================================
289
- // Campaign connection parameters
290
- // ========================================================================================
288
+ // ========================================================================================
289
+ // Campaign connection parameters
290
+ // ========================================================================================
291
291
 
292
- /**
292
+ /**
293
293
  * @typedef {Object} ConnectionOptions
294
294
  * @property {string} representation - the representation to use, i.e. "SimpleJson" (the default), "BadgerFish", or "xml"
295
295
  * @property {boolean} rememberMe - The Campaign `rememberMe` attribute which can be used to extend the lifetime of session tokens
@@ -309,16 +309,17 @@ class Credentials {
309
309
  * @property {number} timeout - Can be set to change the HTTP call timeout. Value is passed in ms.
310
310
  * @property {string} cacheRootKey - "default" or "none" - determine the prefix to use for the keys in the caches of schemas, options, etc.
311
311
  * @property {string} instanceKey - an optional value to override the instance key which is used for the caches of schemas, options, etc.
312
+ * @property {boolean} enableRequestIdHeader - an optional value to enable the request ID header for SOAP API calls
312
313
  * @memberOf Campaign
313
314
  */
314
315
 
315
316
 
316
- /**
317
+ /**
317
318
  * @class
318
319
  * @constructor
319
320
  * @memberof Campaign
320
321
  */
321
- class ConnectionParameters {
322
+ class ConnectionParameters {
322
323
 
323
324
  /**
324
325
  * Creates a connection parameters object which can be used to create a Client object
@@ -328,59 +329,59 @@ class ConnectionParameters {
328
329
  * @param {Campaign.ConnectionOptions} options connection options
329
330
  */
330
331
  constructor(endpoint, credentials, options) {
331
- // this._options will be populated with the data from "options" and with
332
- // default values. But the "options" parameter will not be modified
333
- this._options = Object.assign({}, options);
332
+ // this._options will be populated with the data from "options" and with
333
+ // default values. But the "options" parameter will not be modified
334
+ this._options = Object.assign({}, options);
334
335
 
335
- // Default value
336
- if (options === undefined || options === null)
337
- options = { };
336
+ // Default value
337
+ if (options === undefined || options === null)
338
+ options = { };
338
339
  // Before version 1.0.0, the 4th parameter could be a boolean for the 'rememberMe' option.
339
340
  // Passing a boolean is not supported any more in 1.0.0. The Client constructor takes an
340
341
  // option object. The rememberMe parameter can be passed directly to the logon function
341
- if (typeof options != "object")
342
- throw CampaignException.INVALID_CONNECTION_OPTIONS(options);
343
-
344
- this._options.representation = options.representation;
345
- if (this._options.representation === undefined || this._options.representation === null)
346
- this._options.representation = "SimpleJson";
347
-
348
- if (this._options.representation != "xml" && this._options.representation != "BadgerFish" && this._options.representation != "SimpleJson")
349
- throw CampaignException.INVALID_REPRESENTATION(this._options.representation, "Cannot create Campaign client");
350
-
351
- // Defaults for rememberMe
352
- this._options.rememberMe = !!options.rememberMe;
353
-
354
- this._options.entityCacheTTL = options.entityCacheTTL || 1000*300; // 5 mins
355
- this._options.methodCacheTTL = options.methodCacheTTL || 1000*300; // 5 mins
356
- this._options.optionCacheTTL = options.optionCacheTTL || 1000*300; // 5 mins
357
- this._options.traceAPICalls = options.traceAPICalls === null || options.traceAPICalls ? !!options.traceAPICalls : false;
358
- this._options.transport = options.transport || request;
359
-
360
- this._endpoint = endpoint;
361
- this._credentials = credentials;
362
-
363
- var storage;
364
- if (!options.noStorage) {
365
- storage = options.storage;
366
- try {
367
- if (!storage)
368
- storage = localStorage;
369
- } catch (ex) {
370
- /* ignore error if localStorage not found */
371
- }
372
- }
373
- this._options._storage = storage;
374
- this._options.refreshClient = options.refreshClient;
375
- this._options.charset = options.charset === undefined ? "UTF-8": options.charset;
376
- this._options.extraHttpHeaders = {};
377
- if (options.extraHttpHeaders) {
378
- for (let h in options.extraHttpHeaders) this._options.extraHttpHeaders[h] = options.extraHttpHeaders[h];
342
+ if (typeof options != "object")
343
+ throw CampaignException.INVALID_CONNECTION_OPTIONS(options);
344
+
345
+ this._options.representation = options.representation;
346
+ if (this._options.representation === undefined || this._options.representation === null)
347
+ this._options.representation = "SimpleJson";
348
+
349
+ if (this._options.representation != "xml" && this._options.representation != "BadgerFish" && this._options.representation != "SimpleJson")
350
+ throw CampaignException.INVALID_REPRESENTATION(this._options.representation, "Cannot create Campaign client");
351
+
352
+ // Defaults for rememberMe
353
+ this._options.rememberMe = !!options.rememberMe;
354
+
355
+ this._options.entityCacheTTL = options.entityCacheTTL || 1000*300; // 5 mins
356
+ this._options.methodCacheTTL = options.methodCacheTTL || 1000*300; // 5 mins
357
+ this._options.optionCacheTTL = options.optionCacheTTL || 1000*300; // 5 mins
358
+ this._options.traceAPICalls = options.traceAPICalls === null || options.traceAPICalls ? !!options.traceAPICalls : false;
359
+ this._options.transport = options.transport || request;
360
+
361
+ this._endpoint = endpoint;
362
+ this._credentials = credentials;
363
+
364
+ var storage;
365
+ if (!options.noStorage) {
366
+ storage = options.storage;
367
+ try {
368
+ if (!storage)
369
+ storage = localStorage;
370
+ } catch (ex) {
371
+ /* ignore error if localStorage not found */
379
372
  }
380
- this._options.clientApp = options.clientApp;
381
- this._options.noSDKHeaders = !!options.noSDKHeaders;
382
- this._options.noMethodInURL = !!options.noMethodInURL;
383
- this._options.cacheRootKey = options.cacheRootKey === undefined ? "default": options.cacheRootKey;
373
+ }
374
+ this._options._storage = storage;
375
+ this._options.refreshClient = options.refreshClient;
376
+ this._options.charset = options.charset === undefined ? "UTF-8": options.charset;
377
+ this._options.extraHttpHeaders = {};
378
+ if (options.extraHttpHeaders) {
379
+ for (let h in options.extraHttpHeaders) this._options.extraHttpHeaders[h] = options.extraHttpHeaders[h];
380
+ }
381
+ this._options.clientApp = options.clientApp;
382
+ this._options.noSDKHeaders = !!options.noSDKHeaders;
383
+ this._options.noMethodInURL = !!options.noMethodInURL;
384
+ this._options.cacheRootKey = options.cacheRootKey === undefined ? "default": options.cacheRootKey;
384
385
  }
385
386
 
386
387
  /**
@@ -393,8 +394,8 @@ class ConnectionParameters {
393
394
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
394
395
  */
395
396
  static ofUserAndPassword(endpoint, user, password, options) {
396
- const credentials = new Credentials("UserPassword", `${user}/${password}`, "");
397
- return new ConnectionParameters(endpoint, credentials, options);
397
+ const credentials = new Credentials("UserPassword", `${user}/${password}`, "");
398
+ return new ConnectionParameters(endpoint, credentials, options);
398
399
  }
399
400
 
400
401
  /**
@@ -411,8 +412,8 @@ class ConnectionParameters {
411
412
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
412
413
  */
413
414
  static ofBearerToken(endpoint, bearerToken, options) {
414
- const credentials = new Credentials("BearerToken", bearerToken);
415
- return new ConnectionParameters(endpoint, credentials, options);
415
+ const credentials = new Credentials("BearerToken", bearerToken);
416
+ return new ConnectionParameters(endpoint, credentials, options);
416
417
  }
417
418
 
418
419
  /**
@@ -427,8 +428,8 @@ class ConnectionParameters {
427
428
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
428
429
  */
429
430
  static ofImsBearerToken(endpoint, bearerToken, options) {
430
- const credentials = new Credentials("ImsBearerToken", bearerToken);
431
- return new ConnectionParameters(endpoint, credentials, options);
431
+ const credentials = new Credentials("ImsBearerToken", bearerToken);
432
+ return new ConnectionParameters(endpoint, credentials, options);
432
433
  }
433
434
 
434
435
  /**
@@ -441,8 +442,8 @@ class ConnectionParameters {
441
442
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
442
443
  */
443
444
  static ofUserAndServiceToken(endpoint, user, serviceToken, options) {
444
- const credentials = new Credentials("ImsServiceToken", `_ims_/${user}/${serviceToken}`, "");
445
- return new ConnectionParameters(endpoint, credentials, options);
445
+ const credentials = new Credentials("ImsServiceToken", `_ims_/${user}/${serviceToken}`, "");
446
+ return new ConnectionParameters(endpoint, credentials, options);
446
447
  }
447
448
 
448
449
  /**
@@ -455,8 +456,8 @@ class ConnectionParameters {
455
456
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
456
457
  */
457
458
  static ofSessionToken(endpoint, sessionToken, options) {
458
- const credentials = new Credentials("SessionToken", sessionToken, "");
459
- return new ConnectionParameters(endpoint, credentials, options);
459
+ const credentials = new Credentials("SessionToken", sessionToken, "");
460
+ return new ConnectionParameters(endpoint, credentials, options);
460
461
  }
461
462
 
462
463
  /**
@@ -470,8 +471,8 @@ class ConnectionParameters {
470
471
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
471
472
  */
472
473
  static ofSessionAndSecurityToken(endpoint, sessionToken, securityToken, options) {
473
- const credentials = new Credentials("SessionAndSecurityToken", sessionToken, securityToken);
474
- return new ConnectionParameters(endpoint, credentials, options);
474
+ const credentials = new Credentials("SessionAndSecurityToken", sessionToken, securityToken);
475
+ return new ConnectionParameters(endpoint, credentials, options);
475
476
  }
476
477
 
477
478
  /**
@@ -487,8 +488,8 @@ class ConnectionParameters {
487
488
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
488
489
  */
489
490
  static ofSecurityToken(endpoint, securityToken, options) {
490
- const credentials = new Credentials("SecurityToken", "", securityToken);
491
- return new ConnectionParameters(endpoint, credentials, options);
491
+ const credentials = new Credentials("SecurityToken", "", securityToken);
492
+ return new ConnectionParameters(endpoint, credentials, options);
492
493
  }
493
494
 
494
495
  /**
@@ -499,8 +500,8 @@ class ConnectionParameters {
499
500
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
500
501
  */
501
502
  static ofAnonymousUser(endpoint, options) {
502
- const credentials = new Credentials("AnonymousUser", "", "");
503
- return new ConnectionParameters(endpoint, credentials, options);
503
+ const credentials = new Credentials("AnonymousUser", "", "");
504
+ return new ConnectionParameters(endpoint, credentials, options);
504
505
  }
505
506
 
506
507
 
@@ -514,58 +515,58 @@ class ConnectionParameters {
514
515
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
515
516
  */
516
517
  static async ofExternalAccount(client, extAccountName) {
517
- var queryDef = {
518
- "schema": "nms:extAccount",
519
- "operation": "get",
520
- "select": {
521
- "node": [
522
- { "expr": "@id" },
523
- { "expr": "@name" },
524
- { "expr": "@label" },
525
- { "expr": "@type" },
526
- { "expr": "@account" },
527
- { "expr": "@password" },
528
- { "expr": "@server" }
529
- ]
530
- },
531
- "where": {
532
- "condition": [
533
- { "expr": client.sdk.escapeXtk`@name=${extAccountName}` },
534
- { "expr": "@type=3" }
535
- ]
536
- }
537
- };
538
- // Convert to current representation
539
- queryDef = client._convertToRepresentation(queryDef, "SimpleJson");
540
- const query = client.NLWS.xtkQueryDef.create(queryDef);
541
- const extAccount = await query.executeQuery();
542
-
543
- const cipher = await client._getSecretKeyCipher();
544
- const type = EntityAccessor.getAttributeAsLong(extAccount, "type");
545
- if (type == 3) {
546
- // Mid-souring
547
- const endpoint = EntityAccessor.getAttributeAsString(extAccount, "server");
548
- const user = EntityAccessor.getAttributeAsString(extAccount, "account");
549
- const password = cipher.decryptPassword(EntityAccessor.getAttributeAsString(extAccount, "password"));
550
- return ConnectionParameters.ofUserAndPassword(endpoint, user, password, client._connectionParameters._options);
518
+ var queryDef = {
519
+ "schema": "nms:extAccount",
520
+ "operation": "get",
521
+ "select": {
522
+ "node": [
523
+ { "expr": "@id" },
524
+ { "expr": "@name" },
525
+ { "expr": "@label" },
526
+ { "expr": "@type" },
527
+ { "expr": "@account" },
528
+ { "expr": "@password" },
529
+ { "expr": "@server" }
530
+ ]
531
+ },
532
+ "where": {
533
+ "condition": [
534
+ { "expr": client.sdk.escapeXtk`@name=${extAccountName}` },
535
+ { "expr": "@type=3" }
536
+ ]
551
537
  }
552
- throw CampaignException.CREDENTIALS_FOR_INVALID_EXT_ACCOUNT(extAccountName, type);
538
+ };
539
+ // Convert to current representation
540
+ queryDef = client._convertToRepresentation(queryDef, "SimpleJson");
541
+ const query = client.NLWS.xtkQueryDef.create(queryDef);
542
+ const extAccount = await query.executeQuery();
543
+
544
+ const cipher = await client._getSecretKeyCipher();
545
+ const type = EntityAccessor.getAttributeAsLong(extAccount, "type");
546
+ if (type == 3) {
547
+ // Mid-souring
548
+ const endpoint = EntityAccessor.getAttributeAsString(extAccount, "server");
549
+ const user = EntityAccessor.getAttributeAsString(extAccount, "account");
550
+ const password = cipher.decryptPassword(EntityAccessor.getAttributeAsString(extAccount, "password"));
551
+ return ConnectionParameters.ofUserAndPassword(endpoint, user, password, client._connectionParameters._options);
552
+ }
553
+ throw CampaignException.CREDENTIALS_FOR_INVALID_EXT_ACCOUNT(extAccountName, type);
553
554
  }
554
555
 
555
- }
556
+ }
556
557
 
557
- // ========================================================================================
558
- // File Uploader
559
- // ========================================================================================
558
+ // ========================================================================================
559
+ // File Uploader
560
+ // ========================================================================================
560
561
 
561
- /**
562
+ /**
562
563
  * @typedef {Object} FileUploadOptions
563
564
  * @property {"publishIfNeeded"|"none"|undefined} the post-processing action to execute. Defaults to "publishIfNeeded"
564
565
  * @memberOf Campaign
565
566
  */
566
567
 
567
568
 
568
- /**
569
+ /**
569
570
  * File Uploader API for JS SDK(Currently available only in browsers)
570
571
  * @private
571
572
  * @ignore
@@ -573,172 +574,174 @@ class ConnectionParameters {
573
574
  * @param client
574
575
  * @returns {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
575
576
  */
576
- const fileUploader = (client) => {
577
+ const fileUploader = (client) => {
577
578
 
578
579
  return {
579
- /**
580
+ /**
580
581
  * This is the exposed/public method for fileUploader instance which will do all the processing related to the upload process internally and returns the promise containing all the required data.
581
582
  * @ignore
582
583
  * @param file, where file is an instance of [File](https://developer.mozilla.org/en-US/docs/Web/API/File)
583
584
  * @param {FileUploadOptions|undefined} options
584
585
  * @returns {Promise<{name: string, md5: string, type: string, size: string, url: string}>}
585
586
  */
586
- upload: (file, options, fileResPrefix) => {
587
- console.log(`fileuploader.upload is an experimental feature and is not currently fully functional. It is work in progress and will change in the future.`);
588
- return new Promise((resolve, reject) => {
589
- const action = (options && options.action) ? options.action : "publishIfNeeded";
590
- if (action !== "publishIfNeeded" && action !== "none")
591
- reject(CampaignException.BAD_PARAMETER("action", action, "The 'action' parameter of the upload API should be 'publishIfNeeded' or 'none'"));
592
- try {
593
- if (!Util.isBrowser()) {
594
- throw 'File uploading is only supported in browser based calls.';
595
- }
596
- const data = new FormData();
597
- data.append('file_noMd5', file);
598
- const headers = client._getAuthHeaders(false);
599
- for (let h in client._connectionParameters._options.extraHttpHeaders)
600
- headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
601
- client._makeHttpCall({
602
- url: `${client._connectionParameters._endpoint}/nl/jsp/uploadFile.jsp`,
603
- processData: false,
604
- method: 'POST',
605
- data: data,
606
- headers: headers
607
- }).then((okay) => {
608
- if (!okay.startsWith('Ok')) {
609
- throw okay;
610
- }
611
- const iframe = document.createElement('iframe');
612
- iframe.style.display = 'block';
613
- iframe.style.border = 'none';
614
- iframe.style.height = 0;
615
- iframe.style.width = 0;
616
- if(options && options.className) {
617
- iframe.className = options.className;
587
+ upload: (file, options, fileResPrefix) => {
588
+ if (client._traceAPICalls) {
589
+ console.warn(`fileuploader.upload is an experimental feature and is not currently fully functional. It is work in progress and will change in the future.`);
590
+ }
591
+ return new Promise((resolve, reject) => {
592
+ const action = (options && options.action) ? options.action : "publishIfNeeded";
593
+ if (action !== "publishIfNeeded" && action !== "none")
594
+ reject(CampaignException.BAD_PARAMETER("action", action, "The 'action' parameter of the upload API should be 'publishIfNeeded' or 'none'"));
595
+ try {
596
+ if (!Util.isBrowser()) {
597
+ throw 'File uploading is only supported in browser based calls.';
598
+ }
599
+ const data = new FormData();
600
+ data.append('file_noMd5', file);
601
+ const headers = client._getAuthHeaders(false);
602
+ for (let h in client._connectionParameters._options.extraHttpHeaders)
603
+ headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
604
+ client._makeHttpCall({
605
+ url: `${client._connectionParameters._endpoint}/nl/jsp/uploadFile.jsp`,
606
+ processData: false,
607
+ method: 'POST',
608
+ data: data,
609
+ headers: headers
610
+ }).then((okay) => {
611
+ if (!okay.startsWith('Ok')) {
612
+ throw okay;
613
+ }
614
+ const iframe = document.createElement('iframe');
615
+ iframe.style.display = 'block';
616
+ iframe.style.border = 'none';
617
+ iframe.style.height = 0;
618
+ iframe.style.width = 0;
619
+ if(options && options.className) {
620
+ iframe.className = options.className;
621
+ }
622
+ document.controller = { // Written to support https://git.corp.adobe.com/Campaign/ac/blob/v6-master/nl/datakit/nl/jsp/uploadFile.jsp
623
+ uploadFileCallBack: async (data) => {
624
+ if (!data || data.length !== 1) {
625
+ // Tried to replicate the logic for file upload functionality written here:
626
+ // https://git.corp.adobe.com/Campaign/ac/blob/v6-master/wpp/xtk/web/dce/uploader.js
627
+ return reject(CampaignException.FILE_UPLOAD_FAILED(file.name, 'Malformed data:' + data.toString()));
628
+ }
629
+ const result = {
630
+ name: data[0].fileName,
631
+ md5: data[0].md5,
632
+ type: file.type,
633
+ size: file.size,
634
+ };
635
+ if (action === "publishIfNeeded") {
636
+ try {
637
+ // Following https://jira.corp.adobe.com/browse/NEO-88828 the fileRes internal name is defined as is:
638
+ // If a prefix is not provided, we keep the old behavior which is to use the prefix 'RES' and the xtkResource counter (i.e.'RES1'...)
639
+ // If a prefix is provided, we use it with a UUID (i.e. 'customPrefix-123e4567-e89b-12d3-a456-426614174000')
640
+ const oldBehaviorPrefix = 'RES';
641
+ const prefix = Util.validateFileResPrefix(fileResPrefix, oldBehaviorPrefix);
642
+ const getUUIDOrFallback = async() => {
643
+ try {
644
+ return Util.getUUID();
645
+ } catch (error) {
646
+ // In case getUUID throws, fall back to increasing the counter
647
+ return await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' });
618
648
  }
619
- document.controller = { // Written to support https://git.corp.adobe.com/Campaign/ac/blob/v6-master/nl/datakit/nl/jsp/uploadFile.jsp
620
- uploadFileCallBack: async (data) => {
621
- if (!data || data.length !== 1) {
622
- // Tried to replicate the logic for file upload functionality written here:
623
- // https://git.corp.adobe.com/Campaign/ac/blob/v6-master/wpp/xtk/web/dce/uploader.js
624
- return reject(CampaignException.FILE_UPLOAD_FAILED(file.name, 'Malformed data:' + data.toString()));
625
- }
626
- const result = {
627
- name: data[0].fileName,
628
- md5: data[0].md5,
629
- type: file.type,
630
- size: file.size,
631
- };
632
- if (action === "publishIfNeeded") {
633
- try {
634
- // Following https://jira.corp.adobe.com/browse/NEO-88828 the fileRes internal name is defined as is:
635
- // If a prefix is not provided, we keep the old behavior which is to use the prefix 'RES' and the xtkResource counter (i.e.'RES1'...)
636
- // If a prefix is provided, we use it with a UUID (i.e. 'customPrefix-123e4567-e89b-12d3-a456-426614174000')
637
- const oldBehaviorPrefix = 'RES';
638
- const prefix = Util.validateFileResPrefix(fileResPrefix, oldBehaviorPrefix);
639
- const getUUIDOrFallback = async() => {
640
- try {
641
- return Util.getUUID();
642
- } catch (error) {
643
- // In case getUUID throws, fall back to increasing the counter
644
- return await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' });
645
- }
646
- };
647
- const suffix = (prefix === oldBehaviorPrefix) ?
648
- await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' }) : await getUUIDOrFallback();
649
-
650
- const internalName = (prefix === oldBehaviorPrefix) ? `${prefix}${suffix}` : `${prefix}_${suffix}`;
651
-
652
- const fileRes = {
653
- internalName,
654
- md5: data[0].md5,
655
- label: data[0].fileName,
656
- fileName: data[0].fileName,
657
- originalName: data[0].fileName,
658
- useMd5AsFilename: '1',
659
- storageType: 5,
660
- xtkschema: 'xtk:fileRes',
661
- };
662
- await client.NLWS.xtkSession.write(fileRes);
663
- await client.NLWS.xtkFileRes
664
- .create(fileRes)
665
- .publishIfNeeded();
666
- const url = await client.NLWS.xtkFileRes
667
- .create(fileRes)
668
- .getURL();
669
- result.url = url;
670
- } catch (ex) {
671
- reject(
672
- CampaignException.FILE_UPLOAD_FAILED(
673
- file.name,
674
- ex
675
- )
676
- );
677
- }
678
- }
679
- resolve(result);
680
- }
681
- };
682
- const html = `<body>${okay}</body>`;
683
- document.body.appendChild(iframe);
684
- iframe.contentWindow.document.open();
685
- iframe.contentWindow.document.write(html);
686
- iframe.contentWindow.document.close();
687
- }).catch((ex) => {
688
- reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
689
- });
690
- } catch (ex) {
691
- reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
649
+ };
650
+ const suffix = (prefix === oldBehaviorPrefix) ?
651
+ await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' }) : await getUUIDOrFallback();
652
+
653
+ const internalName = (prefix === oldBehaviorPrefix) ? `${prefix}${suffix}` : `${prefix}_${suffix}`;
654
+
655
+ const fileRes = {
656
+ internalName,
657
+ md5: data[0].md5,
658
+ label: data[0].fileName,
659
+ fileName: data[0].fileName,
660
+ originalName: data[0].fileName,
661
+ useMd5AsFilename: '1',
662
+ storageType: 5,
663
+ xtkschema: 'xtk:fileRes',
664
+ };
665
+ await client.NLWS.xtkSession.write(fileRes);
666
+ await client.NLWS.xtkFileRes
667
+ .create(fileRes)
668
+ .publishIfNeeded();
669
+ const url = await client.NLWS.xtkFileRes
670
+ .create(fileRes)
671
+ .getURL();
672
+ result.url = url;
673
+ } catch (ex) {
674
+ reject(
675
+ CampaignException.FILE_UPLOAD_FAILED(
676
+ file.name,
677
+ ex
678
+ )
679
+ );
680
+ }
681
+ }
682
+ resolve(result);
692
683
  }
684
+ };
685
+ const html = `<body>${okay}</body>`;
686
+ document.body.appendChild(iframe);
687
+ iframe.contentWindow.document.open();
688
+ iframe.contentWindow.document.write(html);
689
+ iframe.contentWindow.document.close();
690
+ }).catch((ex) => {
691
+ reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
693
692
  });
694
- },
693
+ } catch (ex) {
694
+ reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
695
+ }
696
+ });
697
+ },
695
698
 
696
- /**
699
+ /**
697
700
  * Exposed method to call aemAssetDownload.jssp which will
698
701
  * download the asset from AEM and upload it to Campaign.
699
702
  */
700
- uploadAemAsset: async (assetDownloadUrl) => {
701
- const url = `${client._connectionParameters._endpoint}/nms/aemAssetDownload.jssp`;
702
- const headers = client._getAuthHeaders(false);
703
- headers['Content-Type'] = 'application/json';
704
-
705
- try {
706
- // We need to pass the Authorization header to AEM to download the asset from AEM
707
- // as well as authenticating campaign server.
708
- // A user token having access to campaign as well as AEM is required
709
- if(headers['Authorization'] === undefined || headers['Authorization'] === '' || headers['Authorization'] === 'null') {
710
- throw 'Bearer token is missing';
711
- }
712
- // Serialize json data (required for fetch)
713
- const jsonData = JSON.stringify({
714
- 'assetDownloadUrl': assetDownloadUrl
715
- });
716
- for (let h in client._connectionParameters._options.extraHttpHeaders)
717
- headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
718
- var response = await client._makeHttpCall({
719
- url: url,
720
- method: 'POST',
721
- data: jsonData,
722
- headers: headers
723
- });
703
+ uploadAemAsset: async (assetDownloadUrl) => {
704
+ const url = `${client._connectionParameters._endpoint}/nms/aemAssetDownload.jssp`;
705
+ const headers = client._getAuthHeaders(false);
706
+ headers['Content-Type'] = 'application/json';
724
707
 
725
- // response is returned as string when using fetch(in browser)
726
- // & returned as json using axios(nodejs).
727
- if(typeof response === 'string')
728
- response = JSON.parse(response);
729
- if(response.publishedURL)
730
- return response;
731
- else
732
- throw 'Publishing failed';
733
- } catch (ex) {
734
- if(ex instanceof CampaignException)
735
- throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex.faultString, ex.statusCode);
736
- else
737
- throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex, ex.statusCode);
738
- }
739
- },
708
+ try {
709
+ // We need to pass the Authorization header to AEM to download the asset from AEM
710
+ // as well as authenticating campaign server.
711
+ // A user token having access to campaign as well as AEM is required
712
+ if(headers['Authorization'] === undefined || headers['Authorization'] === '' || headers['Authorization'] === 'null') {
713
+ throw 'Bearer token is missing';
714
+ }
715
+ // Serialize json data (required for fetch)
716
+ const jsonData = JSON.stringify({
717
+ 'assetDownloadUrl': assetDownloadUrl
718
+ });
719
+ for (let h in client._connectionParameters._options.extraHttpHeaders)
720
+ headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
721
+ var response = await client._makeHttpCall({
722
+ url: url,
723
+ method: 'POST',
724
+ data: jsonData,
725
+ headers: headers
726
+ });
727
+
728
+ // response is returned as string when using fetch(in browser)
729
+ // & returned as json using axios(nodejs).
730
+ if(typeof response === 'string')
731
+ response = JSON.parse(response);
732
+ if(response.publishedURL)
733
+ return response;
734
+ else
735
+ throw 'Publishing failed';
736
+ } catch (ex) {
737
+ if(ex instanceof CampaignException)
738
+ throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex.faultString, ex.statusCode);
739
+ else
740
+ throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex, ex.statusCode);
741
+ }
742
+ },
740
743
 
741
- /**
744
+ /**
742
745
  * Exposed public method of the fileUploader api,
743
746
  * specifically designed to download files from the 'upload' folder of the Campaign instance
744
747
  * @param {string} md5 md5 of the file content
@@ -750,64 +753,64 @@ const fileUploader = (client) => {
750
753
  * handle this file) expl : image/png, text/plain;charset=ISO-8859-1
751
754
  * @returns {Promise<File(string)>}
752
755
  */
753
- download: async (md5, ext, options) => {
754
- if (!md5 || typeof md5 !== 'string') {
755
- throw CampaignException.BAD_PARAMETER(
756
- "md5",
757
- md5,
758
- "'md5' is mandatory parameter with type as 'string' for download file."
759
- );
760
- }
756
+ download: async (md5, ext, options) => {
757
+ if (!md5 || typeof md5 !== 'string') {
758
+ throw CampaignException.BAD_PARAMETER(
759
+ "md5",
760
+ md5,
761
+ "'md5' is mandatory parameter with type as 'string' for download file."
762
+ );
763
+ }
761
764
 
762
- if (!ext || typeof ext !== "string") {
763
- throw CampaignException.BAD_PARAMETER(
764
- "ext",
765
- ext,
766
- "'ext' is mandatory parameter with type as 'string' for download file."
767
- );
768
- }
765
+ if (!ext || typeof ext !== "string") {
766
+ throw CampaignException.BAD_PARAMETER(
767
+ "ext",
768
+ ext,
769
+ "'ext' is mandatory parameter with type as 'string' for download file."
770
+ );
771
+ }
769
772
 
770
- try {
771
- const fileName =
773
+ try {
774
+ const fileName =
772
775
  options && options.fileName ? options.fileName : md5;
773
- const contentType =
776
+ const contentType =
774
777
  options && options.contentType ? options.contentType : "";
775
778
 
776
- let queryString = `md5=${encodeURIComponent(md5)}&ext=${encodeURIComponent(ext)}&fileName=${encodeURIComponent(fileName)}`;
779
+ let queryString = `md5=${encodeURIComponent(md5)}&ext=${encodeURIComponent(ext)}&fileName=${encodeURIComponent(fileName)}`;
777
780
 
778
- if (contentType) {
779
- queryString += `&contentType=${encodeURIComponent(contentType)}`;
780
- }
781
+ if (contentType) {
782
+ queryString += `&contentType=${encodeURIComponent(contentType)}`;
783
+ }
781
784
 
782
- const headers = client._getAuthHeaders(false);
783
- for (let h in client._connectionParameters._options.extraHttpHeaders)
784
- headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
785
- const rawFileResponse = await client._makeHttpCall({
786
- url: `${client._connectionParameters._endpoint}/nl/jsp/downloadFile.jsp?${queryString}`,
787
- headers: headers,
788
- });
785
+ const headers = client._getAuthHeaders(false);
786
+ for (let h in client._connectionParameters._options.extraHttpHeaders)
787
+ headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
788
+ const rawFileResponse = await client._makeHttpCall({
789
+ url: `${client._connectionParameters._endpoint}/nl/jsp/downloadFile.jsp?${queryString}`,
790
+ headers: headers,
791
+ });
789
792
 
790
- return rawFileResponse;
791
- } catch (ex) {
792
- throw CampaignException.FILE_DOWNLOAD_FAILED(md5, ex);
793
- }
793
+ return rawFileResponse;
794
+ } catch (ex) {
795
+ throw CampaignException.FILE_DOWNLOAD_FAILED(md5, ex);
794
796
  }
797
+ }
795
798
 
796
799
  };
797
- };
800
+ };
798
801
 
799
802
 
800
- // ========================================================================================
801
- // ACC Client
802
- // ========================================================================================
803
+ // ========================================================================================
804
+ // ACC Client
805
+ // ========================================================================================
803
806
 
804
- /**
807
+ /**
805
808
  * @private
806
809
  * @class
807
810
  * @constructor
808
811
  * @memberof Campaign
809
812
  */
810
- class Client {
813
+ class Client {
811
814
 
812
815
  /**
813
816
  * ACC API Client.
@@ -817,11 +820,11 @@ class Client {
817
820
  * @param {Campaign.ConnectionParameters} user user name, for instance admin
818
821
  */
819
822
  constructor(sdk, connectionParameters) {
820
- this.sdk = sdk;
821
- this.reinit(connectionParameters);
823
+ this.sdk = sdk;
824
+ this.reinit(connectionParameters);
822
825
 
823
- this._observers = [];
824
- this._cacheChangeListeners = [];
826
+ this._observers = [];
827
+ this._cacheChangeListeners = [];
825
828
  }
826
829
 
827
830
  /**
@@ -832,91 +835,91 @@ class Client {
832
835
  * @param {Campaign.ConnectionParameters} user user name, for instance admin
833
836
  */
834
837
  reinit(connectionParameters) {
835
- this._connectionParameters = connectionParameters; // ## TODO security concern (password kept in memory)
836
- this._representation = connectionParameters._options.representation;
837
-
838
- this._sessionInfo = undefined;
839
- this._sessionToken = undefined;
840
- this._securityToken = undefined;
841
- this._bearerToken = undefined; // set when using Bearer authentication and "ImsBearer" credential type
842
- this._installedPackages = {}; // package set (key and value = package id, ex: "nms:amp")
843
-
844
- this._secretKeyCipher = undefined;
845
-
846
- this._storage = connectionParameters._options._storage;
847
-
848
- var instanceKey = connectionParameters._options.instanceKey;
849
- if (!instanceKey)
850
- instanceKey = connectionParameters._endpoint || "";
851
- if (instanceKey.startsWith("http://")) instanceKey = instanceKey.substr(7);
852
- if (instanceKey.startsWith("https://")) instanceKey = instanceKey.substr(8);
853
-
854
- // Determine the cache root key. There are 3 possible values:
855
- // * no value or "default" is the default behavior, i.e. all cache keys are prefixed with "acc.js.sdk.${sdk.getSDKVersion().version}.${instanceKey}.cache."
856
- // * "none" (or actually anything else for now), where cache keys are not prefixed by anything
857
- const rootKeyType = connectionParameters._options.cacheRootKey;
858
- let rootKey = "";
859
- if (!rootKeyType || rootKeyType === "default")
860
- rootKey = `acc.js.sdk.${this.sdk.getSDKVersion().version}.${instanceKey}.cache.`;
861
-
862
- // Clear storage cache if the sdk versions or the instances are different
863
- if (this._storage && typeof this._storage.removeItem === 'function') {
864
- for (let key in this._storage) {
865
- if (key.startsWith("acc.js.sdk.") && !key.startsWith(rootKey)) {
866
- this._storage.removeItem(key);
867
- }
838
+ this._connectionParameters = connectionParameters; // ## TODO security concern (password kept in memory)
839
+ this._representation = connectionParameters._options.representation;
840
+
841
+ this._sessionInfo = undefined;
842
+ this._sessionToken = undefined;
843
+ this._securityToken = undefined;
844
+ this._bearerToken = undefined; // set when using Bearer authentication and "ImsBearer" credential type
845
+ this._installedPackages = {}; // package set (key and value = package id, ex: "nms:amp")
846
+
847
+ this._secretKeyCipher = undefined;
848
+
849
+ this._storage = connectionParameters._options._storage;
850
+
851
+ var instanceKey = connectionParameters._options.instanceKey;
852
+ if (!instanceKey)
853
+ instanceKey = connectionParameters._endpoint || "";
854
+ if (instanceKey.startsWith("http://")) instanceKey = instanceKey.substr(7);
855
+ if (instanceKey.startsWith("https://")) instanceKey = instanceKey.substr(8);
856
+
857
+ // Determine the cache root key. There are 3 possible values:
858
+ // * no value or "default" is the default behavior, i.e. all cache keys are prefixed with "acc.js.sdk.${sdk.getSDKVersion().version}.${instanceKey}.cache."
859
+ // * "none" (or actually anything else for now), where cache keys are not prefixed by anything
860
+ const rootKeyType = connectionParameters._options.cacheRootKey;
861
+ let rootKey = "";
862
+ if (!rootKeyType || rootKeyType === "default")
863
+ rootKey = `acc.js.sdk.${this.sdk.getSDKVersion().version}.${instanceKey}.cache.`;
864
+
865
+ // Clear storage cache if the sdk versions or the instances are different
866
+ if (this._storage && typeof this._storage.removeItem === 'function') {
867
+ for (let key in this._storage) {
868
+ if (key.startsWith("acc.js.sdk.") && !key.startsWith(rootKey)) {
869
+ this._storage.removeItem(key);
868
870
  }
869
871
  }
872
+ }
870
873
 
871
- this._entityCache = new XtkEntityCache(this._storage, `${rootKey}XtkEntityCache`, connectionParameters._options.entityCacheTTL);
872
- this._entityCacheRefresher = new CacheRefresher(this._entityCache, this, "xtk:schema", `${rootKey}XtkEntityCache`);
873
- this._methodCache = new MethodCache(this._storage, `${rootKey}MethodCache`, connectionParameters._options.methodCacheTTL);
874
- this._optionCache = new OptionCache(this._storage, `${rootKey}OptionCache`, connectionParameters._options.optionCacheTTL);
875
- this._optionCacheRefresher = new CacheRefresher(this._optionCache, this, "xtk:option", `${rootKey}OptionCache`);
876
- this.NLWS = new Proxy(this, clientHandler());
874
+ this._entityCache = new XtkEntityCache(this._storage, `${rootKey}XtkEntityCache`, connectionParameters._options.entityCacheTTL);
875
+ this._entityCacheRefresher = new CacheRefresher(this._entityCache, this, "xtk:schema", `${rootKey}XtkEntityCache`);
876
+ this._methodCache = new MethodCache(this._storage, `${rootKey}MethodCache`, connectionParameters._options.methodCacheTTL);
877
+ this._optionCache = new OptionCache(this._storage, `${rootKey}OptionCache`, connectionParameters._options.optionCacheTTL);
878
+ this._optionCacheRefresher = new CacheRefresher(this._optionCache, this, "xtk:option", `${rootKey}OptionCache`);
879
+ this.NLWS = new Proxy(this, clientHandler());
877
880
 
878
- this._transport = connectionParameters._options.transport;
879
- this._traceAPICalls = connectionParameters._options.traceAPICalls;
880
- this._refreshClient = connectionParameters._options.refreshClient;
881
+ this._transport = connectionParameters._options.transport;
882
+ this._traceAPICalls = connectionParameters._options.traceAPICalls;
883
+ this._refreshClient = connectionParameters._options.refreshClient;
881
884
 
882
- // expose utilities
883
- /**
885
+ // expose utilities
886
+ /**
884
887
  * File Uploader API
885
888
  * @type {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
886
889
  */
887
- this.fileUploader = fileUploader(this);
890
+ this.fileUploader = fileUploader(this);
888
891
 
889
- /**
892
+ /**
890
893
  * Accessor to DOM helpers
891
894
  * @type {XML.DomUtil}
892
895
  */
893
- this.DomUtil = DomUtil;
894
- /**
896
+ this.DomUtil = DomUtil;
897
+ /**
895
898
  * Accessor to a XtkCaster
896
899
  * @type {XtkCaster}
897
900
  */
898
- this.XtkCaster = XtkCaster;
899
- /**
901
+ this.XtkCaster = XtkCaster;
902
+ /**
900
903
  * The application object. Only valid when logged
901
904
  * @type {Campaign.Application}
902
905
  */
903
- this.application = null;
904
-
905
- // Context for observability. See logon() function which will fill this context
906
- this._lastStatsReport = Date.now();
907
- this._observabilityContext = {
908
- eventId: 0,
909
- client: {
910
- sdkVersion: this.sdk.getSDKVersion().version,
911
- endpoint: this._connectionParameters._endpoint,
912
- createdAt: Date.now(),
913
- clientApp: this._connectionParameters._options.clientApp,
914
- instanceKey: instanceKey
915
- }
916
- };
917
- if (this._connectionParameters._credentials) {
918
- this._observabilityContext.client.type = this._connectionParameters._credentials.type;
906
+ this.application = null;
907
+
908
+ // Context for observability. See logon() function which will fill this context
909
+ this._lastStatsReport = Date.now();
910
+ this._observabilityContext = {
911
+ eventId: 0,
912
+ client: {
913
+ sdkVersion: this.sdk.getSDKVersion().version,
914
+ endpoint: this._connectionParameters._endpoint,
915
+ createdAt: Date.now(),
916
+ clientApp: this._connectionParameters._options.clientApp,
917
+ instanceKey: instanceKey
919
918
  }
919
+ };
920
+ if (this._connectionParameters._credentials) {
921
+ this._observabilityContext.client.type = this._connectionParameters._credentials.type;
922
+ }
920
923
  }
921
924
 
922
925
  /**
@@ -925,7 +928,7 @@ class Client {
925
928
  * @param {*} transport
926
929
  */
927
930
  setTransport(transport) {
928
- this._transport = transport;
931
+ this._transport = transport;
929
932
  }
930
933
 
931
934
  /**
@@ -934,8 +937,8 @@ class Client {
934
937
  * @returns {string} the user agent string
935
938
  */
936
939
  _getUserAgentString() {
937
- const version = this.sdk.getSDKVersion();
938
- return `${version.name}/${version.version} ${version.description}`;
940
+ const version = this.sdk.getSDKVersion();
941
+ return `${version.name}/${version.version} ${version.description}`;
939
942
  }
940
943
 
941
944
  /**
@@ -944,18 +947,18 @@ class Client {
944
947
  * @returns {Object} the headers
945
948
  */
946
949
  _getAuthHeaders(setCookie) {
947
- const headers = {};
948
- if (this._bearerToken) {
949
- headers['Authorization'] = `Bearer ${this._bearerToken}`;
950
- }
951
- else {
952
- headers['X-Security-Token'] = this._securityToken;
953
- headers['X-Session-Token'] = this._sessionToken;
954
- if (setCookie) {
955
- headers['Cookie'] = '__sessiontoken=' + this._sessionToken;
956
- }
950
+ const headers = {};
951
+ if (this._bearerToken) {
952
+ headers['Authorization'] = `Bearer ${this._bearerToken}`;
953
+ }
954
+ else {
955
+ headers['X-Security-Token'] = this._securityToken;
956
+ headers['X-Session-Token'] = this._sessionToken;
957
+ if (setCookie) {
958
+ headers['Cookie'] = '__sessiontoken=' + this._sessionToken;
957
959
  }
958
- return headers;
960
+ }
961
+ return headers;
959
962
  }
960
963
 
961
964
  /**
@@ -967,12 +970,12 @@ class Client {
967
970
  * @returns {XML.XtkObject} the object converted in the requested representation
968
971
  */
969
972
  _toRepresentation(xml, representation) {
970
- representation = representation || this._representation;
971
- if (representation == "xml")
972
- return xml;
973
- if (representation == "BadgerFish" || representation == "SimpleJson")
974
- return DomUtil.toJSON(xml, representation);
975
- throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert XML document to this representation");
973
+ representation = representation || this._representation;
974
+ if (representation == "xml")
975
+ return xml;
976
+ if (representation == "BadgerFish" || representation == "SimpleJson")
977
+ return DomUtil.toJSON(xml, representation);
978
+ throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert XML document to this representation");
976
979
  }
977
980
 
978
981
  /**
@@ -985,14 +988,14 @@ class Client {
985
988
  * @returns {DOMElement} the object converted to XML
986
989
  */
987
990
  _fromRepresentation(rootName, entity, representation) {
988
- representation = representation || this._representation;
989
- if (representation == "xml")
990
- return entity;
991
- if (representation == "BadgerFish" || representation == "SimpleJson") {
992
- var xml = DomUtil.fromJSON(rootName, entity, representation);
993
- return xml;
994
- }
995
- throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert to XML from this representation");
991
+ representation = representation || this._representation;
992
+ if (representation == "xml")
993
+ return entity;
994
+ if (representation == "BadgerFish" || representation == "SimpleJson") {
995
+ var xml = DomUtil.fromJSON(rootName, entity, representation);
996
+ return xml;
997
+ }
998
+ throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert to XML from this representation");
996
999
  }
997
1000
 
998
1001
  /**
@@ -1005,12 +1008,12 @@ class Client {
1005
1008
  * @returns {DOMElement} the converted object
1006
1009
  */
1007
1010
  _convertToRepresentation(entity, fromRepresentation, toRepresentation) {
1008
- toRepresentation = toRepresentation || this._representation;
1009
- if (this._isSameRepresentation(fromRepresentation, toRepresentation))
1010
- return entity;
1011
- var xml = this._fromRepresentation("root", entity, fromRepresentation);
1012
- entity = this._toRepresentation(xml, toRepresentation);
1011
+ toRepresentation = toRepresentation || this._representation;
1012
+ if (this._isSameRepresentation(fromRepresentation, toRepresentation))
1013
1013
  return entity;
1014
+ var xml = this._fromRepresentation("root", entity, fromRepresentation);
1015
+ entity = this._toRepresentation(xml, toRepresentation);
1016
+ return entity;
1014
1017
  }
1015
1018
 
1016
1019
  /**
@@ -1022,11 +1025,11 @@ class Client {
1022
1025
  * @returns a boolean indicating if the 2 representations are the same or not
1023
1026
  */
1024
1027
  _isSameRepresentation(rep1, rep2) {
1025
- if (!rep1 || !rep2) throw CampaignException.INVALID_REPRESENTATION(undefined, "Cannot compare to undefined representation");
1026
- if (rep1 != "xml" && rep1 != "SimpleJson" && rep1 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep1, "Cannot compare to invalid representation");
1027
- if (rep2 != "xml" && rep2 != "SimpleJson" && rep2 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep2, "Cannot compare to invalid representation");
1028
- if (rep1 == rep2) return true;
1029
- return rep1 == rep2;
1028
+ if (!rep1 || !rep2) throw CampaignException.INVALID_REPRESENTATION(undefined, "Cannot compare to undefined representation");
1029
+ if (rep1 != "xml" && rep1 != "SimpleJson" && rep1 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep1, "Cannot compare to invalid representation");
1030
+ if (rep2 != "xml" && rep2 != "SimpleJson" && rep2 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep2, "Cannot compare to invalid representation");
1031
+ if (rep1 == rep2) return true;
1032
+ return rep1 == rep2;
1030
1033
  }
1031
1034
 
1032
1035
  /**
@@ -1035,7 +1038,7 @@ class Client {
1035
1038
  * @param {boolean} trace indicates whether to activate tracing or not
1036
1039
  */
1037
1040
  traceAPICalls(trace) {
1038
- this._traceAPICalls = !!trace;
1041
+ this._traceAPICalls = !!trace;
1039
1042
  }
1040
1043
 
1041
1044
  /**
@@ -1043,7 +1046,7 @@ class Client {
1043
1046
  * @param {Campaign.Observer} observer
1044
1047
  */
1045
1048
  registerObserver(observer) {
1046
- this._observers.push(observer);
1049
+ this._observers.push(observer);
1047
1050
  }
1048
1051
 
1049
1052
  /**
@@ -1051,81 +1054,81 @@ class Client {
1051
1054
  * @param {Campaign.Observer} observer
1052
1055
  */
1053
1056
  unregisterObserver(observer) {
1054
- for (var i=0; i<this._observers.length; i++) {
1055
- if (this._observers[i] == observer) {
1056
- this._observers.splice(i, 1);
1057
- break;
1058
- }
1057
+ for (var i=0; i<this._observers.length; i++) {
1058
+ if (this._observers[i] == observer) {
1059
+ this._observers.splice(i, 1);
1060
+ break;
1059
1061
  }
1062
+ }
1060
1063
  }
1061
1064
 
1062
1065
  unregisterAllObservers() {
1063
- this._observers = [];
1066
+ this._observers = [];
1064
1067
  }
1065
1068
 
1066
1069
  _notifyObservers(callback) {
1067
- this._observers.map((observer) => callback(observer));
1070
+ this._observers.map((observer) => callback(observer));
1068
1071
  }
1069
1072
 
1070
1073
  _trackEvent(eventName, parentEvent, payload, pushDownOptions) {
1071
- try {
1072
- if (payload && payload.name === 'CampaignException') {
1073
- payload = {
1074
- detail: payload.detail,
1075
- errorCode: payload.errorCode,
1076
- faultCode: payload.faultCode,
1077
- faultString: payload.faultString,
1078
- message: payload.message,
1079
- statusCode: payload.statusCode,
1080
- };
1081
- }
1082
- this._observabilityContext.eventId = this._observabilityContext.eventId + 1;
1083
- const now = Date.now();
1084
- const event = {
1085
- client: this._observabilityContext.client,
1086
- session: this._observabilityContext.session,
1087
- eventId: this._observabilityContext.eventId,
1088
- eventName: eventName,
1089
- payload: payload,
1090
- timestamp: now,
1091
- };
1092
- if (pushDownOptions) {
1093
- event.pushDownOptions = pushDownOptions;
1094
- }
1095
- if (parentEvent) event.parentEventId = parentEvent.eventId;
1096
- this._notifyObservers((observer) => observer.event && observer.event(event, parentEvent));
1097
-
1098
- // Regularly report internal stats every 5 mins
1099
- if ((now - this._lastStatsReport) >= 300000) {
1100
- this._lastStatsReport = now;
1101
- this._trackInternalStats();
1102
- }
1074
+ try {
1075
+ if (payload && payload.name === 'CampaignException') {
1076
+ payload = {
1077
+ detail: payload.detail,
1078
+ errorCode: payload.errorCode,
1079
+ faultCode: payload.faultCode,
1080
+ faultString: payload.faultString,
1081
+ message: payload.message,
1082
+ statusCode: payload.statusCode,
1083
+ };
1084
+ }
1085
+ this._observabilityContext.eventId = this._observabilityContext.eventId + 1;
1086
+ const now = Date.now();
1087
+ const event = {
1088
+ client: this._observabilityContext.client,
1089
+ session: this._observabilityContext.session,
1090
+ eventId: this._observabilityContext.eventId,
1091
+ eventName: eventName,
1092
+ payload: payload,
1093
+ timestamp: now,
1094
+ };
1095
+ if (pushDownOptions) {
1096
+ event.pushDownOptions = pushDownOptions;
1097
+ }
1098
+ if (parentEvent) event.parentEventId = parentEvent.eventId;
1099
+ this._notifyObservers((observer) => observer.event && observer.event(event, parentEvent));
1103
1100
 
1104
- return event;
1105
- } catch (error) {
1106
- console.info(`Failed to track observability event`, error);
1101
+ // Regularly report internal stats every 5 mins
1102
+ if ((now - this._lastStatsReport) >= 300000) {
1103
+ this._lastStatsReport = now;
1104
+ this._trackInternalStats();
1107
1105
  }
1106
+
1107
+ return event;
1108
+ } catch (error) {
1109
+ console.info(`Failed to track observability event`, error);
1110
+ }
1108
1111
  }
1109
1112
 
1110
1113
  _trackInternalStats() {
1111
- this._trackCacheStats('entityCache', this._entityCache);
1112
- this._trackCacheStats('optionCache', this._optionCache);
1113
- this._trackCacheStats('methodCache', this._methodCache);
1114
+ this._trackCacheStats('entityCache', this._entityCache);
1115
+ this._trackCacheStats('optionCache', this._optionCache);
1116
+ this._trackCacheStats('methodCache', this._methodCache);
1114
1117
  }
1115
1118
 
1116
1119
  _trackCacheStats(name, cache) {
1117
- if (!cache || !cache._stats) return;
1118
- this._trackEvent('CACHE//stats', undefined, {
1119
- name: name,
1120
- reads: cache._stats.reads,
1121
- writes: cache._stats.writes,
1122
- removals: cache._stats.removals,
1123
- clears: cache._stats.clears,
1124
- memoryHits: cache._stats.memoryHits,
1125
- storageHits: cache._stats.storageHits,
1126
- loads: cache._stats.loads,
1127
- saves: cache._stats.saves,
1128
- });
1120
+ if (!cache || !cache._stats) return;
1121
+ this._trackEvent('CACHE//stats', undefined, {
1122
+ name: name,
1123
+ reads: cache._stats.reads,
1124
+ writes: cache._stats.writes,
1125
+ removals: cache._stats.removals,
1126
+ clears: cache._stats.clears,
1127
+ memoryHits: cache._stats.memoryHits,
1128
+ storageHits: cache._stats.storageHits,
1129
+ loads: cache._stats.loads,
1130
+ saves: cache._stats.saves,
1131
+ });
1129
1132
  }
1130
1133
 
1131
1134
  /**
@@ -1134,36 +1137,36 @@ class Client {
1134
1137
  * @returns {boolean} a boolean indicating if the client is logged or not
1135
1138
  */
1136
1139
  isLogged() {
1137
- if (!this._connectionParameters._credentials)
1138
- return false;
1139
-
1140
- // If using anonymous credentials => always logged
1141
- const credentialsType = this._connectionParameters._credentials._type;
1142
- if (credentialsType == "AnonymousUser")
1143
- return true;
1144
- else if (credentialsType == "ImsBearerToken") {
1145
- return !!this._bearerToken;
1146
- }
1140
+ if (!this._connectionParameters._credentials)
1141
+ return false;
1142
+
1143
+ // If using anonymous credentials => always logged
1144
+ const credentialsType = this._connectionParameters._credentials._type;
1145
+ if (credentialsType == "AnonymousUser")
1146
+ return true;
1147
+ else if (credentialsType == "ImsBearerToken") {
1148
+ return !!this._bearerToken;
1149
+ }
1147
1150
 
1148
- // When using bearer token authentication we are considered logged only after
1149
- // the bearer token has been converted into session token and security token
1150
- // by method xtk:session#BearerTokenLogon
1151
- if( credentialsType == "BearerToken")
1152
- return this._sessionToken != undefined &&
1151
+ // When using bearer token authentication we are considered logged only after
1152
+ // the bearer token has been converted into session token and security token
1153
+ // by method xtk:session#BearerTokenLogon
1154
+ if( credentialsType == "BearerToken")
1155
+ return this._sessionToken != undefined &&
1153
1156
  this._sessionToken != null &&
1154
1157
  this._sessionToken != "" &&
1155
1158
  this._securityToken != undefined &&
1156
1159
  this._securityToken != null &&
1157
1160
  this._securityToken != "";
1158
1161
 
1159
- // with session token authentication, we do not expect a security token
1160
- // with security token authentication, we do not expect a session token
1161
- const needsSecurityToken = credentialsType != "SessionToken";
1162
- const hasSecurityToken = this._securityToken !== null && this._securityToken !== undefined && this._securityToken !== "";
1163
- const needsSessionToken = credentialsType != "SecurityToken";
1164
- const hasSessionToken = this._sessionToken !== null && this._sessionToken !== undefined && this._sessionToken !== "";
1162
+ // with session token authentication, we do not expect a security token
1163
+ // with security token authentication, we do not expect a session token
1164
+ const needsSecurityToken = credentialsType != "SessionToken";
1165
+ const hasSecurityToken = this._securityToken !== null && this._securityToken !== undefined && this._securityToken !== "";
1166
+ const needsSessionToken = credentialsType != "SecurityToken";
1167
+ const hasSessionToken = this._sessionToken !== null && this._sessionToken !== undefined && this._sessionToken !== "";
1165
1168
 
1166
- return (!needsSecurityToken || hasSecurityToken) && (!needsSessionToken || hasSessionToken);
1169
+ return (!needsSecurityToken || hasSecurityToken) && (!needsSessionToken || hasSessionToken);
1167
1170
  }
1168
1171
 
1169
1172
  /**
@@ -1178,26 +1181,30 @@ class Client {
1178
1181
  * parameters should be set
1179
1182
  */
1180
1183
  _prepareSoapCall(urn, method, isStatic, internal, extraHttpHeaders, pushDownOptions) {
1181
- // Generate unique request ID for every SOAP call
1182
- let requestId;
1184
+
1185
+ // Send request ID header if enableRequestIdHeader flag is set to true
1186
+ const enableRequestIdHeader = this._connectionParameters._options &&
1187
+ this._connectionParameters._options.enableRequestIdHeader;
1188
+ let updatedExtraHttpHeaders = extraHttpHeaders;
1189
+ if (enableRequestIdHeader) {
1183
1190
  try {
1184
- requestId = Util.getUUID();
1191
+ const requestId = Util.getUUID();
1192
+ updatedExtraHttpHeaders = Object.assign({}, extraHttpHeaders, {
1193
+ "x-request-id": requestId,
1194
+ });
1185
1195
  } catch (error) {
1186
1196
  console.error("Failed to generate request ID", error);
1187
1197
  }
1188
- const updatedExtraHttpHeaders = requestId ? Object.assign({}, extraHttpHeaders, {
1189
- "x-request-id": requestId,
1190
- })
1191
- : extraHttpHeaders;
1192
- const soapCall = new SoapMethodCall(this._transport, urn, method,
1193
- this._sessionToken, this._securityToken,
1194
- this._getUserAgentString(),
1195
- Object.assign({}, this._connectionParameters._options, pushDownOptions),
1196
- updatedExtraHttpHeaders,
1197
- this._bearerToken);
1198
- soapCall.internal = !!internal;
1199
- soapCall.isStatic = isStatic;
1200
- return soapCall;
1198
+ }
1199
+ const soapCall = new SoapMethodCall(this._transport, urn, method,
1200
+ this._sessionToken, this._securityToken,
1201
+ this._getUserAgentString(),
1202
+ Object.assign({}, this._connectionParameters._options, pushDownOptions),
1203
+ updatedExtraHttpHeaders,
1204
+ this._bearerToken);
1205
+ soapCall.internal = !!internal;
1206
+ soapCall.isStatic = isStatic;
1207
+ return soapCall;
1201
1208
  }
1202
1209
 
1203
1210
  /**
@@ -1208,35 +1215,35 @@ class Client {
1208
1215
  * parameters should be set
1209
1216
  */
1210
1217
  async _retrySoapCall(soapCall) {
1211
- soapCall.retry = false;
1212
- soapCall._retryCount = soapCall._retryCount + 1;
1213
- var newClient = await this._refreshClient(this);
1214
- soapCall.finalize(newClient._soapEndPoint(), newClient);
1215
- const safeCallData = Util.trim(soapCall.request.data);
1218
+ soapCall.retry = false;
1219
+ soapCall._retryCount = soapCall._retryCount + 1;
1220
+ var newClient = await this._refreshClient(this);
1221
+ soapCall.finalize(newClient._soapEndPoint(), newClient);
1222
+ const safeCallData = Util.trim(soapCall.request.data);
1223
+ if (this._traceAPICalls) {
1224
+ console.log(`RETRY SOAP//request ${safeCallData}`);
1225
+ }
1226
+ const pushDownOptions = soapCall._pushDownOptions;
1227
+ const event = this._trackEvent('SOAP//request', undefined, {
1228
+ urn: soapCall.urn,
1229
+ methodName: soapCall.methodName,
1230
+ internal: soapCall.internal,
1231
+ retry: true,
1232
+ retryCount: soapCall._retryCount,
1233
+ safeCallData: safeCallData,
1234
+ }, pushDownOptions);
1235
+ try {
1236
+ await soapCall.execute();
1237
+ const safeCallResponse = Util.trim(soapCall.response);
1216
1238
  if (this._traceAPICalls) {
1217
- console.log(`RETRY SOAP//request ${safeCallData}`);
1218
- }
1219
- const pushDownOptions = soapCall._pushDownOptions;
1220
- const event = this._trackEvent('SOAP//request', undefined, {
1221
- urn: soapCall.urn,
1222
- methodName: soapCall.methodName,
1223
- internal: soapCall.internal,
1224
- retry: true,
1225
- retryCount: soapCall._retryCount,
1226
- safeCallData: safeCallData,
1227
- }, pushDownOptions);
1228
- try {
1229
- await soapCall.execute();
1230
- const safeCallResponse = Util.trim(soapCall.response);
1231
- if (this._traceAPICalls) {
1232
- console.log(`SOAP//response ${safeCallResponse}`);
1233
- }
1234
- this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1235
- } catch(error) {
1236
- this._trackEvent('SOAP//failure', event, error, pushDownOptions);
1237
- throw error;
1239
+ console.log(`SOAP//response ${safeCallResponse}`);
1238
1240
  }
1239
- return;
1241
+ this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1242
+ } catch(error) {
1243
+ this._trackEvent('SOAP//failure', event, error, pushDownOptions);
1244
+ throw error;
1245
+ }
1246
+ return;
1240
1247
  }
1241
1248
 
1242
1249
  /**
@@ -1246,7 +1253,7 @@ class Client {
1246
1253
  * @return {string} soap call End point
1247
1254
  */
1248
1255
  _soapEndPoint() {
1249
- return this._connectionParameters._endpoint + "/nl/jsp/soaprouter.jsp";
1256
+ return this._connectionParameters._endpoint + "/nl/jsp/soaprouter.jsp";
1250
1257
  }
1251
1258
 
1252
1259
  // Serializes parameters for a SOAP call
@@ -1254,88 +1261,88 @@ class Client {
1254
1261
  // @param {DOMDocument} schema is the XML schema of the method call
1255
1262
  // @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
1256
1263
  // @param {Campaign.XtkMethodParam[]} inputParameters is the list of input parameters. The first paramater in the array is the "this" parameter for non-static method calls
1257
- // @param {string} representation is the representation to use to interpret the input parameters
1264
+ // @param {string} representation is the representation to use to interpret the input parameters
1258
1265
  async _writeSoapCallParameters(entitySchemaId, schema, soapCall, inputParameters, representation) {
1259
- const methodName = soapCall.methodName;
1260
- var isThisParam = !soapCall.isStatic;
1261
-
1262
- for (const ip of inputParameters) {
1263
- const type = ip.type;
1264
- const paramName = ip.name;
1265
- var paramValue = ip.value;
1266
-
1267
- if (type == "string")
1268
- soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1269
- else if (type == "primarykey")
1270
- soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1271
- else if (type == "boolean")
1272
- soapCall.writeBoolean(ip.name, XtkCaster.asBoolean(ip.value));
1273
- else if (type == "byte")
1274
- soapCall.writeByte(ip.name, XtkCaster.asByte(ip.value));
1275
- else if (type == "short")
1276
- soapCall.writeShort(ip.name, XtkCaster.asShort(ip.value));
1277
- else if (type == "int")
1278
- soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1279
- else if (type == "long")
1280
- soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1281
- else if (type == "int64")
1282
- soapCall.writeInt64(ip.name, XtkCaster.asInt64(ip.value));
1283
- else if (type == "datetime")
1284
- soapCall.writeTimestamp(ip.name, XtkCaster.asTimestamp(ip.value));
1285
- else if (type == "date")
1286
- soapCall.writeDate(ip.name, XtkCaster.asDate(ip.value));
1287
- else if (type == "DOMDocument" || type == "DOMElement") {
1288
- var docName = undefined;
1289
- let paramRepresentation = representation;
1290
- if (paramValue.__xtkProxy) {
1291
- // A xtk proxy object is passed as a parameter. The call context contains the schema so we
1292
- // can use it to determine the XML document root (docName)
1293
- const paramValueContext = paramValue["."];
1294
- paramValue = paramValueContext.object;
1295
- const xtkschema = paramValueContext.schemaId;
1296
- const index = xtkschema.indexOf(":");
1297
- docName = xtkschema.substring(index+1);
1298
- paramRepresentation = paramValueContext.representation; // xtk proxy may have it's own representation
1299
- }
1300
- else {
1301
- // Hack for workflow API. The C++ code checks that the name of the XML element is <variables>. When
1302
- // using xml representation at the SDK level, it's ok since the SDK caller will set that. But this does
1303
- // not work when using "BadgerFish" representation where we do not know the root element name.
1304
- if (entitySchemaId == "xtk:workflow" && paramName == "parameters" && (
1305
- methodName == "StartWithParameters" || methodName == "PostEvent" || methodName == "SimulateWithParameters" ||
1266
+ const methodName = soapCall.methodName;
1267
+ var isThisParam = !soapCall.isStatic;
1268
+
1269
+ for (const ip of inputParameters) {
1270
+ const type = ip.type;
1271
+ const paramName = ip.name;
1272
+ var paramValue = ip.value;
1273
+
1274
+ if (type == "string")
1275
+ soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1276
+ else if (type == "primarykey")
1277
+ soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1278
+ else if (type == "boolean")
1279
+ soapCall.writeBoolean(ip.name, XtkCaster.asBoolean(ip.value));
1280
+ else if (type == "byte")
1281
+ soapCall.writeByte(ip.name, XtkCaster.asByte(ip.value));
1282
+ else if (type == "short")
1283
+ soapCall.writeShort(ip.name, XtkCaster.asShort(ip.value));
1284
+ else if (type == "int")
1285
+ soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1286
+ else if (type == "long")
1287
+ soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1288
+ else if (type == "int64")
1289
+ soapCall.writeInt64(ip.name, XtkCaster.asInt64(ip.value));
1290
+ else if (type == "datetime")
1291
+ soapCall.writeTimestamp(ip.name, XtkCaster.asTimestamp(ip.value));
1292
+ else if (type == "date")
1293
+ soapCall.writeDate(ip.name, XtkCaster.asDate(ip.value));
1294
+ else if (type == "DOMDocument" || type == "DOMElement") {
1295
+ var docName = undefined;
1296
+ let paramRepresentation = representation;
1297
+ if (paramValue.__xtkProxy) {
1298
+ // A xtk proxy object is passed as a parameter. The call context contains the schema so we
1299
+ // can use it to determine the XML document root (docName)
1300
+ const paramValueContext = paramValue["."];
1301
+ paramValue = paramValueContext.object;
1302
+ const xtkschema = paramValueContext.schemaId;
1303
+ const index = xtkschema.indexOf(":");
1304
+ docName = xtkschema.substring(index+1);
1305
+ paramRepresentation = paramValueContext.representation; // xtk proxy may have it's own representation
1306
+ }
1307
+ else {
1308
+ // Hack for workflow API. The C++ code checks that the name of the XML element is <variables>. When
1309
+ // using xml representation at the SDK level, it's ok since the SDK caller will set that. But this does
1310
+ // not work when using "BadgerFish" representation where we do not know the root element name.
1311
+ if (entitySchemaId == "xtk:workflow" && paramName == "parameters" && (
1312
+ methodName == "StartWithParameters" || methodName == "PostEvent" || methodName == "SimulateWithParameters" ||
1306
1313
  methodName == "SpawnWithParameters" || methodName == "SpawnWithParametersEx") )
1307
- docName = "variables";
1308
- if (entitySchemaId == "nms:rtEvent" && methodName == "PushEvent")
1309
- docName = "rtEvent";
1310
- // Try to guess the document name. This is usually available in the xtkschema attribute
1311
- var xtkschema = EntityAccessor.getAttributeAsString(paramValue, "xtkschema");
1312
- if (!xtkschema) xtkschema = paramValue["@xtkschema"];
1313
- if (xtkschema) {
1314
- const index = xtkschema.indexOf(":");
1315
- docName = xtkschema.substring(index+1);
1316
- }
1317
- if (!docName) docName = paramName; // Use te parameter name as the XML root element
1318
- }
1319
- var xmlValue = this._fromRepresentation(docName, paramValue, paramRepresentation || representation);
1320
- if (type == "DOMDocument") {
1321
- if (isThisParam) {
1322
- isThisParam = false;
1323
- // The xtk:persist#NewInstance requires a xtkschema attribute which we can compute here
1324
- // Actually, we're always adding it, for all non-static methods
1325
- const xmlRoot = xmlValue.nodeType === 9 ? xmlValue.documentElement : xmlValue;
1326
- if (!xmlRoot.hasAttribute("xtkschema"))
1327
- xmlRoot.setAttribute("xtkschema", entitySchemaId);
1328
- soapCall.writeDocument("document", xmlValue);
1329
- }
1330
- else
1331
- soapCall.writeDocument(paramName, xmlValue);
1332
- }
1333
- else
1334
- soapCall.writeElement(paramName, xmlValue);
1314
+ docName = "variables";
1315
+ if (entitySchemaId == "nms:rtEvent" && methodName == "PushEvent")
1316
+ docName = "rtEvent";
1317
+ // Try to guess the document name. This is usually available in the xtkschema attribute
1318
+ var xtkschema = EntityAccessor.getAttributeAsString(paramValue, "xtkschema");
1319
+ if (!xtkschema) xtkschema = paramValue["@xtkschema"];
1320
+ if (xtkschema) {
1321
+ const index = xtkschema.indexOf(":");
1322
+ docName = xtkschema.substring(index+1);
1323
+ }
1324
+ if (!docName) docName = paramName; // Use te parameter name as the XML root element
1325
+ }
1326
+ var xmlValue = this._fromRepresentation(docName, paramValue, paramRepresentation || representation);
1327
+ if (type == "DOMDocument") {
1328
+ if (isThisParam) {
1329
+ isThisParam = false;
1330
+ // The xtk:persist#NewInstance requires a xtkschema attribute which we can compute here
1331
+ // Actually, we're always adding it, for all non-static methods
1332
+ const xmlRoot = xmlValue.nodeType === 9 ? xmlValue.documentElement : xmlValue;
1333
+ if (!xmlRoot.hasAttribute("xtkschema"))
1334
+ xmlRoot.setAttribute("xtkschema", entitySchemaId);
1335
+ soapCall.writeDocument("document", xmlValue);
1335
1336
  }
1336
1337
  else
1337
- throw CampaignException.BAD_SOAP_PARAMETER(soapCall, paramName, paramValue, `Unsupported parameter type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}`);
1338
+ soapCall.writeDocument(paramName, xmlValue);
1339
+ }
1340
+ else
1341
+ soapCall.writeElement(paramName, xmlValue);
1338
1342
  }
1343
+ else
1344
+ throw CampaignException.BAD_SOAP_PARAMETER(soapCall, paramName, paramValue, `Unsupported parameter type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}`);
1345
+ }
1339
1346
  }
1340
1347
 
1341
1348
  // Deserializes results for a SOAP call
@@ -1343,76 +1350,76 @@ class Client {
1343
1350
  // @param {DOMDocument} schema is the XML schema of the method call
1344
1351
  // @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
1345
1352
  // @param {Campaign.XtkMethodParam[]} outputParameters is the list of output parameters. The first paramater in the array is the "this" parameter for non-static method calls
1346
- // @param {string} representation is the representation to use to interpret the parameters
1353
+ // @param {string} representation is the representation to use to interpret the parameters
1347
1354
  async _readSoapCallResult(entitySchemaId, schema, soapCall, outputParameters, representation) {
1348
- const methodName = soapCall.methodName;
1349
- var isThisParam = !soapCall.isStatic;
1350
- for (const op of outputParameters) {
1351
- const type = op.type;
1352
- const paramName = op.name;
1353
- var returnValue = op.value;
1354
-
1355
- if (isThisParam) {
1356
- isThisParam = false;
1357
- // Non static methods, such as xtk:query#SelectAll return a element named "entity" which is the object itself on which
1358
- // the method is called. This is the new version of the object (in XML form)
1359
- const entity = soapCall.getEntity();
1360
- if (entity)
1361
- returnValue = this._toRepresentation(entity, representation);
1362
- }
1363
- else if (type == "string")
1364
- returnValue = soapCall.getNextString();
1365
- else if (type == "primarykey")
1366
- returnValue = soapCall.getNextPrimaryKey();
1367
- else if (type == "boolean")
1368
- returnValue = soapCall.getNextBoolean();
1369
- else if (type == "byte")
1370
- returnValue = soapCall.getNextByte();
1371
- else if (type == "short")
1372
- returnValue = soapCall.getNextShort();
1373
- else if (type == "long")
1374
- returnValue = soapCall.getNextLong();
1375
- else if (type == "int64")
1376
- // int64 are represented as strings to make sure no precision is lost
1377
- returnValue = soapCall.getNextInt64();
1378
- else if (type == "datetime")
1379
- returnValue = soapCall.getNextDateTime();
1380
- else if (type == "date")
1381
- returnValue = soapCall.getNextDate();
1382
- else if (type == "DOMDocument") {
1383
- returnValue = soapCall.getNextDocument();
1384
- returnValue = this._toRepresentation(returnValue, representation);
1385
- }
1386
- else if (type == "DOMElement") {
1355
+ const methodName = soapCall.methodName;
1356
+ var isThisParam = !soapCall.isStatic;
1357
+ for (const op of outputParameters) {
1358
+ const type = op.type;
1359
+ const paramName = op.name;
1360
+ var returnValue = op.value;
1361
+
1362
+ if (isThisParam) {
1363
+ isThisParam = false;
1364
+ // Non static methods, such as xtk:query#SelectAll return a element named "entity" which is the object itself on which
1365
+ // the method is called. This is the new version of the object (in XML form)
1366
+ const entity = soapCall.getEntity();
1367
+ if (entity)
1368
+ returnValue = this._toRepresentation(entity, representation);
1369
+ }
1370
+ else if (type == "string")
1371
+ returnValue = soapCall.getNextString();
1372
+ else if (type == "primarykey")
1373
+ returnValue = soapCall.getNextPrimaryKey();
1374
+ else if (type == "boolean")
1375
+ returnValue = soapCall.getNextBoolean();
1376
+ else if (type == "byte")
1377
+ returnValue = soapCall.getNextByte();
1378
+ else if (type == "short")
1379
+ returnValue = soapCall.getNextShort();
1380
+ else if (type == "long")
1381
+ returnValue = soapCall.getNextLong();
1382
+ else if (type == "int64")
1383
+ // int64 are represented as strings to make sure no precision is lost
1384
+ returnValue = soapCall.getNextInt64();
1385
+ else if (type == "datetime")
1386
+ returnValue = soapCall.getNextDateTime();
1387
+ else if (type == "date")
1388
+ returnValue = soapCall.getNextDate();
1389
+ else if (type == "DOMDocument") {
1390
+ returnValue = soapCall.getNextDocument();
1391
+ returnValue = this._toRepresentation(returnValue, representation);
1392
+ }
1393
+ else if (type == "DOMElement") {
1394
+ returnValue = soapCall.getNextElement();
1395
+ returnValue = this._toRepresentation(returnValue, representation);
1396
+ }
1397
+ else {
1398
+ const schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
1399
+ // type can reference a schema element. The naming convension is that the type name
1400
+ // is {schemaName}{elementNameCamelCase}. For instance, the type "sessionUserInfo"
1401
+ // matches the "userInfo" element of the "xtkSession" schema
1402
+ let element;
1403
+ if (type.substr(0, schemaName.length) == schemaName) {
1404
+ const shortTypeName = type.substr(schemaName.length, 1).toLowerCase() + type.substr(schemaName.length + 1);
1405
+ element = DomUtil.getFirstChildElement(schema, "element");
1406
+ while (element) {
1407
+ if (element.getAttribute("name") == shortTypeName) {
1408
+ // Type found in schema: Process as a DOM element
1387
1409
  returnValue = soapCall.getNextElement();
1388
1410
  returnValue = this._toRepresentation(returnValue, representation);
1411
+ break;
1412
+ }
1413
+ element = DomUtil.getNextSiblingElement(element, "element");
1389
1414
  }
1390
- else {
1391
- const schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
1392
- // type can reference a schema element. The naming convension is that the type name
1393
- // is {schemaName}{elementNameCamelCase}. For instance, the type "sessionUserInfo"
1394
- // matches the "userInfo" element of the "xtkSession" schema
1395
- let element;
1396
- if (type.substr(0, schemaName.length) == schemaName) {
1397
- const shortTypeName = type.substr(schemaName.length, 1).toLowerCase() + type.substr(schemaName.length + 1);
1398
- element = DomUtil.getFirstChildElement(schema, "element");
1399
- while (element) {
1400
- if (element.getAttribute("name") == shortTypeName) {
1401
- // Type found in schema: Process as a DOM element
1402
- returnValue = soapCall.getNextElement();
1403
- returnValue = this._toRepresentation(returnValue, representation);
1404
- break;
1405
- }
1406
- element = DomUtil.getNextSiblingElement(element, "element");
1407
- }
1408
1415
 
1409
- }
1410
- if (!element)
1411
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Unsupported return type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}'`);
1412
- }
1413
- op.value = returnValue;
1416
+ }
1417
+ if (!element)
1418
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Unsupported return type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}'`);
1414
1419
  }
1415
- soapCall.checkNoMoreArgs();
1420
+ op.value = returnValue;
1421
+ }
1422
+ soapCall.checkNoMoreArgs();
1416
1423
  }
1417
1424
 
1418
1425
  /**
@@ -1427,46 +1434,46 @@ class Client {
1427
1434
  * @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
1428
1435
  * @param {Campaign.XtkMethodParam[]} inputParams is the list of input parameters. The first paramater in the array is the "this" parameter for non-static method calls
1429
1436
  * @param {Campaign.XtkMethodParam[]} outputParams is the list of output parameters. The first paramater in the array is the "this" parameter for non-static method calls
1430
- * @param {string} representation is the representation to use to interpret the parameters
1437
+ * @param {string} representation is the representation to use to interpret the parameters
1431
1438
  */
1432
1439
  async _makeInterceptableSoapCall(entitySchemaId, schema, soapCall, inputParams, outputParams, representation) {
1433
- // Call observers and give them a chance to modify the parameters before the call is actually made
1434
- if (!soapCall.internal) {
1435
- await this._beforeSoapCall({
1436
- urn: soapCall.urn,
1437
- name: soapCall.methodName,
1438
- }, inputParams, representation);
1439
- }
1440
+ // Call observers and give them a chance to modify the parameters before the call is actually made
1441
+ if (!soapCall.internal) {
1442
+ await this._beforeSoapCall({
1443
+ urn: soapCall.urn,
1444
+ name: soapCall.methodName,
1445
+ }, inputParams, representation);
1446
+ }
1440
1447
 
1441
- // Make SOAP call
1442
- await this._writeSoapCallParameters(entitySchemaId, schema, soapCall, inputParams, representation);
1443
- await this._makeSoapCall(soapCall);
1444
- await this._readSoapCallResult(entitySchemaId, schema, soapCall, outputParams, representation);
1448
+ // Make SOAP call
1449
+ await this._writeSoapCallParameters(entitySchemaId, schema, soapCall, inputParams, representation);
1450
+ await this._makeSoapCall(soapCall);
1451
+ await this._readSoapCallResult(entitySchemaId, schema, soapCall, outputParams, representation);
1445
1452
 
1446
- // Specific handling of query results
1447
- // https://github.com/adobe/acc-js-sdk/issues/3
1448
- if (entitySchemaId === "xtk:queryDef" && soapCall.methodName === "ExecuteQuery") {
1449
- const returnValue = outputParams[1].value; // first parameter is the "this", second one (index 1) is the query result
1450
- const emptyResult = Object.keys(returnValue).length == 0;
1451
- const object = inputParams[0].value; // first parmater is the "this"
1452
- const operation = EntityAccessor.getAttributeAsString(object, "operation");
1453
- if (operation == "getIfExists" && emptyResult)
1454
- outputParams[1].value = null;
1455
- else if (operation == "select" && emptyResult) {
1456
- const querySchemaId = EntityAccessor.getAttributeAsString(object, "schema");
1457
- const index = querySchemaId.indexOf(':');
1458
- const querySchemaName = querySchemaId.substr(index + 1).replace(':', '_');
1459
- outputParams[1].value[querySchemaName] = [];
1460
- }
1453
+ // Specific handling of query results
1454
+ // https://github.com/adobe/acc-js-sdk/issues/3
1455
+ if (entitySchemaId === "xtk:queryDef" && soapCall.methodName === "ExecuteQuery") {
1456
+ const returnValue = outputParams[1].value; // first parameter is the "this", second one (index 1) is the query result
1457
+ const emptyResult = Object.keys(returnValue).length == 0;
1458
+ const object = inputParams[0].value; // first parmater is the "this"
1459
+ const operation = EntityAccessor.getAttributeAsString(object, "operation");
1460
+ if (operation == "getIfExists" && emptyResult)
1461
+ outputParams[1].value = null;
1462
+ else if (operation == "select" && emptyResult) {
1463
+ const querySchemaId = EntityAccessor.getAttributeAsString(object, "schema");
1464
+ const index = querySchemaId.indexOf(':');
1465
+ const querySchemaName = querySchemaId.substr(index + 1).replace(':', '_');
1466
+ outputParams[1].value[querySchemaName] = [];
1461
1467
  }
1468
+ }
1462
1469
 
1463
- // Call observers and give them a chance to modify the results
1464
- if (!soapCall.internal) {
1465
- await this._afterSoapCall({
1466
- urn: soapCall.urn,
1467
- name: soapCall.methodName
1468
- }, inputParams, representation, outputParams);
1469
- }
1470
+ // Call observers and give them a chance to modify the results
1471
+ if (!soapCall.internal) {
1472
+ await this._afterSoapCall({
1473
+ urn: soapCall.urn,
1474
+ name: soapCall.methodName
1475
+ }, inputParams, representation, outputParams);
1476
+ }
1470
1477
  }
1471
1478
 
1472
1479
  /**
@@ -1477,233 +1484,233 @@ class Client {
1477
1484
  * @param {SOAP.SoapMethodCall} soapCall the SOAP method to call
1478
1485
  */
1479
1486
  _makeSoapCall(soapCall) {
1480
- const that = this;
1481
- if (soapCall.requiresLogon() && !that.isLogged())
1482
- throw CampaignException.NOT_LOGGED_IN(soapCall, `Cannot execute SOAP call ${soapCall.urn}#${soapCall.methodName}: you are not logged in. Use the Logon function first`);
1483
- soapCall.finalize(this._soapEndPoint());
1484
-
1485
- const safeCallData = Util.trim(soapCall.request.data);
1486
- if (that._traceAPICalls)
1487
- console.log(`SOAP//request ${safeCallData}`);
1488
- that._notifyObservers((observer) => observer.onSOAPCall && observer.onSOAPCall(soapCall, safeCallData) );
1489
-
1490
- const pushDownOptions = soapCall._pushDownOptions;
1491
- const event = this._trackEvent('SOAP//request', undefined, {
1492
- urn: soapCall.urn,
1493
- methodName: soapCall.methodName,
1494
- internal: soapCall.internal,
1495
- retry: false,
1496
- retryCount: soapCall._retryCount,
1497
- safeCallData: safeCallData,
1498
- }, pushDownOptions);
1499
- return soapCall.execute()
1500
- .then(() => {
1501
- const safeCallResponse = Util.trim(soapCall.response);
1502
- if (that._traceAPICalls)
1503
- console.log(`SOAP//response ${safeCallResponse}`);
1504
- that._notifyObservers((observer) => observer.onSOAPCallSuccess && observer.onSOAPCallSuccess(soapCall, safeCallResponse) );
1505
- this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1506
- return Promise.resolve();
1507
- })
1508
- .catch((ex) => {
1509
- if (that._traceAPICalls)
1510
- console.log(`SOAP//failure ${ex.toString()}`);
1511
- that._notifyObservers((observer) => observer.onSOAPCallFailure && observer.onSOAPCallFailure(soapCall, ex) );
1512
- this._trackEvent('SOAP//failure', event, ex, pushDownOptions);
1513
- // Call session expiration callback in case of 401
1514
- if (ex.statusCode == 401 && that._refreshClient && soapCall.retry) {
1515
- return this._retrySoapCall(soapCall);
1516
- }
1517
- else
1518
- return Promise.reject(ex);
1519
- });
1487
+ const that = this;
1488
+ if (soapCall.requiresLogon() && !that.isLogged())
1489
+ throw CampaignException.NOT_LOGGED_IN(soapCall, `Cannot execute SOAP call ${soapCall.urn}#${soapCall.methodName}: you are not logged in. Use the Logon function first`);
1490
+ soapCall.finalize(this._soapEndPoint());
1491
+
1492
+ const safeCallData = Util.trim(soapCall.request.data);
1493
+ if (that._traceAPICalls)
1494
+ console.log(`SOAP//request ${safeCallData}`);
1495
+ that._notifyObservers((observer) => observer.onSOAPCall && observer.onSOAPCall(soapCall, safeCallData) );
1496
+
1497
+ const pushDownOptions = soapCall._pushDownOptions;
1498
+ const event = this._trackEvent('SOAP//request', undefined, {
1499
+ urn: soapCall.urn,
1500
+ methodName: soapCall.methodName,
1501
+ internal: soapCall.internal,
1502
+ retry: false,
1503
+ retryCount: soapCall._retryCount,
1504
+ safeCallData: safeCallData,
1505
+ }, pushDownOptions);
1506
+ return soapCall.execute()
1507
+ .then(() => {
1508
+ const safeCallResponse = Util.trim(soapCall.response);
1509
+ if (that._traceAPICalls)
1510
+ console.log(`SOAP//response ${safeCallResponse}`);
1511
+ that._notifyObservers((observer) => observer.onSOAPCallSuccess && observer.onSOAPCallSuccess(soapCall, safeCallResponse) );
1512
+ this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1513
+ return Promise.resolve();
1514
+ })
1515
+ .catch((ex) => {
1516
+ if (that._traceAPICalls)
1517
+ console.log(`SOAP//failure ${ex.toString()}`);
1518
+ that._notifyObservers((observer) => observer.onSOAPCallFailure && observer.onSOAPCallFailure(soapCall, ex) );
1519
+ this._trackEvent('SOAP//failure', event, ex, pushDownOptions);
1520
+ // Call session expiration callback in case of 401
1521
+ if (ex.statusCode == 401 && that._refreshClient && soapCall.retry) {
1522
+ return this._retrySoapCall(soapCall);
1523
+ }
1524
+ else
1525
+ return Promise.reject(ex);
1526
+ });
1520
1527
  }
1521
1528
 
1522
1529
  _onLogon() {
1523
- this.application = new Application(this);
1524
- this.application._registerCacheChangeListener();
1525
- this._observabilityContext.instance = {
1526
- buildNumber: this.application.buildNumber,
1527
- version: this.application.version,
1528
- instanceName: this.application.instanceName,
1529
- };
1530
- if (this.application.operator) {
1531
- this._observabilityContext.instance.operator = {
1532
- login: this.application.operator.login,
1533
- id: this.application.operator.id,
1534
- timezone: this.application.operator.timezone,
1535
- rights: this.application.operator.rights,
1536
- packages: this.application.operator.packages,
1537
- };
1538
- }
1539
- this._observabilityContext.session = {
1540
- logonAt: Date.now(),
1530
+ this.application = new Application(this);
1531
+ this.application._registerCacheChangeListener();
1532
+ this._observabilityContext.instance = {
1533
+ buildNumber: this.application.buildNumber,
1534
+ version: this.application.version,
1535
+ instanceName: this.application.instanceName,
1536
+ };
1537
+ if (this.application.operator) {
1538
+ this._observabilityContext.instance.operator = {
1539
+ login: this.application.operator.login,
1540
+ id: this.application.operator.id,
1541
+ timezone: this.application.operator.timezone,
1542
+ rights: this.application.operator.rights,
1543
+ packages: this.application.operator.packages,
1541
1544
  };
1545
+ }
1546
+ this._observabilityContext.session = {
1547
+ logonAt: Date.now(),
1548
+ };
1542
1549
  }
1543
1550
 
1544
1551
  _onLogoff() {
1545
- delete this._observabilityContext.instance;
1546
- delete this._observabilityContext.session;
1552
+ delete this._observabilityContext.instance;
1553
+ delete this._observabilityContext.session;
1547
1554
  }
1548
1555
 
1549
1556
  _updateSessionInfo(sessionInfo, soapCall) {
1550
- this._sessionInfo = sessionInfo;
1551
- this._installedPackages = {};
1552
- const userInfo = DomUtil.findElement(sessionInfo, "userInfo");
1553
- if (!userInfo)
1554
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `userInfo structure missing`);
1555
- let pack = DomUtil.getFirstChildElement(userInfo, "installed-package");
1556
- while (pack) {
1557
- const name = `${DomUtil.getAttributeAsString(pack, "namespace")}:${DomUtil.getAttributeAsString(pack, "name")}`;
1558
- this._installedPackages[name] = name;
1559
- pack = DomUtil.getNextSiblingElement(pack);
1560
- }
1557
+ this._sessionInfo = sessionInfo;
1558
+ this._installedPackages = {};
1559
+ const userInfo = DomUtil.findElement(sessionInfo, "userInfo");
1560
+ if (!userInfo)
1561
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `userInfo structure missing`);
1562
+ let pack = DomUtil.getFirstChildElement(userInfo, "installed-package");
1563
+ while (pack) {
1564
+ const name = `${DomUtil.getAttributeAsString(pack, "namespace")}:${DomUtil.getAttributeAsString(pack, "name")}`;
1565
+ this._installedPackages[name] = name;
1566
+ pack = DomUtil.getNextSiblingElement(pack);
1567
+ }
1561
1568
  }
1562
1569
 
1563
1570
  async _fetchSessionInfo() {
1564
- const userInfoPromise = this.NLWS.xml.xtkSession.getUserInfo();
1565
- const testPromise = this.test();
1566
- const all = Promise.all([userInfoPromise, testPromise]);
1567
- const values = await all;
1568
-
1569
- const sessionInfo = DomUtil.newDocument("sessionInfo");
1570
- const sessionInfoRoot = sessionInfo.documentElement;
1571
- const userInfo = sessionInfo.importNode(values[0], true);
1572
- sessionInfoRoot.appendChild(userInfo);
1573
- const serverInfo = sessionInfo.createElement('serverInfo');
1574
- sessionInfoRoot.appendChild(serverInfo);
1575
- const test = values[1];
1576
- if (test["date"])
1577
- serverInfo.setAttribute("serverDate", new Date(Date.parse(test["date"])).toISOString());
1578
- serverInfo.setAttribute("instanceName", test["instance"]);
1579
- if (test["version"]) {
1580
- const versionParts = test["version"].split(".");
1581
- serverInfo.setAttribute("majNumber", versionParts[0]);
1582
- serverInfo.setAttribute("minNumber", versionParts[1]);
1583
- serverInfo.setAttribute("servicePack", versionParts[2]);
1584
- }
1585
- let buildNumber = test["build"];
1586
- // Alternative method to get the build number (not available unless server has been upgraded at least once)
1587
- if (!buildNumber)
1588
- buildNumber = await this.getOption("NmsServer_LastPostUpgrade", false);
1589
- if (!buildNumber)
1590
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(undefined, `buildNumber structure missing for both /r/test and NmsServer_LastPostUpgrade option`);
1591
- serverInfo.setAttribute("buildNumber", buildNumber);
1592
- return sessionInfoRoot;
1571
+ const userInfoPromise = this.NLWS.xml.xtkSession.getUserInfo();
1572
+ const testPromise = this.test();
1573
+ const all = Promise.all([userInfoPromise, testPromise]);
1574
+ const values = await all;
1575
+
1576
+ const sessionInfo = DomUtil.newDocument("sessionInfo");
1577
+ const sessionInfoRoot = sessionInfo.documentElement;
1578
+ const userInfo = sessionInfo.importNode(values[0], true);
1579
+ sessionInfoRoot.appendChild(userInfo);
1580
+ const serverInfo = sessionInfo.createElement('serverInfo');
1581
+ sessionInfoRoot.appendChild(serverInfo);
1582
+ const test = values[1];
1583
+ if (test["date"])
1584
+ serverInfo.setAttribute("serverDate", new Date(Date.parse(test["date"])).toISOString());
1585
+ serverInfo.setAttribute("instanceName", test["instance"]);
1586
+ if (test["version"]) {
1587
+ const versionParts = test["version"].split(".");
1588
+ serverInfo.setAttribute("majNumber", versionParts[0]);
1589
+ serverInfo.setAttribute("minNumber", versionParts[1]);
1590
+ serverInfo.setAttribute("servicePack", versionParts[2]);
1591
+ }
1592
+ let buildNumber = test["build"];
1593
+ // Alternative method to get the build number (not available unless server has been upgraded at least once)
1594
+ if (!buildNumber)
1595
+ buildNumber = await this.getOption("NmsServer_LastPostUpgrade", false);
1596
+ if (!buildNumber)
1597
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(undefined, `buildNumber structure missing for both /r/test and NmsServer_LastPostUpgrade option`);
1598
+ serverInfo.setAttribute("buildNumber", buildNumber);
1599
+ return sessionInfoRoot;
1593
1600
  }
1594
1601
 
1595
1602
  /**
1596
1603
  * Login to an instance
1597
1604
  */
1598
1605
  logon() {
1599
- const that = this;
1600
-
1601
- this.application = null;
1602
- this._sessionToken = "";
1603
- this._securityToken = "";
1604
- this._bearerToken = undefined;
1605
- const credentials = this._connectionParameters._credentials;
1606
-
1607
- const sdkVersion = this.sdk.getSDKVersion();
1608
- const version = `${sdkVersion.name} ${sdkVersion.version}`;
1609
- const clientApp = this._connectionParameters._options.clientApp;
1610
- if (!this._connectionParameters._options.noSDKHeaders) {
1611
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Version"] = version;
1612
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type}`;
1613
- if (clientApp)
1614
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Client-App"] = clientApp;
1615
- }
1616
- // See NEO-35259
1617
- this._connectionParameters._options.extraHttpHeaders['X-Query-Source'] = `${version}${clientApp? "," + clientApp : ""}`;
1606
+ const that = this;
1607
+
1608
+ this.application = null;
1609
+ this._sessionToken = "";
1610
+ this._securityToken = "";
1611
+ this._bearerToken = undefined;
1612
+ const credentials = this._connectionParameters._credentials;
1613
+
1614
+ const sdkVersion = this.sdk.getSDKVersion();
1615
+ const version = `${sdkVersion.name} ${sdkVersion.version}`;
1616
+ const clientApp = this._connectionParameters._options.clientApp;
1617
+ if (!this._connectionParameters._options.noSDKHeaders) {
1618
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Version"] = version;
1619
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type}`;
1620
+ if (clientApp)
1621
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Client-App"] = clientApp;
1622
+ }
1623
+ // See NEO-35259
1624
+ this._connectionParameters._options.extraHttpHeaders['X-Query-Source'] = `${version}${clientApp? "," + clientApp : ""}`;
1618
1625
 
1619
- this._trackEvent('SDK//logon', undefined, {});
1626
+ this._trackEvent('SDK//logon', undefined, {});
1620
1627
 
1621
- // Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
1622
- if (credentials._type != "SecurityToken" && typeof document != "undefined") {
1623
- document.cookie = '__sessiontoken=;path=/;';
1624
- }
1625
- if (credentials._type == "SessionToken" || credentials._type == "AnonymousUser" || credentials._type == "SessionAndSecurityToken") {
1626
- that._sessionInfo = undefined;
1627
- that._installedPackages = {};
1628
- that._sessionToken = credentials._sessionToken;
1629
- that._securityToken = credentials._type == "SessionAndSecurityToken" ? credentials._securityToken : "";
1630
- that._bearerToken = undefined;
1631
- that._onLogon();
1632
- return Promise.resolve();
1633
- }
1634
- else if (credentials._type == "SecurityToken") {
1635
- that._sessionInfo = undefined;
1636
- that._installedPackages = {};
1637
- that._sessionToken = "";
1638
- that._securityToken = credentials._securityToken;
1639
- that._bearerToken = undefined;
1640
- that._onLogon();
1641
- return Promise.resolve();
1642
- }
1643
- else if (credentials._type == "ImsBearerToken") {
1644
- that._sessionInfo = undefined;
1645
- that._installedPackages = {};
1646
- that._sessionToken = "";
1647
- that._securityToken = "";
1648
- that._bearerToken = credentials._bearerToken;
1649
-
1650
- // With IMS Bearer token, we do not call the Logon or BearerTokenLogon method any more. As a consequence,
1651
- // we do not have the user and server information returned by those methods, so we need to get the corresponding
1652
- // information by other means
1653
- if (!this._connectionParameters._options.sessionInfo) {
1654
- that._onLogon();
1655
- return Promise.resolve();
1656
- }
1657
- return that._fetchSessionInfo().then((sessionInfo) => {
1658
- that._updateSessionInfo(sessionInfo, undefined);
1659
- that._onLogon();
1660
- });
1628
+ // Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
1629
+ if (credentials._type != "SecurityToken" && typeof document != "undefined") {
1630
+ document.cookie = '__sessiontoken=;path=/;';
1631
+ }
1632
+ if (credentials._type == "SessionToken" || credentials._type == "AnonymousUser" || credentials._type == "SessionAndSecurityToken") {
1633
+ that._sessionInfo = undefined;
1634
+ that._installedPackages = {};
1635
+ that._sessionToken = credentials._sessionToken;
1636
+ that._securityToken = credentials._type == "SessionAndSecurityToken" ? credentials._securityToken : "";
1637
+ that._bearerToken = undefined;
1638
+ that._onLogon();
1639
+ return Promise.resolve();
1640
+ }
1641
+ else if (credentials._type == "SecurityToken") {
1642
+ that._sessionInfo = undefined;
1643
+ that._installedPackages = {};
1644
+ that._sessionToken = "";
1645
+ that._securityToken = credentials._securityToken;
1646
+ that._bearerToken = undefined;
1647
+ that._onLogon();
1648
+ return Promise.resolve();
1649
+ }
1650
+ else if (credentials._type == "ImsBearerToken") {
1651
+ that._sessionInfo = undefined;
1652
+ that._installedPackages = {};
1653
+ that._sessionToken = "";
1654
+ that._securityToken = "";
1655
+ that._bearerToken = credentials._bearerToken;
1656
+
1657
+ // With IMS Bearer token, we do not call the Logon or BearerTokenLogon method any more. As a consequence,
1658
+ // we do not have the user and server information returned by those methods, so we need to get the corresponding
1659
+ // information by other means
1660
+ if (!this._connectionParameters._options.sessionInfo) {
1661
+ that._onLogon();
1662
+ return Promise.resolve();
1661
1663
  }
1662
- else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
1663
- const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon", true, false, this._connectionParameters._options.extraHttpHeaders);
1664
- // No retry for logon SOAP methods
1665
- soapCall.retry = false;
1666
- if (credentials._type == "UserPassword") {
1667
- const user = credentials._getUser();
1668
- const password = credentials._getPassword();
1669
- if (!this._connectionParameters._options.noSDKHeaders)
1670
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type} ${user}`;
1671
- soapCall.writeString("login", user);
1672
- soapCall.writeString("password", password);
1673
- var parameters = null;
1674
- if (this._connectionParameters._options.rememberMe) {
1675
- parameters = soapCall.createElement("parameters");
1676
- parameters.setAttribute("rememberMe", "true");
1677
- }
1678
- soapCall.writeElement("parameters", parameters);
1679
- }
1680
- else {
1681
- const bearerToken = credentials._bearerToken;
1682
- soapCall.writeString("bearerToken", bearerToken);
1683
- }
1684
- return this._makeSoapCall(soapCall).then(function() {
1685
- const sessionToken = soapCall.getNextString();
1686
- const sessionInfo = soapCall.getNextDocument();
1687
- that._updateSessionInfo(sessionInfo, soapCall);
1688
- const securityToken = soapCall.getNextString();
1689
- soapCall.checkNoMoreArgs();
1690
- // Sanity check: we should have both a session token and a security token.
1691
- if (!sessionToken)
1692
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no session token was returned`);
1693
- if (!securityToken)
1694
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no security token was returned`);
1695
- // store member variables after all parameters are decode the ensure atomicity
1696
- that._sessionToken = sessionToken;
1697
- that._securityToken = securityToken;
1698
- that._bearerToken = undefined;
1699
-
1700
- that._onLogon();
1701
- });
1664
+ return that._fetchSessionInfo().then((sessionInfo) => {
1665
+ that._updateSessionInfo(sessionInfo, undefined);
1666
+ that._onLogon();
1667
+ });
1668
+ }
1669
+ else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
1670
+ const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon", true, false, this._connectionParameters._options.extraHttpHeaders);
1671
+ // No retry for logon SOAP methods
1672
+ soapCall.retry = false;
1673
+ if (credentials._type == "UserPassword") {
1674
+ const user = credentials._getUser();
1675
+ const password = credentials._getPassword();
1676
+ if (!this._connectionParameters._options.noSDKHeaders)
1677
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type} ${user}`;
1678
+ soapCall.writeString("login", user);
1679
+ soapCall.writeString("password", password);
1680
+ var parameters = null;
1681
+ if (this._connectionParameters._options.rememberMe) {
1682
+ parameters = soapCall.createElement("parameters");
1683
+ parameters.setAttribute("rememberMe", "true");
1684
+ }
1685
+ soapCall.writeElement("parameters", parameters);
1702
1686
  }
1703
1687
  else {
1704
- //throw CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon");
1705
- return Promise.reject(CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon"));
1688
+ const bearerToken = credentials._bearerToken;
1689
+ soapCall.writeString("bearerToken", bearerToken);
1706
1690
  }
1691
+ return this._makeSoapCall(soapCall).then(function() {
1692
+ const sessionToken = soapCall.getNextString();
1693
+ const sessionInfo = soapCall.getNextDocument();
1694
+ that._updateSessionInfo(sessionInfo, soapCall);
1695
+ const securityToken = soapCall.getNextString();
1696
+ soapCall.checkNoMoreArgs();
1697
+ // Sanity check: we should have both a session token and a security token.
1698
+ if (!sessionToken)
1699
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no session token was returned`);
1700
+ if (!securityToken)
1701
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no security token was returned`);
1702
+ // store member variables after all parameters are decode the ensure atomicity
1703
+ that._sessionToken = sessionToken;
1704
+ that._securityToken = securityToken;
1705
+ that._bearerToken = undefined;
1706
+
1707
+ that._onLogon();
1708
+ });
1709
+ }
1710
+ else {
1711
+ //throw CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon");
1712
+ return Promise.reject(CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon"));
1713
+ }
1707
1714
  }
1708
1715
 
1709
1716
  /**
@@ -1713,41 +1720,41 @@ class Client {
1713
1720
  * @returns {Campaign.SessionInfo} details about the session
1714
1721
  */
1715
1722
  getSessionInfo(representation) {
1716
- representation = representation || this._representation;
1717
- return this._toRepresentation(this._sessionInfo, representation);
1723
+ representation = representation || this._representation;
1724
+ return this._toRepresentation(this._sessionInfo, representation);
1718
1725
  }
1719
1726
 
1720
1727
  /**
1721
1728
  * Logs off from an instance to which one previous logged on using the "logon" call
1722
1729
  */
1723
1730
  logoff() {
1724
- var that = this;
1725
- try {
1726
- if (!that.isLogged()) return;
1727
- that.application._unregisterCacheChangeListener();
1728
- that._unregisterAllCacheChangeListeners();
1729
- this.stopRefreshCaches();
1730
- const credentials = this._connectionParameters._credentials;
1731
- if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
1732
- var soapCall = that._prepareSoapCall("xtk:session", "Logoff", true, false, this._connectionParameters._options.extraHttpHeaders);
1733
- return this._makeSoapCall(soapCall).then(function() {
1734
- that._sessionToken = "";
1735
- that._securityToken = "";
1736
- that._bearerToken = undefined;
1737
- that.application = null;
1738
- soapCall.checkNoMoreArgs();
1739
- });
1740
- }
1741
- else {
1742
- that._sessionToken = "";
1743
- that._securityToken = "";
1744
- that._bearerToken = undefined;
1745
- that.application = null;
1746
- }
1747
- } finally {
1748
- this._trackEvent('SDK//logoff', undefined, {});
1749
- this._onLogoff();
1731
+ var that = this;
1732
+ try {
1733
+ if (!that.isLogged()) return;
1734
+ that.application._unregisterCacheChangeListener();
1735
+ that._unregisterAllCacheChangeListeners();
1736
+ this.stopRefreshCaches();
1737
+ const credentials = this._connectionParameters._credentials;
1738
+ if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
1739
+ var soapCall = that._prepareSoapCall("xtk:session", "Logoff", true, false, this._connectionParameters._options.extraHttpHeaders);
1740
+ return this._makeSoapCall(soapCall).then(function() {
1741
+ that._sessionToken = "";
1742
+ that._securityToken = "";
1743
+ that._bearerToken = undefined;
1744
+ that.application = null;
1745
+ soapCall.checkNoMoreArgs();
1746
+ });
1747
+ }
1748
+ else {
1749
+ that._sessionToken = "";
1750
+ that._securityToken = "";
1751
+ that._bearerToken = undefined;
1752
+ that.application = null;
1750
1753
  }
1754
+ } finally {
1755
+ this._trackEvent('SDK//logoff', undefined, {});
1756
+ this._onLogoff();
1757
+ }
1751
1758
  }
1752
1759
 
1753
1760
  /**
@@ -1778,59 +1785,59 @@ class Client {
1778
1785
  * @param {string} description the optional description of the option
1779
1786
  */
1780
1787
  async setOption(name, rawValue, description) {
1781
- // First, read the current option value to make sure we have the right type
1782
- await this.getOption(name, true);
1783
- const option = await this._optionCache.getOption(name);
1784
- // Note: option is never null or undefined there: Campaign will return a value of type 0 and value ""
1785
- var type = option.type;
1786
- var value = XtkCaster.as(rawValue, type);
1787
-
1788
- // Document attribute for value depends on value type
1789
- var attName = XtkCaster._variantStorageAttribute(type);
1790
- if (!attName) {
1791
- // could not infer the storage type of the attribute to use to store the value (when option did not exist before) => assume string
1792
- type = 6;
1793
- attName = "stringValue";
1794
- }
1795
- var doc = { xtkschema: "xtk:option", _operation: "insertOrUpdate", _key: "@name", name: name, dataType: type };
1796
- if (description != null && description != undefined)
1797
- doc.description = description;
1798
- doc[attName] = value;
1799
- await this.NLWS.xtkSession.write(doc);
1800
- // Once set, cache the value
1801
- await this._optionCache.put(name, [value, type]);
1788
+ // First, read the current option value to make sure we have the right type
1789
+ await this.getOption(name, true);
1790
+ const option = await this._optionCache.getOption(name);
1791
+ // Note: option is never null or undefined there: Campaign will return a value of type 0 and value ""
1792
+ var type = option.type;
1793
+ var value = XtkCaster.as(rawValue, type);
1794
+
1795
+ // Document attribute for value depends on value type
1796
+ var attName = XtkCaster._variantStorageAttribute(type);
1797
+ if (!attName) {
1798
+ // could not infer the storage type of the attribute to use to store the value (when option did not exist before) => assume string
1799
+ type = 6;
1800
+ attName = "stringValue";
1801
+ }
1802
+ var doc = { xtkschema: "xtk:option", _operation: "insertOrUpdate", _key: "@name", name: name, dataType: type };
1803
+ if (description != null && description != undefined)
1804
+ doc.description = description;
1805
+ doc[attName] = value;
1806
+ await this.NLWS.xtkSession.write(doc);
1807
+ // Once set, cache the value
1808
+ await this._optionCache.put(name, [value, type]);
1802
1809
  }
1803
1810
 
1804
1811
  /**
1805
1812
  * Clears the options cache
1806
1813
  */
1807
1814
  async clearOptionCache() {
1808
- await this._optionCache.clear();
1815
+ await this._optionCache.clear();
1809
1816
  }
1810
1817
 
1811
1818
  /**
1812
1819
  * Clears the method cache
1813
1820
  */
1814
1821
  async clearMethodCache() {
1815
- await this._methodCache.clear();
1822
+ await this._methodCache.clear();
1816
1823
  }
1817
1824
 
1818
1825
  /**
1819
1826
  * Clears the entity cache
1820
1827
  */
1821
1828
  async clearEntityCache() {
1822
- await this._entityCache.clear();
1829
+ await this._entityCache.clear();
1823
1830
  }
1824
1831
 
1825
1832
  /**
1826
1833
  * Clears all caches (options, methods, entities)
1827
1834
  */
1828
1835
  async clearAllCaches() {
1829
- return Promise.all([
1830
- this.clearEntityCache(),
1831
- this.clearMethodCache(),
1832
- this.clearOptionCache(),
1833
- ]);
1836
+ return Promise.all([
1837
+ this.clearEntityCache(),
1838
+ this.clearMethodCache(),
1839
+ this.clearOptionCache(),
1840
+ ]);
1834
1841
  }
1835
1842
 
1836
1843
  /**
@@ -1838,43 +1845,43 @@ class Client {
1838
1845
  * @param {integer} refreshFrequency refresh frequency in ms. 10000 ms by default.
1839
1846
  */
1840
1847
  startRefreshCaches(refreshFrequency) {
1841
- if (refreshFrequency === undefined || refreshFrequency === null)
1842
- refreshFrequency = 10000;
1843
- this._optionCacheRefresher.startAutoRefresh(refreshFrequency);
1844
- // Start auto refresh for entityCache a little later
1845
- setTimeout(() => { this._entityCacheRefresher.startAutoRefresh(refreshFrequency); }, refreshFrequency/2);
1848
+ if (refreshFrequency === undefined || refreshFrequency === null)
1849
+ refreshFrequency = 10000;
1850
+ this._optionCacheRefresher.startAutoRefresh(refreshFrequency);
1851
+ // Start auto refresh for entityCache a little later
1852
+ setTimeout(() => { this._entityCacheRefresher.startAutoRefresh(refreshFrequency); }, refreshFrequency/2);
1846
1853
  }
1847
1854
  /**
1848
1855
  * Stop auto refresh of all caches
1849
1856
  */
1850
1857
  stopRefreshCaches() {
1851
- this._optionCacheRefresher.stopAutoRefresh();
1852
- this._entityCacheRefresher.stopAutoRefresh();
1858
+ this._optionCacheRefresher.stopAutoRefresh();
1859
+ this._entityCacheRefresher.stopAutoRefresh();
1853
1860
  }
1854
1861
 
1855
1862
  // Register a callback to be called when a schema has been modified and should be removed
1856
1863
  // from the caches
1857
1864
  _registerCacheChangeListener(listener) {
1858
- this._cacheChangeListeners.push(listener);
1865
+ this._cacheChangeListeners.push(listener);
1859
1866
  }
1860
1867
 
1861
1868
  // Unregister a cache change listener
1862
1869
  _unregisterCacheChangeListener(listener) {
1863
- for (var i = 0; i < this._cacheChangeListeners.length; i++) {
1864
- if (this._cacheChangeListeners[i] == listener) {
1865
- this._cacheChangeListeners.splice(i, 1);
1866
- break;
1867
- }
1870
+ for (var i = 0; i < this._cacheChangeListeners.length; i++) {
1871
+ if (this._cacheChangeListeners[i] == listener) {
1872
+ this._cacheChangeListeners.splice(i, 1);
1873
+ break;
1868
1874
  }
1875
+ }
1869
1876
  }
1870
1877
 
1871
1878
  // Unregister all cache change listener
1872
1879
  _unregisterAllCacheChangeListeners() {
1873
- this._cacheChangeListeners = [];
1880
+ this._cacheChangeListeners = [];
1874
1881
  }
1875
1882
 
1876
1883
  _notifyCacheChangeListeners(schemaId) {
1877
- this._cacheChangeListeners.map((listener) => listener.invalidateCacheItem(schemaId));
1884
+ this._cacheChangeListeners.map((listener) => listener.invalidateCacheItem(schemaId));
1878
1885
  }
1879
1886
 
1880
1887
  /**
@@ -1885,11 +1892,11 @@ class Client {
1885
1892
  * @returns {boolean} a boolean indicating if the package is installed or not
1886
1893
  */
1887
1894
  hasPackage(packageId, optionalName) {
1888
- if (optionalName !== undefined)
1895
+ if (optionalName !== undefined)
1889
1896
  packageId = `${packageId}:${optionalName}`;
1890
- if (!this.isLogged())
1897
+ if (!this.isLogged())
1891
1898
  throw CampaignException.NOT_LOGGED_IN(undefined, `Cannot call hasPackage: session not connected`);
1892
- return this._installedPackages[packageId] !== undefined;
1899
+ return this._installedPackages[packageId] !== undefined;
1893
1900
  }
1894
1901
 
1895
1902
  /**
@@ -1900,12 +1907,12 @@ class Client {
1900
1907
  * @deprecated since version 1.0.0
1901
1908
  */
1902
1909
  async _getSecretKeyCipher() {
1903
- var that = this;
1904
- if (this._secretKeyCipher) return this._secretKeyCipher;
1905
- return that.getOption("XtkSecretKey").then(function(secretKey) {
1906
- that._secretKeyCipher = new Cipher(secretKey);
1907
- return that._secretKeyCipher;
1908
- });
1910
+ var that = this;
1911
+ if (this._secretKeyCipher) return this._secretKeyCipher;
1912
+ return that.getOption("XtkSecretKey").then(function(secretKey) {
1913
+ that._secretKeyCipher = new Cipher(secretKey);
1914
+ return that._secretKeyCipher;
1915
+ });
1909
1916
  }
1910
1917
 
1911
1918
  /**
@@ -1921,17 +1928,17 @@ class Client {
1921
1928
  * @return {XML.XtkObject} A DOM or JSON representation of the entity, or null if the entity is not found
1922
1929
  */
1923
1930
  async getEntityIfMoreRecent(entityType, fullName, representation, internal) {
1924
- const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", true, internal, this._connectionParameters._options.extraHttpHeaders);
1925
- const inputParams = [
1926
- { name: "pk", type: "string", value: entityType + "|" + fullName },
1927
- { name: "md5", type: "string", value: "" },
1928
- { name: "mustExist", type: "boolean", value: false },
1929
- ];
1930
- const outputParams = [
1931
- { name: "doc", type: "DOMDocument" },
1932
- ];
1933
- await this._makeInterceptableSoapCall("xtk:session", undefined, soapCall, inputParams, outputParams, representation);
1934
- return outputParams[0].value;
1931
+ const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", true, internal, this._connectionParameters._options.extraHttpHeaders);
1932
+ const inputParams = [
1933
+ { name: "pk", type: "string", value: entityType + "|" + fullName },
1934
+ { name: "md5", type: "string", value: "" },
1935
+ { name: "mustExist", type: "boolean", value: false },
1936
+ ];
1937
+ const outputParams = [
1938
+ { name: "doc", type: "DOMDocument" },
1939
+ ];
1940
+ await this._makeInterceptableSoapCall("xtk:session", undefined, soapCall, inputParams, outputParams, representation);
1941
+ return outputParams[0].value;
1935
1942
  }
1936
1943
 
1937
1944
  /**
@@ -1945,7 +1952,7 @@ class Client {
1945
1952
  * @see {@link Campaign.XtkSchema}
1946
1953
  */
1947
1954
  newSchema(xml) {
1948
- return newSchema(xml, this.application);
1955
+ return newSchema(xml, this.application);
1949
1956
  }
1950
1957
 
1951
1958
  /**
@@ -1958,71 +1965,71 @@ class Client {
1958
1965
  * @returns {XML.XtkObject} the schema definition, as either a DOM document or a JSON object
1959
1966
  */
1960
1967
  async getSchema(schemaId, representation, internal, withoutCache = false) {
1961
- // Support for Orchestrated Campaign XDM schemas (do not use cache)
1962
- const pipeIndex = schemaId.indexOf("|");
1963
- if( pipeIndex != -1 && schemaId.startsWith("xdm:") ) {
1964
- const entityType = schemaId.substring(0, pipeIndex);
1965
- schemaId = schemaId.substring(pipeIndex + 1);
1966
- const entity = await this.getEntityIfMoreRecent(entityType, schemaId, representation, internal);
1967
- return entity;
1968
- }
1969
- var entity = await this._entityCache.get("xtk:schema", schemaId);
1970
- if (!entity || withoutCache) {
1971
- // special case of "temp:group:*" schemas for nms:group
1972
- // Schema "temp:group:*" is not cached because life cycle of this kind of schema is not the same as the others schemas
1973
- if (schemaId.startsWith("temp:group:")) {
1974
- const parts = schemaId.split(":");
1975
- let queryDef = {
1976
- "schema": "nms:group",
1977
- "operation": "get",
1978
- "select": {
1979
- "node": [
1980
- { "expr": "@id" },
1981
- { "expr": "extension" }
1982
- ]
1983
- },
1984
- "where": {
1985
- "condition": [
1986
- { "expr": "@id=" + XtkCaster.asLong(parts[2]) }
1987
- ]
1988
- }
1989
- };
1990
- // Convert to current representation
1991
- queryDef = this._convertToRepresentation(queryDef, "SimpleJson", "xml");
1992
- const query = this.NLWS.xml.xtkQueryDef.create(queryDef);
1993
- try {
1994
- const groupSchema = await query.executeQuery();
1995
- const extension = DomUtil.findElement(groupSchema, "extension");
1996
- if (extension) {
1997
- entity = extension;
1998
- } else {
1999
- entity = null;
2000
- }
2001
- } catch (ex) {
2002
- if (ex.name == 'CampaignException' && ex.errorCode == 'SOP-330011') {
2003
- entity = null;
2004
- } else {
2005
- throw ex;
2006
- }
2007
- }
2008
- } else {
2009
- entity = await this.getEntityIfMoreRecent("xtk:schema", schemaId, "xml", internal);
2010
- if (entity) {
2011
- const impls = DomUtil.getAttributeAsString(entity, "implements");
2012
- if (impls === "xtk:persist" && schemaId !== "xtk:session" && schemaId !== "xtk:persist") {
2013
- // Ensure xtk:persist is present by loading the xtk:session schema
2014
- const xtkSession = await this.getSchema("xtk:session", "xml", true);
2015
- // it is possible that methodCache content has not be loaded in memory
2016
- // so we re-put the methods
2017
- await this._methodCache.put(xtkSession);
2018
- }
2019
- await this._entityCache.put("xtk:schema", schemaId, entity);
2020
- await this._methodCache.put(entity);
2021
- }
1968
+ // Support for Orchestrated Campaign XDM schemas (do not use cache)
1969
+ const pipeIndex = schemaId.indexOf("|");
1970
+ if( pipeIndex != -1 && schemaId.startsWith("xdm:") ) {
1971
+ const entityType = schemaId.substring(0, pipeIndex);
1972
+ schemaId = schemaId.substring(pipeIndex + 1);
1973
+ const entity = await this.getEntityIfMoreRecent(entityType, schemaId, representation, internal);
1974
+ return entity;
1975
+ }
1976
+ var entity = await this._entityCache.get("xtk:schema", schemaId);
1977
+ if (!entity || withoutCache) {
1978
+ // special case of "temp:group:*" schemas for nms:group
1979
+ // Schema "temp:group:*" is not cached because life cycle of this kind of schema is not the same as the others schemas
1980
+ if (schemaId.startsWith("temp:group:")) {
1981
+ const parts = schemaId.split(":");
1982
+ let queryDef = {
1983
+ "schema": "nms:group",
1984
+ "operation": "get",
1985
+ "select": {
1986
+ "node": [
1987
+ { "expr": "@id" },
1988
+ { "expr": "extension" }
1989
+ ]
1990
+ },
1991
+ "where": {
1992
+ "condition": [
1993
+ { "expr": "@id=" + XtkCaster.asLong(parts[2]) }
1994
+ ]
1995
+ }
1996
+ };
1997
+ // Convert to current representation
1998
+ queryDef = this._convertToRepresentation(queryDef, "SimpleJson", "xml");
1999
+ const query = this.NLWS.xml.xtkQueryDef.create(queryDef);
2000
+ try {
2001
+ const groupSchema = await query.executeQuery();
2002
+ const extension = DomUtil.findElement(groupSchema, "extension");
2003
+ if (extension) {
2004
+ entity = extension;
2005
+ } else {
2006
+ entity = null;
2007
+ }
2008
+ } catch (ex) {
2009
+ if (ex.name == 'CampaignException' && ex.errorCode == 'SOP-330011') {
2010
+ entity = null;
2011
+ } else {
2012
+ throw ex;
2022
2013
  }
2014
+ }
2015
+ } else {
2016
+ entity = await this.getEntityIfMoreRecent("xtk:schema", schemaId, "xml", internal);
2017
+ if (entity) {
2018
+ const impls = DomUtil.getAttributeAsString(entity, "implements");
2019
+ if (impls === "xtk:persist" && schemaId !== "xtk:session" && schemaId !== "xtk:persist") {
2020
+ // Ensure xtk:persist is present by loading the xtk:session schema
2021
+ const xtkSession = await this.getSchema("xtk:session", "xml", true);
2022
+ // it is possible that methodCache content has not be loaded in memory
2023
+ // so we re-put the methods
2024
+ await this._methodCache.put(xtkSession);
2025
+ }
2026
+ await this._entityCache.put("xtk:schema", schemaId, entity);
2027
+ await this._methodCache.put(entity);
2028
+ }
2023
2029
  }
2024
- entity = this._toRepresentation(entity, representation);
2025
- return entity;
2030
+ }
2031
+ entity = this._toRepresentation(entity, representation);
2032
+ return entity;
2026
2033
  }
2027
2034
 
2028
2035
  /**
@@ -2034,37 +2041,37 @@ class Client {
2034
2041
  */
2035
2042
  async getSysEnum(enumName, optionalStartSchemaOrSchemaName) {
2036
2043
 
2037
- // Called with one parameter: enumName must be the fully qualified enumeration name
2038
- // as <namespace>:<schema>:<enum>, for instance "nms:extAccount:encryptionType"
2039
- if (!optionalStartSchemaOrSchemaName) {
2040
- const index = enumName.lastIndexOf(':');
2041
- if (index == -1)
2042
- throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum expects a fully qualified enumeration name. '${enumName}' is not a valid name.`);
2043
- optionalStartSchemaOrSchemaName = enumName.substring(0, index);
2044
- enumName = enumName.substring(index + 1);
2045
- }
2046
-
2047
- if (!optionalStartSchemaOrSchemaName || optionalStartSchemaOrSchemaName == "")
2048
- throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum needs a schema id.`);
2049
-
2050
- // If we have a schema name (and not a schema), then lookup the schema by name
2051
- if (typeof optionalStartSchemaOrSchemaName == "string") {
2052
- const index = optionalStartSchemaOrSchemaName.lastIndexOf(':');
2053
- if (index == -1)
2054
- throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name. '${optionalStartSchemaOrSchemaName}' is not a valid name.`);
2055
- optionalStartSchemaOrSchemaName = await this.getSchema(optionalStartSchemaOrSchemaName, undefined, true);
2056
- if (!optionalStartSchemaOrSchemaName)
2057
- throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `Schema '${optionalStartSchemaOrSchemaName}' not found.`);
2058
- }
2059
- else
2060
- throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name wich is a string. Given ${typeof optionalStartSchemaOrSchemaName} instead`);
2044
+ // Called with one parameter: enumName must be the fully qualified enumeration name
2045
+ // as <namespace>:<schema>:<enum>, for instance "nms:extAccount:encryptionType"
2046
+ if (!optionalStartSchemaOrSchemaName) {
2047
+ const index = enumName.lastIndexOf(':');
2048
+ if (index == -1)
2049
+ throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum expects a fully qualified enumeration name. '${enumName}' is not a valid name.`);
2050
+ optionalStartSchemaOrSchemaName = enumName.substring(0, index);
2051
+ enumName = enumName.substring(index + 1);
2052
+ }
2061
2053
 
2062
- const schema = optionalStartSchemaOrSchemaName;
2063
- for (const e of EntityAccessor.getChildElements(schema, "enumeration")) {
2064
- const n = EntityAccessor.getAttributeAsString(e, "name");
2065
- if (n == enumName)
2066
- return e;
2067
- }
2054
+ if (!optionalStartSchemaOrSchemaName || optionalStartSchemaOrSchemaName == "")
2055
+ throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum needs a schema id.`);
2056
+
2057
+ // If we have a schema name (and not a schema), then lookup the schema by name
2058
+ if (typeof optionalStartSchemaOrSchemaName == "string") {
2059
+ const index = optionalStartSchemaOrSchemaName.lastIndexOf(':');
2060
+ if (index == -1)
2061
+ throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name. '${optionalStartSchemaOrSchemaName}' is not a valid name.`);
2062
+ optionalStartSchemaOrSchemaName = await this.getSchema(optionalStartSchemaOrSchemaName, undefined, true);
2063
+ if (!optionalStartSchemaOrSchemaName)
2064
+ throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `Schema '${optionalStartSchemaOrSchemaName}' not found.`);
2065
+ }
2066
+ else
2067
+ throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name wich is a string. Given ${typeof optionalStartSchemaOrSchemaName} instead`);
2068
+
2069
+ const schema = optionalStartSchemaOrSchemaName;
2070
+ for (const e of EntityAccessor.getChildElements(schema, "enumeration")) {
2071
+ const n = EntityAccessor.getAttributeAsString(e, "name");
2072
+ if (n == enumName)
2073
+ return e;
2074
+ }
2068
2075
  }
2069
2076
 
2070
2077
  /**
@@ -2077,127 +2084,127 @@ class Client {
2077
2084
  * @returns {*} the SOAP call result. If there's just one output parameter, the value itself will be returned. If not, an array will be returned
2078
2085
  */
2079
2086
  async _callMethod(methodName, callContext, parameters) {
2080
- const that = this;
2081
- const schemaId = callContext.schemaId;
2082
-
2083
- var entitySchemaId = schemaId;
2084
- if (schemaId === 'xtk:jobInterface')
2085
- entitySchemaId = callContext.entitySchemaId;
2086
-
2087
- // Get the schema which contains the method call. Methods of the xtk:jobInterface interface are handled specificaaly
2088
- // because xtk:jobInterface is not actually a schema, but just an interface. In practice, it's used as an xtk template
2089
- // rather that an xtk inheritance mechanism
2090
- const methodSchemaId = schemaId === 'xtk:jobInterface' ? 'xtk:job' : schemaId;
2091
- var schema = await that.getSchema(methodSchemaId, "xml", true);
2092
- if (!schema)
2093
- throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Schema '${schemaId}' not found`);
2094
-
2095
- // Lookup the method to call
2096
- var method = await that._methodCache.get(methodSchemaId, methodName);
2097
- if (!method) {
2098
- // first char of the method name may be lower case (ex: nms:seedMember.getAsModel) but the methodName
2099
- // variable has been capitalized. Make an attempt to lookup method name without capitalisation
2100
- const methodNameLC = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
2101
- method = await that._methodCache.get(schemaId, methodNameLC);
2102
- if (method) methodName = methodNameLC;
2103
- }
2104
- if (!method) {
2105
- await this._methodCache.put(schema);
2106
- method = await that._methodCache.get(methodSchemaId, methodName);
2107
- }
2108
- if (!method)
2109
- throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Method '${methodName}' of schema '${schemaId}' not found`);
2110
-
2111
- // Compute the SOAP URN. Again, specically handle xtk:jobInterface as it's not a real schema. The actual entity schema
2112
- // would be available as the entitySchemaId property of the callContext
2113
- var urn = schemaId !== 'xtk:jobInterface' ? await that._methodCache.getSoapUrn(schemaId, methodName)
2114
- : `xtk:jobInterface|${entitySchemaId}`;
2115
-
2116
- const isStatic = DomUtil.getAttributeAsBoolean(method, "static");
2117
- var soapCall = that._prepareSoapCall(urn, methodName, isStatic, false, callContext.headers, callContext.pushDownOptions);
2118
-
2119
- // If method is called with one parameter which is a function, then we assume it's a hook: the function will return
2120
- // the actual list of parameters
2121
- let isfunc = parameters && typeof parameters === "function";
2122
- if (!isfunc && parameters && parameters.length >= 1 && typeof parameters[0] === "function")
2123
- isfunc = true;
2124
- if (isfunc)
2125
- parameters = parameters[0](method, callContext);
2126
-
2127
- // Create input and output parameters arrays. Each array will contain elements for the corresponding parameter name, type and value
2128
- const inputParams = [];
2129
- const outputParams = [];
2130
-
2131
- // For non static methods
2132
- // in case of persistent job: object represents the entity instance
2133
- // in case of non-persistent job: object represents job description
2134
- // the first output parameters represent the entity itself. The name of the corresponding
2135
- // parameter is set the the entity schema name.
2136
- if (!isStatic) {
2137
- var schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
2138
- if (!callContext.object)
2139
- throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Cannot call non-static method '${methodName}' of schema '${schemaId}' : no object was specified`);
2140
- inputParams.push({
2141
- name: schemaName,
2142
- type: "DOMDocument",
2143
- value: callContext.object
2144
- });
2087
+ const that = this;
2088
+ const schemaId = callContext.schemaId;
2089
+
2090
+ var entitySchemaId = schemaId;
2091
+ if (schemaId === 'xtk:jobInterface')
2092
+ entitySchemaId = callContext.entitySchemaId;
2093
+
2094
+ // Get the schema which contains the method call. Methods of the xtk:jobInterface interface are handled specificaaly
2095
+ // because xtk:jobInterface is not actually a schema, but just an interface. In practice, it's used as an xtk template
2096
+ // rather that an xtk inheritance mechanism
2097
+ const methodSchemaId = schemaId === 'xtk:jobInterface' ? 'xtk:job' : schemaId;
2098
+ var schema = await that.getSchema(methodSchemaId, "xml", true);
2099
+ if (!schema)
2100
+ throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Schema '${schemaId}' not found`);
2101
+
2102
+ // Lookup the method to call
2103
+ var method = await that._methodCache.get(methodSchemaId, methodName);
2104
+ if (!method) {
2105
+ // first char of the method name may be lower case (ex: nms:seedMember.getAsModel) but the methodName
2106
+ // variable has been capitalized. Make an attempt to lookup method name without capitalisation
2107
+ const methodNameLC = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
2108
+ method = await that._methodCache.get(schemaId, methodNameLC);
2109
+ if (method) methodName = methodNameLC;
2110
+ }
2111
+ if (!method) {
2112
+ await this._methodCache.put(schema);
2113
+ method = await that._methodCache.get(methodSchemaId, methodName);
2114
+ }
2115
+ if (!method)
2116
+ throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Method '${methodName}' of schema '${schemaId}' not found`);
2117
+
2118
+ // Compute the SOAP URN. Again, specically handle xtk:jobInterface as it's not a real schema. The actual entity schema
2119
+ // would be available as the entitySchemaId property of the callContext
2120
+ var urn = schemaId !== 'xtk:jobInterface' ? await that._methodCache.getSoapUrn(schemaId, methodName)
2121
+ : `xtk:jobInterface|${entitySchemaId}`;
2122
+
2123
+ const isStatic = DomUtil.getAttributeAsBoolean(method, "static");
2124
+ var soapCall = that._prepareSoapCall(urn, methodName, isStatic, false, callContext.headers, callContext.pushDownOptions);
2125
+
2126
+ // If method is called with one parameter which is a function, then we assume it's a hook: the function will return
2127
+ // the actual list of parameters
2128
+ let isfunc = parameters && typeof parameters === "function";
2129
+ if (!isfunc && parameters && parameters.length >= 1 && typeof parameters[0] === "function")
2130
+ isfunc = true;
2131
+ if (isfunc)
2132
+ parameters = parameters[0](method, callContext);
2133
+
2134
+ // Create input and output parameters arrays. Each array will contain elements for the corresponding parameter name, type and value
2135
+ const inputParams = [];
2136
+ const outputParams = [];
2137
+
2138
+ // For non static methods
2139
+ // in case of persistent job: object represents the entity instance
2140
+ // in case of non-persistent job: object represents job description
2141
+ // the first output parameters represent the entity itself. The name of the corresponding
2142
+ // parameter is set the the entity schema name.
2143
+ if (!isStatic) {
2144
+ var schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
2145
+ if (!callContext.object)
2146
+ throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Cannot call non-static method '${methodName}' of schema '${schemaId}' : no object was specified`);
2147
+ inputParams.push({
2148
+ name: schemaName,
2149
+ type: "DOMDocument",
2150
+ value: callContext.object
2151
+ });
2152
+ outputParams.push({
2153
+ name: schemaName,
2154
+ type: "DOMDocument"
2155
+ });
2156
+ }
2157
+
2158
+ // Traverse the <parameters> object and create the corresponding parameter objects
2159
+ const parametersIsArray = (typeof parameters == "object") && parameters.length;
2160
+ const params = DomUtil.getFirstChildElement(method, "parameters");
2161
+ if (params) {
2162
+ var param = DomUtil.getFirstChildElement(params, "param");
2163
+ var paramIndex = 0;
2164
+ while (param) {
2165
+ const inout = DomUtil.getAttributeAsString(param, "inout");
2166
+ const type = DomUtil.getAttributeAsString(param, "type");
2167
+ const paramName = DomUtil.getAttributeAsString(param, "name");
2168
+ const isIn = !inout || inout=="in" || inout=="inout";
2169
+ const isOut = inout=="out" || inout=="inout";
2170
+ if (isIn) {
2171
+ let paramValue = parametersIsArray ? parameters[paramIndex] : parameters;
2172
+ const inputParam = {
2173
+ name: paramName,
2174
+ type: type,
2175
+ value: paramValue
2176
+ };
2177
+ inputParams.push(inputParam);
2178
+ paramIndex = paramIndex + 1;
2179
+ }
2180
+ if (isOut) {
2145
2181
  outputParams.push({
2146
- name: schemaName,
2147
- type: "DOMDocument"
2182
+ name: paramName,
2183
+ type: type,
2148
2184
  });
2185
+ }
2186
+ if( !isIn && !isOut) {
2187
+ throw CampaignException.BAD_PARAMETER("inout", inout, `Parameter '${paramName}' of schema '${entitySchemaId}' is not correctly defined as an input or output parameter`);
2188
+ }
2189
+ param = DomUtil.getNextSiblingElement(param, "param");
2149
2190
  }
2191
+ }
2150
2192
 
2151
- // Traverse the <parameters> object and create the corresponding parameter objects
2152
- const parametersIsArray = (typeof parameters == "object") && parameters.length;
2153
- const params = DomUtil.getFirstChildElement(method, "parameters");
2154
- if (params) {
2155
- var param = DomUtil.getFirstChildElement(params, "param");
2156
- var paramIndex = 0;
2157
- while (param) {
2158
- const inout = DomUtil.getAttributeAsString(param, "inout");
2159
- const type = DomUtil.getAttributeAsString(param, "type");
2160
- const paramName = DomUtil.getAttributeAsString(param, "name");
2161
- const isIn = !inout || inout=="in" || inout=="inout";
2162
- const isOut = inout=="out" || inout=="inout";
2163
- if (isIn) {
2164
- let paramValue = parametersIsArray ? parameters[paramIndex] : parameters;
2165
- const inputParam = {
2166
- name: paramName,
2167
- type: type,
2168
- value: paramValue
2169
- };
2170
- inputParams.push(inputParam);
2171
- paramIndex = paramIndex + 1;
2172
- }
2173
- if (isOut) {
2174
- outputParams.push({
2175
- name: paramName,
2176
- type: type,
2177
- });
2178
- }
2179
- if( !isIn && !isOut) {
2180
- throw CampaignException.BAD_PARAMETER("inout", inout, `Parameter '${paramName}' of schema '${entitySchemaId}' is not correctly defined as an input or output parameter`);
2181
- }
2182
- param = DomUtil.getNextSiblingElement(param, "param");
2183
- }
2184
- }
2185
-
2186
- // Make the SOAP call
2187
- await this._makeInterceptableSoapCall(entitySchemaId, schema, soapCall, inputParams, outputParams, callContext.representation);
2193
+ // Make the SOAP call
2194
+ await this._makeInterceptableSoapCall(entitySchemaId, schema, soapCall, inputParams, outputParams, callContext.representation);
2188
2195
 
2189
- // Simplify the result when there's 0 or 1 return value
2190
- if (!isStatic) {
2191
- const newObject = outputParams.shift().value;
2192
- if (newObject) callContext.object = newObject;
2193
- }
2194
- if (outputParams.length == 0) return null;
2195
- if (outputParams.length == 1) return outputParams[0].value;
2196
- const result = [];
2197
- for (var i=0; i<outputParams.length; i++) {
2198
- result.push(outputParams[i].value);
2199
- }
2200
- return result;
2196
+ // Simplify the result when there's 0 or 1 return value
2197
+ if (!isStatic) {
2198
+ const newObject = outputParams.shift().value;
2199
+ if (newObject) callContext.object = newObject;
2200
+ }
2201
+ if (outputParams.length == 0) return null;
2202
+ if (outputParams.length == 1) return outputParams[0].value;
2203
+ const result = [];
2204
+ for (var i=0; i<outputParams.length; i++) {
2205
+ result.push(outputParams[i].value);
2206
+ }
2207
+ return result;
2201
2208
  }
2202
2209
 
2203
2210
  /**
@@ -2215,48 +2222,48 @@ class Client {
2215
2222
  * In addition, the outputParams array will be modified, and the "value" property of each output param will be set
2216
2223
  */
2217
2224
  async makeSoapCall(urn, methodName, isStatic, inputParams, outputParams, representation) {
2218
- const soapCall = this._prepareSoapCall(urn, methodName, isStatic, false,
2219
- this._connectionParameters._options.extraHttpHeaders);
2225
+ const soapCall = this._prepareSoapCall(urn, methodName, isStatic, false,
2226
+ this._connectionParameters._options.extraHttpHeaders);
2220
2227
  // To support anonymous SOAP calls, we need to disable the logon check
2221
- soapCall.requiresLogon = () => false;
2222
- await this._makeInterceptableSoapCall(urn, null, soapCall, inputParams, outputParams, representation);
2223
- const results = outputParams.map((o)=> o.value);
2224
- return results;
2228
+ soapCall.requiresLogon = () => false;
2229
+ await this._makeInterceptableSoapCall(urn, null, soapCall, inputParams, outputParams, representation);
2230
+ const results = outputParams.map((o)=> o.value);
2231
+ return results;
2225
2232
  }
2226
2233
 
2227
2234
  async _makeHttpCall(request) {
2228
- request.method = request.method || "GET";
2229
- request.headers = request.headers || [];
2230
- if (!request.headers['User-Agent'])
2231
- request.headers['User-Agent'] = this._getUserAgentString();
2232
- let event;
2233
- try {
2234
- const safeCallData = Util.trim(request.data);
2235
- if (this._traceAPICalls)
2236
- console.log(`HTTP//request ${request.method} ${request.url}${safeCallData ? " " + safeCallData : ""}`);
2237
- this._notifyObservers((observer) => observer.onHTTPCall && observer.onHTTPCall(request, safeCallData) );
2238
- event = this._trackEvent('HTTP//request', undefined, {
2239
- url: request.url,
2240
- method: request.method,
2241
- headers: request.request,
2242
- safeCallData: safeCallData,
2243
- });
2244
- const body = await this._transport(request);
2245
-
2246
- const safeCallResponse = Util.trim(body);
2247
- if (this._traceAPICalls)
2248
- console.log(`HTTP//response${safeCallResponse ? " " + safeCallResponse : ""}`);
2249
- this._notifyObservers((observer) => observer.onHTTPCallSuccess && observer.onHTTPCallSuccess(request, safeCallResponse) );
2250
- this._trackEvent('HTTP//response', event, { safeCallResponse: safeCallResponse });
2251
- return body;
2252
- } catch(err) {
2253
- if (this._traceAPICalls)
2254
- console.log("HTTP//failure", err);
2255
- this._notifyObservers((observer) => observer.onHTTPCallFailure && observer.onHTTPCallFailure(request, err) );
2256
- const ex = makeCampaignException({ request:request, response:err.response }, err);
2257
- this._trackEvent('HTTP//failure', event, { }, ex);
2258
- throw ex;
2259
- }
2235
+ request.method = request.method || "GET";
2236
+ request.headers = request.headers || [];
2237
+ if (!request.headers['User-Agent'])
2238
+ request.headers['User-Agent'] = this._getUserAgentString();
2239
+ let event;
2240
+ try {
2241
+ const safeCallData = Util.trim(request.data);
2242
+ if (this._traceAPICalls)
2243
+ console.log(`HTTP//request ${request.method} ${request.url}${safeCallData ? " " + safeCallData : ""}`);
2244
+ this._notifyObservers((observer) => observer.onHTTPCall && observer.onHTTPCall(request, safeCallData) );
2245
+ event = this._trackEvent('HTTP//request', undefined, {
2246
+ url: request.url,
2247
+ method: request.method,
2248
+ headers: request.request,
2249
+ safeCallData: safeCallData,
2250
+ });
2251
+ const body = await this._transport(request);
2252
+
2253
+ const safeCallResponse = Util.trim(body);
2254
+ if (this._traceAPICalls)
2255
+ console.log(`HTTP//response${safeCallResponse ? " " + safeCallResponse : ""}`);
2256
+ this._notifyObservers((observer) => observer.onHTTPCallSuccess && observer.onHTTPCallSuccess(request, safeCallResponse) );
2257
+ this._trackEvent('HTTP//response', event, { safeCallResponse: safeCallResponse });
2258
+ return body;
2259
+ } catch(err) {
2260
+ if (this._traceAPICalls)
2261
+ console.log("HTTP//failure", err);
2262
+ this._notifyObservers((observer) => observer.onHTTPCallFailure && observer.onHTTPCallFailure(request, err) );
2263
+ const ex = makeCampaignException({ request:request, response:err.response }, err);
2264
+ this._trackEvent('HTTP//failure', event, { }, ex);
2265
+ throw ex;
2266
+ }
2260
2267
  }
2261
2268
 
2262
2269
  /**
@@ -2266,16 +2273,16 @@ class Client {
2266
2273
  * @returns {Campaign.RedirStatus} an object describing the status of the redirection server
2267
2274
  */
2268
2275
  async test() {
2269
- const request = {
2270
- url: `${this._connectionParameters._endpoint}/r/test`,
2271
- headers: {}
2272
- };
2273
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2274
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2275
- const body = await this._makeHttpCall(request);
2276
- const xml = DomUtil.parse(body);
2277
- const result = this._toRepresentation(xml);
2278
- return result;
2276
+ const request = {
2277
+ url: `${this._connectionParameters._endpoint}/r/test`,
2278
+ headers: {}
2279
+ };
2280
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2281
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2282
+ const body = await this._makeHttpCall(request);
2283
+ const xml = DomUtil.parse(body);
2284
+ const result = this._toRepresentation(xml);
2285
+ return result;
2279
2286
  }
2280
2287
 
2281
2288
  /**
@@ -2284,26 +2291,26 @@ class Client {
2284
2291
  * @returns {Campaign.PingStatus} an object describing the server status
2285
2292
  */
2286
2293
  async ping() {
2287
- const headers = this._getAuthHeaders(true);
2288
- const request = {
2289
- url: `${this._connectionParameters._endpoint}/nl/jsp/ping.jsp`,
2290
- headers: headers,
2291
- };
2292
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2293
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2294
- const body = await this._makeHttpCall(request);
2295
- const lines = body.split('\n');
2296
- const doc = DomUtil.newDocument("ping");
2297
- const root = doc.documentElement;
2298
- const status = lines[0].trim();
2299
- if (status != "") root.setAttribute("status", status);
2300
-
2301
- if (lines.length > 1) {
2302
- const timestamp = lines[1].trim();
2303
- if (timestamp != "") root.setAttribute("timestamp", timestamp);
2304
- }
2305
- const result = this._toRepresentation(doc);
2306
- return result;
2294
+ const headers = this._getAuthHeaders(true);
2295
+ const request = {
2296
+ url: `${this._connectionParameters._endpoint}/nl/jsp/ping.jsp`,
2297
+ headers: headers,
2298
+ };
2299
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2300
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2301
+ const body = await this._makeHttpCall(request);
2302
+ const lines = body.split('\n');
2303
+ const doc = DomUtil.newDocument("ping");
2304
+ const root = doc.documentElement;
2305
+ const status = lines[0].trim();
2306
+ if (status != "") root.setAttribute("status", status);
2307
+
2308
+ if (lines.length > 1) {
2309
+ const timestamp = lines[1].trim();
2310
+ if (timestamp != "") root.setAttribute("timestamp", timestamp);
2311
+ }
2312
+ const result = this._toRepresentation(doc);
2313
+ return result;
2307
2314
  }
2308
2315
 
2309
2316
  /**
@@ -2314,33 +2321,33 @@ class Client {
2314
2321
  * @returns {Campaign.ReportContext} an object containing the context data for a specific report
2315
2322
  */
2316
2323
  async getReportData(callContext, representation) {
2317
- try {
2318
- if(callContext.formData && callContext.formData.ctx) {
2319
- var xmlCtx = this._fromRepresentation('ctx', callContext.formData.ctx);
2320
- callContext.formData.ctx = DomUtil.toXMLString(xmlCtx);
2321
- }
2322
- const selectionCount = callContext.selection.split(',').length;
2324
+ try {
2325
+ if(callContext.formData && callContext.formData.ctx) {
2326
+ var xmlCtx = this._fromRepresentation('ctx', callContext.formData.ctx);
2327
+ callContext.formData.ctx = DomUtil.toXMLString(xmlCtx);
2328
+ }
2329
+ const selectionCount = callContext.selection.split(',').length;
2323
2330
 
2324
- const headers = this._getAuthHeaders(false);
2325
- headers['Content-Type'] = 'application/x-www-form-urlencoded';
2326
- const request = {
2327
- url: `${this._connectionParameters._endpoint}/report/${callContext.reportName}?${encodeURI(`_noRender=true&_schema=${callContext.schema}&_context=${callContext.context}&_selection=${callContext.selection}`)}&_selectionCount=${selectionCount}`,
2328
- headers: headers,
2329
- method: 'POST',
2330
- data : qsStringify(callContext.formData)
2331
- };
2331
+ const headers = this._getAuthHeaders(false);
2332
+ headers['Content-Type'] = 'application/x-www-form-urlencoded';
2333
+ const request = {
2334
+ url: `${this._connectionParameters._endpoint}/report/${callContext.reportName}?${encodeURI(`_noRender=true&_schema=${callContext.schema}&_context=${callContext.context}&_selection=${callContext.selection}`)}&_selectionCount=${selectionCount}`,
2335
+ headers: headers,
2336
+ method: 'POST',
2337
+ data : qsStringify(callContext.formData)
2338
+ };
2332
2339
 
2333
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2334
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2335
- const body = await this._makeHttpCall(request);
2336
- if(!body.startsWith("<ctx"))
2337
- throw CampaignException.FEATURE_NOT_SUPPORTED("Reports Data");
2338
- const xml = DomUtil.parse(body);
2339
- const result = this._toRepresentation(xml, representation);
2340
- return result;
2341
- } catch(ex) {
2342
- throw CampaignException.REPORT_FETCH_FAILED(callContext.reportName, ex);
2343
- }
2340
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2341
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2342
+ const body = await this._makeHttpCall(request);
2343
+ if(!body.startsWith("<ctx"))
2344
+ throw CampaignException.FEATURE_NOT_SUPPORTED("Reports Data");
2345
+ const xml = DomUtil.parse(body);
2346
+ const result = this._toRepresentation(xml, representation);
2347
+ return result;
2348
+ } catch(ex) {
2349
+ throw CampaignException.REPORT_FETCH_FAILED(callContext.reportName, ex);
2350
+ }
2344
2351
  }
2345
2352
 
2346
2353
  /**
@@ -2350,52 +2357,52 @@ class Client {
2350
2357
  * @returns {Campaign.McPingStatus} an object describing Message Center server status
2351
2358
  */
2352
2359
  async mcPing() {
2353
- const headers = this._getAuthHeaders(true);
2354
- const request = {
2355
- url: `${this._connectionParameters._endpoint}/nl/jsp/mcPing.jsp`,
2356
- headers: headers
2357
- };
2358
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2359
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2360
- const body = await this._makeHttpCall(request);
2361
- const lines = body.split('\n');
2362
- const doc = DomUtil.newDocument("ping");
2363
- const root = doc.documentElement;
2364
- var status = lines[0].trim();
2365
- if (status != "") root.setAttribute("status", status);
2366
-
2367
- var rtCount;
2368
- var threshold;
2369
- if (status == "Error") {
2370
- const error = lines.length > 1 ? lines[1] : "";
2371
- root.setAttribute("error", error);
2372
- const index1 = error.indexOf('(');
2373
- const index2 = error.indexOf('/');
2374
- const index3 = error.indexOf(')');
2375
- if (index1 != -1 && index2 != -1 && index3 != -1) {
2376
- rtCount = error.substring(index1+1, index2);
2377
- threshold = error.substring(index2+1, index3);
2378
- }
2360
+ const headers = this._getAuthHeaders(true);
2361
+ const request = {
2362
+ url: `${this._connectionParameters._endpoint}/nl/jsp/mcPing.jsp`,
2363
+ headers: headers
2364
+ };
2365
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2366
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2367
+ const body = await this._makeHttpCall(request);
2368
+ const lines = body.split('\n');
2369
+ const doc = DomUtil.newDocument("ping");
2370
+ const root = doc.documentElement;
2371
+ var status = lines[0].trim();
2372
+ if (status != "") root.setAttribute("status", status);
2373
+
2374
+ var rtCount;
2375
+ var threshold;
2376
+ if (status == "Error") {
2377
+ const error = lines.length > 1 ? lines[1] : "";
2378
+ root.setAttribute("error", error);
2379
+ const index1 = error.indexOf('(');
2380
+ const index2 = error.indexOf('/');
2381
+ const index3 = error.indexOf(')');
2382
+ if (index1 != -1 && index2 != -1 && index3 != -1) {
2383
+ rtCount = error.substring(index1+1, index2);
2384
+ threshold = error.substring(index2+1, index3);
2379
2385
  }
2380
- else {
2381
- if (lines.length > 1) {
2382
- const timestamp = lines[1].trim();
2383
- if (timestamp != "") root.setAttribute("timestamp", timestamp);
2384
- }
2385
- if (lines.length > 2) {
2386
- const queue = lines[2];
2387
- const index2 = queue.indexOf('/');
2388
- const index3 = queue.indexOf(' pending events');
2389
- if (index2 != -1 && index3 != -1) {
2390
- rtCount = queue.substring(0, index2);
2391
- threshold = queue.substring(index2+1, index3);
2392
- }
2393
- }
2386
+ }
2387
+ else {
2388
+ if (lines.length > 1) {
2389
+ const timestamp = lines[1].trim();
2390
+ if (timestamp != "") root.setAttribute("timestamp", timestamp);
2394
2391
  }
2395
- if (rtCount !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueSize", rtCount);
2396
- if (threshold !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueMaxSize", threshold);
2397
- const result = this._toRepresentation(doc);
2398
- return result;
2392
+ if (lines.length > 2) {
2393
+ const queue = lines[2];
2394
+ const index2 = queue.indexOf('/');
2395
+ const index3 = queue.indexOf(' pending events');
2396
+ if (index2 != -1 && index3 != -1) {
2397
+ rtCount = queue.substring(0, index2);
2398
+ threshold = queue.substring(index2+1, index3);
2399
+ }
2400
+ }
2401
+ }
2402
+ if (rtCount !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueSize", rtCount);
2403
+ if (threshold !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueMaxSize", threshold);
2404
+ const result = this._toRepresentation(doc);
2405
+ return result;
2399
2406
  }
2400
2407
 
2401
2408
  /**
@@ -2404,7 +2411,7 @@ class Client {
2404
2411
  * @returns {Campaign.XtkJobInterface} a job
2405
2412
  */
2406
2413
  jobInterface(soapCallSpec) {
2407
- return new XtkJobInterface(this, soapCallSpec);
2414
+ return new XtkJobInterface(this, soapCallSpec);
2408
2415
  }
2409
2416
 
2410
2417
  // Calls the beforeSoapCall method on all observers which have this method. Ignore any exception
@@ -2414,17 +2421,17 @@ class Client {
2414
2421
  // @param {Array<*>} inputParameters is an array containing the method parameters
2415
2422
  // @param {string} representation is the representation (SimpleJson, xml, etc.) used for this method and in which the object and parameters are set
2416
2423
  async _beforeSoapCall(method, inputParameters, representation) {
2417
- if (!representation) representation = this._representation;
2418
- for (const observer of this._observers) {
2419
- if (observer.beforeSoapCall) {
2420
- try {
2421
- await observer.beforeSoapCall(method, inputParameters, representation);
2422
- }
2423
- catch (any) {
2424
- // Ignore errors occuring in observers
2425
- }
2426
- }
2424
+ if (!representation) representation = this._representation;
2425
+ for (const observer of this._observers) {
2426
+ if (observer.beforeSoapCall) {
2427
+ try {
2428
+ await observer.beforeSoapCall(method, inputParameters, representation);
2429
+ }
2430
+ catch (any) {
2431
+ // Ignore errors occuring in observers
2432
+ }
2427
2433
  }
2434
+ }
2428
2435
  }
2429
2436
 
2430
2437
  // Calls the afterSoapCall method on all observers which have this method. Ignore any exception
@@ -2435,25 +2442,25 @@ class Client {
2435
2442
  // @param {string} representation is the representation (SimpleJson, xml, etc.) used for this method and in which the object and parameters are set
2436
2443
  // @param {Array<*>} outputParameters an array (possibly) empty of the values returned by the SOAP call
2437
2444
  async _afterSoapCall(method, inputParameters, representation, outputParameters) {
2438
- if (!representation) representation = this._representation;
2439
- for (const observer of this._observers) {
2440
- if (observer.afterSoapCall) {
2441
- try {
2442
- await observer.afterSoapCall(method, inputParameters, representation, outputParameters);
2443
- }
2444
- catch (any) {
2445
- // Ignore errors occuring in observers
2446
- }
2447
- }
2445
+ if (!representation) representation = this._representation;
2446
+ for (const observer of this._observers) {
2447
+ if (observer.afterSoapCall) {
2448
+ try {
2449
+ await observer.afterSoapCall(method, inputParameters, representation, outputParameters);
2450
+ }
2451
+ catch (any) {
2452
+ // Ignore errors occuring in observers
2453
+ }
2448
2454
  }
2455
+ }
2449
2456
  }
2450
- }
2457
+ }
2451
2458
 
2452
2459
 
2453
- // Public exports
2454
- Client.CampaignException = CampaignException;
2455
- exports.Client = Client;
2456
- exports.Credentials = Credentials;
2457
- exports.ConnectionParameters = ConnectionParameters;
2460
+ // Public exports
2461
+ Client.CampaignException = CampaignException;
2462
+ exports.Client = Client;
2463
+ exports.Credentials = Credentials;
2464
+ exports.ConnectionParameters = ConnectionParameters;
2458
2465
 
2459
2466
  })();