
ActiveVOS 7.1 or later exposes all its processes and services via simple XML and JavaScript Object Notation (JSON) bindings in addition to SOAP, REST and JMS. The XML (and JSON) binding makes it easy for application developers already familiar with XML/JSON-based REST application development to invoke processes and obtain responses from them.
Using XML or JSON bindings frees developers from needing to obtain and learn SOAP libraries to build applications that leverage ActiveVOS service-based processes. This approach allows JavaScript developers to use various libraries such as jQuery to build process-enabled applications.
ActiveVOS uses the JSON binding for ActiveVOS Central request and task forms. This implementation provides functions that are available for use by developers for process-enabled application projects. Examples of the use of these functions are provided in this document.
This document contains the following sections
This table shows the endpoints for a given service exposed by ActiveVOS using various bindings. The ServiceName indicates the name of the service - LoanApprovalService for example.
| Binding | Service Endpoint | Description |
|---|---|---|
| SOAP 1.1 |
http://host:port/active-bpel/services/ServiceName
|
Default SOAP endpoint for all services except for REST style services Note: The ActiveVOS engine Administration API service (ActiveBpelAdmin) is available only at the SOAP 1.1 endpoint. |
| SOAP 1.2 |
http://host:port/active-bpel/services/soap12/ServiceName
|
SOAP 1.2 endpoint. All services are exposed via this endpoint except the REST and ActiveBpelAdmin services. |
| REST |
http://host:port/active-bpel/services/REST/ServiceName
|
Endpoint for REST binding. Excludes the ActiveBpelAdmin service. |
| XML |
http://host:port/active-bpel/services/XML/ServiceName
|
Endpoint for simple XML binding. Excludes REST and ActiveBpelAdmin services. |
| JSON |
http://host:port/active-bpel/services/JSON/ServiceName
|
Endpoint for JSON binding. Excludes REST and ActiveBpelAdmin services. |
Note that the ActiveVOS Administration service API (ActiveBpelAdmin) is available only at the SOAP 1.1 address. This service is not available in SOAP 1.2, XML or JSON bindings.
Processes deployed to the ActiveVOS server are available as simple XML bindings in addition to the standard SOAP binding providing that the process and deployment is WS-I compliant:
To invoke a process using a XML binding endpoint, you need to:
The response from the POST will be an HTTP 200/OK response with a content-type of text/xml. The response body will contain the service’s response xml. The following snippet shows the HTTP request used to invoke the Loan Approval process via humantaskProcessDemoService service.
POST /active-bpel/services/XML/humantaskProcessDemoService HTTP/1.1 Content-Length: 710 Content-Type: text/xml; charset=UTF-8 Authorization: Basic YWVhZG1pbjphZWFkbWlu Host: localhost:8080 <loan:loanProcessRequest xmlns:loan="http://schemas.active-endpoints.com/sample/LoanRequest/2008/02/loanRequest.xsd"> <loan:loanType>Automobile</loan:loanType> <loan:firstName>John</loan:firstName> <loan:lastName>Smith</loan:lastName> <loan:dayPhone>2039299400</loan:dayPhone> <loan:nightPhone>2035551212</loan:nightPhone> <loan:socialSecurityNumber>123-45-6789</loan:socialSecurityNumber> <loan:amountRequested>15000</loan:amountRequested> <loan:loanDescription>Application to finance the purchase of a Toyota Prius</loan:loanDescription> <loan:otherInfo>Down payment is US$7500</loan:otherInfo> <loan:responseEmail>john.smith@example.com</loan:responseEmail> </loan:loanProcessRequest>
The response looks like:
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Transfer-Encoding: chunked Date: Wed, 10 Mar 2010 22:53:40 GMT <loan:status xmlns:loan="http://www.active-endpoints.com/wsdl/humantaskdemo"> Thank you for applying for the Automobile loan for the amount of US$15000. Your loan is currently pending approval. You will receive an email once a decision has been made. </loan:status>
A fault is indicated with an HTTP response code of 500 and the content-type of text/xml (instead of text/html or text/plain indicating a generic "internal server error"). An example of a fault response is shown here:
HTTP/1.1 500 Internal Server Error Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Transfer-Encoding: chunked Date: Thu, 11 Mar 2010 19:09:51 GMT Connection: close <aex:Fault xmlns:aex="http://www.active-endpoints.com/2004/06/bpel/extensions/"> <faultcode name="systemError" namespace="http://www.active-endpoints.com/2004/06/bpel/extensions/"/> <faultstring>Could not find match for Operation from given parameters</faultstring> </aex:Fault>
When sending attachments the payload of the HTTP body must be multipart/related
content, with the first part being the message xml payload (text/xml),
followed by additional parts representing the attachments. Attachments sent with the payload
are bound the process variable associated with the message Receive activity.
POST /active-bpel/services/XML/humantaskProcessDemoService HTTP/1.1 Content-Type: multipart/related; type="text/xml"; start="<part1_id>"; boundary="the_boundry" Content-Length: 1410 MIME-Version: 1.0 Host: localhost:8080 --the_boundry Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <part1_id> <loan:loanProcessRequest xmlns:loan="http://schemas.active-endpoints.com/sample/LoanRequest/2008/02/loanRequest.xsd"> <loan:loanType>Automobile</loan:loanType> <loan:firstName>John</loan:firstName> <loan:lastName>Smith</loan:lastName> <loan:dayPhone>2039299400</loan:dayPhone> <loan:nightPhone>2035551212</loan:nightPhone> <loan:socialSecurityNumber>123-45-6789</loan:socialSecurityNumber> <loan:amountRequested>15000</loan:amountRequested> <loan:loanDescription>Application to finance the purchase of a Toyota Prius</loan:loanDescription> <loan:otherInfo>Down payment is US$7500</loan:otherInfo> <loan:responseEmail>john.smith@example.com</loan:responseEmail> </loan:loanProcessRequest> --the_boundry Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-ID: <part2_id> [...Text Attachment Content...] --the_boundry Content-Type: image/jpeg Content-ID: <part3_id> Content-Transfer-Encoding: BASE64 Content-Description: Picture A [...Image Content...] --the_boundry--
For testing you can use any HTTP client testing tool available to you. For example, SOAP-UI, cURL (a popular command line tool) and RESTClient, a Java based application to test RESTful web services.
RESTClient is a Java application used to test RESTful services. It can be used to test a variety of HTTP communications including invoking ActiveVOS processes using the XML binding endpoint. To use the GUI version of this tool, download the jar restclient-ui-2.3-jar-with-dependencies.jar library from http://code.google.com/p/rest-client/downloads/list.
To launch the application, run the command java -jar restclient-ui-2.3-jar-with-dependencies.jar.
This will bring up the GUI application similar to the screenshot shown below.
1. To invoke the sample process in provided with this SDK, ensure that your server is running and that you have deployed the humantaskProcessDemo bpr provided with this SDK to it.
To send a XML POST message to invoke a service, set the service URL for the XML binding.
For example, http://localhost:8080/active-bpel/services/XML/humantaskProcessDemoService.

In the Body tab, provide the xml request element. You can copy the <loan:loanProcessRequest>
sample shown in the previous section.

Set authorization information if needed via Auth tab.

