Team LiB
Previous Section Next Section

Hack 65. Work with Mozilla SOAP Services

Your web pages and XUL apps can speak the native language of web services.

Simple Object Access Protocol (SOAP) is a way for you to run methods (effectively function calls) on a remote server. Commands are formatted as XML documents on the client and sent to the server, which processes the commands and returns an XML-formatted response. This hack introduces SOAP with a simple temperature converter that converts between Fahrenheit and Celsius units.

SOAP is intended for remote servers running a web service, but it can be used on a local server (i.e., your workstation) for debugging purposes. SOAP is a form of object-oriented network programming. Clients connect to objects on the server, send commands, and receive responses in the form of messages.

Parameters in both the command and response are nested in XML elements that specify the name, data type, value, and various other attributes. This makes it relatively simple for both client and server to understand the context of what is being requested. Parameters are no longer just strings to be interpreted on the server, as they are in CGI, because SOAP has the vocabulary necessary to specify parameter types such as numbers, strings, URLs, and even complex types such as structs (tables of names and values, each with their own type).

There are many well-written SOAP tutorials on the Web and in print. A good, quick introduction to server-side SOAP can be found at O'Reilly's Perl.com:

http://www.perl.com/pub/a/2001/01/soap.html

6.9.1. Locate SOAP in Firefox

Firefox has a full set of SOAP client APIs that allow you to write all of the logic in JavaScript. These APIs make it quite simple to convert data held in Firefox (in form fields, variables, cookies, and elsewhere) into XML, package it up into a SOAP envelope, send the message to the SOAP server, and extract the values or errors from the response.

While it can be argued that anything you can do with SOAP can also be done with the Common Gateway Interface (CGI), and often with less overhead, SOAP in the browser has one real benefit: its use does not cause the web page to reload. So, your web application can communicate with the server, sending and receiving data, without ever having to redraw the page. There are other benefits too, not the least of which is the typing of data.

This is not the place for a full treatment of SOAP in Firefox. XUL Planet has full reference material for all components of Firefox's SOAP API:

http://www.xulplanet.com/references/xpcomref/group_WebServices.html

See also Ray Whitmer's "SOAP Scripts in Mozilla" for a basic introduction to scripting Firefox's SOAP services with JavaScript:

http://lxr.mozilla.org/mozilla/source/extensions/webservices/docs/Soap_Scripts_in_Mozilla.html
6.9.1.1 Start with XML Schema

XML Schema is a standardized way to describe a class of XML documents. Essentially, it dictates which elements can appear in a conforming XML document, and the type of each element. XML Schema allows for the treatment of XML documents as object instances, with the schema as the class definition. See the W3C's XML Schema Primer for a thorough introduction:

http://www.w3.org/TR/xmlschema-0/

Firefox has some built-in support for XML Schema, but at the time of writing, it is only used internally by the SOAP services. Work is ongoing to allow validation of any XML document against a schema, but this code has not yet been checked in to the source.

6.9.1.2 Review synchronous versus asynchronous messaging

