Team LiB
Previous Section Next Section

Hack 67. Work with Mozilla WSDL Services

Want an easy way to use SOAP web services? WSDL might be the answer.

When scripting a web service with SOAP [Hack #65], you create a proxy object in the browser to represent the object or service you're controlling on the server. Other scripts in the browser can use that proxy as if it were the actual server resource. This is an intuitive approach to web service scripting.

Creating your own proxies can be tedious, however. You must write methods to mirror all of the endpoint's methods that you plan to use. These methods will all do basically the same thing: stuff the input into SOAP parameters, invoke the SOAPCall, and extract the results. Some of this process can be abstracted, but for a web service with more than a couple of methods, you're going to spend a lot of time writing and testing your proxy.

6.11.1. Locate WSDL in Firefox

WSDL (Web Services Description Language) is an XML grammar to describe all of the methods, parameters, and faults (errors) of a web service. A WSDL file lists everything, including the endpoints that can be accessed, the methods available on those endpoints, the parameters and types expected by the methods, and the parameters and faults returned by the methods.

Given the URL to a WSDL file, Firefox can solve many of the tedious aspects of scripting web services for you. With just a few lines of JavaScript, it can create a complete proxy of the web service. Your scripts can then call the methods on that proxy as if they were working with a local, native object. All of the SOAP and XML aspects of the communication remain out of view.

Some of the best documentation on using WSDL in Firefox (or Mozilla) is found at http://devedge.netscape.com. In particular, see:

http://devedge.netscape.com/viewsource/2003/wsdl/01/

This site went offline without warning in late 2004; if that happens again, then find it in the Wayback Machine: http://www.waybackmachine.org.

6.11.2. Create a WSDL File

We'll create our own WSDL to work with the SOAP endpoint created in [Hack #65] . This is not the place for a full tutorial on WSDL. There are numerous WSDL tutorials and reference documents on the Web. Instead, just save the following code as soapdemo.wsdl in your web site:

<?xml version="1.0" ?>
<definitions name="TempConvertService"
  targetNamespace="http://localhost/soapdemo.wsdl"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:tns="http://localhost/soapdemo.wsdl"
  xmlns:xsd="http://www.w3.org/1999/XMLSchema"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">

  <message name="F2CInput">
    <part name="inputInteger" type="xsd:integer"/>
  </message>

  <message name="F2COutput">
    <part name="return" type="xsd:integer"/>
  </message>

  <portType name="TempConvertPortType">
    <operation name="f2c">
      <input message="tns:F2CInput"/>
      <output message="tns:F2COutput"/>
    </operation>
  </portType>

  <binding name="TempConvertSoapBinding" type="tns:TempConvertPortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="f2c">
      <soap:operation soapAction="http://localhost/Temperatures#f2c"/>
      <input>
        <soap:body use="encoded" namespace="http://example.com/Temperatures" 
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output>
        <soap:body use="encoded" namespace="http://example.com/Temperatures" 
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
    </operation>
  </binding>

  <service name="TempConvertService">
    <documentation>
      Convert temperatures between Fahrenheit and Celsius
    </documentation>
    <port name="TempConvertPort" binding="tns:TempConvertSoapBinding">
      <soap:address location="http://localhost/cgi-bin/soapdemo.cgi"/>
    </port>
  </service>
</definitions>

Take note of the URL, wherever you put it, because you'll need it in the next step.


This WSDL file provides all of the information that Firefox needs to create a proxy with a single method named F2C. Let's put it to use.

6.11.3. Create the Proxy in JavaScript

Before we start, make a copy of the HTML file from [Hack #65] . Open that file in your text editor and strip out the JavaScript; we're going to replace it with all-new code for using an automatically generated, asynchronous proxy.

Add two variables to the top of your (now empty) script:

var wsdl_uri = "http://localhost/soapdemo.wsdl";  // adjust as necessary
var gProxy = null;

Now, we can create our proxy with two lines of JavaScript: the first creates a WebServiceProxyFactory, and the second asks the factory for a new proxy. Wrapping it up in a function with some error trapping results in the following code:

function createProxy( aCreationListener ){
  try {
    var factory = new WebServiceProxyFactory(  );
    factory.createProxyAsync( wsdl_uri, "TempConvertPort", 
        "", true, aCreationListener );
  } catch ( ex ) {
    alert("Failed to create the proxy: "+ ex);
  }
}

The bolded line is the key. It provides five parameters:

  • The URL of the WSDL file

  • The name of the port from the service element of the WSDL file

  • An ignored parameter

  • A Boolean that states if the calls we'll make through the proxy will be asynchronous

  • A listener object to receive notifications from the proxy when a call is completed

The documentation for WebServiceProxyFactory describes a synchronous version of the same call, called createProxy(). At the time of writing, createProxy() throws an exception that indicates that it hasn't yet been implemented. For more information, see http://www.xulplanet.com/references/objref/WebServiceProxyFactory.html.

6.11.4. Create an Asynchronous Listener

JavaScript is single threaded, but Firefox is not. Since our proxy handles all calls asynchronously, every method run on the proxy kicks off another communications thread with the server but returns control to our script immediately. When the server returns a result, the proxy notifies whatever listener we provide. The following is a simple approach to a listener. It's not robust enough for all applications, but it is fine for this hack:

function Convert( value, actionToTake ){
  if ( !gProxy ) {
    // create listener as a local so that a different
    // listener is created each time
    var listener = {
      // called when the proxy is ready
      onLoad: function( aProxy ) {
        gProxy = aProxy;
        gProxy.setListener( listener );
        gProxy[ actionToTake ]( value );
      },
      
      onError: function( aError ) {
        alert( "An error has occured: " + aError.message );
      },
      
      // callback function names are hardcoded
      // in Firefox to {methodname}Callback
      F2CCallback: function( aResult ) {
        document.getElementById( "C" ).value = aResult;
      }
    };
    
    createProxy( listener );
  } else {
    gProxy[ actionToTake ]( value );
  }
}

Convert() takes two parameters: the value to be converted and the name of the operation to call on the proxy (which is the same as the name of the operation defined in the WSDL file). Our WSDL file defines only a single operation, f2c, but we've left room here to expand it to include the c2f function found in [Hack #65] .

The name of the operation called on the proxy defines the name of the method called on the listener object. It's always {actionToTake}Callback.


The only remaining piece is the convertFtoC() function called by the button in the HTML. As we've seen, it just needs to pass the value for conversion and the name of the method to call on the proxy.

function convertFtoC(  ){
  Convert( document.getElementById( "F" ).value, 'f2c' );
}

Again, this is just a convention for this hack. There are many other ways to do this.


6.11.5. Note Security Issues

If you've completed both [Hack #65] and this hack, you'd expect that you could just open the HTML file in your browser and start converting temperatures from Fahrenheit to Celsius. You'd almost be right. Firefox (and all Gecko browsers) have a unique security restriction that applies only to web services. Before sending the first SOAP call, they first try to load a file from the root of the web service's server called web-scripts-access.xml. If the file cannot be found, if it is not well formed, or if it does not permit loading of scripts from your web server, all calls to the proxy object will fail. This restriction applies to remote servers.

To permit all web remote service calls (which is good enough for testing this hack across the Web), create a file at the root of the remote web server with just one line:

<wsa:webScriptAccess xmlns:wsa="http://www.mozilla.org/2002/soap/security"/>

The intent of this file is to allow a web service to control which other services and domains they are willing to allow access to their service. For more information about this security issue and configuring the access control file, see:

http://lxr.mozilla.org/mozilla/source/extensions/webservices/docs/New_Security_Model.html.

After saving this file at the root of your web server (the same server that's hosting the SOAP endpoint), your mini WSDL-based web application should run properly.

Seth Dillingham

    Team LiB
    Previous Section Next Section