Plants by WebSphere gets a Web 2.0 makeover

Plants by WebSphere® is a traditional demonstration Web application for IBM® WebSphere Application Server that illustrates commerce functionality, such as product management, shopping cart, and purchase processing. With the release of the WebSphere Application Server Feature Pack for Web 2.0, a new level of user interaction is now possible, enabling Web applications to be more robust and even as responsive as desktop applications. This article discusses the technologies and techniques you can leverage from the Feature Pack for Web 2.0 to “remake” the Plants by WebSphere application to be Web 2.0 ready, with UI redesign, RESTful interactions, plus community and user participation. This content is part of the IBM WebSphere Developer Technical Journal.

Frank Castaneda (castanef@us.ibm.com), Project Zero Development, IBM

Frank Castaneda is an Extreme Blue and Georgia Tech Alumni, currently working on Project Zero focusing on Web 2.0 and radically simplifying web development, and various skunk-works projects.



Charlie Surface (csurface@gmail.com), Advisory Software Engineer , IBM

Charlie Surface is an Advisory Software Engineer at IBM. His current focus is PHP enablement for Project Zero.



Mandar U Jog (mjog@us.ibm.com), Project Zero Development, IBM

Mandar U Jog is an Extreme Blue and Georgia Tech Alumni, currently working on project Zero. His areas of focus are enabling cluster technologies for Project Zero, Web 2.0 and mobile apps on the iPhone. (Look for our blog posting on iSametime at projectzero.org.)



Binh Q Nguyen (binhn@us.ibm.com), Senior Technical Staff Member, IBM

Binh Q Nguyen is a Senior Technical Staff Member at IBM. Currently he is working in the unified communications and collaboration area.



14 May 2008

Introduction

Web 2.0 is characterized by the participation of users to form a viral community: information is propagated directly by the users of the Web site to each other, often through social networking capabilities, such as blogging, blog comments, and reviews. The success of a Web 2.0 application depends largely on its ability to harness its users’ collective contributions to augment the core value of the Web site. Users participate by directly providing content, reviews, self-service, and so on. The more vibrant and active the community, the better the Web site can achieve its objectives.

The IBM WebSphere Application Server Feature Pack for Web 2.0 provides technologies that can enable you to easily program Web 2.0 capabilities into new or existing WebSphere Application Server applications. Specifically, it provides:

  • Ajax development toolkit: This open source Dojo library for rich internet application development contains core functions for Document Object Model (DOM) manipulation, many user interface control elements, layouts, animations, and business charts.
  • Ajax messaging: This component enables the server to “push” data to clients in real time. Ajax messaging uses a Comet application pattern without the need for additional client side plug-ins. The package includes server-side and client-side Ajax components that communicate using Ajax-friendly JSON-based messages.
  • Ajax proxy: This component eliminates browser security concerns with cross-domain scripting when combining internal and external services.
  • Web 2.0 to SOA connectivity: This component provides the capability to extend Java™ EE objects to the Web using REST. Web 2.0 to SOA connectivity enables you to leverage Java EE programming and architecture to build Ajax applications.

Adding Web 2.0 capabilities to a traditional application like Plants by WebSphere will require some restructuring of both data and the user interactive front end. The extent of changes to an application will largely depend on the nature of the application. Regardless, the Feature Pack for Web 2.0 enables you to both add incremental Ajax capabilities to existing applications and build completely new ones. For this exercise, the Plants by WebSphere sample application was entirely redesigned to illustrate RESTful services, and to leverage the power of the Feature Pack for Web 2.0 in the client user interface. This article explains how this redesign was achieved.


Redesign for Web 2.0

