Remote Application Development with Mozilla, Part 2A Case Study of the Mozilla Amazon Browser (MAB)

In our first article we talked about the benefits of remote application development using Mozilla technologies such as XUL and web services support. In this article we present a case study of one such application, the Mozilla Amazon Browser (MAB), a tool for searching Amazon's catalogs.

The Mozilla Amazon Browser is an interesting case study for a number of reasons. First, it's a working prototype application, not an example constructed solely for the purpose of demonstrating the technology. Second, it exercises many areas of Mozilla's support for remote development and thus shows off the capabilities, potential, and limitations of remote XUL applications. Finally, it demonstrates Mozilla's support for web services, an important emerging technology for web application development.

In this article, we will give an overview of MAB (version 0.98,
the latest version available at the time of this writing), discuss the
steps that author Fabio Serra took to get it running remotely, and
outline its structure and organization. We will also explain how
the MAB uses Mozilla's built-in web services support to submit a search
to the Amazon web service, retrieve the search results, and display them
to the user.

Overview

The MAB is a tool for searching the Amazon catalogs and browsing their
products. It lets users search for products (by keyword, ASIN/ISBN,
UPC code, author/artist, and so on) and retrieve information about each
product found, including its title, author/artist, and release date (the
latter two for books/music), along with its suggested retail price,
Amazon's price, and the price of a used copy sold through Amazon (if
available). It also displays comments from other Amazon users
about the product.

Users can also save and reload searches
-- although saved searches do not persist across sessions because the
application does not have access to the user's hard drive, and a mechanism
for saving searches to a remote server has not been implemented -- and aggregate
the results of multiple consecutive searches into a single list.

The UI comprises:

A menu bar with options for saving/reloading searches, starting a
new search, setting preferences, and getting help.

A search form with a menu for selecting the catalog to search,
another for selecting the search type (keyword, title, and so on), and a text
field for entering the search string.

A table of results with columns for product name, catalog,
Amazon price, rating, and year released.

A series of fields showing detailed information about the
selected product, such as manufacturer and prices.

An embedded browser widget for displaying user comments.

A button for opening the Amazon web page for the selected product.

A status bar that displays meta-information about the search,
including total products found and the number retrieved.

Main Amazon Browser window

The MAB can be run either in its own window or as a page in a
browser window. It can also be installed and run locally, although
the local version doesn't currently take advantage of the additional
capabilities of local applications, such as persisting information across
sessions by saving it to the user's hard drive.

Getting the MAB to Run Remotely

Getting the MAB to run remotely was relatively straightforward.
First, since Mozilla does not
recognize remote DTDs (used in Mozilla applications for
localization), localized strings had to be added to the MAB's XUL file
by embedding ENTITY elements into an inline DOCTYPE
declaration in the file:

While not nearly as effective as encapsulating the strings in a
separate DTD file, this approach does make it possible to localize the
application by creating a copy of the XUL file for each localization and
using HTTP content negotiation or explicit links to provide access to
localized versions.

Second, because remote XUL cannot refer to supporting CSS and JS
files using chrome URLs (URLs to local XUL application files installed
into the browser's chrome/ directory), the MAB's XUL file uses
relative URLs to refer to those files:

The only server configuration necessary was to set the Apache web
server on the site hosting the application to serve XUL files with the
appropriate MIME type:

AddType application/vnd.mozilla.xul+xml .xul .XUL

The application is distributed via a web page that offers a standard HTTP link to load the application as a page in a browser or a JavaScript URL with the special chrome flag (for indicating that the window is for a Mozilla-based application) to load the application in its own window:

Both approaches for loading the application offer the same
functionality but very different user experiences. The
page-in-browser approach resembles a web application, while the
separate-window approach is more like a client-server application. Mozilla supports both
methods, and this flexibility allows application developers to choose
the style that best suits their users. With the client-server-like
approach, Mozilla even allows applications with the appropriate
privileges to place an alias on the user's desktop for launching the
application (although the MAB doesn't take advantage of this), for example, by
specifying the following command line:

mozilla -chrome http://www.infodraft.com/~faser/mab/content/mab.xul

Application Structure

MAB application files are organized into a directory tree that is
much like packages in the Mozilla chrome directory. A top-level mab/
directory contains content/, locale/, and skin/
subdirectories, with the XUL and JavaScript files in the content/ and
content/js/ subdirectories and the CSS stylesheets in skin/:

The content of those files is also almost exactly like a local XUL application. The main XUL file, content/mab.xul, starts with the XML declaration, stylesheet processing instructions, and DOCTYPE declaration (for localization), which are common to most XUL files:

The rest of the document comprises XUL tags that define the structure
and functionality of the user interface. Here is the basic
structure (reformatted, annotated, and with non-essential tags removed
for clarity):

The MAB primarily uses the default browser stylesheets to style its
appearance, so its own stylesheet is minimal and limited to tweaking the appearance of elements with minor changes to borders, margins, padding, colors, and fonts. In addition to these main files, there are a few other XUL, JavaScript, and CSS files to handle additional windows, such as the help and preferences windows.

Note that all of the XUL, JavaScript, and CSS used in the application
is almost exactly the same as would be used to build a local XUL-based
application, and in fact the MAB has been packaged for local
installation without any changes to its file structure and code.
Even the advanced features of the Mozilla framework that the MAB
doesn't use, such as XBL, RDF, and XUL templates, work the same or
similarly in remote applications as they do in local ones, although
there are a few bugs specific to remote applications. Unless an application needs to save data to the local hard drive or otherwise get access to restricted system resources, getting it to work remotely requires little modification.

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:

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.

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:

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:

(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:

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.