标签归档:SOAP Web services

[repost ] Call SOAP Web services with Ajax, Part 2: Extend the Web services client

Summary: Implement a Web Browser-based SOAP Web services client using the Asynchronous JavaScript and XML (Ajax) design pattern. In the Part 1 of this series, “Call SOAP Web Services with Ajax, Part 1,” the author introduced a simple Web browser-based JavaScript library for invoking SOAP Web services. In the discussion that follows, the author expands on functions of that JavaScript library by implementing basic support for the Web Services Addressing Language and the Web Services Resource Framework specifications.

View more content in this series

Quick Review

In Part 1 of this series, I introduced a cross-browser JavaScript library providing a simple SOAP Web services client capable of RPC encoded and document-literal style requests. Included in that client is support for request and response handlers, custom XML serializers/deserializers, and SOAP Headers; all of which I make use of in this WS-Addressing and WS-ResourceFramework implementation.

The primary objects defined in ws.js (introduced in Part 1) include:

  1. WS.Call: A Web Service Client that wraps XMLHttpRequest
  2. WS.QName: XML Qualified Name implementation
  3. WS.Binder: Base for custom XML serializers/deserializers
  4. WS.Handler: Base for Request/Response Handlers
  5. SOAP.Element: Base SOAP Element wrapping XML DOM
  6. SOAP.Envelope: SOAP Envelope Object extends SOAP.Element
  7. SOAP.Header: SOAP Header Object extends SOAP.Element
  8. SOAP.Body: SOAP Body Object extends SOAP.Element
  9. XML: Cross-platform utility methods for handling XML

Of this set of objects, five are critical to the WS-Addressing and WS-ResourceFramework implementation: WS.QName,SOAP.ElementWS.HandlerWS.Binder, and WS.Call. I would strongly suggest that you go back to the first article to review the basic function of these objects.

In this installment, I introduce two new JavaScript files. The first defines objects supporting WS-Addressing (wsa.js); the second defines objects supporting a basic implementation of the WS-ResourceFramework (wsrf.js).
Figure 1. Invoking Web Service Resource Framework services from within the Web browser using the Web Services JavaScript Library
Invoking Web Service Resource Framework services from within the Web Browser

The primary objects defined in wsa.js include:

  1. WSA.EndpointReference: WS-Addressing EndpointReference object.
  2. WSA.EndpointReference.ReferenceParameters: Container for WS-Addressing EPR reference parameters.
  3. WSA.EndpointReference.Binder: XML Serializer/Deserializer for WSA.EndpointReference objects.
  4. WSA.MessageContext: Container for WS-Addressing SOAP message header metadata.
  5. WSA.Handler: Request handler that inserts WS-Addressing SOAP message headers into the SOAP Envelope.

The primary objects defined in wsrf.js include:

  1. WSRF.Request.GetResourceProperty: Wrapper for the WS-ResourceFramework GetResourceProperty operation.
  2. WSRF.Request.GetMultipleResourceProperties: Wrapper for the WS-ResourceFrame GetMultipleresourceProperties operation.
  3. WSRF.Resource: Client interface for invoking WS-ResourceFramework operations.

Note that while this might be a significant number of new JavaScript objects to learn, the API they present has been designed to minimize the amount of work you have to do when actually invoking a Web service. For instance, if you skip ahead to Listing 8, you’ll see that the API lets you invoke a method on WS-ResourceFramework-compliant Web services with only a few lines of code — without the need to mess around with the details of the underlying SOAP implementation.

Back to top

Implement WS-Addressing support

The Web Services Addressing specification defines the mechanisms for inserting addressing information into SOAP envelopes. At the core of WS-Addressing is an object known as an EndpointReference, which serves as a reference to and a description of a specific Web service instance. (See Listing 1.) Secondary to the EndpointReference, the WS-Addressing specification defines a number of SOAP message headers that are used to convey addressing information directly within a SOAP envelope.

The wsa.js JavaScript library provides a number of objects that implement basic support for the WS-Addressing EndpointReference and SOAP message header elements.
Listing 1. A Simple WS-Addressing EndpointReference

<EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
  <Address>http://www.example.org/services/HelloWorld</Address>
  <ReferenceParameters>
    <abc:foo xmlns:abc="urn:foo">This is a test</abc:foo>
  </ReferenceParameters>
