Skip to main content

DWR makes interportlet messaging with Ajax easy

Java portlets and Ajax are a perfect fit for Web development

Sami Salkosuo (sami.salkosuo@fi.ibm.com), Software Architect, IBM
Sami Salkosuo has worked at IBM since 1999. His main area of interest is Java programming and he is a Sun Certified Java Programmer, IBM Certified Solution Developer for XML and Related Technologies, and IBM Certified Solution Developer for IBM WebSphere Portal. Beyond Java technology, he also has experience with Python, Fortran, LabVIEW, Visual Basic, LISP, Perl, and PHP.

Summary:  Many developers are looking to use Ajax technologies to improve the user experience of Web-based applications, but Ajax programming can be a tricky task. The open source Direct Web Remoting (DWR) library can make Ajax development easier for Java™ developers by automatically transforming Java classes into JavaScript classes. In this article, you'll learn how how to use DWR and JSR-168-compliant portlets to build an Ajax application quickly and easily.

Date:  14 Jul 2006
Level:  Intermediate
Activity:  5256 views

Portlets are Java platform-based applications for Web portals. JSR-168, a Java Community Process standard for developing portlet applications, addresses portlet lifecycle management, portlet container contracts, packaging, deployment, and other aspects related to portals.

Asynchronous JavaScript + XML, or Ajax, is a technique for developing rich, interactive Web applications. Ajax uses a combination of XML, HTML, DHTML, JavaScript, and DOM.

Portlets and Ajax would seem to be a perfect fit for one another, as they are both focused on using a Web browser as the vehicle for presenting a UI to the user. An easy way to combine the two with Java technology is to use the DWR library. DWR is a Java library, open sourced under the Apache license, for building Ajax-based Web applications. DWR's basic purpose is to hide Ajax details from the developer. You use plain old Java objects (POJOs) on the server side, and DWR dynamically generates JavaScript proxy functions so that client-side development with JavaScript feels like calling JavaBeans directly. The main component of DWR is a Java servlet that handles calls from browser to server.

This article uses DWR to build a sample Ajax application based on three portlets. I show you how to integrate DWR with your portlet apps, but I won't get into the details of how DWR works under the hood; you can find more information about the library on the project's Web site and within the pages of developerWorks (see Resources for details). To build the application I describe, you need a version 1.3 or later of the Java platform and a portal environment compliant with JSR-168. The environment I used for developing and testing this code consisted of IBM Rational Application Developer V6.0, Apache Jetspeed 2.0 portal, and Java 5.0.

You should also be familiar with portlet and Ajax development before you begin. If you'd like to learn more about these topics, check out the Resources section below. You can download the complete code for our sample application, including DWR, from the Download section.

Building the sample interportlet messaging application

Our sample application has three portlets: Orders, Order Details, and Customer Details; Figure 1 shows the sample application:


Figure 1. Sample application
Sample application

The Orders portlet has a list of orders. When the user clicks on an order number, the portlet sends the order number to the Order Details and Customer Details portlets, which then display the appropriate order and customer details.

Setting up the development environment

Before you can develop the portlets, you need to set up your development environment and set up DWR. I use IBM Rational Application Developer V6.0, which has built-in support for Java portlet development, but any development environment will do just fine. Follow these steps to get started:

  1. Create a new JSR-168 portlet project. Name the project InterPortletMessaging, but do not create any portlets just yet.

  2. Download dwr.jar (version 1.1; see Resources for a link). Add dwr.jar to the your project in the /WebContent//WEB-INF/lib directory.

  3. Open web.xml and add the code in Listing 1 to it. This adds the DWR servlet to the application. This servlet is used in the background to process requests and send responses back to the browser.



    Listing 1. DWR servlet
    <servlet>
    
      <servlet-name>dwr-invoker</servlet-name>
      <display-name>DWR Servlet</display-name>
      <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
      <init-param>
        <param-name>debug</param-name>
        <param-value>true</param-value>
      </init-param>
    </servlet>
    
    <servlet-mapping>
      <servlet-name>dwr-invoker</servlet-name>
      <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
    



  4. Create a file called dwr.xml in the WEB-INF directory using the code in Listing 2. This is the DWR configuration file, which tells the container which classes are available in JavaScript. DWR reads this XML file and dynamically generates JavaScript code to represent Java classes as JavaScript classes. This enables you to offer the functionality offered by those Java classes in the browser. You haven't actually created the Java class referenced in Listing 2 yet, but we'll take care of that momentarily.



    Listing 2. dwr.xml
    <!DOCTYPE dwr PUBLIC
        "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
        "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
    
    <dwr>
      <allow>
        <create creator="new" javascript="MessagingBean">
          <param name="class" value="msg.MessagingBean"/>
        </create>
      </allow>
    </dwr>
    

