Level: Introductory David Lection (lection@us.ibm.com), Senior Programmer, IBM
01 Aug 2002 In this article, David introduces the concept of portlet programming for WebSphere Portal Version 4.1. He shows you how to construct a portlet application, including the required classes and support files, and explains how to build and deploy a portlet to a working portal server. You can use the example portlets presented here as building blocks for larger portlet applications.
Part 2 of this series shows you how to implement portlet-to-portlet messaging.
Editor's Note: This is an updated version of an article written by David Lection in November 2001 about WebSphere Portal Server Versions 1.2 and 2.1. This version describes the most recent follow-on product, WebSphere Portal Version 4.1. Introduction to portals
Portals and portal servers are red hot in Internet and Web development today. Just about everyone developing a Web site is using some sort of portal technology. Why is portal technology so popular? If you remember back to the MS-DOS days, you know there was a time when PCs ran one application at a time. When you wanted to switch applications, you'd have to close one application and enter the name of the new app at the DOS prompt. Each application occupied the entire PC screen, and used all of the computer's resources. Then Microsoft introduced Windows. With Windows came the promise of higher worker productivity, since each application was displayed in its own window. You could run multiple applications and switch between them simply by clicking on any running application. Windows as an operating system advanced the state of the art of computing in many ways. One of the most popular extensions was the windowed user interface. Using overlapping window-like
rectangles, Windows was able to aggregate the display of several applications at the same time.
Application aggregation is a primary function of a portal server. Now, fast-forward to the birth of the World Wide Web. While the Web was a great advance in the information age, the tools to view the Web were in their design infancy. The typical design of a browser at the time was in a way like the MS-DOS of the 1980's. You entered a URL and viewed one Web site. As the Web and associated browsers evolved, several schemes emerged that allowed the user to view aggregates of data; browsers offered support for Java and Java applets, plus other kinds of plugin interfaces. These gained popularity for presenting other channels of information -- primarily audio and video information. Because these applet and plugin interfaces were never standardized across the available browsers, it was a nightmare for Web-savvy programmers who tried to build Web pages that would work properly on all of the most popular Web browsers. Meanwhile, the Web servers that served up the Web sites were evolving in their own ways. These servers initially just served up very static content that comprised a Web site, but they evolved quickly into the application servers we know today. With these application servers, dynamic content could be served. Static pages gave way to servlets and JavaServer Pages (JSP) components. Support for portals evolved from application servers and the desire to aggregate and render multiple streams of dynamic content to the user. Initially portals were custom applications built specifically to support a given Web site (Yahoo and eBay are good examples of custom-built portals). As these portals evolved, systems and frameworks to allow customers to build their own portals began to emerge. The Epicentric Portal and Plumtree Corporate Portal are examples of portal server products that allowed customers to craft portals unique to their businesses. These portals gave the customer two functions: a server to aggregate content in uniform and novel ways, and a framework to build portals and extensions. Portlets, the application building blocks of a portal, are in many ways very much like Windows applications. A Windows application presents its data in a window. A portlet also presents its data in a window-like display. The title bar of a Windows application contains controls that let users expand (maximize), and shrink (minimize) the application. Portlets have title bars and similar controls. Take a look at the following sample Windows application and a similar portlet, and you'll see the similarities in each application's user interface. Figure 1. Sample Windows application

Figure 2. Sample portlet application