If you're familiar with the original Plants by WebSphere application (Figure 1), then you will notice that we added many Web 2.0 attributes to the redesigned application (Figure 2). As this sample is a work in progress, some of these features have been fully implemented, and others will be developed in later releases. (See a working demo of the redesigned Plants by WebSphere application.) Major Web 2.0 features that are part of the new sample application include:

  • Social networking capability: Users should be able to create and populate profiles with pertinent data, such as name, address, e-mail address, and so on. This information is used in networking with other users through a site feature called the “Inspiration Garden,” in which a user can create a virtual garden with their purchased plants, and describe it with text and photos to help others with the same interests visualize the possible combinations of colors and textures. Users can post comments about the garden, similar to a blog and blog commenting, which in turn helps the garden owner continue to grow and improve his garden, perhaps even by purchasing more plants (viral marketing!).
  • Participation capability: Users can rate and comment on purchased products and everything else, from the purchasing experience and customer support to plant quality, appropriateness, and so on. A user can only submit one rating per purchased plant, but he can change that rating at any time. The rating displayed for a plant is a cumulative average of all ratings.
  • Mash-ups: Perhaps one of the most powerful applications of the Web is programmable Web-oriented architecture, in which callable services are available all over the Internet. An application can pick and choose which services are most appropriate for augmenting its core functions. In the Plants by WebSphere application, we invoke services from Wikipedia to provide the users with plant descriptions. The data is cached in a local database with a configurable expiration, which prevents repeatedly hitting Wikipedia for the same information.
Figure 1. Original Plants by WebSphere application
Figure 1. Original Plants by WebSphere application
Figure 2. Redesigned Web 2.0 Plants by WebSphere application
Figure 2. Redesigned Web 2.0 Plants by WebSphere application

There is quite a difference between the old and the new. It would have been possible to mix in the changes incrementally rather than completely redesign the application, but this approach enabled us to better show the power of the Feature Pack for Web 2.0 in providing a dramatically updated look and feel.

The client side is made up of mostly JavaScript™ using Dojo components and custom widgets, many of which are detailed in the next sections. The client layer interacts with the server through RESTful services.


RESTful services

The server APIs for client interactions were redesigned using REST (REpresentational State Transfer) principles. The server side is stateless, except for the session cookies to maintain the authentication status of the user. The data format for all APIs is JSON (JavaScript Object Notation), a compact but human-readable data structure.

Resources and URIs

The resources are plants, gardens, accounts, shopping carts, comments, ratings, Wikipedia, and Flickr. Potential operations on each resource are based on HTTP methods GET, PUT, POST and DELETE as appropriate. Some sources are read-only, such as Wikipedia and Flickr, while some other resources have full CRUD (Create, Read, Update, Delete) capability, like the shopping cart and gardens. APIs for each resource is represented as a servlet.

The HTTP methods are mapped like this:

  • GET: read or query the resource
  • PUT: update the resource
  • POST: create a new instance of the resource
  • DELETE: delete an instance of the resource.

The URI convention is /resource[/pathinfo][?querystring], where:

  • resource represents the collection (plants, gardens, and so on)
  • pathinfo is used to indicate a specific member of the collection (/plants/123)
  • querystring contains filters on the collection.

An operation such as GET /plants/123 will return the plant whose ID = 123. As an example, Table 1 illustrates the operations defined on the shopping cart:

Table 1. Shopping cart operations
OperationRequest URIResponseComments
Read shopping cartGET /shoppingCartContent of the current shopping cart.--
Insert an item into the cartPOST /shoppingCart POST parameters {qty:n, item:id}201 if successful
500 if error
item:id is the item ID being added to the cart. qty:n is the quantity.
CheckoutPUT /shoppingCart {authenticated shopping cart, parameters orderstate=10,totalcost, and so on}200 if successful
403 if unauthenticated
Checking out the content of the cart by modifying the orderstate = 10 (PURCHASED) along with other parameters.
Reset cartDELETE /shoppingCart200 if successfulRemoves all entries from the current cart.
Remove an item from the cartDELETE /shoppingCart/itemID200 if successful
404 if item not found
Removes a specific item from the cart. If the item was not found in the cart, a 404 returned.

Data format for Ajax style

JSON is used exclusively for all APIs here to send data between client and server. JSON is compact and very easy to manipulate in JavaScript. It is also very readable, so you don’t need the application’s UI to see and understand data on the wire. Here is a sample response when there are two items in the shopping cart:

