Consuming Services
Table of Contents
Using Stubs
The Javascript returned by "?stub" defines a JavaScript object built specially for each Web Service. It serves two primary purposes:- Databinding. When appropriate, the stub converts XML to JavaScript datatypes.
- Abstract binding details. The stub takes care of all the details of formulating the message which are sent to the endpoint.
Operations as Methods
The WebService object representing a service has methods corresponding to the operations exposed by that web service. For instance, if the "helloworld" service has a "hello" operation, after importing the stub you can invoke the hello operation like this: var theResponse = helloworld.hello(); Of course, in distributed application programming you must be prepared for failures. For instance, say your internet connection has gone down. I recommend right from the start wrapping this method with a try-catch block so you can define some recovery information for the operation:
try {
var theResponse = helloworld.hello();
} catch (e) {
alert("Danger Will Robinson! " + e);
}
If you open and look at the source code of the stub, you
will find a function called "stubs". This function contains simple try-catch
blocks for all the operations of the service. This function is never
executed by the stub, it's just there so you can copy and paste out code
blocks into your script.
These code blocks also indicate the expected type of
each parameter: for instance a function taking a string, a number, and an XML
node, and returning a true/false result would have a code block that looks
like this:
// isEligible operation
try {
/* boolean */
isEligibleReturn = club.isEligible(/* string */ param_userName, /* integer */ param_rating, /* anyType */ param_profile);
} catch (e) {
// fault handling
}
In this case, the user provided adequate inputType and
outputType annotations for us to unwrap the XML message and convert the
result into the above types. In cases where no annotations are included,
often the method call will have to simply pass the parameters and return to
you as XML.
// isEligible operation
try {
/* anyType */
isEligibleReturn = club.isEligible(/* anyType */ param_userName, /* anyType */ param_rating, /* anyType */ param_profile);
} catch (e) {
// fault handling
}
Setting Endpoints and Endpoint Addresses
The WebService object corresponding to a service has a property and two methods which help you determine which binding will be used to invoke the service:| {service}.endpoint | This read/write property
names the endpoint that will be invoked. This corresponds to the WSDL 2.0
endpoint name - and for services exposed by the mashup, it is generally one
of these values:
|
| {service}.getAddress(endpoint) | This method takes an endpoint name (typically one of the above) and returns the endpoint address. |
| {service}.setAddress(endpoint, url) | This method sets the address for a particular named endpoint. |
| {service}.scriptInjectionCallback | This read/write property defines an optional callback when an operation is invoked,
providing a hook for
notification when a normal Web Service call is made versus an attempt at accessing an
endpoint across
domains within a browser environment. The callback parameter indicates whether script
injection was
used (true) or whether a normal Web service call was performed (false).
myMashup.scriptInjectionCallback = function(scriptInjection) { if (scriptInjection) alert("Using script injection"); else alert("Normal Web services call"); } |
// choose an endpoint type
myService.endpoint = "HTTPEndpoint";
// record where the messages were supposed to go
log("Original destination: " + myService.getAddress("HTTPEndpoint"));
// redirect the messages to a different port for logging/debugging purposes.
myService.setAddress("HTTPEndpoint", "http://localhost:12345/services/myService");
Asynchronous Invocation
Because Web Services often involve communicating with services located who-knows-where on the globe, it is usually good practice to make the call asynchronously. In the browser, this prevents the UI from blocking and becoming unresponsive. It offers better performance because you can invoke several operations in parallel rather than waiting for one to complete before starting the next. Asynchronous programming can be a bit more complicated than regular synchronous calling, but the benefits are usually well worth the additional complexity. The stubs support asynchronous calling through the addition of two properties (callback, onError) on the method objects:
helloworld.hello.callback = success;
helloworld.hello.onError = failure;
helloworld.hello();
alert("waiting for response");
function success(helloResponse) {
alert(helloResponse.documentElement.xml);
}
function failure(error) {
alert(error.reason);
}
The callback and onError handlers, when set to a
function, cause the operation to be executed asynchronously. That is, the
call is sent, and the execution continues (displaying the "waiting for
response" alert in this case). At some future time, either the "success" or
"failure" function will be called, depending obviously on whether the
operation was invoked successfully or not.
The callback function will be called with a single
parameter - the response from the Web service. This response will be
unwrapped and typed just as the return value in the synchronous case.
The onError function, returns an error object with the
following properties:
error.code: when the binding is SOAP, the
error.code will be the QName corresponding to the <code> element.
error.reason: a human readable error message.
When the binding is SOAP, the error.reason corresponds to the <reason>
element.
error.detail: additional information about the failure, for instance a stack trace. When the binding is SOAP, the error.detail corresponds to the <detail> element.
Authentication
A service requiring username/password authentication can be accessed by setting the username and password anntations on the WebService object prior to calling an operation:
| {service}.username | Sets the username for authenticated calls. |
| {service}.password | Sets the password for authenticated calls. |
helloworld.username = "joey";
helloworld.password = "fahr451!";
var theResponse = helloworld.hello();
Using Stubs in Web Pages
In order to use the stub in a Web page, you must import it using a normal script import statement:
<script type="text/javascript" src="?stub"></script>
The stub depends upon a WSRequest object to actually make the calls. If you are using IE, you can install WSRequest as an Active-X Object here. If you are using Firefox, you can install WSRequest as an XPI plugin here. Of course, it's often inconvenient to require a download in a web page, so we provide a version written in JavaScript using the XMLHTTPRequest object that is native in both IE and Firefox browsers. In order to use the native version, import it like this:
<script type="text/javascript" src="js/wso2/WSRequest.js"></script>
The native version handles basic messaging with SOAP 1.2, SOAP 1.1, and HTTP endpoints, but doesn't support advanced features such as message-level security, which will soon be supported more fully in the Mashup Server.
When using Firefox, E4X support is built in. While the normal JavaScript stub works fine, returning DOM objects, for a version of the stub that exposes XML results as native E4X XML objects, add the "lang=e4x" parameter to the import:
<script type="text/javascript;e4x=1" src="?stub&lang=e4x"></script>
Using Stubs in Services
When you wish to access one JavaScript service from another, first make a copy of the stub that you wish to use (for now use "?stub&lang=e4x&localhost=true", so you can get direct access to XML results as native E4X objects), and place it in the {servicename}.resources folder. Then you can include it in the JavaScript for your service as follows:
system.include("{location of stub}");
File paths in system.include are interpreted relative to the .resources folder for that service. The affect of the include is as if you had copied and pasted the text of the stub directly into the JavaScript for the service.
Automatic Type Conversions
When a service returns a value (described by one of the XML Schema built-in types), the stub converts that value into a native JavaScript type as follows:
|
XML Schema type |
JavaScript type |
|
xs:anyType |
E4X XML object |
|
xs:anyURI |
string |
|
xs:base64Binary |
string |
|
xs:boolean |
boolean |
|
xs:byte |
number |
|
xs:date |
Date(yyyy, mm, dd, 0:00:00, tz) |
|
xs:dateTime |
Date(yyyy, mm, dd, hh:mm:ss, tz) |
|
xs:decimal |
string |
|
xs:double |
number |
|
xs:duration |
Number (in milliseconds) |
|
xs:ENTITIES |
Array of strings |
|
xs:ENTITY |
string |
|
xs:float |
number |
|
xs:gDay |
Date(1970, 1, dd, 0:00:00, tz) |
|
xs:gMonth |
Date(1970, mm, 1, 0:00:00, tz) |
|
xs:gMonthDay |
Date(1970, mm, dd, 0:00:00, tz) |
|
xs:gYear |
Date(yyyy, 1, 1, 0:00:00, tz) |
|
xs:gYearMonth |
Date (yyyy, mm, 1, 0:00:00, tz) |
|
xs:hexBinary |
string |
|
xs:ID |
string |
|
xs:IDREF |
string |
|
xs:IDREFS |
Array of strings |
|
xs:int |
number |
|
xs:integer |
number |
|
xs:language |
string |
|
xs:long |
number |
|
xs:Name |
string |
|
xs:NCName |
string |
|
xs:negativeInteger |
number |
|
xs:NMTOKEN |
string |
|
xs:NMTOKENS |
Array of strings |
|
xs:nonNegativeInteger |
number |
xs:nonPositiveIntege r |
number |
|
xs:normalizedString |
string |
|
xs:NOTATION |
string |
|
xs:positiveInteger |
number |
|
xs:QName |
E4X QName object consisting of name, prefix, local-name, namespace-uri. (Note that DOM stubs don't support QNames yet.) |
|
xs:short |
number |
|
xs:string |
string |
|
xs:time |
Date(1970, 1, 1 hh:mm:ss, tz) |
|
xs:token |
string |
|
xs:unsignedByte |
number |
|
xs:unsignedInt |
number |
|
xs:unsignedLong |
number |
|
xs:unsignedShort |
number |
Utility Functions
The WebService object also exposes some utility functions that can be used to further manipulate data types:
| String WebService.utils.toXSdate(date) | Convert a Javascript Date to an xs:date format string (discarding the time information.) |
| String WebService.utils.toXStime(date) | Convert a Javascript Date to an xs:time format string (discarding the date information.) |
| String WebService.utils.toXSdateTime(date) | Convert a Javascript Date to an xs:dateTime format string. |
| Date WebService.utils.parseXSdateTime(date) | Convert an xs:date, xs:time, or xs:dateTime format string into a Javascript date. |
| String WebService.utils.scheme(url) | Extract the scheme from a url. |
| String WebService.utils.domain(url) | Extract the domain from a url. |
| String WebService.utils.domainNoPort(url) | Extract the domain from a url, trimming off any port information. |