Now you can use DWR in your portlets. Before you create your sample portlets, though, you need to create a messaging bean and a mockup database bean that will serve as the back end for the sample application.

Create MockupDB and MessagingBean

MockupDB, illustrated in Listing 3, is singleton class that simulates a database of customer orders. All the orders are hard-coded in this class. A real application would probably use a relational database system, but this example is enough for our purposes.


Listing 3. MockupDB
package db;

import java.util.Hashtable;
import java.util.Map;

public class MockupDB {

  private static MockupDB instance=new MockupDB();

  private String[] orders=new String[4];
  private Map orderDetails=new Hashtable();
  private Map customerDetails=new Hashtable();

  private MockupDB()
  {
    String ordStart="ORD";
    orders[0]=ordStart+"000408015";
    orders[1]=ordStart+"001600023";
    orders[2]=ordStart+"000042000";
    orders[3]=ordStart+"011235813";

    orderDetails.put(orders[0],"1. WebSphere Everyplace Connection Manager<br/>"+
                     "2. WebSphere Portal");
    orderDetails.put(orders[1],"1. DB2 Universal Database<br/>2. DB2 Everyplace");
    orderDetails.put(orders[2],"1. Tivoli Access Manager for e-business <br/>2."+
                     "Tivoli Directory Integrator");
    orderDetails.put(orders[3],"1. IBM System z9<br/>2. IBM System p5 550 Express");

    customerDetails.put(orders[0],"<b>Systems and Technology Group</b><br/>"+
                        "Some Road<br/>Finland");
    customerDetails.put(orders[1],"<b>Global Financing</b><br/>Another Street"+
                        "<br/>Finland");
    customerDetails.put(orders[2],"<b>Software</b><br/>Yet Another Road"+
                        "<br/>Finland");
    customerDetails.put(orders[3],"<b>Global Services</b><br/>Still Another "+
                        "Street<br/>Finland");
  }
    
  public static MockupDB getInstance()
  {
    return instance;
  }
    
  public String[] getOrders()
  {
    return orders;
  }
    
  public String getOrderDetails(String orderNro)
  {
    return (String)orderDetails.get(orderNro);
  }

  public String getCustomerDetails(String orderNro)
  {
    return (String)customerDetails.get(orderNro);
  }
}

MessagingBean, illustrated in Listing 4, is a simple POJO with two methods that take an order number and return order details and customer details, respectively. MessagingBean gets details from the MockupDB.


Listing 4. MessagingBean
package msg;

import javax.servlet.http.HttpSession;

import db.MockupDB;

public class MessagingBean {

  public MessagingBean()
  {        
  }
    
  public String getOrderDetails(String orderNumber,HttpSession httpSession)
  {
    String orderDetails=MockupDB.getInstance().getOrderDetails(orderNumber);
    httpSession.setAttribute("orderDetailsOrderNumber",orderNumber);
    httpSession.setAttribute("orderDetails",orderDetails);
    return orderDetails;
  }

  public String getCustomerDetails(String orderNumber,HttpSession httpSession)
  {
    String customerDetails=MockupDB.getInstance().getCustomerDetails(orderNumber);
    httpSession.setAttribute("customerDetailsOrderNumber",orderNumber);
    httpSession.setAttribute("customerDetails",customerDetails);
    return customerDetails;
  }
}

MessagingBean also adds order details and customer details to the HttpSession.

javaScriptFunctions.jsp

javaScriptFunctions.jsp imports a JavaScript library from DWR (engine.js) and the dynamically created library MessagingBean.js. Notice that MessagingBean.js uses the same name as the Java bean introduced in dwr.xml (Listing 2); in fact, DWR generates MessagingBean.js. The DWR framework uses the engine.js library; as a developer, you typically don't need to worry about using it directly.

As you can see in Listing 5, sendOrderNr() functions call to the MessagingBean functions defined in Listing 4. DWR adds the HttpSession automatically to the method call. The last parameter in the JavaScript function is the callback function. This JSP is included in the portlet JSPs that you'll create next.


Listing 5. javaScriptFunctions.jsp
<%@ page contentType="text/html" 
import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>

<SCRIPT type="text/javascript"
	src='<%= renderResponse.encodeURL(renderRequest.getContextPath() +
	"/dwr/interface/MessagingBean.js") %>'> 
</SCRIPT>

<SCRIPT type="text/javascript"
	src='<%= renderResponse.encodeURL(renderRequest.getContextPath() + 
	"/dwr/engine.js") %>'> 
</SCRIPT>

<SCRIPT type="text/javascript">

function <portlet:namespace />sendOrderNr(orderNr)
{
document.getElementById("orderDetailsOrderNumber").innerHTML=orderNr;
document.getElementById("customerDetailsOrderNumber").innerHTML=orderNr;
MessagingBean.getOrderDetails(orderNr,<portlet:namespace />showOrderDetails);
MessagingBean.getCustomerDetails(orderNr,<portlet:namespace />showCustomerDetails);

return false;
}