Listing 1
cart = 
[
   {
      "name": "Dynasty Red",
      "plantid": "41",
      "price": "6.99",
      "qty": "1"
   },
   {
      "name": "Pansy",
      "plantid": "42",
      "price": "6.99",
      "qty": "1"
   }
]

With this design of the services, you can apply Ajax-style programming that fits well with the REST model. The application becomes much more interactive and responsive, similar to a desktop application. The data can be retrieved on demand to transfer the representational state on the client according to the user’s actions. The application no longer loads the entire page, eliminating much of the screen update time.

Let’s examine the shopping cart service usage on the client. The Dojo Ajax style for invoking server APIs is to use XHR. The code below demonstrates how to retrieve the cart content with xhrGet():

Listing 2
var deferred = dojo.xhrGet({
   handleAs: "json",
   url: "shoppingCart",
   timeout: 5000,
   handle: function(response, ioArgs){
      if (response instanceof Error) {
         // handle error
      } else {
         // do something with the cart data
      }
      return response;
   }
});

Furthermore, because the user can insert an item into the shopping cart from various locations in the application, we provide a convenient function: add_to_cart(). When an item is inserted, the shopping cart is animated to show its content for 3 seconds, which serves as a confirmation to the user:

Listing 3
function add_to_cart(item, quantity) {
   var summaryCallback = function(cart) {
      var summary = {
         name: item.name,
         image: item.image,
         quantity: quantity,
         itemCount: cart.length,
         subtotal: compute_cart_subtotal(cart)
      };
      var summaryWidget = dijit.byId("ShoppingCartSummary");
      summaryWidget.update(summary);
      summaryWidget.showUntilTimeout(3000);
   };
	
   var deferred = dojo.xhrPost({
      handleAs: "json",
      url: "shoppingCart",
      content: { qty: quantity, id: item.id },
      timeout: 5000,
      handle: function(response, ioArgs){
         if (response instanceof Error) {
            alert("ERROR: add_to_cart failed");
         } else {
            load_cart_data(summaryCallback);
         }
         return response;
      }
   });
}

The updated cart contents are requested when the xhrPost call successfully completes. It might also be possible to return the cart contents directly from the POST, depending on the version of WebSphere Application Server you are running.

To check out, we use the PUT /shoppingCart operation. However, we had to use xhrPost with an x-method-override header, rather than xhrPut, due to the servlet specification not processing the PUT payload.

Listing 4
var headers = {};
headers["x-method-override"] = "PUT";
var deferred = dojo.xhrPost({
   handleAs: "json",
   url: "shoppingCart/" + orderid,
   timeout: 5000, //Time in milliseconds
   headers: headers,
   content: content,
   handle: function(response, ioArgs){
      if (response instanceof Error) {
         // Handle error
      } else {
         showStep3(orderid);
      }	
      return response;
   }
});

Ajax-izing the application

Converting the application to a Web 2.0 style involves several changes to the user interaction model. The main idea is to replace some of the server's roles with JavaScript code running on the client. The end result is a more responsive user interface that behaves much like a desktop application.

Simple page with multiple fragments

The original Plants application made heavy use of JavaServer™ Pages (JSP). While it is certainly possible to use JSP within a Web 2.0 application, we made the decision to eliminate them from the code. Removing JSP provided a cleaner distinction between the client side user interface and the server side Web services. Instead of the JSP model, which required multiple full HTML pages, we implemented a single page model. The banner, navigation tool bar, and footer would stay on screen, while enabling the main content area to change. The other major change from JSP was that application data was no longer being downloaded with HTML markup.

The application leverages Dojo through custom JavaScript code in order to provide application content navigation. This main content is displayed using a Dojo ContentPane widget, which provides the ability to load snippets of HTML code instead of full pages. This significantly reduces the transition time between application content pages. An added feature is that the ContentPane displays a nice progress indicator while content is loading. This content area is managed by library code that also handles back button history, document title, and the ability to share widgets across content pages. The result is an experience that feels like a desktop application, but maintains the basic things that users would expect from a Web browsing session.

Here is HTML to create the ContentPane with initial content set to the file home.html:

<div id="content"
      dojoType="dijit.layout.ContentPane" href="home.html"></div>