Firefox supports both synchronous and asynchronous messaging with a SOAP server; the rules are the same as for the XMLHttpRequest object [Hack #48] . Synchronous messaging allows only one call to the server at a time, and all processing in the client stops until the response arrives. Asynchronous messaging allows any number of calls to be sent without waiting for a response, but you must also provide a receiver function that will be called for each response as it comes back.

6.9.1.3 Review security

Firefox can use SOAP in web pages and in the chrome. The only real difference between the two is security. From the chrome, SOAP calls can be sent to any server, because the chrome is a trusted source. Web pages can send SOAP requests only to servers in the same domain as the server from which the page was loaded.

If you load the HTML file into the browser from an untrusted URL, or from your own computer, the page's scripts can break this rule and communicate with any server by asking the user for extra privileges. Any untrusted page so loaded must include this security clearance request:

netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");

If the user agrees, SOAP can be used to send a SOAP request to any server on the planet.

6.9.2. Understand the Server

To run SOAP scripts in Firefox, you need a web server with a SOAP endpoint. If you have access to a server with Perl installed, then install the CPAN module SOAP::Lite (http://search.cpan.org/dist/SOAP-Lite/), which you'll need installed for the following example.

Create a new file in your server's cgi directory called soap-temperatures.cgi, with the following contents:

#!/usr/bin/perl -w

use SOAP::Transport::HTTP;

SOAP::Transport::HTTP::CGI
  -> dispatch_to('Temperatures')
  -> handle;

package Temperatures;

sub f2c {
  my ( $class, $f ) = @_;
  
  return ( 5.0 / 9.0 ) * ( $f - 32 );
}

sub c2f {
  my ( $class, $c ) = @_;
  
  return 32 + ( $c * ( 9.0 / 5.0 ) );
}

This SOAP endpoint converts temperatures between Fahrenheit and Celsius. It's not the most useful web service ever provided, but it's good enough for our purposes.

This Perl script, run by the web server, does the following:

  • Imports and activates the SOAP server routines, via the SOAP::Transport::HTTP bundle.

  • Dispatches the incoming call to the appropriate endpoint (the Temperatures package), automatically calling the right function (f2c or c2f) depending on the message that was passed from the client.

  • Converts the input parameter to Fahrenheit or Celsius and returns the result, which is then automatically encoded into a SOAP response and sent back to the client.

For more information on SOAP::Lite and setting up your own SOAP server, see http://www.perl.com/pub/a/2001/01/soap.html and http://www.soaplite.com/.

It's also possible to connect to any of hundreds of publicly available SOAP endpoints, such as those listed at XMethods (http://www.xmethods.net). We're not using those here, because many of them are more complex than is appropriate for your first SOAP hack and because they all use WSDL [Hack #67] .

6.9.3. Make a Web Page with SOAP

Your JavaScript will typically set up a proxy object to represent the endpoint on the server with which your script will communicate. Create methods in your proxy that mirror those on the endpoint. The rest of your scripts will then treat the proxy as if it were the object on the server. The proxy receives the commands and forwards them to the SOAP endpoint and then returns the results back to the caller.

The following JavaScript script uses a minor proxy implementation to handle the communication between the page's scripts (functions convertFtoC and convertCtoF) and the SOAP endpoint on the server:

<html><body>
<script type="text/javascript">
var tempsProxy = {
  invoke: function( call, param ) {
    var s = new SOAPCall( );
    s.transportURI = "http://localhost/cgi-bin/soapdemo.cgi";
    
    var params = new Array( );
    var p = new SOAPParameter( param );
    params.push( p );
    
    s.encode( 0, call, "urn:Temperatures", 0, null, 1, params );
    
    var r = s.invoke( );
    
    if ( r.fault == null ) {  // success
      r = r.getParameters(false, {})[0].value;
      return r;
    }
    else {  // fault
      var f = r.fault;
      var detail = f.detail;
      var ds = new XMLSerializer( );
      var detailStr = detail ? ds.serializeToString(detail) : "";
      
      alert( "Fault namespace: " + f.faultNamespaceURI 
        + "\nFault code: "    + f.faultCode
        + "\nFault string: "  + f.faultString 
        + "\nFault actor: "   + f.faultActor
        + "\nDetail: "        + detailStr );
      
      return "#Err#";
    }
  },
  
  f2c: function( f ) {
    return this.invoke( "f2c", f );
  },
  
  c2f: function( c ) {
    return this.invoke( "c2f", c );
  }
};

function convertFtoC( ) {
  var f = document.getElementById( "F" ).value - 0;
  var c = tempsProxy.f2c( f );

  document.getElementById( "C" ).value = c;
}

function convertCtoF( ) {
  var c = document.getElementById( "C" ).value - 0;
  var f = tempsProxy.c2f( c );
  
  document.getElementById( "F" ).value = f;
}
</script>

<label>F: <input type="text" name="F" id="F" /></label>
<button onclick="convertFtoC( )">F to C</button>
<br>
<label>C: <input type="text" name="C" ID="C" /></label>
<button onclick="convertCtoF( )">C to F</button>
</body</html>

If you're not running this on your workstation, you'll probably have to change the bolded line of code to point to the right server.


You can find a more robust implementation of proxies, including a base class you can use to build your own proxies, in Mozilla's source code:

http://lxr.mozilla.org/seamonkey/source/extensions/webservices/soap/tests/

The preceding HTML produces a web page similar to Figure 6-9.

Figure 6-9. Sample web page that uses SOAP to convert temperatures


Put it into an HTML file, and load it into the browser through the same web server where you installed the Perl CGI.

After loading the page in your browser, enter a number in one of the fields and then click the conversion button to its right. The JavaScript sends the SOAP request to the server, receives the response, and puts the converted value into the other field, all without reloading the web page.

Seth Dillingham

    Team LiB
    Previous Section Next Section