</EndpointReference>

 

The WSA.EndpointReference object is used to represent WS-Addressing EndpointReferences, as illustrated in Listing 2. Compare this code with the XML above, and you should be able to get a good sense of how the API operates.
Listing 2. Create the EndpointReference with WSA.js

var epr = 
  new WSA.EndpointReference(
    "http://www.example.org/services/HelloWorld");
var epr_rp = epr.create_reference_parameters();
epr_rp.create_child(
  new WS.QName('foo','urn:foo','abc')).
    set_value('This is a test');

 

The API for WSA.EndpointReference currently supports the Address and ReferenceParameters properties as defined by the WS-Addressing information model. The Metadata property is currently not implemented, as it is not critical to the basic function of the client being implemented here.

The WS-Addressing SOAP message headers are intended to be set on the SOAP Envelope being sent by the Web services client to the service. Because the WS.Call object defined in the ws.js JavaScript library hides the details of working with the underlying SOAP.Envelope, you use a WS.Handler to insert the appropriate headers for you.

The Web services client invokes the methods of the WS.Handler object on every request, response, and error. For the WS-Addressing implementation, a WSA.Handler has been provided that uses a corresponding WSA.MessageContext object containing the information that is to be inserted into the message. This is illustrated in Listing 3.
Listing 3. Using the WS-Addressing context and handler

var address = 'http://www.example.com/services/HelloWorld';
var ctx     = new WSA.MessageContext();
ctx.to      = new WSA.EndpointReference(address);
ctx.replyto = new WSA.EndpointReference(WSA.ANONYMOUS);
ctx.action  = address + '#SayHello'

var handler = new WSA.Handler();
handler.set_context(ctx);

var call = new WS.Call('');
call.add_handler(handler);

 

The properties on the WSA.MessageContext object correspond to each of the WS-Addressing SOAP message headers:

  • to: A WSA.EndpointReference object whose Address specifies an absolute URI identifying the destination of the message.
  • from: A WSA.EndpointReference object identifying the sender of the message.
  • replyto: A WSA.EndpointReference object identifying where replies should be delivered.
  • faultto: A WSA.EndpointReference object identifying where faults should be delivered.
  • action: An absolute URI identifying the action that the message is intended to trigger.
  • messageid: An absolute URI that uniquely identifies the message.
  • relatesto: An array of URI pairs that identify related messages. The first URI in the pair identifies the type of relationship; the second URI specifies the unique Message ID of the related message.

Once the WSA.Handler has been registered with the WS.Call object used to invoke the Web service, the WS.Call object invokes the handler on every request, handing it a reference to the SOAP.Envelope object. The handler pulls the information from the WSA.MessageContext and inserts the appropriate headers into the message as illustrated in Listing 5.

Back to top

Implement WS-ResourceFramework support

The Web Services Resource Framework defines a convention for the use of Web services standards to access and manipulate instances of stateful resources. Individual Resources are identified and referenced by WS-Addressing EndpointReferences. A handful of common operations may be used to retrieve or modify the properties of the resource.

The wsrf.js JavaScript library provides a partial implementation of the Web Services Resource Framework supporting the GetResourceProperty and GetMultipleResourceProperties operations. The API builds on both the ws.js and wsa.js APIs and is designed more for the purpose of illustrating the use of those two scripts than it is to provide a comprehensive WS-ResourceFramework implementation.

WS-ResourceFramework operations are document-literal SOAP requests that are directed toward specific Resource instances. The target resource is identified by a WS-Addressing EndpointReference, as illustrated in Listing 4.
Listing 4. A WSRF EndpointReference

<EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
  <Address>http://localhost:9080/SoapAjax2/services/DeviceService</Address>
  <ReferenceParameters>
    <abc:DeviceID xmlns:abc="urn:deviceservice">ABC123</abc:DeviceID>
  </ReferenceParameters>
</EndpointReference>

 