ContentPane provides a method to load different content. For example, the following code changes the content of the ContentPane to inspiration.html:

var contentPane = dijit.byId("content");
contentPane.setHref("inspiration.html");

The application uses script tags in index.html to preload the Dojo widget code and HTML templates. Dojo provides a “require” function that behaves much like the include or import directives of other languages. After this point, the application can create and destroy widgets as necessary without requiring additional HTTP requests for markup.

Reusable custom widgets

Dojo provides a framework for creating visual widgets that fit well with the Ajax interaction model. Some widgets interact with a backend service, while others only provide client side capabilities. Table 2 shows a list of the custom widgets used in the application. Any widgets described as a content page are top level containers that are placed inside the main ContentPane. They each have a distinct title and can also be navigated using the browser’s back button.

Table 2. Plants by WebSphere widgets
WidgetDescription
AccountEditDialogCustom dialog to display an AccountEditForm.
AccountEditFormReusable form to collect account information.
AccountPageContent page that displays account information.
CheckoutPageContent page that manages the checkout process.
CommentComment input.
CommentListList of CommentListItem.
CommentListItemWidget to display brief comment and rating information.
FlickrWidgetWidget that allows the user to browse and upload Flickr images.
FlickrWidgetDialogCustom dialog to display a FlickrWidget.
GardenPageContent page displaying a user's garden.
InspirationAbstractReusable widget to display a brief summary about a garden.
InventoryGridTwo dimensional grid of InventoryItems.
InventoryGridRowHorizontal row of InventoryItems.
InventoryItemReusable widget to display basic plant information.
ItemDialogCustom dialog plant information when hovering over InventoryItem.
ItemPageContent page to display plant information from Wikipedia.
LoginDialogDialog with username and password fields.
PlantRatingReusable widget to display rating and comment information.
RatingAreaEditable rating stars.
ShoppingCartReusable table of items from the shopping cart.
ShoppingCartRowSingle item row in the shopping cart.
ShoppingCartSummarySummary dialog displaying last item added to the shopping cart.
TopRatedPlantsTable to display the top rated plant items.

The composition of widgets enables the application to reuse functionality in many different places. For example, the application reuses the InventoryItem widget on several different pages. This is a small widget that displays a plant name and picture alongside its price and an average user rating. Users can add a plant item to their shopping cart wherever an InventoryItem is displayed. Figures 3, 4 and 5 capture the InventoryItems in a variety of locations.

Figure 3 Instances of the InventoryItem widget on an inventory page
Figure 3. Instances of the InventoryItem widget on an inventory page
Figure 4. Instances of the InventoryItem widget on an inspiration garden page
Figure 4. Instances of the InventoryItem widget on an Inspiration Garden page
Figure 5. Instances of the InventoryItem widget on an item detail page
Figure 5. Instances of the InventoryItem widget on an item detail page

Tool bar

The application was designed to have a tool bar that is always present near the top of the panel. Desktop applications frequently use tool bars, and so users have come to expect them. In the Plants application, the items on the tool bar have one of two actions. They either act as simple push buttons, or they open a drop down menu or dialog. Here is the HTML to create the Plants drop down menu:

Listing 5
<div dojotype="dijit.form.DropDownButton" menuid="Edit" id="PlantsMenuDropDown">
   <span>Plants</span>
   <div dojotype="dijit.Menu" id="PlantsMenu">
      <div dojotype="dijit.MenuItem" label="Annual" onclick="inventory('annual');">
      </div>
      <div dojotype="dijit.MenuItem" label="Evergreen" onclick="inventory('evergreen');">
      </div>
      <div dojotype="dijit.MenuItem" label="Perennial" onclick="inventory('perennial');">
      </div>								
   </div>
</div>

Another main ingredient in the desktop look and feel is the use of dialogs. Dialogs allow users to perform an action without navigating away from the current page to do so. In the plants application, dialogs are used for logging users in, displaying item information, displaying a shopping cart summary, uploading images, and editing account information. Figures 6 and 7 are taken from various places within the application.

Figure 6. Login dialog
Figure 6. Login dialog

