Implementing client-side interportlet communication with Dojo and WebSphere Portal

This article describes how to add client-side interportlet communication to your IBM® WebSphere® Portal (hereafter called WebSphere Portal) portlets using the Dojo JavaScript toolkit. It is intended for developers who are beginning to use Ajax with WebSphere Portal and want to replicate on the client the interportlet communication they have previously implemented on the server side. To get the most out of this article, you should have a good understanding of JavaScript programming, WebSphere Portal, and portlet development. See Resources for references which can help you gain this knowledge. The sample portlet application for this article was developed using IBM Rational® Application Developer v7 and was tested on WebSphere Portal V6.0.

Share:

Aron Wallaker (wallaker@ca.ibm.com), IT Specialist, IBM Software Services for WebSphere, IBM

Aron Wallaker is an IT Specialist at the IBM Software Lab in Toronto, Canada. He works on WebSphere Portal and Web application development as part of the IBM Software Services for WebSphere (ISSW) team.



14 March 2007

Also available in Chinese Russian Japanese

Introduction

Many portal developers have used WebSphere Portal to create cooperative portlets that share events and data to enhance the user experience. For example, a selection submitted in one portlet could cause updated information to display in multiple related portlets, helping the portlets to stay synchronized in their presentation. This functionality is implemented on the server and relies on the portlets submitting action requests to the server so that it can perform the data transfers before the page is refreshed.

This approach starts to break down as you add Ajax functionality to portlets because you dynamically update the data displayed by a portlet without submitting an action request or refreshing the page. This article shows how to use the Dojo JavaScript toolkit to share data and events between portlets in the browser, providing cooperative support to dynamically updated portlets.


What is Dojo?

Dojo is an Open Source JavaScript toolkit that you can use to develop of dynamic Web applications. Included in Dojo’s many libraries are Ajax support, DOM manipulation tools, an event handling system, and a customizable widget set. Dojo combines these libraries with a flexible packaging system that enables you to import only the libraries that you need; Dojo resolves all inter-library dependencies for you automatically.

Using Dojo

The dynamic packaging system differentiates the use of Dojo libraries from traditional JavaScript inclusion. Including the Dojo libraries is a two-step process. You:

  1. Include the Dojo bootstrap.
    <script type="text/javascript" src="/path/to/dojo/dojo.js"> 
    </script>
  2. Identify the Dojo libraries your application requires. You use the dojo.require statement to include the Dojo widget managing functions (dojo.widget.*) and the Button widget (dojo.widget.Button).
     <script type="text/javascript">
     dojo.require("dojo.widget.*");
     dojo.require("dojo.widget.Button");
     </script>

The dojo.require statements specify the Dojo resources you are using in your application. The Dojo bootstrap will scan the page for these dojo.require statements and will dynamically include the corresponding libraries so that these resources are available. The dynamic loading process also handles all dependencies between Dojo libraries, so you only need to add require statements for the resources you use directly.

Using Dojo with WebSphere Portal

Dojo’s unique loading strategy poses a challenge to portlet developers. The Dojo bootstrap, dojo.js, should only be included once in an HTML page. Depending on the browser, having dojo.js included more than once can result in JavaScript errors being reported to the end user. The simplest way to avoid this problem in WebSphere Portal is to include dojo.js in your theme’s JSP, and to place the dojo.require statements in your theme and portlet JSP’s as required.

However, for the sample application, I wanted readers to be able to deploy the portlets without needing to modify their theme. Therefore, I included the Dojo libraries in the portlet project, and I wrote a conditional loader in JavaScript.

The conditional loader is contained in the file dojoLoader.jsp:

<script type="text/javascript">
	var path = "<%=request.getContextPath() %>/dojo/dojo.js";
	if(typeof dojo=="undefined") {
		document.write('<S');
		document.write('CRIPT type=\"text/javascript\" src=\"');
		document.write(path);
		document.write('\" ><\/S');
		document.write('CRIPT>');
	} 
</script>

This code checks for the existence of the dojo JavaScript object; when the object is not defined it inserts a script inclusion for dojo.js into the current HTML document. The JavaScript code to perform this is a little confusing to read; all instances of <script> or </script> in strings must be split; otherwise, some browsers will try to parse them as the actual start and end of a script. Modifying the theme JSP would be a much cleaner solution. Use this conditional loader technique only when you cannot modify the theme JSP.

Using Dojo events

Dojo includes an event communication system that enables developers to connect components of an application. This capability goes beyond the traditional DOM events of mapping events to any property, object, or element; it includes advanced features such as Aspect-Oriented Programming (AOP) or event publish/subscribe (pub/sub). This article focuses on the event pub/sub system, known as topics, and how you can use it for communication between portlets.

The Dojo event pub/sub system provides a method of anonymous communication between components based on a shared topic or queue name. A JavaScript component can use the Dojo event library to publish or subscribe to a topic. The publishing component can create an object with data that is related to an event and then publish the object to the topic. Any subscribers for that topic are called with the published object passed as a parameter, enabling them to react to the new data; for example, the subscriber could perform an asynchronous call and/or update its display.

This design maps very well to client-side communication between portlets. Because portlets should use the <portlet:namespace> tag to distinguish their DOM and JavaScript elements, it is very difficult for one portlet to listen for DOM events from another portlet’s HTML. Using Dojo event topics you can have multiple portlets respond to a DOM event in one portlet while remaining independent. For example, a dynamic portlet can perform an asynchronous call to retrieve information and make that updated information available to other portlets using an event topic.

A summary of the dojo.event.topic API

The following is a brief overview of the Dojo topics API and describes how you could use the various methods for communication between JavaScript components.

dojo.event.topic.registerPublisher (String topic, Object obj, String funcName)
Registers a function as a publisher on a topic. Any subsequent call to the function will cause an event to be published to the topic with the function’s arguments being passed on to any registered listeners for the topic.
dojo.event.topic.publish(String topic, Object message )
Manually publishes the passed object to the specified topic. This object will then be passed to any registered listeners for the topic.
dojo.event.topic.subscribe(String topic, Object obj, String funcName)
Subscribes the function to the specified topic. Any subsequent events published to the topic will create a function call for the subscribed function. A listener can subscribe to a topic at any time, even before the topic has been referenced by a publisher. Dojo creates the topic when it is first referenced by a subscriber or publisher.
dojo.event.topic.unsubscribe(String topic, Object obj, String funcName )
Unsubscribes the function from the specified topic.
dojo.event.topic.destroy(String topic)
Destroys the topic and un-registers all listeners of the topic.

The topic API specifies an object and a function name when you reference a publisher or a subscriber. This approach is designed to work with the Dojo widget system, so that a registration can be made for a specific widget instance. If you are not using widgets, you can choose to either implement a topic subscriber as a JavaScript object or as a simple function.

In the sample application, the topic subscribers are implemented as JavaScript objects. If you prefer to use a simple JavaScript function instead, you can do so by specifying the object as window.

For example:

dojo.event.topic.subscribe( "/myApp/myTopic", window, "myHandler");

This code would create a subscription to the topic "/myApp/myTopic". When an event is published to that topic, the JavaScript function myHandler would be called with the published event passed as a parameter.


A working example

Let's explore a simple configuration with an event publisher portlet, two listener portlets, and a single topic. The published event object will contain two data fields that are consumed by the listener portlets. The sequence of events for communication between the portlets will be as follows:

Figure 1 Sample portlet event flow
Figure 1 Sample portlet event flow
  1. A user clicks the Publish Event button on the publisher portlet. This creates a DOM event that triggers a JavaScript handler function.
  2. This handler uses the Dojo library to create an independent event object and to publish it to a topic. This new event is received by any topic subscribers without any connection to the original Publish Event button.
  3. The listener portlets contain topic subscription functions that are called by Dojo and which receive the event object. These functions update the portlet display with information contained in the event.

In the example the publisher portlet keeps a count of the number of times the Publish Event button has been clicked. The published event contains this count and a text message. Each of the listener portlets updates its display with one of the elements of the event message. Each time the listener portlets process an event, the updated area flashes to draw attention to the changes. This flash effect is not part of the event publish/subscription cycle; it has been added to improve the demonstration.

Event publisher portlet

The event publisher portlet needs a button that the user can click to publish an event and a counter to keep track of how many times the button has been clicked. Listing 1 shows HTML/ JavaScript source code to create this button, to add a handler function to process the button click event, to increment the counter, and, finally, to publish our event.

Listing 1. Source for the event publisher portlet
<P>
The button below will publish a Dojo event to all registered subscribers.<br />
<button dojoType="Button" 
  widgetId="<portlet:namespace />_publishButton">Publish Event
</button>
</P>
<script type="text/javascript">
	// Load Dojo's code relating to widget managing functions
	dojo.require("dojo.widget.*");	
	// Load Dojo's code relating to the Button widget
	dojo.require("dojo.widget.Button");
	// Load Dojo's event handling functionality
	dojo.require("dojo.event.*");
	dojo.require("dojo.event.topic.*");

	// Register our init function
	dojo.addOnLoad( <portlet:namespace />_init ); 
	
	// Click counter
	var <portlet:namespace />_counter = 0;

	// Init function for this portlet's Dojo components
	function <portlet:namespace />_init() {
		var pubButton = dojo.widget.byId("<portlet:namespace />_publishButton");
		dojo.event.connect(pubButton,'onClick','<portlet:namespace />_onButton');
	}

	// Button onClick handler
	function <portlet:namespace />_onButton() {
		<portlet:namespace />_counter++;
		var evt = {
			count: <portlet:namespace />_counter,
			message: "Click message #" + <portlet:namespace />_counter
		};
		dojo.event.topic.publish("/myApp/myTopic", evt);
	}