When expressed within a SOAP Envelope using the mechanisms defined in wsa.js, the information within the WSRF EndpointReference takes the form of SOAP message headers, as shown in Listing 5.
Listing 5. A WSRF GetResourceProperty Request

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
 <Header>
  <To xmlns="http://www.w3.org/2005/08/addressing">
    http://localhost:9080/SoapAjax2/services/DeviceService</To>
  <abc:DeviceID xmlns="urn:deviceservice">ABC123</abc:DeviceID>
 </Header>
 <Body>
 <GetResourceProperty 
  xmlns="http://docs.oasis-open.org/wsrf/rp-2" 
  xmlns:ns="urn:foo">ns:bar</GetResourceProperty>
 </Body>
</Envelope>

 

The API presented by wsrf.js is designed to hide all of the details of working with the SOAP Envelope and WS-Addressing headers necessary to enable interaction with WS-ResourceFramework Web services. Taking a peek at the code, however, you see a number of important aspects of how the code works.

Listing 6 illustrates a wrapper object for the WSRF GetResourceProperty operation. This wrapper is used internally by thewsrf.js library and includes the basic mechanism for creating the SOAP Envelope and building the requisite XML for the operation. Note that the object utilizes the SOAP.Element and SOAP.Envelope APIs provided by ws.js. The “qname” parameter passed in on initialization of the wrapper object is the XML Qualified name of the property that is being requested.
Listing 6. The WSRF GetResourceProperty request wrapper

WSRF.Request.GetResourceProperty = Class.create();
WSRF.Request.GetResourceProperty.prototype = {
  initialize : function(qname) {
    this.envelope = new SOAP.Envelope();
    this.set_qname(qname);
  },
  set_qname : function(qname) {
    var body = this.envelope.create_body();
    var method = body.create_child(
      WSRF.Request.QNAME_GETRESOURCEPROPERTY);
    if (!qname.namespace) qname.namespace = '';
    if (!qname.prefix) qname.prefix = 'ns';
    method.declare_namespace(qname);
    method.set_value(qname.value_of());
  }
};

 

Listing 7 contains a snippet of code from the WSRF.Resource object. What you see is the creation of a WS.Call object, the preparation of the WSA.Handler object that will be used to set the appropriate SOAP message headers, the creation of a WSRF.Request.GetResourceProperty wrapper object, and the invocation of the Web services operation.
Listing 7. Invoke WSRF GetResourceProperty

get_resource_property : function(qname, callback) {
  var call = new WS.Call(this.address);
  var handler = new WSA.Handler();
  var wsactx = new WSA.MessageContext(this.epr);
  handler.set_context(wsactx);
  call.add_handler(handler);
  var req = new WSRF.Request.GetResourceProperty(qname);
  call.invoke(req.envelope, callback);
}

 

To invoke the GetResourceProperty operation against a WS-ResourceFramework Web service, an application needs only to supply an EndpointReference for the target WS-Resource and a WS.QName object identifying the property being retrieved as illustrated in Listing 8.
Listing 8. Pull it all together

var ADDRESS = 'http://localhost:9080/SoapAjax2/services/DeviceService'

function getDeviceName(deviceID, container) {
  var epr = new WSA.EndpointReference(ADDRESS);
  var epr_rp = epr.create_reference_parameters();
  epr_rp.create_child(
    new WS.QName(
      'DeviceID',
      'urn:deviceservice')).set_value(deviceID);
  var res = new WSRF.Resource(ADDRESS, epr);
  res.get_resource_property(
    new WS.QName('DeviceName','urn:deviceservice'),
    function(call,envelope) {
      $('soap').innerHTML = arguments[2].escapeHTML();
    }
  );
}

 

Listing 8 wraps the call to the WS-Resource in a convenient function that can be called from anywhere within your HTML page.Listing 9 provides a button that passes in a device id from an input field called id and displays the response SOAP Envelope in a div element called result.
Listing 9. Invoking getDeviceName

<input 
  value="Invoke the Web Service" 
  type="button" 
  onclick="getDeviceName($('id').value,$('result'))" />

 

Back to top

Next Steps

In this installment, you saw how the Ajax Web services client introduced in Part 1 of this series can be extended to support higher order Web services standards such as Web Services Addressing and the Web Services Resource Framework. In the next installment, the author will explore support for the Web Services Description Language.

 

Back to top

Download

Description Name Size Download method
Sample project ws-wsajax2code.zip 14KB HTTP

Information about download methods

 

Resources

Learn