Below is the HTML to create the Login button that opens the LoginDialog:

Listing 6
<div class="bannerRight" id="LoginButton" dojoType="dijit.form.DropDownButton">
   <span>Login</span>
   <div dojoType="ibm.widget.LoginDialog" id="LoginDialog" 
	title="Enter Login information">
   </div>
</div>

The ShoppingCartSummary widget is more complex since it is not statically instantiated. It is animated whenever the user adds an item to the cart.

Figure 7. Shopping Cart Summary dialog
Figure 7. Shopping Cart Summary dialog

The ShoppingCartSummary widget is programmatically created and animated every time an item is inserted:

Listing 7
var contentPane = dijit.byId("content");
var div = document.createElement("DIV");
div.id = "ShoppingCartSummaryContainer";
div.style.display = "none";
var idiv = document.createElement("DIV");
idiv.id = "ShoppingCartSummary";
div.appendChild(idiv);
contentPane.domNode.appendChild(div);
var widget = new ibm.widget.ShoppingCartSummary(null,idiv);

Notice that the widget is initially hidden using the CSS display style. When the widget needs to be displayed (after the “add to cart” action), the two functions below are used to display the widget for a given time before closing it.

Listing 8
showUntilTimeout: function(millis) {
   dojo.byId("ShoppingCartSummaryContainer").style.display = "block";
   this.timeoutId = window.setTimeout(dojo.hitch(this,this._hideSummary),millis);
}
	
_hideSummary: function() {
   if (this.timeoutId != null) {
      window.clearTimeout(this.timeoutId);
   }
   dojo.byId("ShoppingCartSummaryContainer").style.display = "none";
   this.timeoutId = null;
}

The use of Web 2.0 techniques requires you to change your thinking about application development. Building widgets that can be composed and reused takes time, and while this can be a frustrating process, your users will benefit greatly by having an integrated and responsive application.


Leveraging external Web content

The concept of a programmable Web or mashup reinforces the community aspect of Web 2.0. Web developers can create mashups (basically the use of two or more Web applications through public APIs, feeds, screen scraping, and so on) to form new, unique Web applications.

Mashing up with Wikipedia

The first mashup developed for Plants by WebSphere was a mashup with Wikipedia and the item detail widget. We wanted to retrieve a detailed description of the product that is essentially a live document. We could have implemented our own wiki, but without the content and following that Wikipedia has, we would have had a much less informative site. The item detail widget uses the Wikipedia API to look up plant information, display the first few paragraphs from the plant’s Wikipedia entry, and retrieve the image from the entry’s taxonomy information.

The mashup is implemented in two parts: the client side, which is a Dojo widget, and the server side, which is a Java servlet. There are several reasons why we did not implement the mashup entirely on the client side:

  • Cross domain Ajax restrictions: The browser prevents us from making direct Ajax calls to the Web service. There are some Web services that provide a JSON-P interface (or possibly other workarounds), but these usually require a tight coupling between the service and the widget. The Feature Pack for Web 2.0 provides a proxy service to alleviate this issue.
  • Caching external service content: Rather than pull data for each request, Wikipedia suggests copying data and serving it up from your own site to reduce load on the Wikipedia servers. In this application, the mashup content is cached on the server until is expires.
  • Transferring less data: Most of the text from the Wikipedia entry is truncated, so much less data is transferred, and since data is cached on the server, the data is processed and stored much more efficiently.

Figure 8 shows the mashup item detail page.

Figure 8. Mashup item detail
Figure 8. Mashup item detail

This page is a composition of two dijit.layout.ContentPanes and our RatingArea, CommentList, InventoryGridRow widgets. The Wikipedia mashup is contained in the ContentPanes. The item page is initialized with plant information read from the database, which includes among the plant name, ID, and so on. Here is a snippet from the widget template:

Listing 8
<h2> <a href="#CONTENT_INV" dojoAttachEvent="onclick:navCategory">${category}</a> > 
	${item.name} </h2>
