Print

Remote Application Development with Mozilla, Part 2
Pages: 1, 2

Communicating with Amazon

The MAB uses Amazon's web services API to search the company's catalogs and retrieve results. Amazon's API can be accessed via either XML over HTTP or SOAP, and Mozilla supports both methods. The MAB's author chose to use XML over HTTP because it was simpler to implement, and he could not find any advantages to using SOAP (more info on SOAP vs. XML over HTTP at Amazon). XML over HTTP passes parameters to the remote procedure via URL parameters in a standard HTTP request, so the MAB first creates a standard HTTP URL containing the search configuration and string:



var qString = targetUrl[connectionType]+'?t='+ASSID+'&dev-t='+DEVT+'&
'+getSearchBy()+'='+escape(query)+'&mode='+getProductLine()+'&
type='+searchType+'&page='+page+'&f='+f;

In additon to the query variable, which contains the search string entered by the user, the following values make up the URL:

targetUrl[connectionType]
Base URL of Amazon server or proxy.
ASSID
Associate ID: identifies the provider of the application; required for access to Amazon web services.
DEVT
Developer token issued by Amazon to identify the application author; also required.
getSearchBy()
The type of search the user is doing (Title, Keyword, and so on).
getProductLine()
The catalog in which the user is searching (Books, DVDs, and so on).
searchType
Whether or not to include comments in the results; possible values are lite (without comments) or heavy (with comments).
page
Which page of results to retrieve (Amazon returns, at most, ten results at a time).
f
Output format (always "XML" in the MAB).

The MAB then uses Mozilla's XMLHttpRequest object to connect to the Amazon servers and initiate a search. First it creates a new XMLHttpRequest object req. If the user is connecting directly to the Amazon service, the application also requests permission to connect to the Amazon servers, which would otherwise be off-limits due to security restrictions (see A Word About Proxies below for more details). Then the MAB initiates a standard HTTP GET request using the req object and the previously constructed URL. Finally, it adds a load handler to req that will run when the MAB receives a response from the server and will process the results.

var req = new XMLHttpRequest();
  ...
if(connectionType == "direct") {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
}
req.open("GET",qString,true);
req.send(null);
  ...
req.onload = function() {
  ...
}

Displaying the Results

The Amazon web service responds to a request from the MAB by searching its catalogs and returning a set of matching products as a series of XML records containing fields for product attributes. For example:

<Details url="http://www.amazon.com/exec/obidos/redirect?tag=webservices-...">
   <Asin>B00006IZOC</Asin>
   <ProductName>Dial-A-Song: 20 Years of</ProductName>
   <Catalog>Music</Catalog>
   <Artists>
      <Artist>They Might Be Giants</Artist>
   </Artists>
   <ReleaseDate>17 September, 2002</ReleaseDate>
   <Manufacturer>Rhino Records</Manufacturer>
   <ImageUrlSmall>http://images.amazon.com/images/P/B00006IZOC.01.THUMBZZZ.jpg
     </ImageUrlSmall>    
   <ImageUrlMedium>http://images.amazon.com/images/P/B00006IZOC.01.MZZZZZZZ.jpg
     </ImageUrlMedium>    
   <ImageUrlLarge>http://images.amazon.com/images/P/B00006IZOC.01.LZZZZZZZ.jpg
     </ImageUrlLarge>    
   <ListPrice>$31.98</ListPrice>
   <OurPrice>$28.99</OurPrice>
   <UsedPrice>$26.83</UsedPrice>
</Details>

Once the Amazon service has finished returning results and closes the connection, the load handler on the XMLHttpRequest object takes over and uses Mozilla's DOMParser object to convert the XML string into a DOM document:

var responseXML = new DOMParser().parseFromString(req.responseText, 'text/xml');

It then passes the document to an AmazonResult object, a custom object defined by the MAB to store search results and display them to the user:

//Create new
ObjmyAmaz = new AmazonResult();
  ...