function <portlet:namespace />showOrderDetails(orderDetails)
{
document.getElementById("orderDetails").innerHTML=orderDetails;
return false;
}

function <portlet:namespace />showCustomerDetails(customerDetails)
{
document.getElementById("customerDetails").innerHTML=customerDetails;
return false;
}
</SCRIPT>

Create portlets

Now that you have back-end and proxy functions, you can develop the portlets themselves. All three portlets use the same codebase; the only difference is the name of the JSP that each uses.

  1. Create a new portlet using the code in Listing 6 and name it Orders:



    Listing 6. Orders.java
    package interportletmessagingusingajax;
    
    import java.io.*;
    
    import javax.portlet.*;
    
    public class Orders extends GenericPortlet {
    
      // JSP folder name
      public static final String JSP_FOLDER = "/interportletmessagingusingajax/jsp/";
    
      // JSP file name to be rendered on the view mode
      public static final String VIEW_JSP = "OrdersView";         
    
    
      public void init(PortletConfig config) throws PortletException{
        super.init(config);
      }
    
      public void doView(RenderRequest request, RenderResponse response) 
        throws PortletException, IOException {
        // Set the MIME type for the render response
        response.setContentType(request.getResponseContentType());
    
        // Invoke the JSP to render
        PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher( 
          getJspFilePath(request, VIEW_JSP));
        rd.include(request,response);
    
        //this is workaround for portletsession sharing between
        //servlets and portlets
        //see http://weblogs.java.net/blog/wholder/archive/2005/02/session_session.html
        //and http://mail-archives.apache.org/mod_mbox/portals-pluto-dev/200502.mbox/%3Ca
        //2519328f3ba1d1eddfc33c924b6805d@umich.edu%3E
        //
        PortletRequestDispatcher rd2 = getPortletContext().getRequestDispatcher("/dwr/");
        rd2.include(request, response);
    
      }
    
      private static String getJspFilePath(RenderRequest request, String jspFile) {
        String markup = request.getProperty("wps.markup");
        if( markup == null )
          markup = getMarkup(request.getResponseContentType());
        return JSP_FOLDER+markup+"/"+jspFile+"."+getJspExtension(markup);
      }
    	
      private static String getMarkup(String contentType) {
        if( "text/vnd.wap.wml".equals(contentType) )
          return "wml";
        return "html";
      }
    
      private static String getJspExtension(String markupName) {
        return "jsp";
      }
    }
    



  2. Create and open OrdersView.jsp (in the interportletmessagingusingajax/jsp/html directory) and add the code in Listing 7 to it:



    Listing 7. OrdersView.jsp
    <%@ page contentType="text/html" 
    import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:defineObjects/>
    <jsp:include page="javascriptFunctions.jsp" />
    
    <DIV style="margin: 6px">
    
    <H4 style="margin-bottom: 3px">Orders</H4>
    <table cellspacing="0" cellpadding="5" border="1">
    <% db.MockupDB database= db.MockupDB.getInstance();
    
    String[] orders=database.getOrders();
    for(int i=0;i<orders.length;i++)
    {
    %>
    <tr>
    
    <td><%="000000000"+String.valueOf(i+1) %></td>
    <td><a href="" onclick="return <portlet:namespace />sendOrderNr('<%=
      orders[i]%>');"><%=orders[i]%></a></td>
    </tr>
    <%
    }
     %>
    
    </table>
    </DIV>
    



  3. The second portlet is OrderDetailsPortlet.java. Use the code in Listing 6 for this portlet and change the value of the VIEW_JSP variable to OrdersDetailsPortletView.jsp. The code for this JSP is in Listing 8:

    Listing 8. OrdersDetailsPortletView.jsp
    <%@ page contentType="text/html" 
    import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:defineObjects/>
    
    <DIV style="margin: 6px">
    
    <H4 style="margin-bottom: 3px">Order details</H4>
    
    <table cellspacing="0" cellpadding="5" border="1">
    <tr>
    <th>Order number</th>
    <th>Order details</th>
    </tr>
    
    <tr>
    <%
    String orderDetailsOrderNumber=(String)renderRequest.getPortletSession().getAttribute(
      "orderDetailsOrderNumber",PortletSession.APPLICATION_SCOPE);
    String orderDetails=(String)renderRequest.getPortletSession().getAttribute(
      "orderDetails",PortletSession.APPLICATION_SCOPE);
    
    if(orderDetailsOrderNumber==null)
    {
    orderDetailsOrderNumber="";
    }
    
    if(orderDetails==null)
    {
    orderDetails="";
    }
    %>
    <td><div id="orderDetailsOrderNumber"><%=orderDetailsOrderNumber%>
    </div></td>
    <td><div id="orderDetails"><%=orderDetails%></div></td>
    </tr>
    
    
    </table>
    </DIV>
    



  4. The third portlet is CustomerDetailsPortlet.java. Use the code in Listing 6 for this portlet and change the value of the VIEW_JSP variable to CustomerDetailsPortletView.jsp. The code for this JSP is in Listing 9:

    Listing 9. CustomerDetailsPortletView.jsp
    <%@ page contentType="text/html" 
    import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:defineObjects/>
    
    <%
    %>
    
    <DIV style="margin: 6px">
    
    <H4 style="margin-bottom: 3px">Customer details</H4>
    <table cellspacing="0" cellpadding="5" border="1">
    <tr>
    <th>Order number</th>
    <th>Customer details</th>
    </tr>
    
    <tr>
    <%
    String customerDetailsOrderNumber=
      (String)renderRequest.getPortletSession().getAttribute(
      "customerDetailsOrderNumber",PortletSession.APPLICATION_SCOPE);
    String customerDetails=(String)renderRequest.getPortletSession().getAttribute(
      "customerDetails", PortletSession.APPLICATION_SCOPE);
    
    if(customerDetailsOrderNumber==null)
    {
    customerDetailsOrderNumber="";
    }
    
    if(customerDetails==null)
    {
    customerDetails="";
    }
    %>
    <td><div id="customerDetailsOrderNumber"><%=customerDetailsOrderNumber%>
    </div></td>
    <td><div id="customerDetails"><%=customerDetails%></div></td>
    </tr>
    
    </table>
    </DIV>
    