Discuss

About the author

Photo of James M SnellJames Snell is a member of IBM’s Emerging Technologies Toolkit team. He has spent the past few years focusing on emerging Web services technologies and standards, and has been a contributor to the Atom 1.0 specification. He maintains a weblog focused on emerging technologies athttp://www.ibm.com/developerworks/blogs/page/jasnell.

 

 

original:http://www.ibm.com/developerworks/webservices/library/ws-wsajax2/index.html

[repost ] Call SOAP Web services with Ajax, Part 1: Build the Web services client

Summary: Implement a Web browser-based SOAP Web services client using the Asynchronous JavaScript and XML (Ajax) design pattern.

This paper is the first of a short series that illustrates the implementation of a cross-platform, JavaScript-based SOAP Web services client based on the Asynchronous JavaScript and XML (Ajax) design pattern for Web applications.

Popularized through its use in a number of well-known Web application services like GMail, Google Maps, Flickr, and Odeo.com, Ajax provides Web developers with a way of expanding the value and function of their Web applications by using asynchronous XML messaging. The Web Services JavaScript Library introduced here expands on the fundamental mechanisms that power the Ajax pattern by introducing support for invoking SOAP-based Web services.

Web services in the browser

Invoking SOAP Web services from within a Web browser can be a tricky exercise, particularly because the most popular Web browsers each handle generating and processing of XML in slightly different ways. There are few standard APIs or capabilities for XML processing that all browsers implement consistently.

One of the mechanisms that browser implementers agree on is the XMLHttpRequest API, which is at the heart of the Ajax design pattern. Thoroughly described in another recently published paper on developerWorks written by Philip McCarthy, XMLHttpRequest is a Javascript object that you can use to perform asynchronous HTTP requests. The paper describes a sequence diagam (see Figure 1) that is very help in understanding how the XMLHttpRequest object enables the Ajax design (see Resources for a link to the full paper).
Figure 1. Philip McCarthy’s Ajax Roundtrip sequence diagram
Philip McCarthy's Ajax Roundtrip sequence diagram

From this diagram you can see exactly how the XMLHttpRequest object functions. Some piece of JavaScript running within the Web browser creates an instance of the XMLHttpRequest and a function that serves as an asynchronous callback. The script then uses the XMLHttpRequest object to perform an HTTP operation against a server. When a response is received, the callback function is invoked. Within the callback function, the returned data can be processed. If the data happens to be XML, the XMLHttpRequest object will automatically parse that data using the browser’s built in XML processing mechanisms.

Unfortunately, it’s in the details of how the XMLHttpRequest object automatically parses the XML where the primary difficultly with the Ajax approach comes into play. For instance, suppose that the data that I am requesting is a SOAP envelope that contains elements from a number of different XML Namespaces, and I want to grab the value of the attr attribute on theyetAnotherElement. (See Listing 1.)
Listing 1. A SOAP Envelope with multiple namespaces

                
<s:Envelope 
  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <s:Header/>
  <s:Body>
    <m:someElement xmlns:m="http://example">
      <n:someOtherElement 
        xmlns:n="http://example" 
        xmlns:m="urn:example">
        <m:yetAnotherElement 
          n:attr="abc" 
          xmlns:n="urn:foo"/>
      </n:someOtherElement>
    </m:someElement>
  </s:Body>
</s:Envelope>

 

In the Mozilla and Firefox browsers, extracting the value of the attr attribute is a straightforward exercise, as shown in Listing 2.
Listing 2. The method for retrieving the attr attribute in Mozilla and Firefox does not work in Internet Explorer

                
var m = el.getElementsByTagNameNS(
  'urn:example',
  'yetAnotherElement')[0].
    getAttributeNS(
      'urn:foo',
      'attr');
alert(m); // displays 'abc'

 

A Word about Security

Because of a number of very real security concerns, the XMLHttpRequest object in most Web browsers is restricted by default to interact only with resources and services hosted by the same domain as the Web page the user is viewing. For instance, if I’m currently visiting a page located at http://example.com/myapp/, XMLHttpRequest will only be allowed to access resources that are also located on the example.com domain. This precaution is necessary to keep potentially malicious application code from inappropriately accessing information it otherwise should not have access to. Because the Web services client introduced here is based on XMLHttpRequest, this restriction applies equally to the Web services you will be able to invoke.