myAmaz.parseResponse(responseXML);

The AmazonResult object stores the document in a member property and then calls its createTree method to display the data in the XUL tree:

AmazonResult.prototype.parseResponse = function(responseXML) {
   ...
   this.xmlDoc = responseXML;
   ...
   this.createTree();
   ...
}

(Note that this procedure is somewhat different when two searches are being merged together.)

createTree iterates over the search results. For each one, it retrieves the data using the getElementsByTagName and item DOM methods and creates tree rows using the createElement DOM method to create treeitem and treerow elements for each record and treecell elements for each field value. Then it uses the appendChild DOM method to append each row to the tree, causing the row to be displayed to the user:

AmazonResult.prototype.createTree = function() {    
   var nr = this.getNrRecord();
   for(var i=0;i<nr;i++) {
      var rowID = this.xmlDoc.getElementsByTagName("Details")[i].
                  getElementsByTagName('Asin').item(0).firstChild.nodeValue;
      var item = document.createElement('treeitem');
      var row = document.createElement('treerow');
      row.setAttribute('id',rowID);
      ...
      var cell_name = document.createElement('treecell');
      cell_name.setAttribute('label',this.getDetail(rowID,'ProductName',false));
      ... [creation of other cells omitted]
      
      row.appendChild(cell_name);
      ... [appending of other cells omitted] 
      item.appendChild(row);
      guiListTree.appendChild(item);
   }
...
}

Note that while the author considered using an in-memory RDF data source and a XUL template to construct the tree, he ultimately chose to use DOM methods because they were more familiar to him given his experience with traditional web development and avoided issues with accessing Mozilla's RDF API from remote applications. The downside to using DOM methods is the loss of features that come bundled with RDF and XUL templates in Mozilla, such as sorting.

Conclusion

The Mozilla Amazon Browser provides a rich interface for searching Amazon with features not found in existing HTML-based interfaces, and it highlights the potential for remote Mozilla-based applications to improve the capabilities and user experience of Internet applications. Mozilla provides XUL, an application-centric layout language with both basic and complex form controls, web services support for communicating and exchanging data with remote applications, cross-platform support, and many other features. It is an excellent framework for building the next generation of remote Web applications.

Thanks to Fabio Serra, the author of the MAB, for his help with the technical details of its implementation.

Brian King is an independent consultant who works with web and open source technologies.

Myk Melez has been working with Mozilla since 1999, when he started using the browser as a DHTML application platform.


A Word About Proxies

By default, the MAB uses a proxy that runs on the same server as the one from which it is loaded, but it can be reconfigured to connect to the Amazon service directly:


Connection Settings

The advantages of using a proxy for a remote application are:

  • Better security, since web service authentication tokens can be restricted to the proxy server instead of being downloaded to each user's computer (although the MAB doesn't do this).

  • A better user experience, since the users don't have to deal with the details of getting access to the web services themselves.

  • Easier deployment, since the application can avoid Mozilla's stringent cross-domain security restrictions, which prevent a remote application from contacting servers other than the one from which it was loaded, unless the application is cryptographically signed. (These restrictions can be bypassed via the hidden browser preference setting user_pref("signed.applets.codebase_principal_support",true);, but this is only recommended for development work.)

Proxy servers also have drawbacks. In particular, they are slower than direct connections and may have scalability problems. Still, for some applications, particularly those that use a web service that is not freely accessible, are distributed by organizations that have their own level of authentication, or for whom cryptographic signing is prohibitive, a proxy server is the only workable solution.

Note that Mozilla developers are working on a new security model that lets applications bypass cross-domain restrictions when such access is explicitly permitted by the target server. The model relies on web services publishing a simple, machine-readable document that declares which services are available to which client domains. This model should make it much easier for client applications to access web services in the future.


O'Reilly & Associates recently released (September 2002) Creating Applications with Mozilla.


Return to the Mozilla DevCenter.