Part 2 of this series shows you how to implement portlet-to-portlet messaging.
Portals and portal servers are red-hot in Internet and Web development today. Just about everyone who's 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 Server
Earlier this year IBM introduced WebSphere Portal Server, which supports creating and managing portal-based Web sites. Version 1.2 lets you build first-class business-to-business, business-to-employee, and business-to-customer portals. The WPS 1.2 portlet programming API gives you a robust framework for developing portal applications and portlets. This framework is based on 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
The examples that follow show you how to set up and use WebSphere Portal Server to develop portlets of your own.
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 the development machine. You need to install a Java Developer Kit on this machine. WPS was compiled using JDK 1.2.2, and this is the release of the JDK shipped with WebSphere Application Server 3.5.4. You'll also want to install your favorite source code editor and HTML editor. Some example portlets in this article use JSP components to output markup to the user's client machine. WebSphere Studio is a good tool for editing these.
The second machine will be used as the runtime machine. On this machine you need to install WebSphere Application Server 3.5.4 along with the latest set of patches*. If you want this machine to have a fully functional version of WPS, you also need to install IBM DB2 Universal Database Version 7.1, and IBM Secureway Directory Version 3.2. These are prerequisite products for the full release of WPS.
If your runtime machine is meant only for testing your portlets, then you can install the developer version of WPS. This version does not require you to install the SecureWay or DB2 products.
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:
- jetspeed.jar
- Jetspeed-portlets.jar
- turbine-2.0.jar
The easiest way to do this is to reference these files from the runtime machine across a network to the development machine. Consult the WPS documentation (see Resources) for the exact location of these JAR files within the WPS 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 portlet
//*************************************************************************
//*
//* HelloWorld.java - Example Portlet #1 Shows simple portlet structure
//*
//*************************************************************************
package com.ibm.wps.samples.helloworld;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import java.io.*;
public class HelloWorld extends AbstractPortlet
{
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 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 portlet archive (PAR) file. A PAR file is a specially structured JAR file that includes a special XML descriptor called the portlet deployment descriptor. Portlets packaged together in a single PAR file may share resources like images, JSP components, stylesheets, and other resources.
You need to create a portlet deployment descriptor and include this XML document in your HelloWorld PAR file so that you can package and run the HelloWorld sample.
HelloWorld portlet descriptor: portlet.xml
HelloWorld's portlet descriptor
<?xml version="1.0"?>
<!DOCTYPE portlet-app PUBLIC "-//IBM//DTD Portlet Application 1.0//EN"
"portlet.dtd">
<portlet-app>
<portlet-app-name>HelloWorld Portlet Application - Example Portlet #1
</portlet-app-name>
<context-param>
<param-name>Portlet Master</param-name>
<param-value>yourid@yourdomnain.com</param-value>
</context-param>
<portlet>
<portlet-name>HelloWorld</portlet-name>
<portlet-class>com.ibm.wps.samples.helloworld.HelloWorld
</portlet-class>
<portlet-type>instance</portlet-type>
<allows>
<maximized/>
<minimized/>
</allows>
<language locale="en_US">
<title>HelloWorld - Example Portlet #1</title>
<title-short>Hello-Worldd</title-short>
<description>HelloWorld - Example Portlet #1</description>
<keywords>portlet hello world</keywords>
</language>
<supports>
<markup name="html">
<view/>
</markup>
</supports>
</portlet>
</portlet-app>
|
This XML 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 descriptor with the required tags specified. I won't discuss the meaning of each tag here -- you can consult the WPS Info Center documentation (see Resources) for a complete description of each tag and related tag values.
Packaging the portlet application
Now that you have the source code for the portlet and the portlet descriptor, you can package the pieces into a PAR file. Lay out the source code and portlet descriptor document in a directory structure that will make the building of the portlet and PAR file an easy process, such as this structure:
Directory structure for the HelloWorld portlet
d:/HelloWorld
d:/HelloWorld/PORTLET-INF/portlet.xml
d:/HelloWorld/PORTLET-INF/classes/com/ibm/wps/samples/helloworld/
HelloWorld.java
|
Using this directory structure you can create a batch file that compiles the portlet and builds the associated PAR 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.
Batch file buildex1.bat
rem echo off
set bd=D:/HelloWorld
javac -d
%bd%/PORTLET-INF/classes
%bd%/PORTLET-INF/classes/com/ibm/wps/samples/helloworld/HelloWorld.java
jar cvf0 HelloWorld.jar PORTLET-INF
erase HelloWorld.par
rename HelloWorld.jar HelloWorld.par
|
Running this batch file compiles the portlet and builds the PAR file. The next step is 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 the sample portal that's included with WPS:
Figure 3. Sample WPS portal
Once you're logged in, click the Administration tab to display the Portlet Administration page. For this example, you'll install the HelloWorld portlet application using the Portlet Application Administration portlet. You need to copy your portlet PAR file to a directory accessible from the portal server machine. Click Install and import the portlet. You'll see a series of screens and confirmations.
Adding the portlet to a portal page
Once the portlet is installed, proceed to the portal customizer to add the portlet to a portal page. The customizer is an application of the portal that lets you create portal pages and add portlets to the portal pages. Once you've created a new portal page it will be added to the set of tabbed pages on your portal home page.
Figure 4. The WPS 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 in order to round out the portlet development picture.
Portlets and JavaServer Pages components
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 WPS that entity is a JavaServer Pages (JSP) component.
The WPS portlet API provides first-class support for the use of JSP components to render portlet markup. In fact the runtime linkage and passing data between a portlet and a JSP component is very similar to how a servlet passes data to the 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.
Java beans used in a JSP component may also have a reference stored 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 Portlet Class
//*************************************************************************
//*
//* HelloAgain.java - An Example Portlet that uses a JSP for rendering
//*
//*************************************************************************
package com.ibm.wps.samples.helloagain;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import java.io.*;
public class HelloAgain extends AbstractPortlet
{
public void init(PortletConfig portletConfig) throws UnavailableException
{
super.init( portletConfig );
}
protected static final String jsp = "/PORTLET-INF/html/HelloAgain.jsp";
public void service( PortletRequest request, PortletResponse response)
throws PortletException, IOException
{
HelloAgainBean hab = new HelloAgainBean();
// Make a bean
PortletSession session = request.getSession();
// Get the portlet session
PortletContext context = getPortletConfig().getContext();
// Get the portlet context
User user = session.getUser();
// Get portal user object
String userName = user.getFullName();
// get user's full name
if( userName == null )
// A valid name returned?
{
// No
userName = "Unknown WPS User";
// Use a default
}
hab.setUserName( userName );
// Save name in bean
request.setAttribute( "HelloAgainBean", hab );
// Save bean in request
context.include(jsp, request, response);
// Invoke the JSP to render
}
}
|
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:
HelloAgain Java Bean
//********************************************************************
//*
//* HelloAgainBean.java - The bean used to pass data to the display
//* JSP in the HelloAgain portlet application
//*
//********************************************************************
package com.ibm.wps.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 display component
<!--------------------------------------------------------------------->
<!-- -->
<!-- HelloAgain,jsp - A sample JSP used to render data from a portlet-->
<!-- -->
<!--------------------------------------------------------------------->
<%@ page contentType="text/html" errorPage="" %>
<jsp:useBean id="HelloAgainBean"
class="com.ibm.wps.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 presented in the first two samples give you the concepts you need to construct powerful portlets for your application.
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
allows the user to customize the settings of the portlet - Configure mode
A portal administrator, during the portlet install process, can invoke configuration of a portlet. When in this mode the portlet displays a dialog that allows the administrator to configure the portlet for the portal. These settings are global in nature, and typically settings for the portlet (the target backend 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.
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).
When the user interacts with one of these user interface controls, and the control generates a
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 set up an action handler for the event, and process the event when an event is delivered to the handler.
The following class is the action event handler for the WorldTime portlet sample:
World Time Action Listener Class
//********************************************************************
//*
//* WorldTimeActionListener.java - An Example Portlet Action Listener
//* event handler
//*
//********************************************************************
package com.ibm.wps.samples.worldtime;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import org.apache.jetspeed.portlet.event.*;
import java.io.*;
public class WorldTimeActionListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
DefaultPortletAction action = (DefaultPortletAction) event.getAction();
if((action != null) &&
(action.getName().equalsIgnoreCase(WorldTime.portletSaveAction)))
{
PortletLog pLog = ((WorldTime) event.getPortlet()).getPortletLog();
PortletRequest request = event.getRequest();
try // Attempt retrieval and save of portlet form data
{
PortletData pData = request.getData();
String homeCityValue =
request.getParameter( WorldTime.homeCity ).trim(); // Get data
String timeOffsetValue =
request.getParameter( WorldTime.timeOffset ).trim();
pData.setAttribute( WorldTime.homeCity, homeCityValue );
pData.setAttribute( WorldTime.timeOffset, timeOffsetValue );
pData.store(); // Save to the portlet persistence store
}
catch( java.io.IOException e )
{
pLog.error("WorldTime: I/O Exception ( "+e+" )
when saving portlet instance data");
}
}
}
}
|
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.
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 Java snippet is the core class for the WorldTime portlet. All of the action happens in the service method.
WorldTime portlet class
//********************************************************************
//*
//* WorldTime.java - An Example Portlet that uses a JSP for rendering
//*
//********************************************************************
package com.ibm.wps.samples.worldtime;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import java.io.*;
public class WorldTime extends AbstractPortlet
{
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
= "/PORTLET-INF/html/WorldTimeNormalView.jsp";
protected static final String jspMaxView
= "/PORTLET-INF/html/WorldTimeMaxView.jsp";
protected static final String jspEditView
= "/PORTLET-INF/html/WorldTimeEditView.jsp";
protected static final String jspHelpView
= "/PORTLET-INF/html/WorldTimeHelpView.jsp";
public void service( PortletRequest request, PortletResponse response)
throws PortletException, IOException
{
String jsp = null;
if( request.getMode() == Portlet.Mode.VIEW )
{
WorldTimeBean wtb = new WorldTimeBean();
// Make a bean
String homeCity = null;
// Init
String timeOffset = null;
// Init
PortletData pData = request.getData();
// Get Data Store Reference
homeCity = pData.getAttribute(WorldTime.homeCity);
timeOffset = pData.getAttribute(WorldTime.timeOffset);
wtb.setHomeCity( ((homeCity != null && homeCity.length() > 0)
? homeCity : unspecifiedCityValue) );
wtb.setTimeOffset( ((timeOffset != null && timeOffset.length() > 0)
? timeOffset : "0") );
request.setAttribute( "WorldTimeBean", wtb );
// Save bean in request
if( (request.getWindow()).isMaximized() == true )
// Is window maxmimized?
{
jsp = jspMaxView;
// Maximized View JSP
}
else
{
jsp = jspNormalView;
// Normal view JSP
}
}
else if( request.getMode() == Portlet.Mode.EDIT )
{
WorldTimeBean wtb = new WorldTimeBean();
// Make a bean
String homeCity = null;
// Init
String timeOffset = null;
// Init
PortletData pData = request.getData();
// Get Data Store Reference
homeCity = pData.getAttribute(WorldTime.homeCity);
timeOffset = pData.getAttribute(WorldTime.timeOffset);
wtb.setHomeCity( ((homeCity != null && homeCity.length() > 0)
? homeCity : unspecifiedCityValue) );
wtb.setTimeOffset( ((timeOffset != null && timeOffset.length() > 0)
? timeOffset : "0") );
PortletURI saveURI = response.createReturnURI();
// Create a save URI encoded
DefaultPortletAction action =
new DefaultPortletAction( WorldTime.portletSaveAction );
saveURI.addAction(action);
// with a save action
wtb.setSaveURI(saveURI.toString());
// Save the URI in the bean
PortletURI cancelURI = response.createReturnURI();
// Create a cancel URI
wtb.setCancelURI(cancelURI.toString());
// Save
request.setAttribute( "WorldTimeBean", wtb );
// Save bean in request
jsp = jspEditView;
// point at edit JSP
}
else if( request.getMode() == Portlet.Mode.HELP )
{
jsp = jspHelpView;
// point at help JSP
}
// delegate rendering to JSP
(getPortletConfig().getContext()).include( jsp, request, response );
}
}
|
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
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 view and edits 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.
World Time Java bean class
//********************************************************************
//*
//* WorldTimeBean.java - A sample Java bean that passes data from a
//* portlet to a JSP for markup rendering
//*
//********************************************************************
package com.ibm.wps.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) );
}
}
|
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 basic 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 these 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: portlets and WebSphere Personalization, portlet performance, and portlets that support multiple mobile and handheld devices. I'll also introduce other helper classes that WPS offers for the construction of portlets.
| Name | Size | Download method |
|---|---|---|
| portalsamples | HTTP |
Information about download methods
- Read the second article in this series, "Give and take -- portlet messaging techniques" (developerWorks, March 2002).
- Visit the WebSphere Portal Server product site.
- Download portlets from the Portlet marketplace.
- Learn how to make portal applications mobile at the pervasive computing portal site.
- Consider working with IBM to build your own custom portal Web site. Visit PartnerWorld for Developers for information (including an extensive resource list of related technical articles).

David B. Lection is a Senior Programmer and tools architect for WebSphere Portal Server and related products. You can contact David at lection@us.ibm.com.