The sample application is now ready. The next step is to package the portlet as a WAR file and test it in the Apache Jetspeed portal.


Testing the sample application

In this section, you'll see the sample application in action. First, you'll create the portlet WAR and install it into the Jetspeed portal. Next, you'll add the portlets to the portal and see how they work. You'll be building them all onto a single page, but you could put them on multiple pages if you needed to; the mechanisms behind the scenes would still work.

Install portlet application into Jetspeed

Install the portlet WAR file to Jetspeed by copying the WAR file to the directory <Jetspeed install dir>/webapps/jetspeed/WEB-INF/deploy. Jetspeed then automatically installs the portlet and it is ready to be used.

Use the following steps to add a new page to the Jetspeed portal:

  1. Go to your Jetspeed portal and log in as an administrator.

  2. Click the Edit icon in the right corner and add new page named Inter-Portlet Messaging, as shown in Figure 2:



    Figure 2. Add new page
    Add new page



  3. Select the Inter-Portlet Messaging page and click the Edit icon. Then click the Add a portlet icon to add portlets in the page. Select the Orders, Order Details, and Customer Details portlets and click Select portlets to add your portlets to the portal page. When you're done, your page should look like Figure 3:

    Figure 3. Portlets on the page
    Portlets on the page

Portlets

The Orders portlet, shown in Figure 4, lists orders:


Figure 4. Orders portlet
Orders portlet

When you click an order number, the other portlets show the details of that particular order. The Customer Details portlet displays customer information, as illustrated in Figure 5. The information is retrieved from MockupDB.


Figure 5. Customer Details portlet
Customer Details portlet

The Order Details portlet also presents information retrieved from MockupDB, as you can see in Figure 6:


Figure 6. Order Details portlet
Order Details portlet

If you'd like, you can go back and add one or more portlets to different pages. You will see that your portlets do not need to be on a single page because portlet content is stored in a user session.


Conclusion

This article introduced one way to achieve interportlet communication using Ajax. Ajax is a very powerful technique for developing interactive Web pages, and Ajax-enabled portlets greatly improve the user experience by eliminating the request-response delay that is typical in portals.

You can use the sample code in this article as a starting point for developing your own applications; the code also shows how DWR extends the Java programming model to Web browsers. With DWR, it's almost as if JavaBeans were available in the browser. DWR simplifies your work by hiding almost all the details of Ajax and allows you to concentrate on the task at hand instead of the nuts and bolts of Ajax development.



Download

DescriptionNameSizeDownload method
Source codej-ajaxportlet.war3MB HTTP

Information about download methods


Resources

Learn

Get products and technologies

About the author

Sami Salkosuo

Sami Salkosuo has worked at IBM since 1999. His main area of interest is Java programming and he is a Sun Certified Java Programmer, IBM Certified Solution Developer for XML and Related Technologies, and IBM Certified Solution Developer for IBM WebSphere Portal. Beyond Java technology, he also has experience with Python, Fortran, LabVIEW, Visual Basic, LISP, Perl, and PHP.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, WebSphere, Web development
ArticleID=146261
ArticleTitle=DWR makes interportlet messaging with Ajax easy
publish-date=07142006
author1-email=sami.salkosuo@fi.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers