@adobe/acc-js-sdk 1.1.15 → 1.1.16
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/compile.js +1 -0
- package/docs/_data/navigation.yml +2 -0
- package/docs/changeLog.html +7 -0
- package/docs/xtkInterface.html +1 -1
- package/docs/xtkJob.html +131 -0
- package/package-lock.json +1 -1
- package/package.json +1 -1
- package/src/client.js +35 -21
- package/src/util.js +18 -0
- package/src/xtkJob.js +337 -0
- package/test/mock.js +109 -1
- package/test/util.test.js +9 -0
- package/test/xtkJob.test.js +713 -0
package/compile.js
CHANGED
package/docs/changeLog.html
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
layout: page
|
|
3
3
|
title: Change Log
|
|
4
4
|
---
|
|
5
|
+
<section class="changelog"><h1>Version 1.1.16</h1>
|
|
6
|
+
<h2>2022/11/29</h2>
|
|
7
|
+
|
|
8
|
+
<li>Added support for xtk:job interface and job-related methods. See <a href="https://opensource.adobe.com/acc-js-sdk/xtkJob.html">Jobs documentation</a> for more details</li>
|
|
9
|
+
</section>
|
|
10
|
+
|
|
11
|
+
|
|
5
12
|
<section class="changelog"><h1>Version 1.1.15</h1>
|
|
6
13
|
<h2>2022/11/28</h2>
|
|
7
14
|
|
package/docs/xtkInterface.html
CHANGED
|
@@ -17,4 +17,4 @@ const delivery = client.NLWS.nmsDelivery.create({ label: "Hello" });
|
|
|
17
17
|
await delivery.newInstance();
|
|
18
18
|
</pre>
|
|
19
19
|
|
|
20
|
-
<p>There are 2 common interfaces: <a href="{{ site.baseurl }}/xtkPersist.html">xtk:persist</a> and <a href="">xtk:jobInterface</a> which are documented below.</p>
|
|
20
|
+
<p>There are 2 common interfaces: <a href="{{ site.baseurl }}/xtkPersist.html">xtk:persist</a> and <a href="{{ site.baseurl }}/xtkJob.html">xtk:jobInterface</a> which are documented below.</p>
|
package/docs/xtkJob.html
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: XTK Jobs (xkt:job, xkt:jobInterface)
|
|
4
|
+
---
|
|
5
|
+
<p>This section describes how long running jobs are handled in ACC and ACC api. There are 2 schemas for jobs</p>
|
|
6
|
+
<ul>
|
|
7
|
+
<li>xtk:job which represents an acutal job, and which is implemented by several objects such as nms:delivery</li>
|
|
8
|
+
<li>xtk:jobInterface which contains methods to submit jobs and get their statuses. Other schemas do not actually implement the xtk:jobInterface interface</li>
|
|
9
|
+
</ul>
|
|
10
|
+
|
|
11
|
+
<p>In term of SOAP calls, running a job is simply executing a SOAP call synchronously or asynchronously in a separate thread or process. However, calls must be made on both the xtk:jobInterface and job entity schema. The SDK provides a helper interface to submit and handle jobs</p>
|
|
12
|
+
|
|
13
|
+
<h1>Simple Jobs</h1>
|
|
14
|
+
|
|
15
|
+
<p>
|
|
16
|
+
Simple jobs are non-static methods with no parameters, such as the nms:delivery#Prepare method which is used to prepare a delivery.
|
|
17
|
+
Such jobs can be executed synchronously (xtk:jobInterface#Execute) or asynchronously (xtk:jobInterface#Submit). Both methods return
|
|
18
|
+
a job id which can be used to retreive (poll) more about the job.
|
|
19
|
+
<p>
|
|
20
|
+
|
|
21
|
+
<p>
|
|
22
|
+
First, we need to retreive a delivery, which is the object upon which to run the Prepare method, but also implements xtk:job interface.
|
|
23
|
+
The Prepare method requires a complete delivery object, so we use SelectAll
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<pre class="code">
|
|
27
|
+
const queryDef = {
|
|
28
|
+
schema: "nms:delivery",
|
|
29
|
+
operation: "get",
|
|
30
|
+
select: { node: [ { expr: "@id" } ] },
|
|
31
|
+
where: { condition: [ { expr:`@internalName='DM19'` } ] }
|
|
32
|
+
}
|
|
33
|
+
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
34
|
+
await query.selectAll();
|
|
35
|
+
const delivery = await query.executeQuery();
|
|
36
|
+
</pre>
|
|
37
|
+
|
|
38
|
+
<p>
|
|
39
|
+
Now we can create a job for the Prepare method using the <b>client.jobInterface</b> function which returns a XtkJobInterface object.
|
|
40
|
+
We pass it a job specification containing the schema, method, and object
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<pre class="code">
|
|
44
|
+
const job = await client.jobInterface({
|
|
45
|
+
xtkschema: 'nms:delivery',
|
|
46
|
+
method: 'Prepare',
|
|
47
|
+
object: delivery
|
|
48
|
+
});
|
|
49
|
+
</pre>
|
|
50
|
+
|
|
51
|
+
<p>
|
|
52
|
+
Finally we can submit the job and get it's status, progress, result, etc.
|
|
53
|
+
</p>
|
|
54
|
+
|
|
55
|
+
<pre class="code">
|
|
56
|
+
await job.submit();
|
|
57
|
+
var status = await job.getStatus();
|
|
58
|
+
</pre>
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
<h1>Soap calls</h1>
|
|
62
|
+
<p>
|
|
63
|
+
The <b>SubmitSoapCall</b> method allows to run more complex jobs with parameters. The principle is the same, for instance calling the <b>PrepareProof</b> method
|
|
64
|
+
which takes a boolean parameter
|
|
65
|
+
</p>
|
|
66
|
+
|
|
67
|
+
<pre class="code">
|
|
68
|
+
const job = await client.jobInterface({
|
|
69
|
+
xtkschema: 'nms:delivery',
|
|
70
|
+
method: 'PrepareProof',
|
|
71
|
+
object: delivery,
|
|
72
|
+
args: [ false ]
|
|
73
|
+
});
|
|
74
|
+
</pre>
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
<h1>Job Status</h1>
|
|
78
|
+
<p>
|
|
79
|
+
The status of a job is made of 3 pieces of information
|
|
80
|
+
</p>
|
|
81
|
+
<ul>
|
|
82
|
+
<li>The job status code</li>
|
|
83
|
+
<li>Job logs</li>
|
|
84
|
+
<li>Job properties which are arbitrary key value pairs and also contain progress information</li>
|
|
85
|
+
</ul>
|
|
86
|
+
|
|
87
|
+
<p>
|
|
88
|
+
For convenience, the SDK provides a <b>getStatus</b> function which will fetch and return the full job status object with strong
|
|
89
|
+
typing. When getStatus is called several time, each call will fetch the most recent status, and new logs since the previous call.
|
|
90
|
+
</p>
|
|
91
|
+
|
|
92
|
+
<table>
|
|
93
|
+
<thead>
|
|
94
|
+
<tr><th>Status code</th><th>Description</th></tr>
|
|
95
|
+
</thead>
|
|
96
|
+
<tbody>
|
|
97
|
+
<tr><td><b>0</b></td><td>Being edited</td></tr>
|
|
98
|
+
<tr><td><b>2</b></td><td>Running: execution is in progress</td></tr>
|
|
99
|
+
<tr><td><b>3</b></td><td>Canceling: a cancel request was submitted and the job will be canceld as soon as possible</td></tr>
|
|
100
|
+
<tr><td><b>4</b></td><td>Canceled</td></tr>
|
|
101
|
+
<tr><td><b>5</b></td><td>Finished: the job has finished successfully and getResult can be called</td></tr>
|
|
102
|
+
<tr><td><b>6</b></td><td>Error: the job failed. Details about the error can be found in the logs</td></tr>
|
|
103
|
+
<tr><td><b>7</b></td><td>Pause pending: a pause request was submitted and the job will be paused as soon as possible</td></tr>
|
|
104
|
+
<tr><td><b>8</b></td><td>Pause: the job is paused</td></tr>
|
|
105
|
+
<tr><td><b>9</b></td><td>Purge pending: a purge request was submitted and the job will be purged as soon as possible</td></tr>
|
|
106
|
+
</tbody>
|
|
107
|
+
</table>
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
<h1>Job Progress</h1>
|
|
111
|
+
<p>
|
|
112
|
+
The progress of a job is available as 2 integers: current and max which represent the current progression and max value for progression.
|
|
113
|
+
Both values are returned by the getStatus call as properties (i.e. <b>properties.progress.current</b> and <b>properties.progress.max</b>).
|
|
114
|
+
The SDK provides the <b>getProgress</b> function to retreive the progress as a percentage (and a valid number)
|
|
115
|
+
</p>
|
|
116
|
+
|
|
117
|
+
<pre class="code">
|
|
118
|
+
// Returns progress as a percentage in the [0..1] range
|
|
119
|
+
var progressPercent = job.getProgress();
|
|
120
|
+
</pre>
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
<h1>Job Result</h1>
|
|
124
|
+
<p>
|
|
125
|
+
Typically, a client would call the getStatus method every few seconds to get updates on the progress. When a job is finished and successfull,
|
|
126
|
+
one can get the result using the <b>getResult</b> function
|
|
127
|
+
</p>
|
|
128
|
+
|
|
129
|
+
<pre class="code">
|
|
130
|
+
var result = await job.getResult();
|
|
131
|
+
</pre>
|
package/package-lock.json
CHANGED
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -36,6 +36,7 @@ const request = require('./transport.js').request;
|
|
|
36
36
|
const Application = require('./application.js').Application;
|
|
37
37
|
const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
|
|
38
38
|
const { Util } = require('./util.js');
|
|
39
|
+
const { XtkJobInterface } = require('./xtkJob.js');
|
|
39
40
|
const qsStringify = require('qs-stringify');
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -173,16 +174,7 @@ const clientHandler = (representation, headers, pushDownOptions) => {
|
|
|
173
174
|
return callContext;
|
|
174
175
|
|
|
175
176
|
// get Schema id from namespace (find first upper case letter)
|
|
176
|
-
|
|
177
|
-
for (var i=0; i<namespace.length; i++) {
|
|
178
|
-
const c = namespace[i];
|
|
179
|
-
if (c >='A' && c<='Z') {
|
|
180
|
-
schemaId = schemaId + ":" + c.toLowerCase() + namespace.substr(i+1);
|
|
181
|
-
break;
|
|
182
|
-
}
|
|
183
|
-
schemaId = schemaId + c;
|
|
184
|
-
}
|
|
185
|
-
callContext.schemaId = schemaId;
|
|
177
|
+
callContext.schemaId = Util.schemaIdFromNamespace(namespace);
|
|
186
178
|
|
|
187
179
|
const caller = function(thisArg, argumentsList) {
|
|
188
180
|
const callContext = thisArg["."];
|
|
@@ -1473,11 +1465,21 @@ class Client {
|
|
|
1473
1465
|
const result = [];
|
|
1474
1466
|
const schemaId = callContext.schemaId;
|
|
1475
1467
|
|
|
1476
|
-
var
|
|
1468
|
+
var entitySchemaId = schemaId;
|
|
1469
|
+
if (schemaId === 'xtk:jobInterface')
|
|
1470
|
+
entitySchemaId = callContext.entitySchemaId;
|
|
1471
|
+
|
|
1472
|
+
// Get the schema which contains the method call. Methods of the xtk:jobInterface interface are handled specificaaly
|
|
1473
|
+
// because xtk:jobInterface is not actually a schema, but just an interface. In practice, it's used as an xtk template
|
|
1474
|
+
// rather that an xtk inheritance mechanism
|
|
1475
|
+
const methodSchemaId = schemaId === 'xtk:jobInterface' ? 'xtk:job' : schemaId;
|
|
1476
|
+
var schema = await that.getSchema(methodSchemaId, "xml", true);
|
|
1477
1477
|
if (!schema)
|
|
1478
1478
|
throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Schema '${schemaId}' not found`);
|
|
1479
1479
|
var schemaName = schema.getAttribute("name");
|
|
1480
|
-
|
|
1480
|
+
|
|
1481
|
+
// Lookup the method to call
|
|
1482
|
+
var method = that._methodCache.get(methodSchemaId, methodName);
|
|
1481
1483
|
if (!method) {
|
|
1482
1484
|
// first char of the method name may be lower case (ex: nms:seedMember.getAsModel) but the methodName
|
|
1483
1485
|
// variable has been capitalized. Make an attempt to lookup method name without capitalisation
|
|
@@ -1487,13 +1489,16 @@ class Client {
|
|
|
1487
1489
|
}
|
|
1488
1490
|
if (!method) {
|
|
1489
1491
|
this._methodCache.put(schema);
|
|
1490
|
-
method = that._methodCache.get(
|
|
1492
|
+
method = that._methodCache.get(methodSchemaId, methodName);
|
|
1491
1493
|
}
|
|
1492
1494
|
if (!method)
|
|
1493
1495
|
throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Method '${methodName}' of schema '${schemaId}' not found`);
|
|
1494
|
-
// console.log(method.toXMLString());
|
|
1495
1496
|
|
|
1496
|
-
|
|
1497
|
+
// Compute the SOAP URN. Again, specically handle xtk:jobInterface as it's not a real schema. The actual entity schema
|
|
1498
|
+
// would be available as the entitySchemaId property of the callContext
|
|
1499
|
+
var urn = schemaId !== 'xtk:jobInterface' ? that._methodCache.getSoapUrn(schemaId, methodName)
|
|
1500
|
+
: `xtk:jobInterface|${entitySchemaId}`;
|
|
1501
|
+
|
|
1497
1502
|
var soapCall = that._prepareSoapCall(urn, methodName, false, callContext.headers, callContext.pushDownOptions);
|
|
1498
1503
|
|
|
1499
1504
|
// If method is called with one parameter which is a function, then we assume it's a hook: the function will return
|
|
@@ -1510,13 +1515,13 @@ class Client {
|
|
|
1510
1515
|
if (!object)
|
|
1511
1516
|
throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Cannot call non-static method '${methodName}' of schema '${schemaId}' : no object was specified`);
|
|
1512
1517
|
|
|
1513
|
-
const rootName =
|
|
1518
|
+
const rootName = entitySchemaId.substr(entitySchemaId.indexOf(':') + 1);
|
|
1514
1519
|
object = that._fromRepresentation(rootName, object, callContext.representation);
|
|
1515
1520
|
// The xtk:persist#NewInstance requires a xtkschema attribute which we can compute here
|
|
1516
1521
|
// Actually, we're always adding it, for all non-static methods
|
|
1517
1522
|
const xmlRoot = object.nodeType === 9 ? object.documentElement : object;
|
|
1518
1523
|
if (!xmlRoot.hasAttribute("xtkschema"))
|
|
1519
|
-
xmlRoot.setAttribute("xtkschema",
|
|
1524
|
+
xmlRoot.setAttribute("xtkschema", entitySchemaId);
|
|
1520
1525
|
soapCall.writeDocument("document", object);
|
|
1521
1526
|
}
|
|
1522
1527
|
const parametersIsArray = (typeof parameters == "object") && parameters.length;
|
|
@@ -1525,7 +1530,7 @@ class Client {
|
|
|
1525
1530
|
var param = DomUtil.getFirstChildElement(params, "param");
|
|
1526
1531
|
var paramIndex = 0;
|
|
1527
1532
|
while (param) {
|
|
1528
|
-
|
|
1533
|
+
const inout = DomUtil.getAttributeAsString(param, "inout");
|
|
1529
1534
|
if (!inout || inout=="in") {
|
|
1530
1535
|
const type = DomUtil.getAttributeAsString(param, "type");
|
|
1531
1536
|
const paramName = DomUtil.getAttributeAsString(param, "name");
|
|
@@ -1568,9 +1573,9 @@ class Client {
|
|
|
1568
1573
|
// Hack for workflow API. The C++ code checks that the name of the XML element is <variables>. When
|
|
1569
1574
|
// using xml representation at the SDK level, it's ok since the SDK caller will set that. But this does
|
|
1570
1575
|
// not work when using "BadgerFish" representation where we do not know the root element name.
|
|
1571
|
-
if (
|
|
1576
|
+
if (entitySchemaId == "xtk:workflow" && methodName == "StartWithParameters" && paramName == "parameters")
|
|
1572
1577
|
docName = "variables";
|
|
1573
|
-
if (
|
|
1578
|
+
if (entitySchemaId == "nms:rtEvent" && methodName == "PushEvent")
|
|
1574
1579
|
docName = "rtEvent";
|
|
1575
1580
|
// Try to guess the document name. This is usually available in the xtkschema attribute
|
|
1576
1581
|
var xtkschema = EntityAccessor.getAttributeAsString(paramValue, "xtkschema");
|
|
@@ -1634,7 +1639,7 @@ class Client {
|
|
|
1634
1639
|
else if (type == "DOMDocument") {
|
|
1635
1640
|
returnValue = soapCall.getNextDocument();
|
|
1636
1641
|
returnValue = that._toRepresentation(returnValue, callContext.representation);
|
|
1637
|
-
if (
|
|
1642
|
+
if (entitySchemaId === "xtk:queryDef" && methodName === "ExecuteQuery" && paramName === "output") {
|
|
1638
1643
|
// https://github.com/adobe/acc-js-sdk/issues/3
|
|
1639
1644
|
// Check if query operation is "getIfExists". The "object" variable at this point
|
|
1640
1645
|
// is always an XML, regardless of the xml/json representation
|
|
@@ -1868,6 +1873,15 @@ class Client {
|
|
|
1868
1873
|
const result = this._toRepresentation(doc);
|
|
1869
1874
|
return result;
|
|
1870
1875
|
}
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* Creates a Job object which can be used to submit jobs, retrieve status, logs and progress, etc.
|
|
1879
|
+
* @param {Campaign.XtkSoapCallSpec} soapCallSpec the definition of the SOAP call
|
|
1880
|
+
* @returns {Campaign.XtkJobInterface} a job
|
|
1881
|
+
*/
|
|
1882
|
+
jobInterface(soapCallSpec) {
|
|
1883
|
+
return new XtkJobInterface(this, soapCallSpec);
|
|
1884
|
+
}
|
|
1871
1885
|
}
|
|
1872
1886
|
|
|
1873
1887
|
|
package/src/util.js
CHANGED
|
@@ -133,6 +133,24 @@ class Util {
|
|
|
133
133
|
}
|
|
134
134
|
return obj;
|
|
135
135
|
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get Schema id from namespace (find first upper case letter)
|
|
139
|
+
* @param {string} namespace a SDK namespace, i.e. xtkWorkflow, nmsDelivery, etc.
|
|
140
|
+
* @return {string} the corresponding schema id, i.e. xtk:workflow, nms:delivery, etc.
|
|
141
|
+
*/
|
|
142
|
+
static schemaIdFromNamespace(namespace) {
|
|
143
|
+
var schemaId = "";
|
|
144
|
+
for (var i=0; i<namespace.length; i++) {
|
|
145
|
+
const c = namespace[i];
|
|
146
|
+
if (c >='A' && c<='Z') {
|
|
147
|
+
schemaId = schemaId + ":" + c.toLowerCase() + namespace.substr(i+1);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
schemaId = schemaId + c;
|
|
151
|
+
}
|
|
152
|
+
return schemaId;
|
|
153
|
+
}
|
|
136
154
|
}
|
|
137
155
|
|
|
138
156
|
/**
|