If you need to be able to access Web services located on another domain, you can use the following two possible solutions:

  • Digitally sign your JavaScript. By digitally signing a JavaScript script, you are telling the Web browser that it can be trusted not to perform any malicious activity and that the restriction on what data XMLHttpRequest can access should be lifted.
  • Use a proxy. A simpler solution is to pass all requests from XMLHttpRequest through a proxy resource located on the same domain as the loaded page. This proxy forwards the requests on to the remote location and returns the results to the browser. From the point of view of the XMLHttpRequest object, the interaction occurs within the existing security configuration.

Unfortunately, this code will not work in Internet Explorer Version 6 because the browser does not implement the getElementsByTagNameNS function and, in fact, takes the rather unhelpful approach of treating XML Namespace prefixes as if they were part of the element and attribute names.

Internet Explorer’s lack of great support for XML Namespaces makes it rather difficult to deal with namespace-intensive XML formats like SOAP in a browser-independent manner. To perform something as simple as grabbing the value of an attribute in the result, you have to write special case code such that the expected behavior is consistent across multiple browsers. Luckily, this special case code can be encapsulated and reused.

In order to invoke Web services from within a Web browser and reliably process the SOAP messages, you need to first understand the security issues. (See the sidebar “A Word about Security.”) You also need to write a JavaScript script library (Figure 2) that can abstract away the inconsistencies of the underlying browser XML implementations, allowing you to work directly with the Web services data.
Figure 2. Invoking Web Services from Javascript within the Web Browser using the Web Services JavaScript Library
Invoking Web Services from Javascript within the Web Browser

The Web Services JavaScript Library (ws.js) illustrated in Figure 2 is a collection of JavaScript objects and utility functions that provide a basic level of support for SOAP 1.1-based Web Services. Ws.js defines the following objects:

  • WS.Call: A Web Service Client that wraps XMLHttpRequest
  • WS.QName: XML Qualified Name implementation
  • WS.Binder: Base for custom XML serializers/deserializers
  • WS.Handler: Base for Request/Response Handlers
  • SOAP.Element: Base SOAP Element wrapping XML DOM
  • SOAP.Envelope: SOAP Envelope Object extends SOAP.Element
  • SOAP.Header: SOAP Header Object extends SOAP.Element
  • SOAP.Body: SOAP Body Object extends SOAP.Element
  • XML: Cross-platform utility methods for handling XML

At the core of ws.js is the WS.Call object which provides the methods for invoking a Web service. WS.Call is primarily responsible for the interactions with the XMLHttpRequest object and the processing of SOAP responses.

The WS.Call object exposes the following three methods:

  • add_handler. Adds a Request/Response handler to the processing chain. Handler objects are invoked before and after a Web service call to allow extensible pre- and post-invocation processing to occur.
  • invoke. Sends the specified SOAP.Envelope object to the the Web service and invokes a callback when a response is received. Use this method when invoking document-style Web services that use literal XML encoding.
  • invoke_rpc. Creates a SOAP.Envelope encapsulating an RPC-Style request and sends that to the Web service, invoking a callback when a response is received.

While the WS.Call object is generally not much more than a thin wrapper on top of the XMLHttpRequest object, it does perform a number of actions that will make your life easier. These actions include setting the SOAPAction HTTP header that is required by the SOAP 1.1 specification.

Back to top

Using ws.js

The API presented by the Web services JavaScript Library is rather straightforward.

The SOAP.* objects (SOAP.ElementSOAP.EnvelopeSOAP.Header and SOAP.Body) provide the means of building and reading SOAP Envelopes, as shown in Listing 3, so that the underlying details of working with the XML document object model is abstracted away.
Listing 3. Building a SOAP Envelope

                
var envelope = new SOAP.Envelope();
var body = envelope.create_body();
var el = body.create_child(new WS.QName('method','urn:foo'));
el.create_child(new WS.QName('param','urn:foo')).set_value('bar');

 

Listing 4 shows the SOAP Envelope that is produced by the code in Listing 3.
Listing 4. Building a SOAP Envelope

                
<Envelope xmlns="http://schemas.xmlsoap.org">
  <Body>
    <method xmlns="urn:foo">
      <param>bar</param>
    </method>
  </Body>
