@adobe/acc-js-sdk 1.1.19 → 1.1.20
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/docs/caches.html +26 -1
- package/docs/changeLog.html +20 -0
- package/package-lock.json +4 -4
- package/package.json +1 -1
- package/src/cache.js +41 -30
- package/src/cacheRefresher.js +31 -31
- package/src/client.js +42 -33
- package/src/methodCache.js +9 -9
- package/src/optionCache.js +7 -7
- package/src/util.js +17 -0
- package/src/xtkEntityCache.js +5 -5
- package/test/cacheRefresher.test.js +29 -29
- package/test/caches.test.js +151 -123
- package/test/client.test.js +55 -8
- package/test/observability.test.js +2 -2
- package/test/util.test.js +58 -37
package/docs/caches.html
CHANGED
|
@@ -43,10 +43,35 @@ client.clearAllCaches();
|
|
|
43
43
|
<p>It's possible to disable persistent caches using the <b>noStorage</b> connection option.</p>
|
|
44
44
|
|
|
45
45
|
<p>It is also possible to setup one's own persistent cache, by passing a <b>storage</b> object as a connection option.
|
|
46
|
-
|
|
46
|
+
See the "Custom Storage" section below for more details.</p>
|
|
47
47
|
|
|
48
48
|
<p>Additionally, since version 1.1.18, the <b>storage</b> object should also support the for...in operator to iterate through its keys</p>
|
|
49
49
|
|
|
50
|
+
|
|
51
|
+
<h1>Cache root key</h1>
|
|
52
|
+
|
|
53
|
+
<p>
|
|
54
|
+
By default, the SDK will prefix all cache entity by a root key, which is made of the SDK version and the instance URL.
|
|
55
|
+
It is possible to change this using the `cacheRootKey` connection parameter.
|
|
56
|
+
</p>
|
|
57
|
+
<ul>
|
|
58
|
+
<li>* `default` or undefined: default prefix</li>
|
|
59
|
+
<li>* `none`: no prefix</li>
|
|
60
|
+
</ul>
|
|
61
|
+
|
|
62
|
+
<h1>Custom storage</h1>
|
|
63
|
+
|
|
64
|
+
A custom storage is a JavaScript object with the following functions:
|
|
65
|
+
* `getItem` is given a cache key and should return the corresponding value
|
|
66
|
+
* `setItem` is given a cache key and value and should cache the corresponding key/value pair
|
|
67
|
+
|
|
68
|
+
Optionally, the storage object can contain the following
|
|
69
|
+
* `removeItem` is given a cache key and should remove the corresponding key/value pair from the cache
|
|
70
|
+
* The storage object should also be iterable using the for..in construct
|
|
71
|
+
|
|
72
|
+
The get/set/remove item function can be either synchronous or asynchronous, i.e. can optionally return a promise.
|
|
73
|
+
|
|
74
|
+
|
|
50
75
|
<h1>Auto-refresh caches</h1>
|
|
51
76
|
|
|
52
77
|
<p>The SDK includes a mechnism to maintain the schemas and options caches up-to-date by polling the Campaign server on a
|
package/docs/changeLog.html
CHANGED
|
@@ -3,6 +3,26 @@ layout: page
|
|
|
3
3
|
title: Change Log
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
<section class="changelog"><h1>Version 1.1.20</h1>
|
|
7
|
+
<h2>2023/01/11</h2>
|
|
8
|
+
|
|
9
|
+
<li>
|
|
10
|
+
Upgrade json5 dependency from 2.2.1 to 2.2.3 to fix a vulnerability
|
|
11
|
+
</li>
|
|
12
|
+
|
|
13
|
+
<li>
|
|
14
|
+
Add support for asynchronous caches. The signature of cache objects (Cache, MethodCache,
|
|
15
|
+
OptionCache, XtkEntityCache, SafeStorage) have changed to asynchronous functions.
|
|
16
|
+
However, the delegate object used to configure custom caches now support either synchronous
|
|
17
|
+
or async results. See the <a href="https://opensource.adobe.com/acc-js-sdk/caches.html">Cache documentation for more details</a>
|
|
18
|
+
</li>
|
|
19
|
+
<li>
|
|
20
|
+
Ability to configure the prefix to use for the cached objects. Default to a string containing
|
|
21
|
+
the SDK version and instance domain.
|
|
22
|
+
</li>
|
|
23
|
+
</section>
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
<section class="changelog"><h1>Version 1.1.19</h1>
|
|
7
27
|
<h2>2022/12/21</h2>
|
|
8
28
|
|
package/package-lock.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/acc-js-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.20",
|
|
4
4
|
"lockfileVersion": 1,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"dependencies": {
|
|
@@ -2876,9 +2876,9 @@
|
|
|
2876
2876
|
"dev": true
|
|
2877
2877
|
},
|
|
2878
2878
|
"json5": {
|
|
2879
|
-
"version": "2.2.
|
|
2880
|
-
"resolved": "https://
|
|
2881
|
-
"integrity": "sha512-
|
|
2879
|
+
"version": "2.2.3",
|
|
2880
|
+
"resolved": "https://artifactory.corp.adobe.com/artifactory/api/npm/npm-adobe-release/json5/-/json5-2.2.3.tgz",
|
|
2881
|
+
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
|
2882
2882
|
"dev": true
|
|
2883
2883
|
},
|
|
2884
2884
|
"klaw": {
|
package/package.json
CHANGED
package/src/cache.js
CHANGED
|
@@ -12,6 +12,8 @@ governing permissions and limitations under the License.
|
|
|
12
12
|
(function() {
|
|
13
13
|
"use strict";
|
|
14
14
|
|
|
15
|
+
const { Util } = require("./util");
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
/**********************************************************************************
|
|
17
19
|
*
|
|
@@ -78,11 +80,11 @@ class SafeStorage {
|
|
|
78
80
|
* @returns {Utils.CachedObject} the cached object, or undefined if not found.
|
|
79
81
|
* The storage serDeser fucntion will be used to deserialize the cached value
|
|
80
82
|
*/
|
|
81
|
-
getItem(key) {
|
|
83
|
+
async getItem(key) {
|
|
82
84
|
if (!this._delegate || this._rootKey === undefined || this._rootKey === null)
|
|
83
85
|
return;
|
|
84
86
|
const itemKey = `${this._rootKey}${key}`;
|
|
85
|
-
const raw = this._delegate.getItem(itemKey);
|
|
87
|
+
const raw = await Util.asPromise(this._delegate.getItem(itemKey));
|
|
86
88
|
if (!raw)
|
|
87
89
|
return undefined;
|
|
88
90
|
try {
|
|
@@ -98,28 +100,28 @@ class SafeStorage {
|
|
|
98
100
|
* @param {Utils.CachedObject} json the object to cache
|
|
99
101
|
* The storage serDeser fucntion will be used to serialize the cached value
|
|
100
102
|
*/
|
|
101
|
-
|
|
103
|
+
async setItem(key, json) {
|
|
102
104
|
if (!this._delegate || this._rootKey === undefined || this._rootKey === null)
|
|
103
105
|
return;
|
|
104
106
|
try {
|
|
105
107
|
//if (json && typeof json === "object") {
|
|
106
108
|
const raw = this._serDeser(json, true);
|
|
107
|
-
this._delegate.setItem(`${this._rootKey}${key}`, raw);
|
|
109
|
+
await Util.asPromise(this._delegate.setItem(`${this._rootKey}${key}`, raw));
|
|
108
110
|
return;
|
|
109
111
|
} catch(ex) { /* Ignore errors in safe class */
|
|
112
|
+
await this.removeItem(key);
|
|
110
113
|
}
|
|
111
|
-
this.removeItem(key);
|
|
112
114
|
}
|
|
113
115
|
|
|
114
116
|
/**
|
|
115
117
|
* Removes an item from the storage
|
|
116
118
|
* @param {string} key the item key (relative to the root key)
|
|
117
119
|
*/
|
|
118
|
-
removeItem(key) {
|
|
120
|
+
async removeItem(key) {
|
|
119
121
|
if (!this._delegate || this._rootKey === undefined || this._rootKey === null)
|
|
120
122
|
return;
|
|
121
123
|
try {
|
|
122
|
-
this._delegate.removeItem(`${this._rootKey}${key}`);
|
|
124
|
+
await this._delegate.removeItem(`${this._rootKey}${key}`);
|
|
123
125
|
} catch(ex) { /* Ignore errors in safe class */
|
|
124
126
|
}
|
|
125
127
|
}
|
|
@@ -178,7 +180,12 @@ class Cache {
|
|
|
178
180
|
this._makeKeyFn = makeKeyFn || ((x) => x);
|
|
179
181
|
this._cache = {};
|
|
180
182
|
// timestamp at which the cache was last cleared
|
|
181
|
-
|
|
183
|
+
// The variable is set with special "null" value to indicate that the
|
|
184
|
+
// timestamp at which the cache was clear is not known, and therefore
|
|
185
|
+
// needs to be fetched. It will be fetched dynamically when needed,
|
|
186
|
+
// resulting in either an undefined value (cache was never cleared)
|
|
187
|
+
// or a actual timestamp.
|
|
188
|
+
this._lastCleared = null;
|
|
182
189
|
this._stats = {
|
|
183
190
|
reads: 0,
|
|
184
191
|
writes: 0,
|
|
@@ -192,53 +199,57 @@ class Cache {
|
|
|
192
199
|
}
|
|
193
200
|
|
|
194
201
|
// Load timestamp at which the cache was last cleared
|
|
195
|
-
_loadLastCleared() {
|
|
196
|
-
const json = this._storage.getItem("lastCleared");
|
|
202
|
+
async _loadLastCleared() {
|
|
203
|
+
const json = await this._storage.getItem("lastCleared");
|
|
197
204
|
return json ? json.timestamp : undefined;
|
|
198
205
|
}
|
|
199
206
|
|
|
200
|
-
_saveLastCleared() {
|
|
207
|
+
async _saveLastCleared() {
|
|
201
208
|
const now = Date.now();
|
|
202
209
|
this._lastCleared = now;
|
|
203
|
-
this._storage.setItem("lastCleared", { timestamp: now});
|
|
210
|
+
await this._storage.setItem("lastCleared", { timestamp: now});
|
|
204
211
|
}
|
|
205
212
|
|
|
206
213
|
// Load from local storage
|
|
207
|
-
_load(key) {
|
|
214
|
+
async _load(key) {
|
|
208
215
|
this._stats.loads = this._stats.loads + 1;
|
|
209
|
-
|
|
216
|
+
// A null value here indicates that we have not yet loaded the
|
|
217
|
+
// timestamp at which the cache was cleared last
|
|
218
|
+
if (this._lastCleared === null)
|
|
219
|
+
this._lastCleared = await this._loadLastCleared();
|
|
220
|
+
const json = await this._storage.getItem(key);
|
|
210
221
|
if (!json || !json.cachedAt || json.cachedAt <= this._lastCleared) {
|
|
211
|
-
this._storage.removeItem(key);
|
|
222
|
+
await this._storage.removeItem(key);
|
|
212
223
|
return;
|
|
213
224
|
}
|
|
214
225
|
return json;
|
|
215
226
|
}
|
|
216
227
|
|
|
217
228
|
// Save to local storage
|
|
218
|
-
_save(key, cached) {
|
|
229
|
+
async _save(key, cached) {
|
|
219
230
|
this._stats.saves = this._stats.saves + 1;
|
|
220
|
-
this._storage.setItem(key, cached);
|
|
231
|
+
await this._storage.setItem(key, cached);
|
|
221
232
|
}
|
|
222
233
|
|
|
223
234
|
// Remove from local storage
|
|
224
|
-
_remove(key) {
|
|
225
|
-
this._storage.removeItem(key);
|
|
235
|
+
async _remove(key) {
|
|
236
|
+
await this._storage.removeItem(key);
|
|
226
237
|
}
|
|
227
238
|
|
|
228
|
-
_getIfActive(key) {
|
|
239
|
+
async _getIfActive(key) {
|
|
229
240
|
// In memory cache?
|
|
230
241
|
var cached = this._cache[key];
|
|
231
242
|
var memoryHit = !!cached;
|
|
232
243
|
// Local storage ?
|
|
233
244
|
if (!cached) {
|
|
234
|
-
cached = this._load(key);
|
|
245
|
+
cached = await this._load(key);
|
|
235
246
|
this._cache[key] = cached;
|
|
236
247
|
}
|
|
237
248
|
if (!cached)
|
|
238
249
|
return undefined;
|
|
239
250
|
if (cached.expiresAt <= Date.now()) {
|
|
240
251
|
delete this._cache[key];
|
|
241
|
-
this._remove(key);
|
|
252
|
+
await this._remove(key);
|
|
242
253
|
return undefined;
|
|
243
254
|
}
|
|
244
255
|
this._stats.memoryHits = this._stats.memoryHits + 1;
|
|
@@ -251,10 +262,10 @@ class Cache {
|
|
|
251
262
|
* @param {*} key the key or keys of the value to retreive
|
|
252
263
|
* @returns {*} the cached value, or undefined if not found
|
|
253
264
|
*/
|
|
254
|
-
get() {
|
|
265
|
+
async get() {
|
|
255
266
|
this._stats.reads = this._stats.reads + 1;
|
|
256
267
|
const key = this._makeKeyFn.apply(this, arguments);
|
|
257
|
-
const cached = this._getIfActive(key);
|
|
268
|
+
const cached = await this._getIfActive(key);
|
|
258
269
|
return cached;
|
|
259
270
|
}
|
|
260
271
|
|
|
@@ -264,7 +275,7 @@ class Cache {
|
|
|
264
275
|
* @param {*} value the value to cache
|
|
265
276
|
* @returns {CachedObject} a cached object containing the cached value
|
|
266
277
|
*/
|
|
267
|
-
put() {
|
|
278
|
+
async put() {
|
|
268
279
|
this._stats.writes = this._stats.writes + 1;
|
|
269
280
|
const value = arguments[arguments.length -1];
|
|
270
281
|
const key = this._makeKeyFn.apply(this, arguments);
|
|
@@ -272,7 +283,7 @@ class Cache {
|
|
|
272
283
|
const expiresAt = now + this._ttl;
|
|
273
284
|
const cached = new CachedObject(value, now, expiresAt);
|
|
274
285
|
this._cache[key] = cached;
|
|
275
|
-
this._save(key, cached);
|
|
286
|
+
await this._save(key, cached);
|
|
276
287
|
return cached;
|
|
277
288
|
}
|
|
278
289
|
|
|
@@ -280,20 +291,20 @@ class Cache {
|
|
|
280
291
|
* Removes everything from the cache. It does not directly removes data from persistent storage if there is, but it marks the cache
|
|
281
292
|
* as cleared so that subsequent get operation will not actually return any data cached in persistent storage
|
|
282
293
|
*/
|
|
283
|
-
clear() {
|
|
294
|
+
async clear() {
|
|
284
295
|
this._stats.clears = this._stats.clears + 1;
|
|
285
296
|
this._cache = {};
|
|
286
|
-
this._saveLastCleared();
|
|
297
|
+
await this._saveLastCleared();
|
|
287
298
|
}
|
|
288
299
|
|
|
289
300
|
/**
|
|
290
301
|
* Remove a key from the cache
|
|
291
302
|
* @param {string} key the key to remove
|
|
292
303
|
*/
|
|
293
|
-
remove(key) {
|
|
304
|
+
async remove(key) {
|
|
294
305
|
this._stats.removals = this._stats.removals + 1;
|
|
295
306
|
delete this._cache[key];
|
|
296
|
-
this._remove(key);
|
|
307
|
+
await this._remove(key);
|
|
297
308
|
}
|
|
298
309
|
}
|
|
299
310
|
|
package/src/cacheRefresher.js
CHANGED
|
@@ -47,7 +47,7 @@ governing permissions and limitations under the License.
|
|
|
47
47
|
* @param {string} name is the propertie name
|
|
48
48
|
* @param {string} rawValue string value
|
|
49
49
|
*/
|
|
50
|
-
put(name, rawValue) {
|
|
50
|
+
async put(name, rawValue) {
|
|
51
51
|
return super.put(name, { value: rawValue });
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -57,8 +57,8 @@ governing permissions and limitations under the License.
|
|
|
57
57
|
* @param {string} name the propertie name
|
|
58
58
|
* @returns {*} the value
|
|
59
59
|
*/
|
|
60
|
-
get(name) {
|
|
61
|
-
const option = super.get(name);
|
|
60
|
+
async get(name) {
|
|
61
|
+
const option = await super.get(name);
|
|
62
62
|
return option ? option.value : undefined;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -149,13 +149,13 @@ governing permissions and limitations under the License.
|
|
|
149
149
|
const soapCall = this._client._prepareSoapCall("xtk:session", "GetModifiedEntities", true, true, this._connectionParameters._options.extraHttpHeaders);
|
|
150
150
|
|
|
151
151
|
if (this._lastTime === undefined) {
|
|
152
|
-
const storedTime = this._refresherStateCache.get("time");
|
|
152
|
+
const storedTime = await this._refresherStateCache.get("time");
|
|
153
153
|
if (storedTime != undefined) {
|
|
154
154
|
this._lastTime = storedTime;
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
if (this._buildNumber === undefined) {
|
|
158
|
-
const storedBuildNumber = this._refresherStateCache.get("buildNumber");
|
|
158
|
+
const storedBuildNumber = await this._refresherStateCache.get("buildNumber");
|
|
159
159
|
if (storedBuildNumber != undefined) {
|
|
160
160
|
this._buildNumber = storedBuildNumber;
|
|
161
161
|
}
|
|
@@ -192,37 +192,37 @@ governing permissions and limitations under the License.
|
|
|
192
192
|
// Do a soap call GetModifiedEntities instead of xtksession.GetModifiedEnties because we don't want to go through methodCache
|
|
193
193
|
// which might not contain the method GetModifiedEntities just after a build updgrade from a old version of acc
|
|
194
194
|
// This is an internal SOAP call that cannot be intercepted by observers onBeforeCall / onAfterCall
|
|
195
|
-
|
|
196
|
-
.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
195
|
+
try {
|
|
196
|
+
await this._client._makeSoapCall(soapCall);
|
|
197
|
+
let doc = soapCall.getNextDocument();
|
|
198
|
+
soapCall.checkNoMoreArgs();
|
|
199
|
+
doc = that._client._toRepresentation(doc, 'xml');
|
|
200
|
+
that._lastTime = DomUtil.getAttributeAsString(doc, "time"); // save time to be able to send it as an attribute in the next soap call
|
|
201
|
+
that._buildNumber = DomUtil.getAttributeAsString(doc, "buildNumber");
|
|
202
|
+
await that._refresh(doc, event);
|
|
203
|
+
await that._refresherStateCache.put("time", that._lastTime);
|
|
204
|
+
await that._refresherStateCache.put("buildNumber", that._buildNumber);
|
|
205
|
+
}
|
|
206
|
+
catch(ex) {
|
|
207
|
+
// if the method GetModifiedEntities is not found in this acc version we disable the autoresfresh of the cache
|
|
208
|
+
if (soapCall.methodName == "GetModifiedEntities" && ex.errorCode == "SOP-330006") {
|
|
209
|
+
this._client._trackEvent('CACHE_REFRESHER//abort', undefined, {
|
|
210
|
+
cacheSchemaId: this._cacheSchemaId,
|
|
211
|
+
error: ex,
|
|
212
|
+
});
|
|
213
|
+
this.stopAutoRefresh();
|
|
214
|
+
} else {
|
|
215
|
+
throw ex;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
// Refresh Cache : remove entities modified recently listed in xmlDoc
|
|
221
|
-
_refresh(xmlDoc, event) {
|
|
221
|
+
async _refresh(xmlDoc, event) {
|
|
222
222
|
const clearCache = XtkCaster.asBoolean(DomUtil.getAttributeAsString(xmlDoc, "emptyCache"));
|
|
223
223
|
const evicted = [];
|
|
224
224
|
if (clearCache == true) {
|
|
225
|
-
this._cache.clear();
|
|
225
|
+
await this._cache.clear();
|
|
226
226
|
} else {
|
|
227
227
|
var child = DomUtil.getFirstChildElement(xmlDoc, "entityCache");
|
|
228
228
|
while (child) {
|
|
@@ -230,7 +230,7 @@ governing permissions and limitations under the License.
|
|
|
230
230
|
const schemaId = DomUtil.getAttributeAsString(child, "schema");
|
|
231
231
|
if (schemaId === this._cacheSchemaId) {
|
|
232
232
|
evicted.push(schemaId);
|
|
233
|
-
this._cache.remove(pkSchemaId);
|
|
233
|
+
await this._cache.remove(pkSchemaId);
|
|
234
234
|
// Notify listeners to refresh in SchemaCache
|
|
235
235
|
if (schemaId === "xtk:schema") {
|
|
236
236
|
const schemaIds = pkSchemaId.split("|");
|
package/src/client.js
CHANGED
|
@@ -196,8 +196,7 @@ const clientHandler = (representation, headers, pushDownOptions) => {
|
|
|
196
196
|
var promise = callContext.client._callMethod(methodName, callContext, argumentsList);
|
|
197
197
|
return promise.then(function(optionAndValue) {
|
|
198
198
|
const optionName = argumentsList[0];
|
|
199
|
-
client._optionCache.put(optionName, optionAndValue);
|
|
200
|
-
return optionAndValue;
|
|
199
|
+
return client._optionCache.put(optionName, optionAndValue).then(() => optionAndValue);
|
|
201
200
|
});
|
|
202
201
|
}
|
|
203
202
|
// static method
|
|
@@ -308,6 +307,7 @@ class Credentials {
|
|
|
308
307
|
* @property {boolean} noSDKHeaders - set to disable "ACC-SDK" HTTP headers
|
|
309
308
|
* @property {boolean} noMethodInURL - Can be set to true to remove the method name from the URL
|
|
310
309
|
* @property {number} timeout - Can be set to change the HTTP call timeout. Value is passed in ms.
|
|
310
|
+
* @property {string} cacheRootKey - "default" or "none" - determine the prefix to use for the keys in the caches of schemas, options, etc.
|
|
311
311
|
* @memberOf Campaign
|
|
312
312
|
*/
|
|
313
313
|
|
|
@@ -379,6 +379,7 @@ class ConnectionParameters {
|
|
|
379
379
|
this._options.clientApp = options.clientApp;
|
|
380
380
|
this._options.noSDKHeaders = !!options.noSDKHeaders;
|
|
381
381
|
this._options.noMethodInURL = !!options.noMethodInURL;
|
|
382
|
+
this._options.cacheRootKey = options.cacheRootKey === undefined ? "default": options.cacheRootKey;
|
|
382
383
|
}
|
|
383
384
|
|
|
384
385
|
/**
|
|
@@ -645,7 +646,14 @@ class Client {
|
|
|
645
646
|
var instanceKey = connectionParameters._endpoint || "";
|
|
646
647
|
if (instanceKey.startsWith("http://")) instanceKey = instanceKey.substr(7);
|
|
647
648
|
if (instanceKey.startsWith("https://")) instanceKey = instanceKey.substr(8);
|
|
648
|
-
|
|
649
|
+
|
|
650
|
+
// Determine the cache root key. There are 3 possible values:
|
|
651
|
+
// * no value or "default" is the default behavior, i.e. all cache keys are prefixed with "acc.js.sdk.${sdk.getSDKVersion().version}.${instanceKey}.cache."
|
|
652
|
+
// * "none" (or actually anything else for now), where cache keys are not prefixed by anything
|
|
653
|
+
const rootKeyType = connectionParameters._options.cacheRootKey;
|
|
654
|
+
let rootKey = "";
|
|
655
|
+
if (!rootKeyType || rootKeyType === "default")
|
|
656
|
+
rootKey = `acc.js.sdk.${sdk.getSDKVersion().version}.${instanceKey}.cache.`;
|
|
649
657
|
|
|
650
658
|
// Clear storage cache if the sdk versions or the instances are different
|
|
651
659
|
if (this._storage && typeof this._storage.removeItem === 'function') {
|
|
@@ -656,11 +664,11 @@ class Client {
|
|
|
656
664
|
}
|
|
657
665
|
}
|
|
658
666
|
|
|
659
|
-
this._entityCache = new XtkEntityCache(this._storage, `${rootKey}
|
|
660
|
-
this._entityCacheRefresher = new CacheRefresher(this._entityCache, this, "xtk:schema", `${rootKey}
|
|
661
|
-
this._methodCache = new MethodCache(this._storage, `${rootKey}
|
|
662
|
-
this._optionCache = new OptionCache(this._storage, `${rootKey}
|
|
663
|
-
this._optionCacheRefresher = new CacheRefresher(this._optionCache, this, "xtk:option", `${rootKey}
|
|
667
|
+
this._entityCache = new XtkEntityCache(this._storage, `${rootKey}XtkEntityCache`, connectionParameters._options.entityCacheTTL);
|
|
668
|
+
this._entityCacheRefresher = new CacheRefresher(this._entityCache, this, "xtk:schema", `${rootKey}XtkEntityCache`);
|
|
669
|
+
this._methodCache = new MethodCache(this._storage, `${rootKey}MethodCache`, connectionParameters._options.methodCacheTTL);
|
|
670
|
+
this._optionCache = new OptionCache(this._storage, `${rootKey}OptionCache`, connectionParameters._options.optionCacheTTL);
|
|
671
|
+
this._optionCacheRefresher = new CacheRefresher(this._optionCache, this, "xtk:option", `${rootKey}OptionCache`);
|
|
664
672
|
this.NLWS = new Proxy(this, clientHandler());
|
|
665
673
|
|
|
666
674
|
this._transport = connectionParameters._options.transport;
|
|
@@ -1447,11 +1455,11 @@ class Client {
|
|
|
1447
1455
|
async getOption(name, useCache = true) {
|
|
1448
1456
|
var value;
|
|
1449
1457
|
if (useCache) {
|
|
1450
|
-
value = this._optionCache.get(name);
|
|
1458
|
+
value = await this._optionCache.get(name);
|
|
1451
1459
|
}
|
|
1452
1460
|
if (value === undefined) {
|
|
1453
1461
|
const option = await this.NLWS.xtkSession.getOption(name);
|
|
1454
|
-
value = this._optionCache.put(name, option);
|
|
1462
|
+
value = await this._optionCache.put(name, option);
|
|
1455
1463
|
}
|
|
1456
1464
|
return value;
|
|
1457
1465
|
}
|
|
@@ -1467,7 +1475,7 @@ class Client {
|
|
|
1467
1475
|
async setOption(name, rawValue, description) {
|
|
1468
1476
|
// First, read the current option value to make sure we have the right type
|
|
1469
1477
|
await this.getOption(name, true);
|
|
1470
|
-
const option = this._optionCache.getOption(name);
|
|
1478
|
+
const option = await this._optionCache.getOption(name);
|
|
1471
1479
|
// Note: option is never null or undefined there: Campaign will return a value of type 0 and value ""
|
|
1472
1480
|
var type = option.type;
|
|
1473
1481
|
var value = XtkCaster.as(rawValue, type);
|
|
@@ -1483,40 +1491,41 @@ class Client {
|
|
|
1483
1491
|
if (description != null && description != undefined)
|
|
1484
1492
|
doc.description = description;
|
|
1485
1493
|
doc[attName] = value;
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
});
|
|
1494
|
+
await this.NLWS.xtkSession.write(doc);
|
|
1495
|
+
// Once set, cache the value
|
|
1496
|
+
await this._optionCache.put(name, [value, type]);
|
|
1490
1497
|
}
|
|
1491
1498
|
|
|
1492
1499
|
/**
|
|
1493
1500
|
* Clears the options cache
|
|
1494
1501
|
*/
|
|
1495
|
-
clearOptionCache() {
|
|
1496
|
-
this._optionCache.clear();
|
|
1502
|
+
async clearOptionCache() {
|
|
1503
|
+
await this._optionCache.clear();
|
|
1497
1504
|
}
|
|
1498
1505
|
|
|
1499
1506
|
/**
|
|
1500
1507
|
* Clears the method cache
|
|
1501
1508
|
*/
|
|
1502
|
-
clearMethodCache() {
|
|
1503
|
-
this._methodCache.clear();
|
|
1509
|
+
async clearMethodCache() {
|
|
1510
|
+
await this._methodCache.clear();
|
|
1504
1511
|
}
|
|
1505
1512
|
|
|
1506
1513
|
/**
|
|
1507
1514
|
* Clears the entity cache
|
|
1508
1515
|
*/
|
|
1509
|
-
clearEntityCache() {
|
|
1510
|
-
this._entityCache.clear();
|
|
1516
|
+
async clearEntityCache() {
|
|
1517
|
+
await this._entityCache.clear();
|
|
1511
1518
|
}
|
|
1512
1519
|
|
|
1513
1520
|
/**
|
|
1514
1521
|
* Clears all caches (options, methods, entities)
|
|
1515
1522
|
*/
|
|
1516
|
-
clearAllCaches() {
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1523
|
+
async clearAllCaches() {
|
|
1524
|
+
return Promise.all([
|
|
1525
|
+
this.clearEntityCache(),
|
|
1526
|
+
this.clearMethodCache(),
|
|
1527
|
+
this.clearOptionCache(),
|
|
1528
|
+
]);
|
|
1520
1529
|
}
|
|
1521
1530
|
|
|
1522
1531
|
/**
|
|
@@ -1629,7 +1638,7 @@ class Client {
|
|
|
1629
1638
|
* @returns {XML.XtkObject} the schema definition, as either a DOM document or a JSON object
|
|
1630
1639
|
*/
|
|
1631
1640
|
async getSchema(schemaId, representation, internal) {
|
|
1632
|
-
var entity = this._entityCache.get("xtk:schema", schemaId);
|
|
1641
|
+
var entity = await this._entityCache.get("xtk:schema", schemaId);
|
|
1633
1642
|
if (!entity) {
|
|
1634
1643
|
entity = await this.getEntityIfMoreRecent("xtk:schema", schemaId, "xml", internal);
|
|
1635
1644
|
if (entity) {
|
|
@@ -1638,8 +1647,8 @@ class Client {
|
|
|
1638
1647
|
// Ensure xtk:persist is present by loading the xtk:session schema
|
|
1639
1648
|
await this.getSchema("xtk:session", "xml", true);
|
|
1640
1649
|
}
|
|
1641
|
-
this._entityCache.put("xtk:schema", schemaId, entity);
|
|
1642
|
-
this._methodCache.put(entity);
|
|
1650
|
+
await this._entityCache.put("xtk:schema", schemaId, entity);
|
|
1651
|
+
await this._methodCache.put(entity);
|
|
1643
1652
|
}
|
|
1644
1653
|
}
|
|
1645
1654
|
entity = this._toRepresentation(entity, representation);
|
|
@@ -1714,24 +1723,24 @@ class Client {
|
|
|
1714
1723
|
throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Schema '${schemaId}' not found`);
|
|
1715
1724
|
|
|
1716
1725
|
// Lookup the method to call
|
|
1717
|
-
var method = that._methodCache.get(methodSchemaId, methodName);
|
|
1726
|
+
var method = await that._methodCache.get(methodSchemaId, methodName);
|
|
1718
1727
|
if (!method) {
|
|
1719
1728
|
// first char of the method name may be lower case (ex: nms:seedMember.getAsModel) but the methodName
|
|
1720
1729
|
// variable has been capitalized. Make an attempt to lookup method name without capitalisation
|
|
1721
1730
|
const methodNameLC = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
|
|
1722
|
-
method = that._methodCache.get(schemaId, methodNameLC);
|
|
1731
|
+
method = await that._methodCache.get(schemaId, methodNameLC);
|
|
1723
1732
|
if (method) methodName = methodNameLC;
|
|
1724
1733
|
}
|
|
1725
1734
|
if (!method) {
|
|
1726
|
-
this._methodCache.put(schema);
|
|
1727
|
-
method = that._methodCache.get(methodSchemaId, methodName);
|
|
1735
|
+
await this._methodCache.put(schema);
|
|
1736
|
+
method = await that._methodCache.get(methodSchemaId, methodName);
|
|
1728
1737
|
}
|
|
1729
1738
|
if (!method)
|
|
1730
1739
|
throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Method '${methodName}' of schema '${schemaId}' not found`);
|
|
1731
1740
|
|
|
1732
1741
|
// Compute the SOAP URN. Again, specically handle xtk:jobInterface as it's not a real schema. The actual entity schema
|
|
1733
1742
|
// would be available as the entitySchemaId property of the callContext
|
|
1734
|
-
var urn = schemaId !== 'xtk:jobInterface' ? that._methodCache.getSoapUrn(schemaId, methodName)
|
|
1743
|
+
var urn = schemaId !== 'xtk:jobInterface' ? await that._methodCache.getSoapUrn(schemaId, methodName)
|
|
1735
1744
|
: `xtk:jobInterface|${entitySchemaId}`;
|
|
1736
1745
|
|
|
1737
1746
|
const isStatic = DomUtil.getAttributeAsBoolean(method, "static");
|
package/src/methodCache.js
CHANGED
|
@@ -75,8 +75,8 @@ class MethodCache extends Cache {
|
|
|
75
75
|
* @deprecated
|
|
76
76
|
* @param {Element} schema DOM document node represening the schema
|
|
77
77
|
*/
|
|
78
|
-
cache(schema) {
|
|
79
|
-
return this.put(schema);
|
|
78
|
+
async cache(schema) {
|
|
79
|
+
return await this.put(schema);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -84,7 +84,7 @@ class MethodCache extends Cache {
|
|
|
84
84
|
*
|
|
85
85
|
* @param {Element} schema DOM document node represening the schema
|
|
86
86
|
*/
|
|
87
|
-
put(schema) {
|
|
87
|
+
async put(schema) {
|
|
88
88
|
var namespace = DomUtil.getAttributeAsString(schema, "namespace");
|
|
89
89
|
var name = DomUtil.getAttributeAsString(schema, "name");
|
|
90
90
|
var impls = DomUtil.getAttributeAsString(schema, "implements");
|
|
@@ -103,7 +103,7 @@ class MethodCache extends Cache {
|
|
|
103
103
|
while (child) {
|
|
104
104
|
const methodName = DomUtil.getAttributeAsString(child, "name");
|
|
105
105
|
const cached = { method: child, urn: schemaId };
|
|
106
|
-
super.put(schemaId, methodName, cached);
|
|
106
|
+
await super.put(schemaId, methodName, cached);
|
|
107
107
|
child = DomUtil.getNextSiblingElement(child, "method");
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -124,7 +124,7 @@ class MethodCache extends Cache {
|
|
|
124
124
|
let cached = this._cache[key].value;
|
|
125
125
|
cached = { method: cached.method, urn: urn };
|
|
126
126
|
const methodName = DomUtil.getAttributeAsString(cached.method, "name");
|
|
127
|
-
super.put(schemaId, methodName, cached);
|
|
127
|
+
await super.put(schemaId, methodName, cached);
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -137,8 +137,8 @@ class MethodCache extends Cache {
|
|
|
137
137
|
* @param {string} methodName the method name
|
|
138
138
|
* @returns {Campaign.SoapMethodDefinition} the method definition, or undefined if the schema or the method is not found
|
|
139
139
|
*/
|
|
140
|
-
get(schemaId, methodName) {
|
|
141
|
-
const cached = super.get(schemaId, methodName);
|
|
140
|
+
async get(schemaId, methodName) {
|
|
141
|
+
const cached = await super.get(schemaId, methodName);
|
|
142
142
|
return cached ? cached.method : undefined;
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -149,8 +149,8 @@ class MethodCache extends Cache {
|
|
|
149
149
|
* @param {string} methodName the method name
|
|
150
150
|
* @returns {string} the URN (or Soap action header), or undefined if the schema or the method is not found
|
|
151
151
|
*/
|
|
152
|
-
getSoapUrn(schemaId, methodName) {
|
|
153
|
-
const cached = super.get(schemaId, methodName);
|
|
152
|
+
async getSoapUrn(schemaId, methodName) {
|
|
153
|
+
const cached = await super.get(schemaId, methodName);
|
|
154
154
|
return cached ? cached.urn : undefined;
|
|
155
155
|
}
|
|
156
156
|
}
|