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

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

Implement support for Web Services Addressing Language and Web Services Resource Framework

developerWorks
Document options
<script language="JavaScript" type="text/javascript"> </script>
Set printer orientation to landscape mode

Print this page

<script language="JavaScript" type="text/javascript"> </script>
Email this page

E-mail this page

Sample code


New site feature

Kick-start your Java apps


Rate this page

Help us improve this content


Level: Intermediate

James Snell (jasnell@us.ibm.com), Software Engineer, IBM

10 Jan 2006

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.
<script language="JavaScript" type="text/javascript"> </script>

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.Element, WS.Handler, WS.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 the wsrf.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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值