</Envelope>

 

If the SOAP Envelope that you are creating is representative of an RPC-Style request, the SOAP.Body element provides aset_rpc convenience method (illustrated in Listing 5) that will construct the full body of the request given an operation name, an array of input parameters, and a SOAP encoding style URI.
Listing 5. Building an RPC-Request Envelope

                
var envelope = new SOAP.Envelope();
var body = envelope.create_body();
body.set_rpc(
  new WS.QName('param','urn:foo'),
  new Array(
    {name:'param',value:'bar'}
  ), SOAP.NOENCODING
);

 

Each parameter is passed in as a structure of JavaScript objects with the following expected properties:

  • name. Either a string or a WS.QName object specifying the name of the parameter. Required.
  • value. The value of the parameter. If the value is not a simple data type (such as string, integer, and so on) then a WS.Binder should be specified that is capable of serializing the value into the appropriate XML structure. Required.
  • xsitype: WS.QName identifying the XML Schema Instance Type of the parameter (for example, if xsi:type="int", thenxsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema')). Optional.
  • encodingstyle.: A URI identifying the SOAP Encoding Style utilized by this parameter. Optional.
  • binder: A WS.Binder implementation that can serialize the parameter into XML. Optional

For example, to specify a parameter named “abc” with an XML Namespace of “urn:foo”, an xsi:type of “int” and a value of “3,” I would use the code: new Array({name:new WS.QName('abc','urn:foo'), value:3, xsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema')}).

Once I have built the SOAP.Envelope for the service request, I would pass that SOAP.Envelope off to the WS.Call objects invokemethod in order to invoke the method encoded within the envelope: (new WS.Call(service_uri)).invoke(envelope, callback)

As an alternative to building the SOAP.Envelope manually, I could pass the operation WS.QName, the parameters array, and the encoding style to the WS.Call object’s invoke_rpc method, as shown in Listing 6.
Listing 6. Using the WS.Call object to invoke a Web service

                
var call = new WS.Call(serviceURI); 
var nsuri = 'urn:foo';
var qn_op = new WS.QName('method',nsuri);
var qn_op_resp = new WS.QName('methodResponse',nsuri);  
  call.invoke_rpc(
    qn_op,
    new Array(
      {name:'param',value:'bar'}
    ),SOAP.NOENCODING,
    function(call,envelope) {
      // envelope is the response SOAP.Envelope
      // the XML Text of the response is in arguments[2]
    }
  );

 

Upon calling either the invoke method or the invoke_rpc method, the WS.Call object would create an underlying XMLHttpRequest object, pass in the XML elements containing the SOAP Envelope, receive and parse the response, and invoke the callback function provided.

To make it possible to extend the pre- and post-processing of the SOAP messages, the WS.Call object allows you to register a collection of WS.Handler objects, as shown in Listing 7. These are invoked for every request, every response, and every error during the invocation cycle. New handlers can be implemented by extending the WS.Handler JavaScript object.
Listing 7. Creating and registering response/response handlers

                
var MyHandler = Class.create();
MyHandler.prototype = (new WS.Handler()).extend({
  on_request : function(envelope) {
     // pre-request processing
  },
  on_response : function(call,envelope) {
     // post-response, pre-callback processing
  },
  on_error : function(call,envelope) {
  }
});

var call = new WS.Call(...);
call.add_handler(new MyHandler());

 

Handlers are most useful for the task of inserting or extracting information from the SOAP Envelopes being passed around. For instance, you could imagine a handler that automatically inserts appropriate Web Services Addressing elements into the header of the SOAP Envelope as in the example shown in Listing 8.
Listing 8. A sample handler that adds a WS-Addressing Action header to the request

                
var WSAddressingHandler = Class.create();
WSAddressingHandler.prototype = (new WS.Handler()).extend({
  on_request : function(call,envelope) {  		
    envelope.create_header().create_child(
        new WS.QName('Action','http://ws-addressing','wsa')
      ).set_value('http://www.example.com');
  }
});

 

WS.Binder objects (Listing 9) perform custom serialization and deserialization of SOAP.Element objects. WS.Binder implementations must provide the following two methods:

  • to_soap_element. Serializes a JavaScript object to a SOAP.Element. The first parameter passed in is the value to serialize. The second parameter is the SOAP.Element to which the value must be serialized. The method does not return any value.
  • to_value_object. Deserializes a SOAP.Element to a JavaScript object. The method must return the deserialized value object.

Listing 9. A sample WS.Binding implementation

                
var MyBinding = Class.create();
MyBinding.prototype = (new WS.Binding()).extend({
  to_soap_element : function(value,element) {  		
    ...
  },
  to_value_object : function(element) {
    ...
  }
});

 

Back to top

A simple example

I have provided a sample project to illustrate the basic functionality of the Web Services JavaScript Library. The Web service (shown in Listing 10) used by the demo has been implemented on WebSphere Application Server and provides a simple Hello World function.
Listing 10. A simple Java-based Hello World Web service

                
package example;

public class HelloWorld {
  public String sayHello(String name) {
    return "Hello " + name;
  }
}

 

After implementing and deploying the service to the WebSphere Application Server, the WSDL description of the service (Listing 11) defines the SOAP message that you need to pass in to invoke the Hello World service.
Listing 11. Snippet from the HelloWorld.wsdl

                
<wsdl:portType name="HelloWorld">
  <wsdl:operation name="sayHello">
    <wsdl:input 
      message="impl:sayHelloRequest" 
      name="sayHelloRequest"/>
    <wsdl:output 
      message="impl:sayHelloResponse" 
      name="sayHelloResponse"/>
  </wsdl:operation>
</wsdl:portType>

 

Using the Web Services JavaScript Library, you can implement a method that invokes the Hello World Service, as shown inListing 12.
Listing 12. Using WS.Call to invoke the HelloWorld Service

                
<html>
<head>
...
<script 
  type="text/javascript" 
  src="scripts/prototype.js"></script>
<script 
  type="text/javascript" 
  src="scripts/ws.js"></script>
<script type="text/javascript">
function sayHello(name, container) {
  var call = new WS.Call('/AjaxWS/services/HelloWorld'); 
  var nsuri = 'http://example';
  var qn_op = new WS.QName('sayHello',nsuri);
  var qn_op_resp = new WS.QName('sayHelloResponse',nsuri);  
  call.invoke_rpc(
    qn_op,
    new Array(
      {name:'name',value:name}
    ),null,
    function(call,envelope) {
      var ret = 
        envelope.get_body().get_all_children()[0].
          get_all_children()[0].get_value();
      container.innerHTML = ret;
      $('soap').innerHTML = arguments[2].escapeHTML();
    }
  );
}
</script>
</head>
...

 

You can then invoke the Hello World service by calling the sayHello function from anywhere in our Web application. See Listing 13.
Listing 13. Calling the sayHello function

                
<body>
<input name="name" id="name" />
<input value="Invoke the Web Service"
       type="button" 
       onclick="sayHello($('name').value,$('result'))" />
<div id="container">Result:
<div id="result">
</div>
<div id="soap">
</div>
</div>
</body>

 

A successful call will yield the result illustrated in Figure 3. Running this example in Mozilla, Firefox, and Internet Explorer should all yield the same results.
Figure 3. The Hello World Example in Firefox
The Hello World Example in Firefox

Back to top

Next steps

The Web Services JavaScript Library can be used to incorporate basic SOAP Web services into your Web applications in a simple, browser-independent manner. In the next installment of this series, you can explore the use of the libary to invoke more advanced Web services based on the WS-Resource Framework family of specifications as well as explore ways in which the Web services capabilities can be expanded and integrated into a Web application.

 

Back to top

Download

Description Name Size Download method
Sample project ws-wsajaxcode.zip 19 KB HTTP

Information about download methods

 

Resources

Learn

Get products and technologies

Discuss

About the author

Photo of James M SnellJames Snell is a member of IBM’s Emerging Technologies Toolkit team. He has spent the past few years focusing on emerging Web services technologies and standards, and has been a contributor to the Atom 1.0 specification. He maintains a weblog focused on emerging technologies at http://www.ibm.com/developerworks/blogs/page/jasnell.

 

original:http://www.ibm.com/developerworks/webservices/library/ws-wsajax/