Portlets, like their Windows application predecessors, need to work cooperatively within the
operating system. An unstable or poorly performing Windows application can impact the overall
system: this is also true of a portlet that is not well developed.
Introducing WebSphere Portal Version 4.1
Last year IBM introduced WebSphere Portal Server, which supports creating and managing portal-based Web sites. WebSphere Portal empowers you to build first-class business-to-business, business-to-employee, and business-to-customer portals. IBM announced WebSphere Portal Version 4.1 in April 2002. This latest release of IBM's flagship portal server offering raises the bar in function, performance, and scalability for portal servers. Version 4.1 supports many new functions and capabilities:
- J2EE compliance
- Support for Web-services-based portlets
- A new, more powerful page customizer
- Page groups
- New portal look and feel including more selectable themes and skins
- Portlet API enhancements
This is a just partial list of the new enhancements in WebSphere Portal Version 4.1. For further detailed
information on this release see Resources. The WebSphere Portal Version 4.1 portlet programming API gives you an improved, robust, second-generation framework for developing portlets and portal applications. This framework is based on J2EE Java programming standards and offers a well-crafted set of functions for developing portlets, including:
- Portlet markup rendering
- Event handling
- Single sign-on
- Portlet metadata storage
- User profile
- Client device capabilities
WebSphere Portal is now a J2EE-compliant application. This means, among other things, that portlets now get their Java inheritance from the J2EE Servlet class. This is good news for portlets. Any function or feature available within the Servlet class is now, in general, available to a portlet as well. If this is your first journey into the world of portlet programming, the following examples show you how to set up and use WebSphere Portal to develop portlets of your own.
Portlet programming Before you can develop a portlet, you need to set up a portlet development and runtime environment. This environment can be set up on one machine, but you may want to use two machines for better performance. In a dual-machine setup, the first machine will be your portlet development machine where you'll install your Java and Web development tools. These tools will be used to
develop the various components of your portlets. It is a good idea to use the same Java
Development Kit (JDK) level as the application server. WebSphere Portal Version 4.1 requires
WebSphere Application Server Version 4.02, which uses JDK 1.3.1 As you install tools for the development machine you might want to try out the Portal Toolkit included with WebSphere Portal Version 4.1. The Portal Toolkit is a packaged set of tools and samples that plug in to WebSphere Studio Application Developer and give you a complete portlet development environment. With Application Developer and the Portal Toolkit you can develop new portlets in minutes. Several sample portlets are included in the toolkit, as well as a portlet development wizard that speeds the development of portlet application by creating a complete templated portlet including the Java code, JSP pages, and XML deployment descriptors. (In a future article I'll introduce the Portal Toolkit in further detail and include a tutorial on the installation
of the toolkit and associated software components.) The second machine will be the portal runtime machine. On this machine you need to install WebSphere
Application Server 4.02 along with the latest set of patches. If you intend to install the production version of
WebSphere Portal you'll also need to install IBM DB2 Universal Database Version 7.1 and IBM Secureway Directory Version 3.2. These prerequisite products for the full release of WebSphere Portal are included in the portal package. If your runtime machine is meant only for testing your portlets, then you can install the
developers' version of the portal. Version 4.1 of the portal server requires the installation of WebSphere Application Server, DB2, and the developers' version of the portal. Once you've installed and tested the software on both machines, you need to add
references to the following Java archive (JAR) files, required for portlet development, to your
development machine's CLASSPATH:
- portlet-api.jar
- wpsportlets.jar
- j2ee.jar
- wps.jar
- jlog-2.2.jar
Note: Other JAR files may be required for your portlet application. For the examples in this article, these JAR files are the only ones required. The easiest way to use these JAR files on your development machine is to reference the files from
the runtime machine across a network to the development machine. Consult the WebSphere Portal
documentation (see Resources) for the exact location of these JAR files
within the portal install directories. Now that you have a complete development environment, it's time to do some portlet programming! The obligatory first portlet: HelloWorld!
The standard way to introduce a new programming method or language is to start with a Hello World
application. This is an easy way to get started on portlet programming, and you can use your HelloWorld portlet to validate the setup of the development and runtime machines. HelloWorld (portlet example 1)
//********************************************************************
//*
//* HelloWorld.java - Example Portlet #1 Shows simple portlet structure
//*
//********************************************************************
package com.ibm.wp.samples.helloworld;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import java.io.*;
public class HelloWorld extends PortletAdapter
{
public void init(PortletConfig portletConfig)
throws UnavailableException
{
super.init( portletConfig );
}
public void service( PortletRequest portletRequest,
PortletResponse portletResponse )
throws PortletException, IOException
{
PrintWriter writer = portletResponse.getWriter();
writer.println("<p>Hello Portal! This is my first Portlet!</p>");
}
}
|
HelloWorld, while not high-function, shows the basic structure of a portlet. A simple portlet
requires a single method, the service method. A portlet's service method is called when the portal
is requesting the portlet to render its data. In this sample the data is this markup:
<p>Hello Portal! This is my first Portlet!</p>
|
Portlets, portlet applications, and portlet application
descriptors
A portlet produces markup and is rendered in a rectangular area in the
portal page. A collection of related portlets make up a portlet application and are packaged
together in a Web archive (WAR) file. Portlets packaged together in a single WAR file may
share images, stylesheets, JSP components, and other kinds of resources. A WAR file is a specially
structured JAR file that includes a special XML descriptor called the Web application deployment
descriptor. The filename for the XML descriptor file is web.xml. This file is always stored in
the "web-inf" directory of the WAR file. In addition to the web.xml file in the portlet application's WAR file, a WAR file that
contains a portlet application and associated portlets must also contain a portlet application
descriptor. The portlet application descriptor filename is portlet.xml, and this file is
also always stored in the "web-inf" directory of the WAR file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD
Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app id="WebApp_504848313">
<display-name>Hello World Portlet Application - Portlet
Sample #1</display-name>
<servlet id="Servlet_439329280">
<servlet-name>HelloWorld</servlet-name>
<servlet-class>com.ibm.wp.samples.helloworld.HelloWorld</servlet-class>
</servlet>
<servlet-mapping id="ServletMapping_439329280">
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld/*</url-pattern>
</servlet-mapping>
</web-app>
|
The Web application descriptor describes the portlets in the portlet application WAR file to the
application server as servlets. Each portlet is defined as a servlet, and the portlet
application is synonymous with the definition of the Web application.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE portlet-app-def PUBLIC "-//IBM//DTD Portlet Application 1.1//EN"
"portlet_1.1.dtd">
<portlet-app-def>
<portlet-app uid="504848313">
<portlet-app-name>Hello World Portlet Application - Portlet
Sample #1</portlet-app-name>
<portlet href="WEB-INF/web.xml#Servlet_439329280"
id="Portlet_439329280">
<portlet-name>HelloWorld</portlet-name>
<cache>
<expires>0</expires>
<shared>no</shared>
</cache>
<allows>
<minimized/>
</allows>
<supports>
<markup name="html">
<view/>
</markup>
</supports>
</portlet>
</portlet-app>
<concrete-portlet-app uid="640682430">
<portlet-app-name>Concrete Hello World Portlet Application -
Portlet Sample #1</portlet-app-name>
<context-param>
<param-name>Portlet Master</param-name>
<param-value>yourid@yourdomain.com</param-value>
</context-param>
<concrete-portlet href="Portlet_439329280">
<portlet-name>HelloWorld</portlet-name>
<default-locale>en</default-locale>
<language locale="en_US">
<title>Hello World - Sample Portlet #1</title>
<title-short>Hello-Worldd</title-short>
<description>Hello World - Sample Portlet #1</description>
<keywords>portlet hello world</keywords>
</language>
</concrete-portlet>
</concrete-portlet-app>
</portlet-app-def>
|
This document describes the portlet application, each portlet in the application, and each
portlet's title and capabilities. This is a fairly vanilla version of a portlet application
descriptor with the required tags specified. I won't discuss the meaning of each tag here -- you can
consult the WebSphere Portal Guide to Portlet Programming (see Resources)
for a complete description of each tag and related tag values for both the Web application
descriptor and the portlet application descriptor documents. Building and packaging the portlet application
Now that you have the source code for the portlet and the XML descriptor documents, you can build and package the application components into a WAR file. Lay out the source code, and the Web and portlet descriptor documents, in a directory structure that will make the building of the portlet and WAR file an easy process, such as this structure:
d:/HelloWorld
d:/HelloWorld/WEB-INF/web.xml
d:/HelloWorld/WEB-INF/portlet.xml
d:/HelloWorld/WEB-INF/classes/com/ibm/wp/samples/helloworld/HelloWorld.java
|
With this directory structure you can create a batch file that compiles the portlet and builds
the associated WAR file. This batch file assumes the JDK CLASSPATH has been set up to point at the portal JAR files required to compile this portlet. For this example, I named this batch file BuildEx1.bat and placed it in the HelloWorld directory. Be sure to modify line 2 of the batch file to point at the base directory where you stored your portlet files, as shown below. Note that some lines in the example below (and in the following examples) have been split so that they'll display here.
echo off
set bd=D:/HelloWorld
javac -d
%bd%/WEB-INF/classes
%bd%/WEB-INF/classes/com/ibm/wp/samples/helloworld/HelloWorld.java
jar cvf0 HelloWorld.war WEB-INF
|
Running this batch file compiles the portlet and builds the WAR file. Now that you have the portlet
application successfully built it is time to run the portlet application on your runtime portal machine. Installing the portlet application
You need
to log into the portal in order to install your portlet and test it. You display the portal by
entering the URL of your portal in your browser's address field. The portal will display showing the
generic home page. You'll need to click the login icon ( ) to log into the portal, and then log in as an administrator. Here's
a sample rendering of the standard portal home page that's included with WebSphere Portal: Figure 3. Sample portal homepage

Once you're logged in to the portal, select the Portal Administration page group to display the Portlet Administration pages.
For this example, you'll install the HelloWorld portlet application using the Install Portlets page.
You need to copy your portlet WAR file to a directory accessible from the
portal server machine. Click Install and install the portlet. You' see a series of screens
and confirmations as the installation of the portlet is completed. Adding the portlet to a portal page
Once the portlet is installed, you'll need to use the portal page customizer to add the portlet to a portal page. The customizer is an application of the portal that lets you add and arrange portlets on a portal page. To enter the page customizer you'll need to change to the Work with Pages page group and select Edit Layout and Content tab. The page displayed will show the page customizer. To keep it simple, we'll add the portlet to the Welcome page. This page is grouped in the Home page group of pages. At the top of the customerizer page you select the page group and page to be modified. Make sure the Home page group and welcome page are selected. Click on the get portlets link to get a list of portlets to add to the page. Select HelloWorld the list of all portlets
and press Go. HelloWorld will be returned in the customizer's list of portlets. Select the portlet and then
click the Add portlet icon in the top left column of the customizer. This will add the portlet to the left column
of the page. When you have completed page customization you'll need to activate the page. Figure 4. The WebSphere Portal page customizer

When you display the page, you'll see the portlet and the familiar "Hello Portal World" phrase. Figure 5. HelloWorld portlet screen shot

HelloAgain (portlet example 2)
HelloWorld is a great introduction to portlet programming, but I need to introduce a couple more portlet concepts to round out the portlet development picture. Portlets and JavaServer Pages
When the portal aggregator calls a portlet to render its data, the portlet responds by emitting a
stream of markup and placing this markup in a print writer available from the portlet response
object. This is simple enough to implement from a portlet's perspective, but it becomes more
difficult as the complexity of the portlet's user interface increases. What is needed is a method
for a portlet to delegate rendering to another entity, and in WebSphere Portal that entity is a JSP component. The WebSphere Portal portlet API provides first-class support for the use of JSP components to render portlet
markup. In fact, portlets and servlets use the runtime linkage to pass data to a
JSP component. A portlet creates a Java bean containing data to be passed to a particular JSP component. The
portlet places a reference to this bean in the portlet request. The portlet then calls the portlet
context method include() to invoke the component. The JSP component uses
the useBean tag to establish a reference to the bean, extracts data from
the bean as needed, and combines the bean data with appropriate markup. The component then emits
this markup to the output stream directly. The portlet aggregator combines the result with other
markup from other portlets into a portal page. Your portlet may also store the reference to your Java bean in the portlet session object instead
of the portlet request object. These beans will have a longer lifecycle; they will typically be
available until explicitly deleted, or when the portal session is terminated. Beans placed in a
session have higher overhead in application server configurations with multiple machines arranged in
a cluster. The beans must be serialized and copied to each machine in the cluster to maintain the
portal session state across all cluster machines. The HelloAgain portlet sample demonstrates using a bean and a JSP component to render a personalized hello message.
//******************************************************************
//*
//* HelloAgain - A sample portlet that uses a JSP for rendering
//*
//******************************************************************
package com.ibm.wp.samples.helloagain;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import java.io.*;
public class HelloAgain extends PortletAdapter
{
public void init(PortletConfig portletConfig)
throws UnavailableException
{
super.init( portletConfig );
}
protected static final String jsp = "/WEB-INF/html/HelloAgain.jsp";
public void service( PortletRequest request, PortletResponse response)
throws PortletException, IOException
{
// Make a bean
HelloAgainBean hab = new HelloAgainBean();
// Get the portlet context
PortletContext context = getPortletConfig().getContext();
// Get portal user object
User user = request.getUser();
// get user's full name
String userName = user.getFullName();
// A valid name returned?
if( userName == null )
{
userName = "Unknown WebSphere Portal User";
}
// Save name in bean
hab.setUserName( userName );
// Save bean in request
request.setAttribute( "HelloAgainBean", hab );
// Invoke the JSP to render
context.include(jsp, request, response);
}
}
|
In the above portlet code the first order of business is to create the bean that will be passed to the JSP. Once the bean is created the user's name is retrieved from the portal user object and copied to the bean. A reference to the bean is placed in the portlet request and the portlet context include method is called to invoke the JSP to render the markup for the portlet. The associated Java bean has a single Java String attribute:
//********************************************************************
//*
//* HelloAgainBean.java - The bean used to pass data to the display
//* JSP in the HelloAgain portlet application
//*
//********************************************************************
package com.ibm.wp.samples.helloagain;
import java.util.*;
public class HelloAgainBean
{
private String userName = "";
public void setUserName(String s)
{
userName = s;
}
public String getUserName()
{
return( userName );
}
}
|
The JSP component establishes a reference to the bean, and embeds the value of the user's name in the output markup:
<!---------------------------------------------------------------------->
<!-- -->
<!-- HelloAgain,jsp - A sample JSP used to render data from a portlet -->
<!-- -->
<!---------------------------------------------------------------------->
<%@ page contentType="text/html" errorPage="" %>
<jsp:useBean id="HelloAgainBean"
class="com.ibm.wp.samples.helloagain.HelloAgainBean" scope="request" />
<h1>Hello Again <%=HelloAgainBean.getUserName()%></h1>
<br><h2>This is markup rendered from a JSP</h2>
|
A batch file is included with the example to build the sample. The build process is the same process as the HelloWorld Portlet. Once you have successfully built the portlet, install it on your portal and run it. You will have output similar to this: Figure 6. HelloAgain Portlet Screen Shot

World Time (portlet example 3)
A final
sample, WorldTime, ties together all of the concepts presented. This example displays the time for
your city. The portlet offers a customization page where you can enter your hour offset from
Greenwich Mean Time and your home city name. If the portlet is maximized it will display the time in
a city from each of the 24 time zones. The portlet also includes a help page that explains how to
customize the portlet. This sample introduces four new portlet concepts. These new concepts, plus the use
of JSP components and the portlet structure shown in the first two samples, give you the concepts you need to construct powerful portlets for your application. Portlet modes
When a portlet is called to render content it is passed a mode indicator in the portlet
request object. The following portlet modes are possible:
- View mode
This is the default mode for a portlet. When a portlet is in this mode it is rendering data
in its default display mode.
- Edit mode
This mode is made active when the user presses the edit icon
displayed in the portlet's title bar. When a portlet is in edit mode it displays a dialog that
let the user customize the settings of the portlet.
- Configure mode
A portal administrator, during the manage portlets process, can invoke configuration of the
portlet by selecting the Modify Parameters function. When in this mode the portlet displays a dialog that lets the administrator configure
the portlet for the portal. These settings are global in nature, and typically settings for the
portlet (the target back-end server URL, for example), and not settings for a particular user.
- Help mode
This mode is made active when the user presses the help icon
displayed in the portlet's title bar. When a portlet is in help mode it should display help
information for the user. This help information should explain how the user customizes the portlet
settings and how the portlet display is to be interpreted.
Portlets must check this mode value and render the appropriate markup to produce the desired user
interface. Typically portlets will do this by creating a JSP component and Java bean for each mode,
and invoking this bean and JSP when the associated portlet mode is requested for display. Portlet window states
A portlet in some cases will also want to check its window state to determine if the user has
maximized the portlet. The use maximizes a portlet by clicking the maximize icon
displayed in the portlet's title bar. When a portlet is maximized all other portlets on the page
are hidden. This gives the portlet the maximum amount of the screen area for rendering its
content. Portlets that can be maximized typically have a special JSP component for the maximized
view. This JSP component takes advantage of the extra screen area to display more content, or content of higher detail to the user. So far I've only covered the display of content to the user. Typically portlets offer more than
just content display to their users, they also offer user interface metaphors that allow the user to
interact with the content in various ways. Most portlets use forms to present their user
interface. Forms can consist of entry data fields and various buttons (including radio buttons, check
boxes, and push buttons). The following Java snippet is the core class for the WorldTime portlet. I'll further
describe the processing taking place in the service and actionPerformed
methods.
//******************************************************************
//*
//* WorldTime.java - A sample portlet that uses a JSP for rendering
//*
//******************************************************************
package com.ibm.wp.samples.worldtime;
import org.apache.jetspeed.portlet.DefaultPortletAction;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import org.apache.jetspeed.portlet.event.*;
import java.io.*;
public class WorldTime extends AbstractPortlet implements ActionListener
{
public void init(PortletConfig portletConfig) throws
UnavailableException
{
super.init( portletConfig );
}
public final static String homeCity
= "HomeCity"; // Field and Persistence
public final static String timeOffset
= "TimeOffset"; // Names
public final static String portletSaveAction
= "save"; // Save action
public final static String unspecifiedCityValue
= "Unspecified City"; // Unspecified city
protected static final String jspNormalView
= "/WEB-INF/html/WorldTimeNormalView.jsp";
protected static final String jspMaxView
= "/WEB-INF/html/WorldTimeMaxView.jsp";
protected static final String jspEditView
= "/WEB-INF/html/WorldTimeEditView.jsp";
protected static final String jspHelpView
= "/WEB-INF/html/WorldTimeHelpView.jsp";
public void service( PortletRequest request, PortletResponse response)
throws PortletException, IOException
{
String jsp = null;
// View Mode?
if( request.getMode() == Portlet.Mode.VIEW )
{
// Make a bean
WorldTimeBean wtb = new WorldTimeBean();
String homeCity = null;
String timeOffset = null;
// Get Data Store Reference
PortletData pData = request.getData();
homeCity = (String) pData.getAttribute(WorldTime.homeCity);
timeOffset = (String) pData.getAttribute(WorldTime.timeOffset);
wtb.setHomeCity( ((homeCity != null && homeCity.length() > 0)
? homeCity : unspecifiedCityValue) );
wtb.setTimeOffset( ((timeOffset != null && timeOffset.length() > 0)
? timeOffset : "0") );
// Save bean in request
request.setAttribute( "WorldTimeBean", wtb );
// Is window maximized?
if( (request.getWindow()).getWindowState() ==
PortletWindow.State.MAXIMIZED )
{
// Maximized View JSP
jsp = jspMaxView;
}
else
{
// Normal view JSP
jsp = jspNormalView;
}
}
// Edit mode?
else if( request.getMode() == Portlet.Mode.EDIT )
{
// Make a bean
WorldTimeBean wtb = new WorldTimeBean();
String homeCity = null;
String timeOffset = null;
// Get Data Store Reference
PortletData pData = request.getData();
homeCity = (String) pData.getAttribute(WorldTime.homeCity);
timeOffset = (String) pData.getAttribute(WorldTime.timeOffset);
wtb.setHomeCity( ((homeCity != null && homeCity.length() > 0)
? homeCity : unspecifiedCityValue) );
wtb.setTimeOffset( ((timeOffset != null && timeOffset.length() > 0)
? timeOffset : "0") );
// Create a save URI encoded with a save action
PortletURI saveURI = response.createReturnURI();
DefaultPortletAction action = new
DefaultPortletAction( WorldTime.portletSaveAction );
saveURI.addAction(action);
// Save the URI in the bean
wtb.setSaveURI(saveURI.toString());
// Create a cancel URI and save in the bean
PortletURI cancelURI = response.createReturnURI();
wtb.setCancelURI(cancelURI.toString());
// Save bean in request
request.setAttribute( "WorldTimeBean", wtb );
// Point at edit JSP
jsp = jspEditView;
}
else if( request.getMode() == Portlet.Mode.HELP )
{
jsp = jspHelpView;
}
// delegate rendering to JSP
(getPortletConfig().getContext()).include( jsp, request, response );
}
// Portlet's action handler
public void actionPerformed(ActionEvent event)
{
PortletLog pLog = getPortletLog();
System.out.println( "WorldTimeActionListener: Event" );
System.out.println( "WorldTimeActionListener: Event
type:("+event.getAction()+")" );
DefaultPortletAction action = (DefaultPortletAction) event.getAction();
if( (action != null) &&
(action.getName().equalsIgnoreCase(WorldTime.portletSaveAction)) )
{
PortletRequest request = event.getRequest();
System.out.println( "WorldTimeActionListener: Action Event" );
try // Attempt retrieval and save of portlet form data
{
PortletData pData = request.getData();
String homeCityValue = request.getParameter( WorldTime.homeCity );
String timeOffsetValue = request.getParameter( WorldTime.timeOffset );
if( (homeCityValue != null) && (homeCityValue.length() > 0) )
{
homeCityValue = homeCityValue.trim();
}
else
{
homeCityValue = WorldTime.unspecifiedCityValue;
}
if( (timeOffsetValue != null) && (timeOffsetValue.length() > 0) )
{
timeOffsetValue = timeOffsetValue.trim();
}
else
{
timeOffsetValue = "0";
}
pData.setAttribute( WorldTime.homeCity, homeCityValue );
pData.setAttribute( WorldTime.timeOffset, timeOffsetValue );
pData.store();
}
catch( AccessDeniedException ade )
{
pLog.error( "WorldTime: Java AccessDeniedException Exception ( " + ade
+ " ) thrown when saving instance data to the portlet store");
}
catch( java.io.IOException e )
{
pLog.error( "WorldTime: Java I/O Exception ( "+ e
+ " ) thrown when saving instance data to the portlet store");
}
}
}
}
|
This portlet's service method has been enhanced to test for the portlet mode and window state. For the view and edit portlet modes a bean is passed to the appropriate JSP component. In normal view mode the user's time and home city are displayed. In maximized view mode a list of cities and their local time is displayed. In the portlet's customize mode (edit mode in the code), users enter their home city and time offset from Greenwich Mean Time. In edit mode two URIs are created. These URIs are passed to the JSP component and assigned to the save and cancel buttons in the display form. These URIs are encoded so that when one a user presses one of these buttons, the portal can decode the URI, determine which portlet generated the button event, and call the portlet event handler with the event. When the JSP component is determined (and the bean created and loaded with data, for portlet display modes that require a bean), control is passed to the component to render the portlet's user interface. The following screens show the various portlet display modes and window sizes. Figure 7. WorldTime normal view

Figure 8. WorldTime maximized view

Figure 9. WorldTime edit view

Figure 10. WorldTime help view

Notice that all portlet modes display within the portal page. The portlet help mode
is an exception to this rule. When you invoke portlet help, the help is displayed
in a separate browser window. Portlet event handling
When the user
interacts with one of these user interface controls, and the control generates an
http submit event to the application server, the http
flow is reflected to the portal server. The portal server determines which portlet generated
the event and delivers the event to the portlet as an action event. It is the portlet's responsibility to include an action handler that is called when the
portlet needs to process an event. The WorldTime portlet class includes an actionPerformed method
to process action events. In previous versions of the portlet API the action handler was stored
in a separate Java class. With WebSphere Portal Version 4.1 and portlet API 1.1 the action
handler (and any other included portlet event handlers) are implemented directly within the
portlet class. The action handler tests for a specific event. This handler is implemented to process a save
action. A save action is generated when the user clicks Save on the customization page
of the portlet. Portlet instance data
The primary function of the above event handler is to retrieve the data the user just entered
into the portlet customization page. You need to retrieve the data from each field on the form and
save it in the portlet's data store so that you can use it for subsequent display. Fields defined in
the JSP component by name are accessible to the event handler as parameters of the portlet request and are retrieved using the getParameter() method. The data values are subsequently stored by name in the
portlets data store for the user, by calling setAttribute for each data item on the portlet data object. Calling the store method on the portlet data object commits the data values to persistent storage. The following is the source for the JSP components used in the WorldTime portlet. The following class is the implementation of the bean that is passed to the JSP in the view and edit modes of the portlet. The bean handles calculation and formatting of the time for any time zone. The bean also contains the home city, home city time offset, and the event handler URLs used to represent the Save and Cancel buttons on the customization page.
//********************************************************************
//*
//* WorldTimeBean.java - A sample Java bean that passes data from a
//* portlet to a JSP for markup rendering
//*
//********************************************************************
package com.ibm.wp.samples.worldtime;
import java.util.*;
import java.text.*;
public class WorldTimeBean
{
private String homeCity = WorldTime.unspecifiedCityValue;
private int timeOffset = 0;
private String saveURI = "";
private String cancelURI = "";
public void setSaveURI(String s)
{
saveURI = s;
}
public String getSaveURI()
{
return( saveURI );
}
public void setCancelURI(String s)
{
cancelURI = s;
}
public String getCancelURI()
{
return( cancelURI );
}
public void setHomeCity(String s)
{
homeCity = s;
}
public String getHomeCity()
{
return( homeCity );
}
public String getHomeTime()
{
return( getLocalTime(timeOffset) );
}
public String getLocalTime( int localTimeOffset )
{
GregorianCalendar now = new GregorianCalendar();
int realTimeOffset = (-timeOffset) + localTimeOffset;
now.add( Calendar.HOUR_OF_DAY, realTimeOffset );
Date timeNow = now.getTime();
String localTime =
DateFormat.getTimeInstance(DateFormat.SHORT).format(timeNow);
return( localTime );
}
public void setTimeOffset( String inTimeOffset )
{
try
{
timeOffset = (int) Integer.parseInt( inTimeOffset );
}
catch( Exception e )
{
timeOffset = 0;
}
}
public String getTimeOffset()
{
return( Integer.toString(timeOffset) );
}
}
|
 |
Summary
This article only scratches the surface of the potential in portlet programming. I've shown how to get started in portlet programming, including setting up a portlet development and runtime environment. I also used the HelloWorld portlet to show a very basic portlet and give you a feel for the structure of a portlet as well as how to build, package and deploy a portlet on a portal server. I introduced the concepts of portlet modes, portlet window states, using JSP components and Java beans to render data in a portlet, and portlet event handling. These concepts give you the basics of portlet programming. If you combine the concepts with your existing application's data connectors, you will be able to build powerful portlets and bring your product into the portal era of the Internet. In future articles I'll discuss portlet programming topics that include: portlet messaging, portlet performance, as well as tutorials and introductions for the Portal Toolkit.
Download | Name | Size | Download method |
|---|
| i-portalv4.zip | | HTTP |
Resources
About the author  | 
|  |
David B. Lection is a Senior Programmer and tools architect for WebSphere Portal and related products. You can contact David at lection@us.ibm.com.
|
Rate this page
|