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