>> Go button to send the requestThe following snippet shows one approach to sending an HTTP POST to a service endpoint.
The complete code is available in com.activevos.examples.xmlbinding.SimpleXmlServiceRequest class
provided to you in the examples folder.
public class SimpleXmlServiceRequest {
/**
* Class to hold service response data.
*/
static class ServiceResponse {
static final int SUCCESS = 0;
static final int FAULTED = 1;
static final int ERROR = 2;
/** Code indicating if the service invoke was a success, fault or other error.*/
int responseCode;
/** Response xml data */
String responseData;
}
/**
* Invokes XML service using POST method returns service response.
*/
public static ServiceResponse invokeService(URL aXmlServiceUrl, String aXmlPayload,
String aUsername, String aPassword) throws IOException {
HttpURLConnection httpConnection = null;
BufferedReader reader = null;
OutputStreamWriter writer = null;
try
{
// create connection
URLConnection c = aXmlServiceUrl.openConnection();
httpConnection = (HttpURLConnection)c;
httpConnection.setRequestProperty("Content-Type", "text/xml");
httpConnection.setRequestProperty("Content-Length", Integer.toString(aXmlPayload.length()));
// Set credentials (if secured using BASIC auth).
if (aUsername != null && aPassword != null) {
// code to set the authorization header (e.g. BASIC)
}
httpConnection.setDoOutput(true);
httpConnection.setInstanceFollowRedirects(true);
// send the payload
writer = new OutputStreamWriter(httpConnection.getOutputStream());
writer.write(aXmlPayload);
writer.flush();
// read response
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK
|| httpConnection.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED ) {
reader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
} else {
reader = new BufferedReader(new InputStreamReader(httpConnection.getErrorStream()));
}
// read response
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
ServiceResponse response = new ServiceResponse();
response.responseData = sb.toString();
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK
|| httpConnection.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED ) {
// Success!
response.responseCode = ServiceResponse.SUCCESS;
} else if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR
&& httpConnection.getContentType().toLowerCase().startsWith("text/xml") ) {
// Faulted! (response code is 500 and content-type is text/xml
response.responseCode = ServiceResponse.FAULTED;
} else {
// http/transport or other error
response.responseCode = ServiceResponse.ERROR;
}
return response;
}
finally {
//
// clean up code goes here. E.g.: close writer, reader and disconnect http connection.
}
}
public static void main(String[] args) {
// Create sample request. In this example, the sample request is created using
// a string. Ideally, the XML element should be built using DOM i.e. with DocumentBuilderFactory,
// and DocumentBuilder.
String xmlRequest = "<loan:loanProcessRequest xmlns:loan=\"http://schemas.active-endpoints.com/sample/LoanRequest/2008/02/loanRequest.xsd\">\n"
+ " <loan:loanType>Automobile</loan:loanType>\n"
+ " <loan:firstName>John</loan:firstName>\n"
+ " <loan:lastName>Smith</loan:lastName>\n"
+ " <loan:dayPhone>2039299400</loan:dayPhone>\n"
+ " <loan:nightPhone>2035551212</loan:nightPhone>\n"
+ " <loan:socialSecurityNumber>123-45-6789</loan:socialSecurityNumber>\n"
+ " <loan:amountRequested>15000</loan:amountRequested>\n"
+ " <loan:loanDescription>Application to finance the purchase of a Toyota Prius</loan:loanDescription>\n"
+ " <loan:otherInfo>Down payment is US$7500</loan:otherInfo>\n"
+ " <loan:responseEmail>john.smith@example.com</loan:responseEmail>\n"
+ "</loan:loanProcessRequest>";
try {
URL loanRequestUrl = new URL(
"http://localhost:8080/active-bpel/services/XML/humantaskProcessDemoService");
System.out.println("Invoking service...");
ServiceResponse response = invokeService(loanRequestUrl, xmlRequest, "username", "password");
if ( response.responseCode == ServiceResponse.SUCCESS ) {
System.out.println("Success:");
} else if ( response.responseCode == ServiceResponse.FAULTED ) {
System.out.println("Faulted:");
} else {
System.out.println("Error:");
}
System.out.println(response.responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Processes deployed to the ActiveVOS server are available as JSON (JavaScript Object Notation) bindings. Similar to services with XML binding, the services must be WS-I compliant:
In order to invoke a service using JSON, the service request message, which is normally defined in XML must be represented in JSON. The ActiveVOS server represents XML elements in JSON notation based on the methodology described by Google GData convention at http://code.google.com/apis/gdata/json.html.
XML element is represented as a JSON object.
<contactInfo />JSON equivalent:
{
"contactInfo" : {}
}
Attributes: Element attributes are represented as string properties.
<contactInfo type="home" default="true" />JSON equivalent:
{
"contactInfo" : {
"type" : "home",
"default": "true"
}
}
In JavaScript, accessing attributes can be done as follows
(assuming the JSON data is assigned to variable named doc)
var doc = { "contactInfo" : {
"type": "home",
"default": "true"
}
};
// type attribute is accessed via doc.contactInfo["type"] or doc.contactInfo.type.
alert("contact information type: " + doc.contactInfo.type);
Child elements are converted to Object type properties.
<contactInfo type="home" default="true" > <phone /> </contactInfo>JSON equivalent (see 'phone' element object in line 5):
{
"contactInfo" : {
"type" : "home",
"default": "true",
"phone" : {}
}
}
Element text: Text values of elements are converted to string property named $t.
The following shows how the <phone/> element text value (203-555-1212) is represented.
<contactInfo type="home" default="true" > <phone type="voice">203-555-1212</phone> </contactInfo>JSON:
{
"contactInfo" : {
"type" : "home",
"default": "true",
"phone" : {
"type" : "voice",
"$t" : "203-555-1212"
}
}
}
Example JavaScript:
// JavaScript:
var doc = { .... }; // define json
// the phone number is doc.contactInfo.phone.$t
alert("phone number: " + doc.contactInfo.phone.$t);
Repeating elements: Elements that may appear more than once are converted to an array of objects.
<contactInfo type="home" default="true" > <phone type="voice">203-555-1212</phone> <phone type="fax">203-555-1213</phone> </contactInfo>JSON:
{
"contactInfo" : {
"type" : "home",
"default": "true",
"phone" : [
{
"type" : "voice",
"$t" : "203-555-1212"
},
{
"type" : "fax",
"$t" : "203-555-1213"
}
]
}
}
Example:
// JavaScript:
// Access phone via array index: doc.contactInfo.phone[0].$t
var i;
for (i=0; i < doc.contactInfo.phone.length; i++) {
alert("phone " + i + " = " + doc.contactInfo.phone[i].$t);
}
If an element has a namespace prefix, the prefix and element name are concatenated using "$".
Attribute prefixes are also presented in the same way.
For example, <c:contactInfo> is represented as { c$contactInfo: {} }.
Attribute xmlns:c="urn:ns:contactinfo" is represented as xmlns$c:"urn:ns:contactinfo".
The following example xml uses prefixed elements xmlns:p="urn:ns:person",
xmlns:c="urn:ns:contactinfo" and also two elements that are unqualified
(email and photo).
<p:person xmlns:p="urn:ns:person">
<p:firstName>John</p:firstName>
<p:lastName>Smith</p:lastName>
<c:contactInfo xmlns:c="urn:ns:contactinfo" type="home" default="true" >
<c:phone type="voice">203-555-1212</c:phone>
<c:phone type="fax">203-555-1213</c:phone>
<email>jsmith@example.com</email>
</c:contactInfo>
<photo>http://example.com/jsmith/profile.png</photo>
</p:person>
JSON
{
"p$person" : {
"xmlns$p" : "urn:ns:person",
"p$firstName" : {
"$t" : "John"
},
"p$lastName" : {
"$t" : "Smith"
},
"c$contactInfo" : {
"xmlns$c" : "urn:ns:contactinfo",
"default" : "true",
"type" : "home",
"c$phone" : [
{
"type" : "voice",
"$t" : "203-555-1212"
},
{
"type" : "fax",
"$t" : "203-555-1213"
}
],
"email" : {
"$t" : "jsmith@example.com"
}
},
"photo" : {
"$t" : "http://example.com/jsmith/profile.png"
}
}
}
Example:
// JavaScript:
var doc = { ... }; // JSON representation of person.
// first Name: /p:person/p:firstName/text()
alert("firstName =" + doc.p$person.p$firstName.$t);
// photo /p:person/photo/text()
alert("photo =" + doc.p$person.photo.$t);
// email /p:person/c:contactInfo/email/text()
alert("email =" + doc.p$person.c$contactInfo.email.$t);
var i;
for (i=0; i < doc.p$person.c$contactInfo.c$phone.length; i++) {
alert("phone " + i + "=" + doc.p$person.c$contactInfo.c$phone[i].$t);
}
Default namespace: Instead of using elements with prefixes, you can
declare the namespace on each element. For example instead of
<c:contactInfo xmlns:c="urn:ns:contactinfo">,
you can use <contactInfo xmlns="urn:ns:contactinfo">.
This results in JSON object properties without the "$" in middle
of the property name which is easier to use. E.g. contactInfo instead of
c$contactInfo. The ActiveVOS server always uses this methodology
when it serializes (converts) XML to JSON.
The prefixed element <p:person xmlns:p="urn:ns:person">
used above can be represented using the default namespace of each element (when the namespace
changes):
<person xmlns="urn:ns:person">
<firstName>John</firstName>
<lastName>Smith</lastName>
<contactInfo xmlns="urn:ns:contactinfo" type="home" default="true" >
<phone type="voice">203-555-1212</phone>
<phone type="fax">203-555-1213</phone>
<email xmlns="">jsmith@example.com</email>
</contactInfo>
<photo xmlns="">http://example.com/jsmith/profile.png</photo>
</person>
The following shows the JSON representation and its usage in JavaScript. Note that is easier to read and use compared to JSON properties that are based on concatenation of prefix/element with a $. Both formats work with ActiveVOS, but ActiveVOS always uses the non-prefix method when it converts XML to JSON.
{
"person" : {
"xmlns" : "urn:ns:person",
"firstName" : {
"$t" : "John"
},
"lastName" : {
"$t" : "Smith"
},
"contactInfo" : {
"xmlns" : "urn:ns:contactinfo",
"default" : "true",
"type" : "home",
"phone" : [
{
"type" : "voice",
"$t" : "203-555-1212"
},
{
"type" : "fax",
"$t" : "203-555-1213"
}
],
"email" : {
"xmlns" : "",
"$t" : "jsmith@example.com"
}
},
"photo" : {
"xmlns" : "",
"$t" : "http://example.com/jsmith/profile.png"
}
}
}
Example:
// JavaScript:
var doc = { ... }; // JSON representation of person using default namespace (and no prefixes).
// first Name:
alert("firstName =" + doc.person.firstName.$t);
// (compare above to prefixed version doc.p$person.p$firstName.$t)
// photo
alert("photo =" + doc.person.photo.$t);
// (compare to prefixed version doc.p$person.photo.$t)
// email /p:person/c:contactInfo/email/text()
alert("email =" + doc.person.contactInfo.email.$t);
// (compare to doc.p$person.c$contactInfo.email.$t)
var i;
for (i=0; i < doc.person.contactInfo.phone.length; i++) {
alert("phone " + i + "=" + doc.person.contactInfo.phone[i].$t);
}
One advantage of using the non-prefixed method when dealing with JSON representations
is that you do not have to determine the actual prefix bound to the element
at runtime to access element properties.
So, instead of doc.ns1$person.ns5$contactInfo.email.type,
you can use doc.person.contactInfo.email.type.
For the XML document that uses prefixes, you must assign a unique prefix for each namespace rather than overloading a prefix to multiple namespaces.
<!-- Prefix 'p' is initially used for ns urn:ns:person. --> <p:person xmlns:p="urn:ns:person"> <!-- Note: prefix 'p' is re-used in contactInfo in a different ns. Avoid this case. --> <p:contactInfo xmlns:p="urn:ns:contactinfo" type="home" default="true" > </p:contactInfo> </p:person>
<first-name> is not allowed due to hyphen(-) in the name).
length.Avoid cases where an element contains attributes and child elements with the same name. For example:
<contactInfo xmlns="urn:ns:contactinfo" type="home" default="true" > <!-- Note 'type' is an attribute (of contactInfo) as well as a child element. Avoid this case. --> <type>foo</type> <phone type="voice">203-555-1212</phone> <phone type="fax">203-555-1213</phone> <email xmlns="">jsmith@example.com</email> </contactInfo>
The AE_JSON_NODE_UTIL Javascript object provided by the ae-avc-util.js script file included with this SDK contains a few helper functions that can be used when working with JSON representation of XML data.
| Function | Description |
|---|---|
| AE_JSON_NODE_UTIL.getElements(aJsonObject) | Returns JSON objects in an array. Use this when the JSON object represents a repeating element. var phones = AE_JSON_NODE_UTIL.getElements(doc.person.contactInfo.phone); // phones is an array. |
| AE_JSON_NODE_UTIL.getText(aJsonObject, aDefaultText) | Returns the text value (the value of $t property) given the JSON object. If the text node does not exist, then the default string value is returned. var phones = AE_JSON_NODE_UTIL.getElements(doc.person.contactInfo.phone); // get first number or return "Not Available" if number does not exist. var phone_number = AE_JSON_NODE_UTIL.getText(phones[0], "Not Available"); // phone_number is 203-555-1212. |
| AE_JSON_NODE_UTIL.isXsiNil(aJsonObject) | Returns true if the aJsonObject element exists and it is XSI nilled. |
| AE_JSON_NODE_UTIL.getAttribute(aJsonObj, aAttributeName, aDefault) | Returns attribute value given its name. If the attribute does not exist, then the default value is returned. Normally you do not have to use this function as you can directly access JSON properties (attributes). This method is useful if your XML has a case where an element child and attribute have the same name (see restrictions above). // get list of phones var phones = AE_JSON_NODE_UTIL.getElements(doc.person.contactInfo.phone); // get phone type (voice, fax etc.) var phone_type = AE_JSON_NODE_UTIL.getAttribute(phones[0], "type", "Not Available"); // phone_type is 'voice'. |
During development you can use the JSON/XML online conversion tool provided by the ActiveVOS at
http://host:port/active-bpel/jsonConverter.html
where host and port is the host and port where ActiveVOS server is installed
(e.g., localhost:8080). This tool allows you to enter well-formed XML content and convert it to JSON, or enter JSON content and convert it to XML.
Invoking a process using JSON is similar to the method described for the XML binding endpoint:
http://host:port/active-bpel/services/JSON/serviceName.The response from the POST is a HTTP 200/OK response with content-type of application/json. The response body will contain a json service response (as a string). The following snippet shows the HTTP request used to invoke the Loan Approval process via humantaskProcessDemoService service. .
POST /active-bpel/services/JSON/humantaskProcessDemoService HTTP/1.1
Content-Length: 581
Content-Type: application/json; charset=UTF-8
Authorization: Basic YWVhZG1pbjphZWFkbWlu
Host: localhost:8080
{"loanProcessRequest":
{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd",
"loanType":{"$t":"Automobile"},
"firstName":{"$t":"John"},
"lastName":{"$t":"Smith"},
"dayPhone":{"$t":"2039299400"},
"nightPhone":{"$t":"2035551212"},
"socialSecurityNumber":{"$t":"123-45-6789"},
"amountRequested":{"$t":"15000"},
"loanDescription":{"$t":"Application to finance the purchase of a Toyota Prius"},
"otherInfo":{"$t":"Down payment is US$7500"},
"responseEmail":{"$t":"john.smith@example.com"}
}
}
The response to the above request looks like:
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
{"status":
{"xmlns":"http:\/\/www.active-endpoints.com\/wsdl\/humantaskdemo",
"$t":"Thank you for applying for the Automobile loan for the amount of US$15000. Your loan is currently pending approval."
}
}
A fault response is returned with HTTP error code 500 and content-type application/json:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json;charset=utf-8
{"Fault":
{"xmlns":"http:\/\/www.active-endpoints.com\/2004\/06\/bpel\/extensions\/",
"faultcode":
{"name":"invalidVariables",
"namespace": "http:\/\/docs.oasis-open.org\/wsbpel\/2.0\/process\/executable",
"xmlns":""
},
"faultstring":
{"xmlns":"",
"$t":" fault error message"
}
}
}
Similar to XML process invokes, the payload of the HTTP body must be multipart/related
content, with the first part being the JSON payload with content-type application/json,
followed by additional parts representing the attachments.
POST /active-bpel/services/JSON/humantaskProcessDemoService HTTP/1.1
Content-Type: multipart/related; type="application/json"; start="<part1_id>"; boundary="the_boundary"
Content-Length: 1234
MIME-Version: 1.0
Host: localhost:8080
--the_boundary
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <part1_id>
{"loanProcessRequest":
{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd",
"loanType":{"$t":"Automobile"},
"firstName":{"$t":"John"},
"lastName":{"$t":"Smith"},
"dayPhone":{"$t":"2039299400"},
"nightPhone":{"$t":"2035551212"},
"socialSecurityNumber":{"$t":"123-45-6789"},
"amountRequested":{"$t":"15000"},
"loanDescription":{"$t":"Application to finance the purchase of a Toyota Prius"},
"otherInfo":{"$t":"Down payment is US$7500"},
"responseEmail":{"$t":"john.smith@example.com"}
}
}
--the_boundary
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-ID: <part2_id>
[...Text Attachment Content...]
--the_boundary
Content-Type: image/jpeg
Content-ID: <part3_id>
Content-Transfer-Encoding: BASE64
Content-Description: Picture A
[...Image Content...]
--the_boundary--
Processes can be invoked using a multipart/form-data type payload (normally used by HTML forms).
When using this content-type, ActiveVOS server requires the form-data to contain one field
with name _json. The value of this field must contain the JSON request.
POST /active-bpel/services/JSON/humantaskProcessDemoService HTTP/1.1
Content-Type: multipart/form-data; boundary="the_boundary"
Content-Length: 3449
MIME-Version: 1.0
Host: localhost:8080
--the_boundary
Content-Disposition: form-data; name="_json"
{"loanProcessRequest":{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd","loanType":{"$t":"Automobile"},"firstName":{"$t":"John"},"lastName":{"$t":"Smith"},"dayPhone":{"$t":"2039299400"},"nightPhone":{"$t":"2035551212"},"socialSecurityNumber":{"$t":"123-45-6789"},"amountRequested":{"$t":"15000"},"loanDescription":{"$t":"Application to finance the purchase of a Toyota Prius"},"otherInfo":{"$t":"Down payment is US$7500"},"responseEmail":{"$t":"john.smith@example.com"}}}
--the_boundary
Content-Disposition: form-data; name="file_1"; filename="picture.gif"
Content-Type: image/gif
[image content]
--the_boundary--
The above request was generated by the HTML form:
<form method='POST'
enctype='multipart/form-data' action='http://localhost:8080/active-bpel/services/JSON/humantaskProcessDemoService'>
<!-- JSON message payload in a hidden field named '_json' -->
<input type="hidden" name="_json" value='{"loanProcessRequest":{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd","loanType":{"$t":"Automobile"},"firstName":{"$t":"FileUploadJohn"},"lastName":{"$t":"Smith"},"dayPhone":{"$t":"2039299400"},"nightPhone":{"$t":"2035551212"},"socialSecurityNumber":{"$t":"123-45-6789"},"amountRequested":{"$t":"15000"},"loanDescription":{"$t":"Application to finance the purchase of a Toyota Prius"},"otherInfo":{"$t":"Down payment is US$7500"},"responseEmail":{"$t":"john.smith@example.com"}}}' />
File1: <input type="file" name="file_1" /> <br/>
<input type="submit" value="Upload File"/>
</form>
Normally the multipart/form-data request generation and handling of the response
is done using JavaScript (for AJAX style browser applications).
Note that the response to a process invoke (with or without attachments) using multipart/form-data,
is an application/json response (as shown in previous examples).
Since a response from a process can have attachments in addition to the response message (JSON),
you can limit the response to the message (JSON) only by specifying messageOnly=true in the
query string. Similarly, to restrict the response to contain only the attachments
(if the process sends back attachments), use attachmentOnly=true in the query string.
(Note: the following applies to ActiveVOS 7.1.2 or later.)
Some AJAX based form submit scripts that support file upload expect the return content-type
to be text/html (instead of application/json) because of the way scripts target
iFrames. In these cases you specify parameter responseContentType=text/html.
If the responseContentType present, ActiveVOS uses the value defined by the parameter as the
response content-type instead of the default application/json.
A few AJAX Fileupload scripts such as the jQuery Forms Plugin
also require responses to multipart/form-data forms POSTs to be wrapped in a HTML element such
as the textarea tag. This can be accomplished by using the responseWrap parameter. The value
of this paramter should be the HTML element tag name.
The following shows HTML file upload form used by jQuery Forms plugins which requires the response to be returned wrapped in a HTML textarea tag with content-type head of text/html:
<form method='POST'
enctype='multipart/form-data' action='http://localhost:8080/active-bpel/services/JSON/humantaskProcessDemoService'>
<!-- JSON message payload in a hidden field named '_json' -->
<input type="hidden" name="_json" value='{"loanProcessRequest":{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd","loanType":{"$t":"Automobile"},"firstName":{"$t":"FileUploadJohn"},"lastName":{"$t":"Smith"},"dayPhone":{"$t":"2039299400"},"nightPhone":{"$t":"2035551212"},"socialSecurityNumber":{"$t":"123-45-6789"},"amountRequested":{"$t":"15000"},"loanDescription":{"$t":"Application to finance the purchase of a Toyota Prius"},"otherInfo":{"$t":"Down payment is US$7500"},"responseEmail":{"$t":"john.smith@example.com"}}}' />
<!-- Force response content-type to text/html -->
<input type="hidden" name="responseContentType" value="text/html" />
<!-- Return response wrapped in a textarea element -->
<input type="hidden" name="responseWrap" value="textarea" />
File1: <input type="file" name="file_1" /> <br/>
<input type="submit" value="Upload File"/>
</form>
You can use the RESTClient test application to send JSON data to the ActiveVOS server. Note that the content-type of the payload should be set to application/json.
The following example shows how to invoke a process using AJAX with jQuery. The scripts used for the request require jQuery 1.3.2+ (http://www.jquery.com) and json2.js (http://www.JSON.org/json2.js). The json2.js script is used to convert a JSON object to a string.
var loanRequestJSON = {"loanProcessRequest":
{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd",
"loanType":{"$t":"Automobile"},
"firstName":{"$t":"John"},
"lastName":{"$t":"Smith"},
"dayPhone":{"$t":"2039299400"},
"nightPhone":{"$t":"2035551212"},
"socialSecurityNumber":{"$t":"123-45-6789"},
"amountRequested":{"$t":"15000"},
"loanDescription":{"$t":"Application to finance the purchase of a Toyota Prius"},
"otherInfo":{"$t":"Down payment is US$7500"},
"responseEmail":{"$t":"john.smith@example.com"}
}
};
// convert JSON to string using function in json2.js script
var jsonStr = JSON.stringify(loanRequestJSON);
// Send jQuery AJAX POST to http://localhost:8080/active-bpel/services/JSON/humantaskProcessDemoService
$.ajax( {
url : "http://localhost:8080/active-bpel/services/JSON/humantaskProcessDemoService",
type : "POST",
contentType : "application/json; charset=utf-8",
data : jsonStr, // JSON payload
dataType : "json", // expected return data type
cache : false,
success : function(aJsonResponse, aTextStatus) {
// callback function on success
alert("status=" + aJsonResponse.status.$t);
},
error : function(aXmlHttpReq, aTextStatus, aErrorThrown) {
// callback function when an error occurs - including faults.
// code that checks for response status code and data
// to determine the type of error and fault.
// var resp_contentType = aXmlHttpReq.getResponseHeader("Content-Type");
// var http_statusCode = aXmlHttpReq.status;
// var http_statusMsg = aTextStatus;
}
});
The AE_AJAX_SERVICE_UTIL Javascript object in the ae-avc-util.js script included with the SDK provides
has a convenience function
postJSON(url, jsonRequest, successCallbackFn, faultCallbackFn, errorCallbackFn) helper function
to POST JSON data.
var loanRequestJSON = {"loanProcessRequest":
{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd",
"loanType":{"$t":"Automobile"},
"firstName":{"$t":"John"},
"lastName":{"$t":"Smith"},
"dayPhone":{"$t":"2039299400"},
"nightPhone":{"$t":"2035551212"},
"socialSecurityNumber":{"$t":"123-45-6789"},
"amountRequested":{"$t":"15000"},
"loanDescription":{"$t":"Application to finance the purchase of a Toyota Prius"},
"otherInfo":{"$t":"Down payment is US$7500"},
"responseEmail":{"$t":"john.smith@example.com"}
}
};
AE_AJAX_SERVICE_UTIL.postJSON(
// service url
"http://localhost:8080/active-bpel/services/JSON/humantaskProcessDemoService",
// JSON request object (not string)
loanRequestJSON,
// success callback of JSON data
function(aJsonResponse) {
alert("status=" + aJsonResponse.status.$t);
},
// fault callback of JSON data
function(aJsonFault) {
// handle fault
},
// http error callback
function(aStatusCode, aStatusMessage) {
// handle transport error
}
);
Here is another example that uses the WS-HumanTask (WSHT) API getMyTasks operation via JSON. This example fetches tasks via the API and populates a HTML table with the results.
<! -- html snippet -->
<table cellpadding="2" border="1">
<thead>
<tr><th colspan="5">Get My Tasks Response (from JSON):</th></tr>
<tr><th>Task ID</th> <th>Status</th><th>Owner</th><th>PresentationName</th><th>PresentationSubject</th></tr>
</thead>
<! -- the table body will be populated using JavaScript -->
<tbody id="taskList">
</tbody>
</table>
// getMyTasks reqests
var getMyTasksRequest = {
"getMyTasks" : {
"xmlns" : "http://www.example.org/WS-HT/api/xsd",
"taskType" : { "$t" : "TASKS" },
"genericHumanRole" : { "$t" : "POTENTIAL_OWNERS" },
"status" : { "$t" : "READY" },
"maxTasks" : { "$t" : "10" }
}
};
// send JSON
AE_AJAX_SERVICE_UTIL.postJSON(
// task-client service url
"http://localhost:8080/active-bpel/services/JSON/AeB4PTaskClient-taskOperations",
// req.
getMyTasksRequest,
// success callback of JSON data
function(aJsonResponse) {
// display results in a table
populateTaskList(aJsonResponse);
},
// fault callback of JSON data
function(aJsonFault) {
alert("Fault!");
},
// http error callback
function(aStatusCode, aStatusMessage) {
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
//
// This function takes a getMyTasksResponse element (in JSON) and populates
// the tasks in an HTML table.
//
function populateTaskList(aJsonResponse) {
// Note: aJsonResponse contains getMyTasksResponse object)
// clear current contents by removing all children of the table (table rows)
$("#taskList").empty();
// check to make sure response exists.
if (!aJsonResponse.getMyTasksResponse) {
alert("Response 'getMyTasksResponse' expected.");
return;
}
// get list of task abstracts (//htdt:getMyTasksResponse/htdt:taskAbstract)
var taskAbstracts = AE_JSON_NODE_UTIL.getElements(aJsonResponse.getMyTasksResponse.taskAbstract);
var i;
// for each taskAbstract, build the html row and append to table tbody.
for (i = 0; i < taskAbstracts.length; i++) {
var html = "<tr>";
html += "<td>" + AE_JSON_NODE_UTIL.getText(taskAbstracts[i].id, "n/a") + "</td>";
html += "<td>" + AE_JSON_NODE_UTIL.getText(taskAbstracts[i].status, "n/a") + "</td>";
html += "<td>" + AE_JSON_NODE_UTIL.getText(taskAbstracts[i].actualOwner, "n/a") + "</td>";
html += "<td>" + AE_JSON_NODE_UTIL.getText(taskAbstracts[i].presentationName, "n/a") + "</td>";
html += "<td>" + AE_JSON_NODE_UTIL.getText(taskAbstracts[i].presentationSubject, "n/a") + "</td>";
html += "</tr>";
// append to table
$("#taskList").append(html);
};
}
The AE_AJAX_SERVICE_UTIL Javascript object (in ae-avc-util.js) has the following
utility functions related to making JSON invokes.
| Function | Description |
|---|---|
| AE_AJAX_SERVICE_UTIL.getActiveVOSServiceUrl(serviceNamePath) | A helper function that creates the endpoint URL to the given service name by appending
the service name to a predefined engine endpoint. The engine URL should be assigned
(at the start of your script) to the global variable
If a value is assigned to the global variable
// Define engine context URL and optional proxy URL at the start of your script.
// If the engine URL is not given, then 'http://localhost:8080/active-bpel' is used.
// Note: AE_ACTIVEVOS_ENGINE_URL is global variable declared in ae-avc-util.js.
// You only need to assign it a value (to server /active-bpel context).
AE_ACTIVEVOS_ENGINE_URL = "http://demoserver:81/active-bpel";
// Optionally, if you are using a proxy for AJAX requests, you can
// assign it a value here:
// AE_ACTIVEVOS_PROXY_URL = "http://localhost:8080/proxy";
// E.g. JSON service URL.
var loanServiceXmlUrl = AE_AJAX_SERVICE_UTIL.getActiveVOSServiceUrl("JSON/humantaskProcessDemoService");
// loanServiceXmlUrl is now equivalent to: AE_ACTIVEVOS_ENGINE_URL + "/services/" + "JSON/humantaskProcessDemoService"
// e.g. : http://demoserver:81/active-bpel/JSON/humantaskProcessDemoService
// If a value to AE_ACTIVEVOS_PROXY_URL is assigned, then the 'loanServiceXmlUrl' becomes part of
// the proxy url string parameter named 'destination'.
// e.g: http://localhost:8080/proxy?destination=http://demoserver:81/active-bpel/JSON/humantaskProcessDemoService
// E.g. XML service URL.
var loanServiceXmlUrl = AE_AJAX_SERVICE_UTIL.getActiveVOSServiceUrl("XML/humantaskProcessDemoService");
|
| AE_AJAX_SERVICE_UTIL.postJSON(aServiceUrl, aJsonData, aOnSuccessFn, aOnFaultFn, aOnErrorFn, aTimeOut) | Sends the JSON request to the server using HTTP POST and calls back with the JSON response.
This function also handles error responses and callbacks either the JSON fault handler
or the HTTP transport level error handler. Only the
var serviceUrl = "http://localhost:8080/active-bpel/JSON/humantaskProcessDemoService";
// or serviceUrl=AE_AJAX_SERVICE_UTIL.getActiveVOSServiceUrl("JSON/humantaskProcessDemoService");
// send JSON
AE_AJAX_SERVICE_UTIL.postJSON(
serviceUrl, // service url
jsonRequest, // request JSON object
function(aJsonResponse) { // success callback of JSON data
// handle success response
alert("Success!");
},
function(aJsonFault) { // fault callback of JSON data
alert("Fault!");
},
function(aStatusCode, aStatusMessage) { // http error callback
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
|
Complete working JSON Process Invoke examples can be found in the /examples/javascript/ directory.
getInstance() operation to fetch task instance details, including input
and output dataTo use these examples, you must deploy all files in this folder to the application server or web server
where the ActiveVOS engine is deployed. For example, when using the Designer and its embedded server,
you can deploy the provided activevos-javascript-examples.war:
Navigate to the embedded server active-bpel webapps folder. E.g:
C:\Program Files\ActiveVOS\Designer\designer\dropins\activevos\eclipse\plugins\org.activebpel.enginep_7.1.2\server\webapps\
/examples/activevos-javascript-examples.war war file to web apps folder.The examples should be available at
http://localhost:8080/active-bpel/activevos-javascript-examples/index.html
The AE_TASK_GLOBALS in ae-avc-tasks.js contains common constants
that can be used from your code. For example, the string 'illegalArgument' (WSHT fault name)
is defined in AE_TASK_GLOBALS.TASK_FAULT_NAMES.ILLEGAL_ARGUMENT.
The 'http://www.example.org/WS-HT' namespace is defined in AE_TASK_GLOBALS.NAMESPACES.XMLNS_HTD.
Additional details are available in the AeTaskGlobals
class in ae-avc-tasks.js script.
The getMyTasks example provided in the Invoking a Process with jQuery section (the full example is located in json-getTasks.htm) demonstrated how to send a WSHT getMyTasks request to the server using AE_AJAX_SERVICE_UTIL.postJSON() util function. The ae-avc-tasks.js script contains AE_TASK_UTIL instance with the following convenience functions:
| Function | Description |
|---|---|
| AE_TASK_UTIL.getFaultData(aJsonFault) | Returns an object
// code that handles fault due to a human task operation invoke.
// check if this is a WSHT fault
var faultData = AE_TASK_UTIL.getFaultData(aJsonFault);
if (faultData != null) {
// wsht fault.
if (faultData.faultName == AE_TASK_GLOBALS.TASK_FAULT_NAMES.ILLEGAL_ARGUMENT) {
alert("illegal arg fault: " + faultData.message);
}
} else {
// system soap fault?
var soapFaultData = AE_AJAX_SERVICE_UTIL.getSystemFault(aJsonFault);
if (soapFaultData != null) {
alert("SOAP fault. Fault name:" + soapFaultData.name
+ ", message:" + soapFaultData.message);
}
}
|
| AE_TASK_UTIL.isFault(aJsonResponse) | Returns true if the json object 'aJsonResponse' is a known WSHT fault (per WSDL). |
| AE_TASK_UTIL.createGetTasksRequest(aParams, aGetTasksTemplate) |
Creates a generic request getTasks request and returns the JSON object. The params object contains the optional values. The options are:
Provide a value of null to remove existing elements. If the optional aGetTasksTemplate object, which is an existing JSON request is given, then aGetTasksTemplate is first cloned, and then the params are applied. To create the following request:
<aeb:getTasks
xmlns:aeb="http://schemas.active-endpoints.com/b4p/wshumantask/2007/10/aeb4p-task-state-wsdl.xsd" >
<htdt:getMyTasks xmlns:htdt="http://www.example.org/WS-HT/api/xsd">
<htdt:taskType>TASKS</htdt:taskType>
<htdt:genericHumanRole>POTENTIAL_OWNERS</htdt:genericHumanRole>
<htdt:status>READY</htdt:status>
<htdt:status>RESERVED</htdt:status>
<htdt:maxTasks>5</htdt:maxTasks>
</htdt:getMyTasks>
<aeb:taskIndexOffset>0</aeb:taskIndexOffset>
</aeb:getTasks>
Normally, you will need to create the JSON object:
var getTasksRequest = {
"getTasks" : {
"xmlns" : "http://schemas.active-endpoints.com/b4p/wshumantask/2007/10/aeb4p-task-state-wsdl.xsd",
"getMyTasks" : {
"xmlns" : "http://www.example.org/WS-HT/api/xsd",
"taskType" : { "$t" : "TASKS" },
"genericHumanRole" : { "$t" : "POTENTIAL_OWNERS" },
"status" : [ {"$t" : "READY"} , {"$t" : "RESERVED"} ],
"maxTasks" : { "$t" : "5"}
},
"taskIndexOffset" : { "$t" : "0" }
}
}
With the
var getTasksRequest = AE_TASK_UTIL.createGetTasksRequest( {
taskType : "TASKS",
genericHumanRole : "POTENTIAL_OWNERS",
status : ["READY", "RESERVED"],
maxTasks : 5,
taskIndexOffset : 0
});
// getTasksRequest contains JSON for
|
The AeTaskApi class (in ae-avc-tasks.js script) can be used to access
and operate on tasks. A few common functions are shown below.
Please refer to AeTaskApi in ae-avc-tasks.js for additional functions and details.
| Function | Description |
|---|---|
| getTasks(aGetTasksRequest, aSuccessCallbackFn, aFaultCallbackFn, aErrorCallbackFn) | Invokes the
// Assign the server URL to AE_ACTIVEVOS_ENGINE_URL global variable. This is where the service
// requests are sent. (note: AE_ACTIVEVOS_ENGINE_URL is global variable declared in ae-avc-util.js.)
AE_ACTIVEVOS_ENGINE_URL = "http://localhost:8080/active-bpel";
// create JSON request for getTasks operation. E.g. get upto 10 unclaimed tasks.
var getTasksRequest = AE_TASK_UTIL.createGetTasksRequest( {
taskType : AE_TASK_GLOBALS.GETMYTASKS_TASK_TYPE.TASKS, // same as string "TASKS"
genericHumanRole : AE_TASK_GLOBALS.GENERIC_HUMAN_ROLE.POTENTIAL_OWNERS, // same as string "POTENTIAL_OWNERS"
status : AE_TASK_GLOBALS.TASK_STATUS.READY, // "READY"
maxTasks : 10
});
// Create AeTaskApi object and get the task list via getTasks() operation.
var taskApi = new AeTaskApi();
taskApi.getTasks(
getTasksRequest, // request JSON object
function(aJsonResponse) { // success callback of JSON data
// handle success response
alert("Success!");
// get list of task abstracts (//htdt:getMyTasksResponse/htdt:taskAbstract)
var jsonTaskAbstracts = AE_JSON_NODE_UTIL.getElements(aJsonResponse.getMyTasksResponse.taskAbstract);
var i;
for (i = 0; i < jsonTaskAbstracts.length; i++) {
// wrap json data in AeTaskAbstract object for convenience accessors.
// (see ae-avc-tasks.js for AeTaskAbstract)
var taskAbstractObj = new AeTaskAbstract( jsonTaskAbstracts[i] );
alert( "Task id: " + taskAbstractObj.getId() );
alert( "Task name: " + taskAbstractObj.getName() );
alert( "Task status: " + taskAbstractObj.getStatus() );
}
},
function(aJsonFault) { // fault callback of JSON data
alert("Fault!");
},
function(aStatusCode, aStatusMessage) { // http error callback
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
|
| getInstance(aTaskId, aSuccessCallbackFn, aFaultCallbackFn, aErrorCallbackFn) | Invokes the AE specific
// ...
// setup AE_ACTIVEVOS_ENGINE_URL etc.
// ...
var taskApi = new AeTaskApi();
taskApi.getInstance(
"urn:b4p:1235", // task ID
function(aTask) { // handle success response
// aTask is an instance of AeTask (see ae-avc-tasks.js).
alert( "Got task, id=" + aTask.getId() );
alert( "Task name: " + aTask.getName() );
alert( "Task status: " + aTask.getStatus() );
// aTask.getJson() returns the underlying raw JSON data structer.
// aTask.getOwner() returns current owner.
var inputPartJson = aTask.getInput(); (// for input by partname, use aTask.getInput('nameOfPart');
},
function(aJsonFault) {
alert("Fault!");
},
function(aStatusCode, aStatusMessage) {
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
|
| invokeSimpleWshtRequest(aCommand, aTaskId, aSuccessCallbackFn, aFaultCallbackFn, aErrorCallbackFn) | Invokes a simple WSHT operation such as
var taskApi = new AeTaskApi();
var taskId = "urn:b4p:1234";
// claim
taskApi.invokeSimpleWshtRequest(
AE_TASK_GLOBALS.SIMPLE_WSHT_OPERATIONS.CLAIM,
taskId,
function(aClaimResponse) {
// success (json data)
},
function(aFaultResponse) {
// fault (json data)
},
function(aStatusCode, aStatusMessage) {
//error
}
);
// start
taskApi.invokeSimpleWshtRequest(
AE_TASK_GLOBALS.SIMPLE_WSHT_OPERATIONS.START,
taskId,
function(aStartResponse) {
// success (json data)
},
// ... fault and error handlers omitted for brevity ...
);
// complete
taskApi.invokeSimpleWshtRequest(
AE_TASK_GLOBALS.SIMPLE_WSHT_OPERATIONS.COMPLETE,
taskId,
function(aStartResponse) {
// success (json data)
},
// ... fault and error handlers omitted for brevity ...
);
|
| setOutput(aTaskId, aPartName, aOutputPart, aSuccessCallbackFn, aFaultCallbackFn, aErrorCallbackFn) | Sets the task output data given the task ID, the output part name and the output JSON data
var taskApi = new AeTaskApi();
var taskId = "urn:b4p:1234";
// message part name per wsdl
var partName = "response";
// the <loan:loanApprovalResponse /> in JSON.
var outputJson = {"loanApprovalResponse":
{
"xmlns":"http:\/\/schemas.active-endpoints.com\/avoscentral\/LoanRequest\/2009\/07\/avc-loanapproval.xsd",
// other attributes and elements omitted for brevity.
}
};
// set output data
taskApi.setOutput(
taskId,
partName,
outputJson,
function(aSetOutputResponse) {
// success (json data)
},
function(aFaultResponse) {
// fault (json data)
},
function(aStatusCode, aStatusMessage) {
//error
}
);
|
The AeTask class (in ae-avc-tasks.js script) is a wrapper for
the <taskInstance /> element. This wrapper provides getters and setters
for frequently used properties.
One way to get an instance of AeTask is using the AeTaskApi.getInstance(...) function:
// ...
// setup AE_ACTIVEVOS_ENGINE_URL etc.
// ...
var taskApi = new AeTaskApi();
taskApi.getInstance(
"urn:b4p:1235", // task ID
function(aTask) { // handle success response
// aTask is an instance of AeTask (see ae-avc-tasks.js).
alert( "Got task, id: " + aTask.getId() );
alert( "Task name: " + aTask.getName() );
alert( "Task status: " + aTask.getStatus() );
// aTask.getJson() returns the underlying raw JSON data structer.
// aTask.getOwner() returns current owner.
},
function(aJsonFault) {
alert("Fault!");
},
function(aStatusCode, aStatusMessage) {
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
Please refer to AeTask in ae-avc-tasks.js for additional functions and details.
Getters and Setters to task input/output data are described below:
| Function | Description |
|---|---|
| getInputPart(aPartName) | Returns the task input part data given the part name (per WSDL message). If the aPartName is not given, then the first available part is returned.
//
// task is an instance of AeTask, obtained via AeTaskApi.getInstance(...)
// (assuming using the Loan Approval human task example)
//
// <message name="WshtLoanInput">
// <part name="request" element="loan:loanProcessRequest" />
// </message>
// <message name="WshtLoanOutput">
// <part name="response" element="loan:loanApprovalResponse" />
// </message>
var loanRequestInput = task.getInput("request"); // 'request' is the part name
// note: task.getInput() returns first available part since part name is not given.
alert("Firt Name = " + loanRequestInput.loanProcessRequest.firstName);
alert("Loan Amount = " + loanRequestInput.loanProcessRequest.amountRequested);
|
| getOutputPart(aPartName) | Returns the task out part data given the part name (per WSDL message).
If the aPartName is not given, then the first available part is returned.
If part data is not available, then
var loanOutput = task.getOutput("response"); // 'response' is the output part name
// check for null in case output is not set.
if (loanOutput != null) {
alert("Approved? = " + loanOutput.loanApprovalResponse.responseToLoanRequest);
}
|
| setOutputPart(aPartName, aPartData) | Sets the output part data in the
// First time use, create JSON output:
// var loanOutput = { {"loanApprovalResponse" : ... }};
// or getOutput() to access current value if the output has already been set.
var loanOutput = task.getOutput("response");
// modify data
AE_JSON_NODE_UTIL.setText(loanOutput.loanApprovalResponse.responseDescription, "Some Text");
// Set output (in-memory only)
task.setOutput("response", loanOutput);
// Now, save all available parts to the server using the AeTaskApi.
var taskApi = new AeTaskApi();
task.saveOutputParts(
taskApi,
function(aSetOutputResponse) {
// success (json data)
},
function(aFaultResponse) {
// fault (json data)
},
function(aStatusCode, aStatusMessage) {
//error
}
);
|
In some cases, you may want to display attachment information on a web page.
In order to do this, you need to access the list of attachment meta data (attachment infos)
from the WSHT getAttachmentInfos operation or via the attachmentInfo elements that
are part of taskInstance (obtained from getInstance extension operation).
The URL to the attachment content can be built using the AE_TASK_UTIL.getAttachmentUrl(taskId, attachmentName, attachmentId) function.
//
// 1) Using getAttachmentInfos wsht API call.
//
var taskId = "urn:b4p:1235"; // task id
var getAttachmentInfosReq = {
"getAttachmentInfos" : {
"xmlns" : "http://www.example.org/WS-HT/api/xsd",
"identifier" : {
"$t" : taskId
}
}
};
AE_AJAX_SERVICE_UTIL.postJSON(
// task-client service url
"http://localhost:8080/active-bpel/services/JSON/AeB4PTaskClient-taskOperations",
// req.
getAttachmentInfosReq,
// success callback of JSON data
function(aJsonResponse) {
// handle getAttachmentInfosResponse
var attachmentInfoList = AE_JSON_NODE_UTIL.getElements(aJsonResponse.getAttachmentInfosResponse.info);
var i;
for (i = 0; i < attachmentInfoList; i++) {
var info = attachmentInfoList[i];
var attachmentId = AE_JSON_NODE_UTIL.getText(info.attachmentId);
var attachmentName = AE_JSON_NODE_UTIL.getText(info.name); // file name
var contentType = AE_JSON_NODE_UTIL.getText(info.contentType); // mime type.
var attachUrl = AE_TASK_UTIL.getAttachmentUrl(taskId, attachmentName, attachmentId);
// do something with this info such as displaying on page.
// (the attachUrl can be used for href attribute in <a> tags and src in <img> tags)
}
},
// fault callback of JSON data
function(aJsonFault) {
alert("Fault!");
},
// http error callback
function(aStatusCode, aStatusMessage) {
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
//
// 2) Alternate method of getting attachment info via AeTask object.
//
var taskApi = new AeTaskApi();
taskApi.getInstance(
"urn:b4p:1235", // task ID
function(aTask) { // handle success response
var attachmentInfoList = aTask.getAttachments();
var i;
for (i = 0; i < attachmentInfoList; i++) {
var info = attachmentInfoList[i].attachmentInfo;
var attachmentId = AE_JSON_NODE_UTIL.getText(info.attachmentId);
var attachmentName = AE_JSON_NODE_UTIL.getText(info.name); // file name
var contentType = AE_JSON_NODE_UTIL.getText(info.contentType); // mime type.
var attachUrl = AE_TASK_UTIL.getAttachmentUrl(aTask.getId(), attachmentName, attachmentId);
// do something with this info such as displaying on page.
// (the attachUrl can be used for href attribute in <a> tags and src in <img> tags
}
},
function(aJsonFault) {
alert("Fault!");
},
function(aStatusCode, aStatusMessage) {
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
In cases where the request and response contains xsd:dateTime
type elements, the contents of these elements take the form
YYYY-MM-DDTHH:MM:SS.sssZ (UTC time). However the user interface
in a browser deals with local time instead of UTC. The following functions
in the AE_UTIL object in the included ae-avc-utils.js can be used.
| Function | Description |
|---|---|
| AE_UTIL.xsdDateTimeToJsDateTime(xsdDateTimeStr) | Parses the ISO8601 xsd dateTime (YYYY-MM-DDTHH:MM:SS.sssZ) string and returns JavaScript Date object. // task created on date. E.g: "2010-03-15T17:15:00.881Z" (12.15PM Eastern Time/GMT-5). var createdOnXsdStr = AE_JSON_NODE_UTIL.getText(taskAbstracts[i].createdOn); // convert to a JavaScript date object. var createdDate = AE_UTIL.xsdDateTimeToJsDateTime(createdOnXsdStr); |
| AE_UTIL.xsdDateToJsDate(xsdDateStr) | Parses the xsd date (YYYY-MM-DD) string and returns JavaScript Date object. |
| AE_UTIL.xsdTimeToJsTime(xsdTimeStr) | Parses the xsd time (HH:MM:SS) string and returns JavaScript Date object. The returned date object contains the parsed time (but uses current date). |
| AE_UTIL.toXsdDateTime(date) | Converts a JavaScript Date object into a ISO8601 dateTime string (YYYY-MM-DDTHH:MM:SS.sssZ). |
| AE_UTIL.toXsdDateTimeFromDateAndTimeStr(date, time) | The date and time parameters are both JavaScript date objects. This function converts a date and time JavaScript Date objects into a ISO8601 dateTime string (YYYY-MM-DDTHH:MM:SS.sssZ). |
| AE_UTIL.toXsdDate(date) | Converts a JavaScript Date object into a ISO8601 date string (YYYY-MM-DD). Timezone information is not used. |
| AE_UTIL.toXsdTime(date) | Converts a JavaScript Date object into a ISO8601 time string (HH:MM:SS). Timezone information is not used. |
When working with forms that use date and time types, first convert the raw JSON the date/time information (ISO8601) to a Javascript Date object before presenting it to the user (e.g. via AE_UTIL.xsdDateTimeToJsDateTime(...) ). Conversely, the local date/time information from the user should be first converted to a ISO8601 (e.g. via AE_UTIL.toXsdDateTime(...)) before sending it to the ActiveVOS server.
You can create HTML forms and basic supporting JavaScript using ActiveVOS Designer (7.1 or later).
The Process Request Form action available under File -> New -> Other -> Orchestration
brings up a wizard style dialog. From this dialog you can choose your request WSDL, port-type, operation
and the destination where the generated HTML file is saved.
(Click to view larger images)
Select WSDL port-type and operation.
Select location where the HTML file will be saved.
The generated html forms looks similar to (in the case of Loan Approval process):
The basic structure of a generated request form HTML looks like the following:
<html>
<head>
<!-- header content -->
</head>
<body>
<!--
Main DIV that contains all markup
related to this request form UI
-->
<div id="processRequestForm$ID">
<!-- DIV that contains UI related request form and data entry -->
<div id="processRequestForm$ID">
<div>Display Name UI</div>
<!-- container for the form UI controls -->
<div>
<form id="loanApplicationInputForm$ID">
<!-- actual form content, for example: -->
First Name: <input id="firstName$ID" name="firstName" value="" size="50" /> <br/>
Last Name: <input id="lastName$ID" name="lastName" value="" size="50" /> <br/>
</form>
<!-- Send button -->
<input type="button" id="sendRequest$ID" value="Send Request" />
</div>
</div>
<!--
DIV that contains html to show
the results after submitting a form (invoking a process).
Note this DIV is initially hidden, and only shown when
response data needs to be displayed.
-->
<div id="responseContainer$ID" style="display: none;">
</div>
</div>
<!-- Script -->
<script type="text/javascript">
// <![CDATA[
// JavaScript to implement JSON process invoke
// ]]>
</script>
</body>
</html>
The HTML above is a skeleton used to illustrate various elements used in ActiveVOS Designer generated forms.
The actual form may be a little more detailed and is targeted for use with jQuery and jQueryUI.
Note that all elements used in the form have an id attribute. The id attribute is
used as the primary selector when ActiveVOS needs to access various elements within the HTML document.
Also note that the id attribute values that are generated end with the
$ID suffix (for example processRequestForm$ID in
<div id="processRequestForm$ID">).
All elements in an HTML document must have unique values for the
idattribute. In cases where you need to display the same form more than once (a requirement of ActiveVOS Central), the elements cannot be duplicated with the same values for theidattribute. When the forms are used with ActiveVOS Central, the forms server automatically replaces the$IDsuffix with a unique value so that a form can be cloned and used in the same HTML document. For example, at runtime ActiveVOS Central may have two loan request form instances<div id="processRequestForm_01">and<div id="processRequestForm_02">(note where$IDhas been replaced with_01and_02in this example).Since this document pertains to using single instance of forms (outside of ActiveVOS Central), you can use the generated html as is after performing a search-and-replace of
$IDsuffix with any string that does not have a$. For example, if all occurrences of$IDis replaced with an empty value, you essentially remove the$IDsuffix. E.g.<div id="processRequestForm$ID">becomes<div id="processRequestForm">.
Using jQuery form input data can be used with the id selectors.
For example getting the current value of the firstName input field is
$("#firstName$ID").val(). The field value can be prepopulated with data
using $("#firstName$ID").val("John"). The complete script that
drives the form can be found at the end of the form in the <script> section.
The basic mechanics of the script looks similar to following skeleton code
:
// The jQuery 'ready' event is fired once the page (form) is loaded and ready for processing.
$(document).ready(function() {
// bind button click event handler code when the Send button is pressed.
$("#sendRequest$ID").click( function() {
sendForm(); // see fn below.
});
});
// send form
function sendForm() {
// first grab data entered by user.
var firstNameStr = $("#firstName$ID").val();
// ..
// .. get other UI data such as loanType, lastName, phone etc.
// ..
// build JSON request
var loanRequestJSON = {"loanProcessRequest":
{"xmlns":"http:\/\/schemas.active-endpoints.com\/sample\/LoanRequest\/2008\/02\/loanRequest.xsd",
"loanType":{"$t": loanTypeStr},
"firstName":{"$t": firstNameStr},
"lastName":{"$t": lastNameStr},
"dayPhone":{"$t": dayPhoneStr},
"nightPhone":{"$t": nightPhoneStr,
"socialSecurityNumber":{"$t": ssnStr},
"amountRequested":{"$t": loanAmount},
"loanDescription":{"$t": loanDesc},
"responseEmail":{"$t": email}
}
};
// JSON endpoint URL (e.g: http://localhost:8080/active-bpel/services/JSON/humantaskProcessDemoService)
var loanServiceUrl = AE_AJAX_SERVICE_UTIL.getActiveVOSServiceUrl("JSON/humantaskProcessDemoService");
// send JSON request
AE_AJAX_SERVICE_UTIL.postJSON(
loanServiceUrl,
loanRequestJSON,
function(aJsonResponse) {
// success result handler:
// show <status/> element text in the response div.
var statusText = AE_JSON_NODE_UTIL.getText(aJsonResponse.status);
// (above is same as aJsonResponse.status.$t)
// append the status text string to the <div id="responseContainer$ID" /> div
$("#responseContainer$ID").html("<p>Status=" + statusText + "</p>");
// show the div (since it was initially hidden)
$("#responseContainer$ID").show();
},
function(aJsonFault) {
alert("Fault!");
},
function(aStatusCode, aStatusMessage) {
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);
}
The code above demonstrates the approach taken to handle form submissions. The actual code in the generated form is a little more detailed, but still follows the methodology described above. In the generated code the script related to a form is enclosed in a function:
// Function that encapsulates the form script.
var AeRequestForm$ID = function() {
// variable defining the name of service
var mServiceName = "humantaskProcessDemoService";
//
// internal functions: pseudo code shown below for brevity
//
// This function is called when the form is loaded.
function documentReady() {
// initialize and populate UI here.
// code to bind the SendButton click event to invoke _submitRequest() function
// also invoke _setupValidation();
}
// function is called (by documentReady() )
function _setupValidation() {
// optional code to setup & initialize your form data validation
}
// Function returns the JSON data structure for this operation
function getInputRequest() {
// code that creates JSON object. For example:
// var json = { "loanProcessRequest": {...} };
// return json;
}
// function called when the Send Request button is pressed.
function _submitRequest() {
// 1. validate the form by calling avcform_validate().
// 2. var jsonReq = getInputRequest();
// 3. get form UI data and populate jsonReq object
// 4. serviceUrl = AE_AJAX_SERVICE_UTIL.getActiveVOSServiceUrl("JSON/" + mServiceName);
// 5. invoke json request via:
// AE_REQUESTS_UTIL.postJSON(serviceUrl, jsonReq, _showResponseCallback, ....);
//
}
// validate the form
function avcform_validate() {
// check form date and validate (e.g. verify required fields have data etc.)
// return true if user submitted data is valid
}
// Called by postJSON(..) code in _submitRequest() function.
function _showResponseCallback(aJsonResponse) {
// called to display response from a json invoke
}
// Called by postJSON(..) code in _submitRequest() function.
function _showFaultCallback(aJsonFault) {
// handle fault
}
// Called by postJSON(..) code in _submitRequest() function.
function _communicationErrorCallback(aStatusCode, aError) {
// error handler code
}
}
// The jQuery 'ready' event is fired once the page (form) is loaded
// and ready for processing.
$(document).ready(function() {
// Create Request Form JavaScript object
var requestForm = new AeRequestForm$ID();
// initialize form
requestForm.documentReady();
});
One approach to making cross domain AJAX request is to use a proxy. In this scenario, your script calls an endpoint on your web application server that is hosting your script and application. That endpoint in turn forwards (proxies) all requests to the actual destination (e.g. ActiveVOS engine where your services are hosted).
(Note: the following applies to ActiveVOS 7.1.2 or later.)
JSONP requests are supported in ActiveVOS 7.1.2 engine. When making JSONP request,
the string version of the JSON data must be sent in a parameter named _json
and the callback function name via parameter named callback
(if a value is not given, then the engine will callback on a function named jsonpCallback).
Since JSONP requests are based on HTTP GET method, the amount of data that can be
sent in a HTTP query string is limited. This means, JSONP requests are better suited for request messages
whose payload is small. Note that attachments are not supported with JSONP.
The basic format of a JSONP request to service deployed on ActiveVOS is:
http://host:port/active-bpel/services/JSON/serviceName?callback=callbackFnName&_json=string_version_of_json
You can use the helper function AE_AJAX_SERVICE_UTIL.getJSON(...) for JSONP.
var getTasksRequest = {
"getMyTasks" :
{
"xmlns" : "http://www.example.org/WS-HT/api/xsd",
"taskType" : { "$t" : "TASKS" },
"genericHumanRole" : { "$t" : "POTENTIAL_OWNERS" },
"status" : [ {"$t" : "READY"} , {"$t" : "RESERVED"} ],
"maxTasks" : { "$t" : "5"}
}
};
// get task list using JSONP
AE_AJAX_SERVICE_UTIL.getJSON(
// task-client service url
"http://localhost:8080/active-bpel/services/JSON/AeB4PTaskClient-taskOperations",
// req.
getMyTasksRequest,
// success callback of JSON data
function(aJsonResponse) {
alert("Success!");
// handle result. e.g. display results in a table
},
// fault callback of JSON data
function(aJsonFault) {
alert("Fault!");
},
// http error callback
function(aStatusCode, aStatusMessage) {
alert("Transport error: " + aStatusCode + " " + aStatusMessage);
}
);