<table class="main">
   <tr>
      <td class="sidemargin"> </td>
      <td class="detailpic">
         <div class="wikipediaimage" dojoType="dijit.layout.ContentPane" 
			layoutAlign="client" href="wikipedia/image/${item.wikiword}">
         </div>
         <table class="aux">
            <tr>
               <td align="left">
                  <div dojoType="ibm.widget.RatingArea" itemid="${item.id}" 
				rating="readonly" displayReviewedBy=false></div>
               </td>
               <td>
                  <span class="noteText">(Average customer rating)</span>
               </td>
            </tr>
         </table>			
         <div dojoType="ibm.widget.CommentList" itemid="${item.id}"></div>
      </td>
      <td class="middlemargin">
      </td>
      <td valign="top">
         <h1>${item.name} 
            <span class="noteText"><a target="top" 
			href="http://en.wikipedia.org/wiki/${item.wikiword}">(Image 
				and description from Wikipedia)</a>
            </span>
         </h1> 
         <div dojoAttachPoint="content" class="wikipediaentry" 
			dojoType="dijit.layout.ContentPane" layoutAlign="client" 
				href="wikipedia/${item.wikiword}">
         </div>

In the template, you see that one ContentPane is populated with the data from wikipedia/image/${item.wikiword} and the other from wikipedia/${item.wikiword}. If you now look at the WikipediaServlet.java from the demo, you will see the inner workings of the mashup. The servlet works in two modes: caching mode (default) or without cache. In caching mode, the servlet caches images and text from Wikipedia on the file system. The entry point to the mashup will be either processGet or processCachedGet, which calls getWikiMarkup(). getWikiMarkup uses the Wikipedia /Special:Export/ web API to get the XML document with the Wikipedia entry for the wiki word. The function uses a DOMParser to extract the mediawiki-markup from the XML document, then the mediawiki-markup is searched for the taxonomy image name, or put through some regular expression and truncation logic to produce the summary text displayed.

Listing 9
dp.parse("http://en.wikipedia.org/wiki/Special:Export/"+wikiWord);
Document doc = dp.getDocument();
// get the wikitext from the text element of the XML
// use regex to convert from wikitext to HTML
// truncate and return the HTML

Both resources wikipedia/image/$wikiword and wikipedia/$wikiword return an HTML document that is inserted into the content pane. The image document contains a link to a locally downloaded image (in cached mode), which is served up by WebSphere Application Server, leveraging edge and browser caches. The image document must go through some additional logic to generate, since the image can be located on one of two servers on Wikipedia. The getWikiImageURL() function of the WikipediaServlet function tries to locate the image in both possible locations and determines the correct URL to use.

Mashing up with Flickr

The second mashup used here is with Flickr. The account information page (Figure 9) lets the user upload an image, which is retrieved from Flickr. The FlickrWidget seen below is made up of a mashup client side.

Figure 9. Flickr mashup
Figure 9. Flickr mashup

The FlickrWidget requests the FlickrServlet for the list of images: flickr/${APIKey}/userid/{$userid}/max/${maxImages}. The FlickrServlet then uses the Flickr Web API at api.flickr.com/services/rest to retrieve an XML document describing the image URLs in the user’s account and returns them in a JSON formatted response (Figure 10). When an image is chosen, the image is copied to the server by the FlickrServlet and the image is set to the user’s profile image.

Figure 10. Flickr URLs from user account
Figure 10. Flickr URLs from user account

You could easily extend this capability by enabling users to use Flickr for setting up their own garden pages.

Other examples of potential mashups you might consider could include Google maps with climate zones and garden locations, social networking sites such as Facebook and mySpace, and many more. These and other mashup possibilities might even be added to the next iteration of the Plants by WebSphere sample application, so stay tuned!


Conclusion

As you can see from this sample application, the IBM WebSphere Application Server Feature Pack for Web 2.0 is very powerful. It provides a rich set of features that enable the development of a new level of robust user interfaces with Ajax style interactions. Dojo has done most of the hard work to eliminate most of the major browsers’ peculiarities and provided a common framework and library for easily building rich Internet applications.

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Web development
ArticleID=307550
ArticleTitle=Plants by WebSphere gets a Web 2.0 makeover
publish-date=05142008