</script>

Reading through the code, you see that the dojoType tag identifies the Publish Event button as a Dojo Button widget. In the JavaScript section, the dojo.require statements identify the Dojo libraries that are used by this component. The call to dojo.addOnLoad() adds the init function to the list of functions Dojo will call after the page DOM has finished loading. This technique is similar to setting a function in the window.onLoad handler except that Dojo handles having multiple init functions which all need to run after the document has loaded. This capability is very useful in portal applications because it enables each portlet to specify a JavaScript init function without having to worry about the window.onLoad handler being overwritten.

The JavaScript functions and variables in this portlet are name-spaced using the <portlet:namespace> tag from the standard portlet tag library. This tag is replaced by an alpha-numeric string that is unique to the portlet instance which prevents namespace collisions when multiple portlets are assembled into a page. The init function locates the Publish Event button by its widgetId, and connects the onclick event of that widget to the event handler. The event handler increments the counter, constructs an event object, and uses the dojo.event.topic.publish API to publish the event object to the topic called myApp/myTopic. The event object has two elements:

  • count, the value of the counter
  • message, a text message containing the counter

Dojo will pass the event object to each of the event subscribers, which can then process the contents as they see fit.

Event subscriber portlet

The event subscriber portlet needs a display field which will be updated with information from the published event (when it arrives). The subscriber portlet also needs to register its event handling function for the topic. This registration is most conveniently done in an init function, similar to that used in the event publisher. The HTML/ JavaScript source for the event subscriber portlet is shown in Listing 2.

Listing 2. Source for the event subscriber portlet
<P>Button Click Count<br />
<span id="<portlet:namespace />_count" style="font-size : x-large;">0</span>
</P>
<script type="text/javascript">
  // Load Dojo's event handling functionality
  dojo.require("dojo.event.*");
  dojo.require("dojo.event.topic.*");
  dojo.require("dojo.lfx.html");
  dojo.require("dojo.gfx.color");

  dojo.addOnLoad( <portlet:namespace />_init ); 

  // Init function for this portlet's Dojo components
  function <portlet:namespace />_init() {
	<portlet:namespace />_myListener = new <portlet:namespace />_listener();
	<portlet:namespace />_myListener.load();
  }

  // event listener object
  function <portlet:namespace />_listener() {
    // Event handler - override for each portlet
    this.handleEvent = function(args) {
	  var countElement = document.getElementById("<portlet:namespace />_count");
	  countElement.innerHTML = args.count;
	  dojo.lfx.html.highlight("<portlet:namespace />_count",
	    dojo.gfx.color.named.blue,500).play();
     }
	    
    this.load = function() {
        dojo.event.topic.subscribe("/myApp/myTopic", this, this.handleEvent);
     }
  }
</script>

Similar to the event publisher portlet, the dojo.require statements specify the Dojo libraries needed by this component, and dojo.addOnLoad registers the portlet’s init function. The init function creates a new event listener object and subscribes it to the topic called /myApp/myTopic by calling its load method. When an event is published to this topic, the handleEvent method of the listener object is called.The event handler locates the DOM element where the message count is displayed, and updates the element's HTML with the new value passed in the event object.

Then, the handler calls dojo.lfx.html.highlight() to create a visual highlight effect to draw the user’s attention to the updated area.

The sample application includes a second event subscriber portlet with the same basic functionality; it displays the event message instead of the count. Both listeners receive the same object from the event publication, but choose to work with different members of the object.

Running the example

Let's look at the sample application to see how these portlets work together.

  1. If you have not already done so download the sample Rational Application Developer 7 project interchange file which contains the portlets discussed in this article.
  2. Import the file into Application Developer.
  3. To deploy the portlets, either export a WAR file and deploy it in your WebSphere Portal, or run the portlets in the integrated test environment.
  4. Create a new test page and add all three portlets to this new page.
  5. To test the application, simply navigate to the test page you created in step 4 and click on the Publish Event button.

Each time you click the button, the page displays the two event listener portlets that flash and are updated with the count and the message that are published by the publisher portlet.

Figure 2. Sample portlets
Figure 2. Sample portlets

Conclusion

Adding Ajax functionality to Web applications can greatly improve the user experience. In a WebSphere Portal environment, using Ajax in your portlets can come with the tradeoff of not having advanced functionality such as cooperative portlets. However, you can use the Dojo toolkit to add client-side interportlet communication. Portlet developers can use this technique to create dynamic, cooperative portlets that can stay synchronized while minimizing page refreshes and improving responsiveness.


Download

DescriptionNameSize
Code samplesdojoC2A.zip1466 KB

Resources

Learn

Get products and technologies

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=201908
ArticleTitle=Implementing client-side interportlet communication with Dojo and WebSphere Portal
publish-date=03142007