@adobe/acc-js-sdk 1.1.62 → 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.
- package/.cursor/commands/opsx-apply.md +152 -0
- package/.cursor/commands/opsx-archive.md +157 -0
- package/.cursor/commands/opsx-explore.md +173 -0
- package/.cursor/commands/opsx-propose.md +106 -0
- package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
- package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
- package/.cursor/skills/openspec-explore/SKILL.md +288 -0
- package/.cursor/skills/openspec-propose/SKILL.md +110 -0
- package/.eslintrc.js +2 -2
- package/.github/prompts/opsx-apply.prompt.md +149 -0
- package/.github/prompts/opsx-archive.prompt.md +154 -0
- package/.github/prompts/opsx-explore.prompt.md +170 -0
- package/.github/prompts/opsx-propose.prompt.md +103 -0
- package/.github/skills/openspec-apply-change/SKILL.md +156 -0
- package/.github/skills/openspec-archive-change/SKILL.md +114 -0
- package/.github/skills/openspec-explore/SKILL.md +288 -0
- package/.github/skills/openspec-propose/SKILL.md +110 -0
- package/.github/workflows/codeql-analysis.yml +5 -4
- package/.github/workflows/npm-publish.yml +3 -3
- package/AGENTS.md +117 -0
- package/CLAUDE.md +2 -0
- package/MIGRATION.md +10 -0
- package/README.md +6 -2
- package/ai-docs/coding-rules.md +95 -0
- package/ai-docs/tech-stack.md +43 -0
- package/babel.config.js +5 -0
- package/docs/changeLog.html +28 -2
- package/docs/checkList.html +2 -2
- package/docs/quickstart.html +2 -1
- package/docs/release.html +1 -1
- package/openspec/config.yaml +20 -0
- package/package-lock.json +6055 -4036
- package/package.json +9 -7
- package/src/AGENTS.md +98 -0
- package/src/CLAUDE.md +2 -0
- package/src/application.js +637 -637
- package/src/cache.js +133 -133
- package/src/cacheRefresher.js +190 -190
- package/src/campaign.js +532 -532
- package/src/client.js +1539 -1537
- package/src/crypto.js +52 -52
- package/src/domUtil.js +346 -346
- package/src/entityAccessor.js +61 -61
- package/src/index.js +83 -83
- package/src/methodCache.js +69 -69
- package/src/optionCache.js +26 -26
- package/src/soap.js +321 -322
- package/src/testUtil.js +13 -13
- package/src/transport.js +70 -70
- package/src/util.js +147 -147
- package/src/web/bundler.js +5 -5
- package/src/xtkCaster.js +258 -258
- package/src/xtkEntityCache.js +34 -34
- package/src/xtkJob.js +185 -185
- package/test/AGENTS.md +37 -0
- package/test/CLAUDE.md +2 -0
- package/test/cacheRefresher.test.js +7 -0
- package/test/client.test.js +90 -78
- package/test/jest.config.js +6 -0
- package/test/observability.test.js +6 -1
- 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
|
-
|
|
88
|
-
|
|
86
|
+
const object = callContext.object;
|
|
87
|
+
object[prop] = value;
|
|
88
|
+
return true;
|
|
89
89
|
},
|
|
90
90
|
|
|
91
91
|
get: function(callContext, methodName) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
-
|
|
246
|
+
if (type != "UserPassword" && type != "ImsServiceToken" && type != "SessionToken" && type != "SessionAndSecurityToken" &&
|
|
247
247
|
type != "AnonymousUser" && type != "SecurityToken" && type != "BearerToken" && type != "ImsBearerToken")
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
|
@@ -314,12 +314,12 @@ class Credentials {
|
|
|
314
314
|
*/
|
|
315
315
|
|
|
316
316
|
|
|
317
|
-
/**
|
|
317
|
+
/**
|
|
318
318
|
* @class
|
|
319
319
|
* @constructor
|
|
320
320
|
* @memberof Campaign
|
|
321
321
|
*/
|
|
322
|
-
class ConnectionParameters {
|
|
322
|
+
class ConnectionParameters {
|
|
323
323
|
|
|
324
324
|
/**
|
|
325
325
|
* Creates a connection parameters object which can be used to create a Client object
|
|
@@ -329,59 +329,59 @@ class ConnectionParameters {
|
|
|
329
329
|
* @param {Campaign.ConnectionOptions} options connection options
|
|
330
330
|
*/
|
|
331
331
|
constructor(endpoint, credentials, options) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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);
|
|
335
335
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
336
|
+
// Default value
|
|
337
|
+
if (options === undefined || options === null)
|
|
338
|
+
options = { };
|
|
339
339
|
// Before version 1.0.0, the 4th parameter could be a boolean for the 'rememberMe' option.
|
|
340
340
|
// Passing a boolean is not supported any more in 1.0.0. The Client constructor takes an
|
|
341
341
|
// option object. The rememberMe parameter can be passed directly to the logon function
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}
|
|
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];
|
|
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 */
|
|
380
372
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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;
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
/**
|
|
@@ -394,8 +394,8 @@ class ConnectionParameters {
|
|
|
394
394
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
395
395
|
*/
|
|
396
396
|
static ofUserAndPassword(endpoint, user, password, options) {
|
|
397
|
-
|
|
398
|
-
|
|
397
|
+
const credentials = new Credentials("UserPassword", `${user}/${password}`, "");
|
|
398
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
/**
|
|
@@ -412,8 +412,8 @@ class ConnectionParameters {
|
|
|
412
412
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
413
413
|
*/
|
|
414
414
|
static ofBearerToken(endpoint, bearerToken, options) {
|
|
415
|
-
|
|
416
|
-
|
|
415
|
+
const credentials = new Credentials("BearerToken", bearerToken);
|
|
416
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
417
417
|
}
|
|
418
418
|
|
|
419
419
|
/**
|
|
@@ -428,8 +428,8 @@ class ConnectionParameters {
|
|
|
428
428
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
429
429
|
*/
|
|
430
430
|
static ofImsBearerToken(endpoint, bearerToken, options) {
|
|
431
|
-
|
|
432
|
-
|
|
431
|
+
const credentials = new Credentials("ImsBearerToken", bearerToken);
|
|
432
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
433
433
|
}
|
|
434
434
|
|
|
435
435
|
/**
|
|
@@ -442,8 +442,8 @@ class ConnectionParameters {
|
|
|
442
442
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
443
443
|
*/
|
|
444
444
|
static ofUserAndServiceToken(endpoint, user, serviceToken, options) {
|
|
445
|
-
|
|
446
|
-
|
|
445
|
+
const credentials = new Credentials("ImsServiceToken", `_ims_/${user}/${serviceToken}`, "");
|
|
446
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
447
447
|
}
|
|
448
448
|
|
|
449
449
|
/**
|
|
@@ -456,8 +456,8 @@ class ConnectionParameters {
|
|
|
456
456
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
457
457
|
*/
|
|
458
458
|
static ofSessionToken(endpoint, sessionToken, options) {
|
|
459
|
-
|
|
460
|
-
|
|
459
|
+
const credentials = new Credentials("SessionToken", sessionToken, "");
|
|
460
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
/**
|
|
@@ -471,8 +471,8 @@ class ConnectionParameters {
|
|
|
471
471
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
472
472
|
*/
|
|
473
473
|
static ofSessionAndSecurityToken(endpoint, sessionToken, securityToken, options) {
|
|
474
|
-
|
|
475
|
-
|
|
474
|
+
const credentials = new Credentials("SessionAndSecurityToken", sessionToken, securityToken);
|
|
475
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
476
476
|
}
|
|
477
477
|
|
|
478
478
|
/**
|
|
@@ -488,8 +488,8 @@ class ConnectionParameters {
|
|
|
488
488
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
489
489
|
*/
|
|
490
490
|
static ofSecurityToken(endpoint, securityToken, options) {
|
|
491
|
-
|
|
492
|
-
|
|
491
|
+
const credentials = new Credentials("SecurityToken", "", securityToken);
|
|
492
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
493
493
|
}
|
|
494
494
|
|
|
495
495
|
/**
|
|
@@ -500,8 +500,8 @@ class ConnectionParameters {
|
|
|
500
500
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
501
501
|
*/
|
|
502
502
|
static ofAnonymousUser(endpoint, options) {
|
|
503
|
-
|
|
504
|
-
|
|
503
|
+
const credentials = new Credentials("AnonymousUser", "", "");
|
|
504
|
+
return new ConnectionParameters(endpoint, credentials, options);
|
|
505
505
|
}
|
|
506
506
|
|
|
507
507
|
|
|
@@ -515,58 +515,58 @@ class ConnectionParameters {
|
|
|
515
515
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
516
516
|
*/
|
|
517
517
|
static async ofExternalAccount(client, extAccountName) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
}
|
|
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);
|
|
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
|
+
]
|
|
552
537
|
}
|
|
553
|
-
|
|
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);
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
-
}
|
|
556
|
+
}
|
|
557
557
|
|
|
558
|
-
// ========================================================================================
|
|
559
|
-
// File Uploader
|
|
560
|
-
// ========================================================================================
|
|
558
|
+
// ========================================================================================
|
|
559
|
+
// File Uploader
|
|
560
|
+
// ========================================================================================
|
|
561
561
|
|
|
562
|
-
/**
|
|
562
|
+
/**
|
|
563
563
|
* @typedef {Object} FileUploadOptions
|
|
564
564
|
* @property {"publishIfNeeded"|"none"|undefined} the post-processing action to execute. Defaults to "publishIfNeeded"
|
|
565
565
|
* @memberOf Campaign
|
|
566
566
|
*/
|
|
567
567
|
|
|
568
568
|
|
|
569
|
-
/**
|
|
569
|
+
/**
|
|
570
570
|
* File Uploader API for JS SDK(Currently available only in browsers)
|
|
571
571
|
* @private
|
|
572
572
|
* @ignore
|
|
@@ -574,172 +574,174 @@ class ConnectionParameters {
|
|
|
574
574
|
* @param client
|
|
575
575
|
* @returns {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
|
|
576
576
|
*/
|
|
577
|
-
const fileUploader = (client) => {
|
|
577
|
+
const fileUploader = (client) => {
|
|
578
578
|
|
|
579
579
|
return {
|
|
580
|
-
|
|
580
|
+
/**
|
|
581
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.
|
|
582
582
|
* @ignore
|
|
583
583
|
* @param file, where file is an instance of [File](https://developer.mozilla.org/en-US/docs/Web/API/File)
|
|
584
584
|
* @param {FileUploadOptions|undefined} options
|
|
585
585
|
* @returns {Promise<{name: string, md5: string, type: string, size: string, url: string}>}
|
|
586
586
|
*/
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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' });
|
|
619
648
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
internalName,
|
|
655
|
-
md5: data[0].md5,
|
|
656
|
-
label: data[0].fileName,
|
|
657
|
-
fileName: data[0].fileName,
|
|
658
|
-
originalName: data[0].fileName,
|
|
659
|
-
useMd5AsFilename: '1',
|
|
660
|
-
storageType: 5,
|
|
661
|
-
xtkschema: 'xtk:fileRes',
|
|
662
|
-
};
|
|
663
|
-
await client.NLWS.xtkSession.write(fileRes);
|
|
664
|
-
await client.NLWS.xtkFileRes
|
|
665
|
-
.create(fileRes)
|
|
666
|
-
.publishIfNeeded();
|
|
667
|
-
const url = await client.NLWS.xtkFileRes
|
|
668
|
-
.create(fileRes)
|
|
669
|
-
.getURL();
|
|
670
|
-
result.url = url;
|
|
671
|
-
} catch (ex) {
|
|
672
|
-
reject(
|
|
673
|
-
CampaignException.FILE_UPLOAD_FAILED(
|
|
674
|
-
file.name,
|
|
675
|
-
ex
|
|
676
|
-
)
|
|
677
|
-
);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
resolve(result);
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
const html = `<body>${okay}</body>`;
|
|
684
|
-
document.body.appendChild(iframe);
|
|
685
|
-
iframe.contentWindow.document.open();
|
|
686
|
-
iframe.contentWindow.document.write(html);
|
|
687
|
-
iframe.contentWindow.document.close();
|
|
688
|
-
}).catch((ex) => {
|
|
689
|
-
reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
|
|
690
|
-
});
|
|
691
|
-
} catch (ex) {
|
|
692
|
-
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);
|
|
693
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));
|
|
694
692
|
});
|
|
695
|
-
|
|
693
|
+
} catch (ex) {
|
|
694
|
+
reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
},
|
|
696
698
|
|
|
697
|
-
|
|
699
|
+
/**
|
|
698
700
|
* Exposed method to call aemAssetDownload.jssp which will
|
|
699
701
|
* download the asset from AEM and upload it to Campaign.
|
|
700
702
|
*/
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
try {
|
|
707
|
-
// We need to pass the Authorization header to AEM to download the asset from AEM
|
|
708
|
-
// as well as authenticating campaign server.
|
|
709
|
-
// A user token having access to campaign as well as AEM is required
|
|
710
|
-
if(headers['Authorization'] === undefined || headers['Authorization'] === '' || headers['Authorization'] === 'null') {
|
|
711
|
-
throw 'Bearer token is missing';
|
|
712
|
-
}
|
|
713
|
-
// Serialize json data (required for fetch)
|
|
714
|
-
const jsonData = JSON.stringify({
|
|
715
|
-
'assetDownloadUrl': assetDownloadUrl
|
|
716
|
-
});
|
|
717
|
-
for (let h in client._connectionParameters._options.extraHttpHeaders)
|
|
718
|
-
headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
|
|
719
|
-
var response = await client._makeHttpCall({
|
|
720
|
-
url: url,
|
|
721
|
-
method: 'POST',
|
|
722
|
-
data: jsonData,
|
|
723
|
-
headers: headers
|
|
724
|
-
});
|
|
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';
|
|
725
707
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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
|
+
},
|
|
741
743
|
|
|
742
|
-
|
|
744
|
+
/**
|
|
743
745
|
* Exposed public method of the fileUploader api,
|
|
744
746
|
* specifically designed to download files from the 'upload' folder of the Campaign instance
|
|
745
747
|
* @param {string} md5 md5 of the file content
|
|
@@ -751,64 +753,64 @@ const fileUploader = (client) => {
|
|
|
751
753
|
* handle this file) expl : image/png, text/plain;charset=ISO-8859-1
|
|
752
754
|
* @returns {Promise<File(string)>}
|
|
753
755
|
*/
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
+
}
|
|
762
764
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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
|
+
}
|
|
770
772
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
+
try {
|
|
774
|
+
const fileName =
|
|
773
775
|
options && options.fileName ? options.fileName : md5;
|
|
774
|
-
|
|
776
|
+
const contentType =
|
|
775
777
|
options && options.contentType ? options.contentType : "";
|
|
776
778
|
|
|
777
|
-
|
|
779
|
+
let queryString = `md5=${encodeURIComponent(md5)}&ext=${encodeURIComponent(ext)}&fileName=${encodeURIComponent(fileName)}`;
|
|
778
780
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
781
|
+
if (contentType) {
|
|
782
|
+
queryString += `&contentType=${encodeURIComponent(contentType)}`;
|
|
783
|
+
}
|
|
782
784
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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
|
+
});
|
|
790
792
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
}
|
|
793
|
+
return rawFileResponse;
|
|
794
|
+
} catch (ex) {
|
|
795
|
+
throw CampaignException.FILE_DOWNLOAD_FAILED(md5, ex);
|
|
795
796
|
}
|
|
797
|
+
}
|
|
796
798
|
|
|
797
799
|
};
|
|
798
|
-
};
|
|
800
|
+
};
|
|
799
801
|
|
|
800
802
|
|
|
801
|
-
// ========================================================================================
|
|
802
|
-
// ACC Client
|
|
803
|
-
// ========================================================================================
|
|
803
|
+
// ========================================================================================
|
|
804
|
+
// ACC Client
|
|
805
|
+
// ========================================================================================
|
|
804
806
|
|
|
805
|
-
/**
|
|
807
|
+
/**
|
|
806
808
|
* @private
|
|
807
809
|
* @class
|
|
808
810
|
* @constructor
|
|
809
811
|
* @memberof Campaign
|
|
810
812
|
*/
|
|
811
|
-
class Client {
|
|
813
|
+
class Client {
|
|
812
814
|
|
|
813
815
|
/**
|
|
814
816
|
* ACC API Client.
|
|
@@ -818,11 +820,11 @@ class Client {
|
|
|
818
820
|
* @param {Campaign.ConnectionParameters} user user name, for instance admin
|
|
819
821
|
*/
|
|
820
822
|
constructor(sdk, connectionParameters) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
+
this.sdk = sdk;
|
|
824
|
+
this.reinit(connectionParameters);
|
|
823
825
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
+
this._observers = [];
|
|
827
|
+
this._cacheChangeListeners = [];
|
|
826
828
|
}
|
|
827
829
|
|
|
828
830
|
/**
|
|
@@ -833,91 +835,91 @@ class Client {
|
|
|
833
835
|
* @param {Campaign.ConnectionParameters} user user name, for instance admin
|
|
834
836
|
*/
|
|
835
837
|
reinit(connectionParameters) {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
}
|
|
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);
|
|
869
870
|
}
|
|
870
871
|
}
|
|
872
|
+
}
|
|
871
873
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
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());
|
|
878
880
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
881
|
+
this._transport = connectionParameters._options.transport;
|
|
882
|
+
this._traceAPICalls = connectionParameters._options.traceAPICalls;
|
|
883
|
+
this._refreshClient = connectionParameters._options.refreshClient;
|
|
882
884
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
+
// expose utilities
|
|
886
|
+
/**
|
|
885
887
|
* File Uploader API
|
|
886
888
|
* @type {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
|
|
887
889
|
*/
|
|
888
|
-
|
|
890
|
+
this.fileUploader = fileUploader(this);
|
|
889
891
|
|
|
890
|
-
|
|
892
|
+
/**
|
|
891
893
|
* Accessor to DOM helpers
|
|
892
894
|
* @type {XML.DomUtil}
|
|
893
895
|
*/
|
|
894
|
-
|
|
895
|
-
|
|
896
|
+
this.DomUtil = DomUtil;
|
|
897
|
+
/**
|
|
896
898
|
* Accessor to a XtkCaster
|
|
897
899
|
* @type {XtkCaster}
|
|
898
900
|
*/
|
|
899
|
-
|
|
900
|
-
|
|
901
|
+
this.XtkCaster = XtkCaster;
|
|
902
|
+
/**
|
|
901
903
|
* The application object. Only valid when logged
|
|
902
904
|
* @type {Campaign.Application}
|
|
903
905
|
*/
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
}
|
|
917
|
-
};
|
|
918
|
-
if (this._connectionParameters._credentials) {
|
|
919
|
-
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
|
|
920
918
|
}
|
|
919
|
+
};
|
|
920
|
+
if (this._connectionParameters._credentials) {
|
|
921
|
+
this._observabilityContext.client.type = this._connectionParameters._credentials.type;
|
|
922
|
+
}
|
|
921
923
|
}
|
|
922
924
|
|
|
923
925
|
/**
|
|
@@ -926,7 +928,7 @@ class Client {
|
|
|
926
928
|
* @param {*} transport
|
|
927
929
|
*/
|
|
928
930
|
setTransport(transport) {
|
|
929
|
-
|
|
931
|
+
this._transport = transport;
|
|
930
932
|
}
|
|
931
933
|
|
|
932
934
|
/**
|
|
@@ -935,8 +937,8 @@ class Client {
|
|
|
935
937
|
* @returns {string} the user agent string
|
|
936
938
|
*/
|
|
937
939
|
_getUserAgentString() {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
+
const version = this.sdk.getSDKVersion();
|
|
941
|
+
return `${version.name}/${version.version} ${version.description}`;
|
|
940
942
|
}
|
|
941
943
|
|
|
942
944
|
/**
|
|
@@ -945,18 +947,18 @@ class Client {
|
|
|
945
947
|
* @returns {Object} the headers
|
|
946
948
|
*/
|
|
947
949
|
_getAuthHeaders(setCookie) {
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
}
|
|
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;
|
|
958
959
|
}
|
|
959
|
-
|
|
960
|
+
}
|
|
961
|
+
return headers;
|
|
960
962
|
}
|
|
961
963
|
|
|
962
964
|
/**
|
|
@@ -968,12 +970,12 @@ class Client {
|
|
|
968
970
|
* @returns {XML.XtkObject} the object converted in the requested representation
|
|
969
971
|
*/
|
|
970
972
|
_toRepresentation(xml, representation) {
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
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");
|
|
977
979
|
}
|
|
978
980
|
|
|
979
981
|
/**
|
|
@@ -986,14 +988,14 @@ class Client {
|
|
|
986
988
|
* @returns {DOMElement} the object converted to XML
|
|
987
989
|
*/
|
|
988
990
|
_fromRepresentation(rootName, entity, representation) {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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");
|
|
997
999
|
}
|
|
998
1000
|
|
|
999
1001
|
/**
|
|
@@ -1006,12 +1008,12 @@ class Client {
|
|
|
1006
1008
|
* @returns {DOMElement} the converted object
|
|
1007
1009
|
*/
|
|
1008
1010
|
_convertToRepresentation(entity, fromRepresentation, toRepresentation) {
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
return entity;
|
|
1012
|
-
var xml = this._fromRepresentation("root", entity, fromRepresentation);
|
|
1013
|
-
entity = this._toRepresentation(xml, toRepresentation);
|
|
1011
|
+
toRepresentation = toRepresentation || this._representation;
|
|
1012
|
+
if (this._isSameRepresentation(fromRepresentation, toRepresentation))
|
|
1014
1013
|
return entity;
|
|
1014
|
+
var xml = this._fromRepresentation("root", entity, fromRepresentation);
|
|
1015
|
+
entity = this._toRepresentation(xml, toRepresentation);
|
|
1016
|
+
return entity;
|
|
1015
1017
|
}
|
|
1016
1018
|
|
|
1017
1019
|
/**
|
|
@@ -1023,11 +1025,11 @@ class Client {
|
|
|
1023
1025
|
* @returns a boolean indicating if the 2 representations are the same or not
|
|
1024
1026
|
*/
|
|
1025
1027
|
_isSameRepresentation(rep1, rep2) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
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;
|
|
1031
1033
|
}
|
|
1032
1034
|
|
|
1033
1035
|
/**
|
|
@@ -1036,7 +1038,7 @@ class Client {
|
|
|
1036
1038
|
* @param {boolean} trace indicates whether to activate tracing or not
|
|
1037
1039
|
*/
|
|
1038
1040
|
traceAPICalls(trace) {
|
|
1039
|
-
|
|
1041
|
+
this._traceAPICalls = !!trace;
|
|
1040
1042
|
}
|
|
1041
1043
|
|
|
1042
1044
|
/**
|
|
@@ -1044,7 +1046,7 @@ class Client {
|
|
|
1044
1046
|
* @param {Campaign.Observer} observer
|
|
1045
1047
|
*/
|
|
1046
1048
|
registerObserver(observer) {
|
|
1047
|
-
|
|
1049
|
+
this._observers.push(observer);
|
|
1048
1050
|
}
|
|
1049
1051
|
|
|
1050
1052
|
/**
|
|
@@ -1052,81 +1054,81 @@ class Client {
|
|
|
1052
1054
|
* @param {Campaign.Observer} observer
|
|
1053
1055
|
*/
|
|
1054
1056
|
unregisterObserver(observer) {
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
}
|
|
1057
|
+
for (var i=0; i<this._observers.length; i++) {
|
|
1058
|
+
if (this._observers[i] == observer) {
|
|
1059
|
+
this._observers.splice(i, 1);
|
|
1060
|
+
break;
|
|
1060
1061
|
}
|
|
1062
|
+
}
|
|
1061
1063
|
}
|
|
1062
1064
|
|
|
1063
1065
|
unregisterAllObservers() {
|
|
1064
|
-
|
|
1066
|
+
this._observers = [];
|
|
1065
1067
|
}
|
|
1066
1068
|
|
|
1067
1069
|
_notifyObservers(callback) {
|
|
1068
|
-
|
|
1070
|
+
this._observers.map((observer) => callback(observer));
|
|
1069
1071
|
}
|
|
1070
1072
|
|
|
1071
1073
|
_trackEvent(eventName, parentEvent, payload, pushDownOptions) {
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
// Regularly report internal stats every 5 mins
|
|
1100
|
-
if ((now - this._lastStatsReport) >= 300000) {
|
|
1101
|
-
this._lastStatsReport = now;
|
|
1102
|
-
this._trackInternalStats();
|
|
1103
|
-
}
|
|
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));
|
|
1104
1100
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1101
|
+
// Regularly report internal stats every 5 mins
|
|
1102
|
+
if ((now - this._lastStatsReport) >= 300000) {
|
|
1103
|
+
this._lastStatsReport = now;
|
|
1104
|
+
this._trackInternalStats();
|
|
1108
1105
|
}
|
|
1106
|
+
|
|
1107
|
+
return event;
|
|
1108
|
+
} catch (error) {
|
|
1109
|
+
console.info(`Failed to track observability event`, error);
|
|
1110
|
+
}
|
|
1109
1111
|
}
|
|
1110
1112
|
|
|
1111
1113
|
_trackInternalStats() {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1114
|
+
this._trackCacheStats('entityCache', this._entityCache);
|
|
1115
|
+
this._trackCacheStats('optionCache', this._optionCache);
|
|
1116
|
+
this._trackCacheStats('methodCache', this._methodCache);
|
|
1115
1117
|
}
|
|
1116
1118
|
|
|
1117
1119
|
_trackCacheStats(name, cache) {
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
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
|
+
});
|
|
1130
1132
|
}
|
|
1131
1133
|
|
|
1132
1134
|
/**
|
|
@@ -1135,36 +1137,36 @@ class Client {
|
|
|
1135
1137
|
* @returns {boolean} a boolean indicating if the client is logged or not
|
|
1136
1138
|
*/
|
|
1137
1139
|
isLogged() {
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
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
|
+
}
|
|
1148
1150
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
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 &&
|
|
1154
1156
|
this._sessionToken != null &&
|
|
1155
1157
|
this._sessionToken != "" &&
|
|
1156
1158
|
this._securityToken != undefined &&
|
|
1157
1159
|
this._securityToken != null &&
|
|
1158
1160
|
this._securityToken != "";
|
|
1159
1161
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
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 !== "";
|
|
1166
1168
|
|
|
1167
|
-
|
|
1169
|
+
return (!needsSecurityToken || hasSecurityToken) && (!needsSessionToken || hasSessionToken);
|
|
1168
1170
|
}
|
|
1169
1171
|
|
|
1170
1172
|
/**
|
|
@@ -1180,29 +1182,29 @@ class Client {
|
|
|
1180
1182
|
*/
|
|
1181
1183
|
_prepareSoapCall(urn, method, isStatic, internal, extraHttpHeaders, pushDownOptions) {
|
|
1182
1184
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
+
// Send request ID header if enableRequestIdHeader flag is set to true
|
|
1186
|
+
const enableRequestIdHeader = this._connectionParameters._options &&
|
|
1185
1187
|
this._connectionParameters._options.enableRequestIdHeader;
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
}
|
|
1188
|
+
let updatedExtraHttpHeaders = extraHttpHeaders;
|
|
1189
|
+
if (enableRequestIdHeader) {
|
|
1190
|
+
try {
|
|
1191
|
+
const requestId = Util.getUUID();
|
|
1192
|
+
updatedExtraHttpHeaders = Object.assign({}, extraHttpHeaders, {
|
|
1193
|
+
"x-request-id": requestId,
|
|
1194
|
+
});
|
|
1195
|
+
} catch (error) {
|
|
1196
|
+
console.error("Failed to generate request ID", error);
|
|
1196
1197
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
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;
|
|
1206
1208
|
}
|
|
1207
1209
|
|
|
1208
1210
|
/**
|
|
@@ -1213,35 +1215,35 @@ class Client {
|
|
|
1213
1215
|
* parameters should be set
|
|
1214
1216
|
*/
|
|
1215
1217
|
async _retrySoapCall(soapCall) {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
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);
|
|
1221
1238
|
if (this._traceAPICalls) {
|
|
1222
|
-
|
|
1239
|
+
console.log(`SOAP//response ${safeCallResponse}`);
|
|
1223
1240
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
retryCount: soapCall._retryCount,
|
|
1231
|
-
safeCallData: safeCallData,
|
|
1232
|
-
}, pushDownOptions);
|
|
1233
|
-
try {
|
|
1234
|
-
await soapCall.execute();
|
|
1235
|
-
const safeCallResponse = Util.trim(soapCall.response);
|
|
1236
|
-
if (this._traceAPICalls) {
|
|
1237
|
-
console.log(`SOAP//response ${safeCallResponse}`);
|
|
1238
|
-
}
|
|
1239
|
-
this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
|
|
1240
|
-
} catch(error) {
|
|
1241
|
-
this._trackEvent('SOAP//failure', event, error, pushDownOptions);
|
|
1242
|
-
throw error;
|
|
1243
|
-
}
|
|
1244
|
-
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;
|
|
1245
1247
|
}
|
|
1246
1248
|
|
|
1247
1249
|
/**
|
|
@@ -1251,7 +1253,7 @@ class Client {
|
|
|
1251
1253
|
* @return {string} soap call End point
|
|
1252
1254
|
*/
|
|
1253
1255
|
_soapEndPoint() {
|
|
1254
|
-
|
|
1256
|
+
return this._connectionParameters._endpoint + "/nl/jsp/soaprouter.jsp";
|
|
1255
1257
|
}
|
|
1256
1258
|
|
|
1257
1259
|
// Serializes parameters for a SOAP call
|
|
@@ -1259,88 +1261,88 @@ class Client {
|
|
|
1259
1261
|
// @param {DOMDocument} schema is the XML schema of the method call
|
|
1260
1262
|
// @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
|
|
1261
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
|
|
1262
|
-
// @param {string}
|
|
1264
|
+
// @param {string} representation is the representation to use to interpret the input parameters
|
|
1263
1265
|
async _writeSoapCallParameters(entitySchemaId, schema, soapCall, inputParameters, representation) {
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
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" ||
|
|
1311
1313
|
methodName == "SpawnWithParameters" || methodName == "SpawnWithParametersEx") )
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
}
|
|
1335
|
-
else
|
|
1336
|
-
soapCall.writeDocument(paramName, xmlValue);
|
|
1337
|
-
}
|
|
1338
|
-
else
|
|
1339
|
-
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);
|
|
1340
1336
|
}
|
|
1341
1337
|
else
|
|
1342
|
-
|
|
1338
|
+
soapCall.writeDocument(paramName, xmlValue);
|
|
1339
|
+
}
|
|
1340
|
+
else
|
|
1341
|
+
soapCall.writeElement(paramName, xmlValue);
|
|
1343
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
|
+
}
|
|
1344
1346
|
}
|
|
1345
1347
|
|
|
1346
1348
|
// Deserializes results for a SOAP call
|
|
@@ -1348,76 +1350,76 @@ class Client {
|
|
|
1348
1350
|
// @param {DOMDocument} schema is the XML schema of the method call
|
|
1349
1351
|
// @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
|
|
1350
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
|
|
1351
|
-
// @param {string}
|
|
1353
|
+
// @param {string} representation is the representation to use to interpret the parameters
|
|
1352
1354
|
async _readSoapCallResult(entitySchemaId, schema, soapCall, outputParameters, representation) {
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
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
|
|
1392
1409
|
returnValue = soapCall.getNextElement();
|
|
1393
1410
|
returnValue = this._toRepresentation(returnValue, representation);
|
|
1411
|
+
break;
|
|
1412
|
+
}
|
|
1413
|
+
element = DomUtil.getNextSiblingElement(element, "element");
|
|
1394
1414
|
}
|
|
1395
|
-
else {
|
|
1396
|
-
const schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
|
|
1397
|
-
// type can reference a schema element. The naming convension is that the type name
|
|
1398
|
-
// is {schemaName}{elementNameCamelCase}. For instance, the type "sessionUserInfo"
|
|
1399
|
-
// matches the "userInfo" element of the "xtkSession" schema
|
|
1400
|
-
let element;
|
|
1401
|
-
if (type.substr(0, schemaName.length) == schemaName) {
|
|
1402
|
-
const shortTypeName = type.substr(schemaName.length, 1).toLowerCase() + type.substr(schemaName.length + 1);
|
|
1403
|
-
element = DomUtil.getFirstChildElement(schema, "element");
|
|
1404
|
-
while (element) {
|
|
1405
|
-
if (element.getAttribute("name") == shortTypeName) {
|
|
1406
|
-
// Type found in schema: Process as a DOM element
|
|
1407
|
-
returnValue = soapCall.getNextElement();
|
|
1408
|
-
returnValue = this._toRepresentation(returnValue, representation);
|
|
1409
|
-
break;
|
|
1410
|
-
}
|
|
1411
|
-
element = DomUtil.getNextSiblingElement(element, "element");
|
|
1412
|
-
}
|
|
1413
1415
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
}
|
|
1418
|
-
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}'`);
|
|
1419
1419
|
}
|
|
1420
|
-
|
|
1420
|
+
op.value = returnValue;
|
|
1421
|
+
}
|
|
1422
|
+
soapCall.checkNoMoreArgs();
|
|
1421
1423
|
}
|
|
1422
1424
|
|
|
1423
1425
|
/**
|
|
@@ -1432,46 +1434,46 @@ class Client {
|
|
|
1432
1434
|
* @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
|
|
1433
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
|
|
1434
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
|
|
1435
|
-
* @param {string}
|
|
1437
|
+
* @param {string} representation is the representation to use to interpret the parameters
|
|
1436
1438
|
*/
|
|
1437
1439
|
async _makeInterceptableSoapCall(entitySchemaId, schema, soapCall, inputParams, outputParams, representation) {
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
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
|
+
}
|
|
1445
1447
|
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
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);
|
|
1450
1452
|
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
}
|
|
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] = [];
|
|
1466
1467
|
}
|
|
1468
|
+
}
|
|
1467
1469
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
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
|
+
}
|
|
1475
1477
|
}
|
|
1476
1478
|
|
|
1477
1479
|
/**
|
|
@@ -1482,233 +1484,233 @@ class Client {
|
|
|
1482
1484
|
* @param {SOAP.SoapMethodCall} soapCall the SOAP method to call
|
|
1483
1485
|
*/
|
|
1484
1486
|
_makeSoapCall(soapCall) {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
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
|
+
});
|
|
1525
1527
|
}
|
|
1526
1528
|
|
|
1527
1529
|
_onLogon() {
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
};
|
|
1543
|
-
}
|
|
1544
|
-
this._observabilityContext.session = {
|
|
1545
|
-
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,
|
|
1546
1544
|
};
|
|
1545
|
+
}
|
|
1546
|
+
this._observabilityContext.session = {
|
|
1547
|
+
logonAt: Date.now(),
|
|
1548
|
+
};
|
|
1547
1549
|
}
|
|
1548
1550
|
|
|
1549
1551
|
_onLogoff() {
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
+
delete this._observabilityContext.instance;
|
|
1553
|
+
delete this._observabilityContext.session;
|
|
1552
1554
|
}
|
|
1553
1555
|
|
|
1554
1556
|
_updateSessionInfo(sessionInfo, soapCall) {
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
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
|
+
}
|
|
1566
1568
|
}
|
|
1567
1569
|
|
|
1568
1570
|
async _fetchSessionInfo() {
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
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;
|
|
1598
1600
|
}
|
|
1599
1601
|
|
|
1600
1602
|
/**
|
|
1601
1603
|
* Login to an instance
|
|
1602
1604
|
*/
|
|
1603
1605
|
logon() {
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
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 : ""}`;
|
|
1623
1625
|
|
|
1624
|
-
|
|
1626
|
+
this._trackEvent('SDK//logon', undefined, {});
|
|
1625
1627
|
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
}
|
|
1662
|
-
return that._fetchSessionInfo().then((sessionInfo) => {
|
|
1663
|
-
that._updateSessionInfo(sessionInfo, undefined);
|
|
1664
|
-
that._onLogon();
|
|
1665
|
-
});
|
|
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();
|
|
1666
1663
|
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
return this._makeSoapCall(soapCall).then(function() {
|
|
1690
|
-
const sessionToken = soapCall.getNextString();
|
|
1691
|
-
const sessionInfo = soapCall.getNextDocument();
|
|
1692
|
-
that._updateSessionInfo(sessionInfo, soapCall);
|
|
1693
|
-
const securityToken = soapCall.getNextString();
|
|
1694
|
-
soapCall.checkNoMoreArgs();
|
|
1695
|
-
// Sanity check: we should have both a session token and a security token.
|
|
1696
|
-
if (!sessionToken)
|
|
1697
|
-
throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no session token was returned`);
|
|
1698
|
-
if (!securityToken)
|
|
1699
|
-
throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no security token was returned`);
|
|
1700
|
-
// store member variables after all parameters are decode the ensure atomicity
|
|
1701
|
-
that._sessionToken = sessionToken;
|
|
1702
|
-
that._securityToken = securityToken;
|
|
1703
|
-
that._bearerToken = undefined;
|
|
1704
|
-
|
|
1705
|
-
that._onLogon();
|
|
1706
|
-
});
|
|
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);
|
|
1707
1686
|
}
|
|
1708
1687
|
else {
|
|
1709
|
-
|
|
1710
|
-
|
|
1688
|
+
const bearerToken = credentials._bearerToken;
|
|
1689
|
+
soapCall.writeString("bearerToken", bearerToken);
|
|
1711
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
|
+
}
|
|
1712
1714
|
}
|
|
1713
1715
|
|
|
1714
1716
|
/**
|
|
@@ -1718,41 +1720,41 @@ class Client {
|
|
|
1718
1720
|
* @returns {Campaign.SessionInfo} details about the session
|
|
1719
1721
|
*/
|
|
1720
1722
|
getSessionInfo(representation) {
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
+
representation = representation || this._representation;
|
|
1724
|
+
return this._toRepresentation(this._sessionInfo, representation);
|
|
1723
1725
|
}
|
|
1724
1726
|
|
|
1725
1727
|
/**
|
|
1726
1728
|
* Logs off from an instance to which one previous logged on using the "logon" call
|
|
1727
1729
|
*/
|
|
1728
1730
|
logoff() {
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
}
|
|
1746
|
-
else {
|
|
1747
|
-
that._sessionToken = "";
|
|
1748
|
-
that._securityToken = "";
|
|
1749
|
-
that._bearerToken = undefined;
|
|
1750
|
-
that.application = null;
|
|
1751
|
-
}
|
|
1752
|
-
} finally {
|
|
1753
|
-
this._trackEvent('SDK//logoff', undefined, {});
|
|
1754
|
-
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
|
+
});
|
|
1755
1747
|
}
|
|
1748
|
+
else {
|
|
1749
|
+
that._sessionToken = "";
|
|
1750
|
+
that._securityToken = "";
|
|
1751
|
+
that._bearerToken = undefined;
|
|
1752
|
+
that.application = null;
|
|
1753
|
+
}
|
|
1754
|
+
} finally {
|
|
1755
|
+
this._trackEvent('SDK//logoff', undefined, {});
|
|
1756
|
+
this._onLogoff();
|
|
1757
|
+
}
|
|
1756
1758
|
}
|
|
1757
1759
|
|
|
1758
1760
|
/**
|
|
@@ -1783,59 +1785,59 @@ class Client {
|
|
|
1783
1785
|
* @param {string} description the optional description of the option
|
|
1784
1786
|
*/
|
|
1785
1787
|
async setOption(name, rawValue, description) {
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
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]);
|
|
1807
1809
|
}
|
|
1808
1810
|
|
|
1809
1811
|
/**
|
|
1810
1812
|
* Clears the options cache
|
|
1811
1813
|
*/
|
|
1812
1814
|
async clearOptionCache() {
|
|
1813
|
-
|
|
1815
|
+
await this._optionCache.clear();
|
|
1814
1816
|
}
|
|
1815
1817
|
|
|
1816
1818
|
/**
|
|
1817
1819
|
* Clears the method cache
|
|
1818
1820
|
*/
|
|
1819
1821
|
async clearMethodCache() {
|
|
1820
|
-
|
|
1822
|
+
await this._methodCache.clear();
|
|
1821
1823
|
}
|
|
1822
1824
|
|
|
1823
1825
|
/**
|
|
1824
1826
|
* Clears the entity cache
|
|
1825
1827
|
*/
|
|
1826
1828
|
async clearEntityCache() {
|
|
1827
|
-
|
|
1829
|
+
await this._entityCache.clear();
|
|
1828
1830
|
}
|
|
1829
1831
|
|
|
1830
1832
|
/**
|
|
1831
1833
|
* Clears all caches (options, methods, entities)
|
|
1832
1834
|
*/
|
|
1833
1835
|
async clearAllCaches() {
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1836
|
+
return Promise.all([
|
|
1837
|
+
this.clearEntityCache(),
|
|
1838
|
+
this.clearMethodCache(),
|
|
1839
|
+
this.clearOptionCache(),
|
|
1840
|
+
]);
|
|
1839
1841
|
}
|
|
1840
1842
|
|
|
1841
1843
|
/**
|
|
@@ -1843,43 +1845,43 @@ class Client {
|
|
|
1843
1845
|
* @param {integer} refreshFrequency refresh frequency in ms. 10000 ms by default.
|
|
1844
1846
|
*/
|
|
1845
1847
|
startRefreshCaches(refreshFrequency) {
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
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);
|
|
1851
1853
|
}
|
|
1852
1854
|
/**
|
|
1853
1855
|
* Stop auto refresh of all caches
|
|
1854
1856
|
*/
|
|
1855
1857
|
stopRefreshCaches() {
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
+
this._optionCacheRefresher.stopAutoRefresh();
|
|
1859
|
+
this._entityCacheRefresher.stopAutoRefresh();
|
|
1858
1860
|
}
|
|
1859
1861
|
|
|
1860
1862
|
// Register a callback to be called when a schema has been modified and should be removed
|
|
1861
1863
|
// from the caches
|
|
1862
1864
|
_registerCacheChangeListener(listener) {
|
|
1863
|
-
|
|
1865
|
+
this._cacheChangeListeners.push(listener);
|
|
1864
1866
|
}
|
|
1865
1867
|
|
|
1866
1868
|
// Unregister a cache change listener
|
|
1867
1869
|
_unregisterCacheChangeListener(listener) {
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
}
|
|
1870
|
+
for (var i = 0; i < this._cacheChangeListeners.length; i++) {
|
|
1871
|
+
if (this._cacheChangeListeners[i] == listener) {
|
|
1872
|
+
this._cacheChangeListeners.splice(i, 1);
|
|
1873
|
+
break;
|
|
1873
1874
|
}
|
|
1875
|
+
}
|
|
1874
1876
|
}
|
|
1875
1877
|
|
|
1876
1878
|
// Unregister all cache change listener
|
|
1877
1879
|
_unregisterAllCacheChangeListeners() {
|
|
1878
|
-
|
|
1880
|
+
this._cacheChangeListeners = [];
|
|
1879
1881
|
}
|
|
1880
1882
|
|
|
1881
1883
|
_notifyCacheChangeListeners(schemaId) {
|
|
1882
|
-
|
|
1884
|
+
this._cacheChangeListeners.map((listener) => listener.invalidateCacheItem(schemaId));
|
|
1883
1885
|
}
|
|
1884
1886
|
|
|
1885
1887
|
/**
|
|
@@ -1890,11 +1892,11 @@ class Client {
|
|
|
1890
1892
|
* @returns {boolean} a boolean indicating if the package is installed or not
|
|
1891
1893
|
*/
|
|
1892
1894
|
hasPackage(packageId, optionalName) {
|
|
1893
|
-
|
|
1895
|
+
if (optionalName !== undefined)
|
|
1894
1896
|
packageId = `${packageId}:${optionalName}`;
|
|
1895
|
-
|
|
1897
|
+
if (!this.isLogged())
|
|
1896
1898
|
throw CampaignException.NOT_LOGGED_IN(undefined, `Cannot call hasPackage: session not connected`);
|
|
1897
|
-
|
|
1899
|
+
return this._installedPackages[packageId] !== undefined;
|
|
1898
1900
|
}
|
|
1899
1901
|
|
|
1900
1902
|
/**
|
|
@@ -1905,12 +1907,12 @@ class Client {
|
|
|
1905
1907
|
* @deprecated since version 1.0.0
|
|
1906
1908
|
*/
|
|
1907
1909
|
async _getSecretKeyCipher() {
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
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
|
+
});
|
|
1914
1916
|
}
|
|
1915
1917
|
|
|
1916
1918
|
/**
|
|
@@ -1926,17 +1928,17 @@ class Client {
|
|
|
1926
1928
|
* @return {XML.XtkObject} A DOM or JSON representation of the entity, or null if the entity is not found
|
|
1927
1929
|
*/
|
|
1928
1930
|
async getEntityIfMoreRecent(entityType, fullName, representation, internal) {
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
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;
|
|
1940
1942
|
}
|
|
1941
1943
|
|
|
1942
1944
|
/**
|
|
@@ -1950,7 +1952,7 @@ class Client {
|
|
|
1950
1952
|
* @see {@link Campaign.XtkSchema}
|
|
1951
1953
|
*/
|
|
1952
1954
|
newSchema(xml) {
|
|
1953
|
-
|
|
1955
|
+
return newSchema(xml, this.application);
|
|
1954
1956
|
}
|
|
1955
1957
|
|
|
1956
1958
|
/**
|
|
@@ -1963,71 +1965,71 @@ class Client {
|
|
|
1963
1965
|
* @returns {XML.XtkObject} the schema definition, as either a DOM document or a JSON object
|
|
1964
1966
|
*/
|
|
1965
1967
|
async getSchema(schemaId, representation, internal, withoutCache = false) {
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
}
|
|
2006
|
-
} catch (ex) {
|
|
2007
|
-
if (ex.name == 'CampaignException' && ex.errorCode == 'SOP-330011') {
|
|
2008
|
-
entity = null;
|
|
2009
|
-
} else {
|
|
2010
|
-
throw ex;
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
} else {
|
|
2014
|
-
entity = await this.getEntityIfMoreRecent("xtk:schema", schemaId, "xml", internal);
|
|
2015
|
-
if (entity) {
|
|
2016
|
-
const impls = DomUtil.getAttributeAsString(entity, "implements");
|
|
2017
|
-
if (impls === "xtk:persist" && schemaId !== "xtk:session" && schemaId !== "xtk:persist") {
|
|
2018
|
-
// Ensure xtk:persist is present by loading the xtk:session schema
|
|
2019
|
-
const xtkSession = await this.getSchema("xtk:session", "xml", true);
|
|
2020
|
-
// it is possible that methodCache content has not be loaded in memory
|
|
2021
|
-
// so we re-put the methods
|
|
2022
|
-
await this._methodCache.put(xtkSession);
|
|
2023
|
-
}
|
|
2024
|
-
await this._entityCache.put("xtk:schema", schemaId, entity);
|
|
2025
|
-
await this._methodCache.put(entity);
|
|
2026
|
-
}
|
|
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;
|
|
2027
2007
|
}
|
|
2008
|
+
} catch (ex) {
|
|
2009
|
+
if (ex.name == 'CampaignException' && ex.errorCode == 'SOP-330011') {
|
|
2010
|
+
entity = null;
|
|
2011
|
+
} else {
|
|
2012
|
+
throw ex;
|
|
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
|
+
}
|
|
2028
2029
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2030
|
+
}
|
|
2031
|
+
entity = this._toRepresentation(entity, representation);
|
|
2032
|
+
return entity;
|
|
2031
2033
|
}
|
|
2032
2034
|
|
|
2033
2035
|
/**
|
|
@@ -2039,37 +2041,37 @@ class Client {
|
|
|
2039
2041
|
*/
|
|
2040
2042
|
async getSysEnum(enumName, optionalStartSchemaOrSchemaName) {
|
|
2041
2043
|
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
if (!optionalStartSchemaOrSchemaName || optionalStartSchemaOrSchemaName == "")
|
|
2053
|
-
throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum needs a schema id.`);
|
|
2054
|
-
|
|
2055
|
-
// If we have a schema name (and not a schema), then lookup the schema by name
|
|
2056
|
-
if (typeof optionalStartSchemaOrSchemaName == "string") {
|
|
2057
|
-
const index = optionalStartSchemaOrSchemaName.lastIndexOf(':');
|
|
2058
|
-
if (index == -1)
|
|
2059
|
-
throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name. '${optionalStartSchemaOrSchemaName}' is not a valid name.`);
|
|
2060
|
-
optionalStartSchemaOrSchemaName = await this.getSchema(optionalStartSchemaOrSchemaName, undefined, true);
|
|
2061
|
-
if (!optionalStartSchemaOrSchemaName)
|
|
2062
|
-
throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `Schema '${optionalStartSchemaOrSchemaName}' not found.`);
|
|
2063
|
-
}
|
|
2064
|
-
else
|
|
2065
|
-
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
|
+
}
|
|
2066
2053
|
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
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
|
+
}
|
|
2073
2075
|
}
|
|
2074
2076
|
|
|
2075
2077
|
/**
|
|
@@ -2082,127 +2084,127 @@ class Client {
|
|
|
2082
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
|
|
2083
2085
|
*/
|
|
2084
2086
|
async _callMethod(methodName, callContext, parameters) {
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
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) {
|
|
2150
2181
|
outputParams.push({
|
|
2151
|
-
|
|
2152
|
-
|
|
2182
|
+
name: paramName,
|
|
2183
|
+
type: type,
|
|
2153
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");
|
|
2154
2190
|
}
|
|
2191
|
+
}
|
|
2155
2192
|
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
const params = DomUtil.getFirstChildElement(method, "parameters");
|
|
2159
|
-
if (params) {
|
|
2160
|
-
var param = DomUtil.getFirstChildElement(params, "param");
|
|
2161
|
-
var paramIndex = 0;
|
|
2162
|
-
while (param) {
|
|
2163
|
-
const inout = DomUtil.getAttributeAsString(param, "inout");
|
|
2164
|
-
const type = DomUtil.getAttributeAsString(param, "type");
|
|
2165
|
-
const paramName = DomUtil.getAttributeAsString(param, "name");
|
|
2166
|
-
const isIn = !inout || inout=="in" || inout=="inout";
|
|
2167
|
-
const isOut = inout=="out" || inout=="inout";
|
|
2168
|
-
if (isIn) {
|
|
2169
|
-
let paramValue = parametersIsArray ? parameters[paramIndex] : parameters;
|
|
2170
|
-
const inputParam = {
|
|
2171
|
-
name: paramName,
|
|
2172
|
-
type: type,
|
|
2173
|
-
value: paramValue
|
|
2174
|
-
};
|
|
2175
|
-
inputParams.push(inputParam);
|
|
2176
|
-
paramIndex = paramIndex + 1;
|
|
2177
|
-
}
|
|
2178
|
-
if (isOut) {
|
|
2179
|
-
outputParams.push({
|
|
2180
|
-
name: paramName,
|
|
2181
|
-
type: type,
|
|
2182
|
-
});
|
|
2183
|
-
}
|
|
2184
|
-
if( !isIn && !isOut) {
|
|
2185
|
-
throw CampaignException.BAD_PARAMETER("inout", inout, `Parameter '${paramName}' of schema '${entitySchemaId}' is not correctly defined as an input or output parameter`);
|
|
2186
|
-
}
|
|
2187
|
-
param = DomUtil.getNextSiblingElement(param, "param");
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
|
-
// Make the SOAP call
|
|
2192
|
-
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);
|
|
2193
2195
|
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
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;
|
|
2206
2208
|
}
|
|
2207
2209
|
|
|
2208
2210
|
/**
|
|
@@ -2220,48 +2222,48 @@ class Client {
|
|
|
2220
2222
|
* In addition, the outputParams array will be modified, and the "value" property of each output param will be set
|
|
2221
2223
|
*/
|
|
2222
2224
|
async makeSoapCall(urn, methodName, isStatic, inputParams, outputParams, representation) {
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
+
const soapCall = this._prepareSoapCall(urn, methodName, isStatic, false,
|
|
2226
|
+
this._connectionParameters._options.extraHttpHeaders);
|
|
2225
2227
|
// To support anonymous SOAP calls, we need to disable the logon check
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
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;
|
|
2230
2232
|
}
|
|
2231
2233
|
|
|
2232
2234
|
async _makeHttpCall(request) {
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
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
|
+
}
|
|
2265
2267
|
}
|
|
2266
2268
|
|
|
2267
2269
|
/**
|
|
@@ -2271,16 +2273,16 @@ class Client {
|
|
|
2271
2273
|
* @returns {Campaign.RedirStatus} an object describing the status of the redirection server
|
|
2272
2274
|
*/
|
|
2273
2275
|
async test() {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
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;
|
|
2284
2286
|
}
|
|
2285
2287
|
|
|
2286
2288
|
/**
|
|
@@ -2289,26 +2291,26 @@ class Client {
|
|
|
2289
2291
|
* @returns {Campaign.PingStatus} an object describing the server status
|
|
2290
2292
|
*/
|
|
2291
2293
|
async ping() {
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
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;
|
|
2312
2314
|
}
|
|
2313
2315
|
|
|
2314
2316
|
/**
|
|
@@ -2319,33 +2321,33 @@ class Client {
|
|
|
2319
2321
|
* @returns {Campaign.ReportContext} an object containing the context data for a specific report
|
|
2320
2322
|
*/
|
|
2321
2323
|
async getReportData(callContext, representation) {
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
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;
|
|
2328
2330
|
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
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
|
+
};
|
|
2337
2339
|
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
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
|
+
}
|
|
2349
2351
|
}
|
|
2350
2352
|
|
|
2351
2353
|
/**
|
|
@@ -2355,52 +2357,52 @@ class Client {
|
|
|
2355
2357
|
* @returns {Campaign.McPingStatus} an object describing Message Center server status
|
|
2356
2358
|
*/
|
|
2357
2359
|
async mcPing() {
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
}
|
|
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);
|
|
2384
2385
|
}
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
if (lines.length > 2) {
|
|
2391
|
-
const queue = lines[2];
|
|
2392
|
-
const index2 = queue.indexOf('/');
|
|
2393
|
-
const index3 = queue.indexOf(' pending events');
|
|
2394
|
-
if (index2 != -1 && index3 != -1) {
|
|
2395
|
-
rtCount = queue.substring(0, index2);
|
|
2396
|
-
threshold = queue.substring(index2+1, index3);
|
|
2397
|
-
}
|
|
2398
|
-
}
|
|
2386
|
+
}
|
|
2387
|
+
else {
|
|
2388
|
+
if (lines.length > 1) {
|
|
2389
|
+
const timestamp = lines[1].trim();
|
|
2390
|
+
if (timestamp != "") root.setAttribute("timestamp", timestamp);
|
|
2399
2391
|
}
|
|
2400
|
-
if (
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
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;
|
|
2404
2406
|
}
|
|
2405
2407
|
|
|
2406
2408
|
/**
|
|
@@ -2409,7 +2411,7 @@ class Client {
|
|
|
2409
2411
|
* @returns {Campaign.XtkJobInterface} a job
|
|
2410
2412
|
*/
|
|
2411
2413
|
jobInterface(soapCallSpec) {
|
|
2412
|
-
|
|
2414
|
+
return new XtkJobInterface(this, soapCallSpec);
|
|
2413
2415
|
}
|
|
2414
2416
|
|
|
2415
2417
|
// Calls the beforeSoapCall method on all observers which have this method. Ignore any exception
|
|
@@ -2419,17 +2421,17 @@ class Client {
|
|
|
2419
2421
|
// @param {Array<*>} inputParameters is an array containing the method parameters
|
|
2420
2422
|
// @param {string} representation is the representation (SimpleJson, xml, etc.) used for this method and in which the object and parameters are set
|
|
2421
2423
|
async _beforeSoapCall(method, inputParameters, representation) {
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
}
|
|
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
|
+
}
|
|
2432
2433
|
}
|
|
2434
|
+
}
|
|
2433
2435
|
}
|
|
2434
2436
|
|
|
2435
2437
|
// Calls the afterSoapCall method on all observers which have this method. Ignore any exception
|
|
@@ -2440,25 +2442,25 @@ class Client {
|
|
|
2440
2442
|
// @param {string} representation is the representation (SimpleJson, xml, etc.) used for this method and in which the object and parameters are set
|
|
2441
2443
|
// @param {Array<*>} outputParameters an array (possibly) empty of the values returned by the SOAP call
|
|
2442
2444
|
async _afterSoapCall(method, inputParameters, representation, outputParameters) {
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
}
|
|
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
|
+
}
|
|
2453
2454
|
}
|
|
2455
|
+
}
|
|
2454
2456
|
}
|
|
2455
|
-
}
|
|
2457
|
+
}
|
|
2456
2458
|
|
|
2457
2459
|
|
|
2458
|
-
// Public exports
|
|
2459
|
-
Client.CampaignException = CampaignException;
|
|
2460
|
-
exports.Client = Client;
|
|
2461
|
-
exports.Credentials = Credentials;
|
|
2462
|
-
exports.ConnectionParameters = ConnectionParameters;
|
|
2460
|
+
// Public exports
|
|
2461
|
+
Client.CampaignException = CampaignException;
|
|
2462
|
+
exports.Client = Client;
|
|
2463
|
+
exports.Credentials = Credentials;
|
|
2464
|
+
exports.ConnectionParameters = ConnectionParameters;
|
|
2463
2465
|
|
|
2464
2466
|
})();
|