The state pattern is a well-known software pattern first described by the Gang of Four in their book Design Patterns. The basic idea is to see an application as a combination of states and actions. This pattern was adapted to fit portlet development by Tim Hanis, Skyler Thomas, and Chris Gerken in December, 2002.
This article describes how to extend the state pattern to multi-portlet applications, and provides techniques to effectively design these applications. It shows how to implement multi-portlet applications in which portlets communicate in an efficient and easy-to-understand way. In addition, this article provides an implementation example for IBM® WebSphere® Portal V5 (hereafter called WebSphere Portal) and the required changes to the state pattern. The implementation is deployed in the WebSphere Portal Test environment for IBM WebSphere Studio Application Developer (hereafter called Application Developer).
For the reasons described in Applying the State Pattern to WebSphere Portal Portlets -- Part 1: Overview, you may choose to develop portlet applications without using the established predefined programming models (for example, JSP portlet, MVC portlet, or Struts) for which Application Developer provides wizards. The state pattern gives full control over every part of the portlet application and provides an excellent structuring of the code that makes it very easy to reuse, update, understand, and maintain. It also simplifies the process flow through the use of dedicated actions and states. Actions are responsible for handling one type of user request (for example, a click on the send button of a form); whereas, the state provides exactly one view (for example, a specific window) of the application.
To enhance the state pattern to an application using more than one portlet, you need to use the messaging concept of WebSphere Portal. Messages provide a framework for submitting data from one sender portlet to one or more receiver portlets. A message in the state pattern environment results in a state change in either the receiver or sender portlet, or both.
To send complex data types, you can use a message class that implements
org.apache.jetspeed.portlet.PortletMessage,
instead of
org.apache.jetspeed.portlet.DefaultPortletMessage,
which only supports strings.
Pre-requisites for the sample application
The source code for the attached application contains two portlets. You need the following to work with the portlet code:
- Websphere Studio Application Developer Version 5.0.1
- Portal Toolkit V5.0.0.0
- WebSphere Portal Test Environment (installed with the Portal Toolkit)
- WebSphere Portal Server V5.0.0.0 (installed with the WebSphere Portal Test Environment)
- The default Portal V5 Cloudscape database, to persist the contact entries
The complete implementation for the sample application is provided in the download ZIP file below.
You should be familiar with the state pattern concept described in the previous two state pattern articles (see Related information), and have an understanding of how to use this pattern to develop a one portlet application.
Components of the new state pattern implementation
In the state pattern implementation, different types of objects are tied together by the state manager portlet. The state manager portlet can be seen as the controller object that invokes other objects as needed. The objects involved in the state pattern implementation are:
StateManagerPortlet
The ancestor of all concrete portlet classes that form your application. The portlet itself has no knowledge about implementation logic, it rather acts as a request dispatcher to forward requests to states, actions and messages.
Action
Classes that inherit from this class have to implement an
actionPerformed and a
setState method. The actions handle the user
interaction from the portlet the action was triggered in. Action classes
can notifiy other portlets about events via messages. A state change of
the sender portlet is invoked by the called action.
Message
Classes that inherit from this class have to implement a
messageReceived method and a setState method.
A message handles the result of a user interaction that occurred in the
sender portlet of the message. A state change of the receiver portlet is
invoked.
State
Classes inherit from this class have to implement a
performView method. Here resides code that
would typically appear in the different do methods of the portlets.
StateURI custom tag
This class provides a custom tag for the JSP to use. The JSP associates an action class with the different actions on the page.
A development approach for multi-portlet applications
Image you have to design a portlet application with more than one portlet. How can the state pattern help you with your task? Where do you start the implementation?
When you design your application, you should have in mind the structure of the application. You could described it with a use case definition or something similar to a storyboard. You at least need to specify the portlets you need and what the different views of the portlets can be.
Consider the following scenario, which builds upon the scenario used in Applying the State Pattern to WebSphere Portal Portlets -- Part 2: Implementation. The major change is that you use two portlets.
You want to have a contact list that enables a user to view, add, edit, and delete items. For usability reasons, you decide to have two portlets:
- ContactListPortlet displays a list of your contacts.
- ContactListDetailPortlet displays details for the entries and is used for adding, editing, and deleting items.
Take a sheet of paper and divide it into two horizontal sections representing your two portlets. Think of the different views you want to present to the user - these will be the states for your portlets. For this sample application the states will be:
ContactListMainState
The main view of all items in the contact list.
ContactListWaitState
Occurs when an item in your contact list is updated by the second portlet. The ContactListPortlet displays a JSP which indicates that your data is changed at the moment.
ContactDetailEmptyState
Displays when no contact is selected in the ContactListPortlet.
ContactDetailDisplayState
Displays the details of a selected item from your contact list.
AddContactState
Displays a form to the user to add a new contact to the contact list.
EditContactState
Occurs when the user is editing data of a selected contact and saves it to the persistent datastore, which, in this example, is the Cloudscape database of the portal.
Add the different states to the sections for the portlets representing them as circles. Your page should look similar to Figure 1.
Figure 1. The state diagram with only portlets and states
The different states in one portlet are connected through actions, representing a user interaction. A state change of another portlet is triggered by a message. For example, if a user clicks on a contact in your ContactListPortlet, it results in a state change to the ContactListDetailPortlet and set its state (through a message) to the ContactDetailDisplayState. The next state in the ContactList portlet will be the same as before.
You can indicate actions in your diagram as diamonds and messages as rectangles, as shown in Figure 2.
Figure 2. Illustrating an action and message
In this example, each action causes a message to be sent to the receiver
portlet. The application has the following actions and messages:
ShowDetailsAction
A user clicks on a contact in the ContactListPortlet. The portlet resides in the same state.
ShowDetailsMessage
Launched by the ShowDetailsAction to display the selected contact in the ContactListDetailPortlet.
AddAction
A user presses the Add button in the ContactListPortlet. Results in a state change to the ContactListWaitState.
AddMessage
Launched by the AddAction to display the AddContactState in the ContactListDetailPortlet.
EditAction
A user presses the Edit button when viewing a contact in the ContactDetailDisplayState. Results in a state change to the EditContactState of the ContactListDetailPortlet.
EditMessage
Launched by the EditAction to set the ContactListPortlet into the ContactListWaitState.
SaveAction
A user saves an added or edited contact by pressing the Save button. Results in a state change. As this action is the same for two scenarios, we have two possible state changes: The ContactListDetailPortlet changes state from AddContactState to ContactDetailEmptyState or from EditContactState to ContactDetailEmptyState.
SaveMessage
Launched by the SaveAction to reload the contact list in the ContactListPortlet.
DeleteAction
A user presses the Delete button in the ContactDetailDisplayState. Results in a state change of the ContactListDetailPortlet to the ContactDetailEmptyState.
DeleteMessage
Launched by the DeleteAction to reload the contact list in the ContactListPortlet.
The resulting state diagram, shown in Figure 3, represents the whole application.
Figure 3. The complete state diagram for the contact list application
This state diagram gives you an overview of all the classes and objects used in the application. You now have a helpful picture that provides you with an overview of your application. The code can be easily divided by different people, because the state pattern provides you with a stable framework and well-defined interfaces. You can extend the state diagram in any direction whenever you add new functionality or refactor the application.
The next section describes a sample implementation. This article provides code which is ready to import into Application Developer.
First, set up the Cloudscape database to store your persistent data of the contact list.
- Open a command prompt and go to the directory
application Developer Home\runtimes\portal_v50\shared\app\cloudscape\bin. - Set the classpath by calling
setCP.bat. - Open the cView Cloudscape tool by calling
cview.batin the same directory. - Create a new database in the directory
c:\temp\dbcalled contactList.
Select File -> New -> Database and enterC:\temp\db\contactListas a Name.
Click OK, and the database is created. - Now create a new table named ADDRESS.
- Create columns in the table with the following properties:
Name Type Nullable Length Auto increment OID INT NO N/A YES LASTNAME VARCHAR YES 255 FIRSTNAME VARCHAR YES 255 TITLE VARCHAR YES 32 PHONE VARCHAR YES 32 ADDRESS VARCHAR YES 128 ZIP VARCHAR YES 10 CITY VARCHAR YES 32 COUNTRY VARCHAR YES 32 EMAIL VARCHAR YES 128 COMPANY VARCHAR YES 32 The database should look like this:
Figure 4. Database for persistent contact list data
- Now you can enter some data into the tables.
- Close the Cloudscape cView tool.
Configuring the data source in Application Developer
Now you create and configure a server to run the application on. You use the WebSphere Portal Test Environment in Application Developer to test your application.
- In the Portlet Perspective of Application Developer change to the Server Configuration view. Right-click on the Servers item and chose New -> Server and Server Configuration.
- Name the server MyPortal. For the Server Type, select WebSphere Portal Version 5.0 - Test Environment.
- After you have created the server, double-click on it and the server configuration opens in Application Developer.
- In the server settings, on the DataSource tab, add a new JDBC
provider. For the database type, select Cloudscape; for the
JDBC provider type, select Cloudscape JDBC Provider. Name the
provider
Cloudscape. - Add a new data source. Select the Cloudscape JDBC Provider and Version 5.0 data source.
- De-select the box for container managed persistence and name
the data source
ds1.
Figure 5. Specifying the data source
- In the resource properties settings for this data source, change the
value to
c:/temp/db/contactList. Save the server configuration.
Figure 6. Server configuration settings
Next you will get your Application Developer ready to import the sample project provided in the download section.
- Open the Application Developer Portlet Wizard and create an empty portlet.
- Name the project
ContactListand leave the default settings for the EAR file. Use J2EE Version 1.3 / WebSphere Portal 5 and click Finish. - Save the
ContactList.zipfile on your local hard drive and unzip the contents to some place in your file system. - In the file system, copy the
comdirectory in theWeb-inf\sourcedirectory to the Java Source directory of your workspace project (typically application Developer Home\workspace\ContactList). - Copy the contents of the
Web-infdirectory except the source directory to theWeb-infdirectory of your workspace project. - Copy the
jspdirectory into the Web Content folder of your workspace project. - Go back to the Application Developer. Right-click on the
ContactList project, and select Refresh to get all the
changes you did on the file system level. Right-click again and select
Rebuild project.
You now have set up your project in Application Developer and are ready to run it in on your local WebSphere Portal Server Test Environment. - Right-click on the ContactList project and choose Run on Server.
- In the dialog box select as server the configured server MyPortal. After the server start is completed, you see a window similar to Figure 7.
Figure 7. Running the sample portal application
The main technique for using the state pattern across portlet borders and supporting an arbitrary number of portlets is the use of the messaging concept. Messaging lets you send data and trigger events between portlets that reside on the same portal page.
For receiving messages, the StateManagerPortlet implements a
MessageListener. Similar to the action handling through
actionPerformed, the
messageReceived()method of the StateManager
Portlet extracts the message class from the event and forwards the request
to that class. The message class has the
responsibility and business logic to react to the message trigger that the
portlet container issues.
public void messageReceived(MessageEvent event) throws PortletException {
Message message = (Message) event.getMessage();
message.messageReceived(event, getPortletConfig().getContext());
message.setState(event.getRequest());
} |
After the message is received and the
messageReceived() method is called, the
setState() method of the message class
executes. Therefore, the message must set the next state for the receiving
portlet. The messageReceived() method can be
used for any type of event processing that is needed before the
performView() method of the state is called.
Because the message classes implement the
org.apache.jetspeed.portlet.PortletMessage
interface, custom messages can contain any type and number of fields to
transport objects and data from one portlet to the other. This capability
gives you great flexibility in designing dynamic behaviour in your portlet
application.
The setState() method implementation in the
message class contains only a couple of lines of code. Here is an example
from the EditMessage class:
public void setState(PortletRequest request) {
ContactListWaitState state = new ContactListWaitState();
setState(request, state);
} |
Therefore, all you have to do is create the target state object and call
the setState() method of the message super
class. The state object is stored to the portlet session. When the
PortletContainer triggers the next call to the
service() method, the state object can be
extracted from the session and executed by the StateManagerPortlet.
Sending of messages is by default only allowed during event processing in
portlets, so it happens during the
actionPerformed() method of an action class. As
an example, examine the actionPerformed()method
of the EditAction class, which triggers the EditMessage described above:
public void actionPerformed(PortletRequest request, PortletContext context)
throws PortletException {
// perform any other action handling here!
EditMessage message = new EditMessage();
context.send(PortletConstants.ADDRESS_LIST_PORTLET, message);
} |
To make this work as designed, the name of the target portlet must be
defined correctly. The constant
PortletConstants.ADDRESS_LIST_PORTLET used
here refers to the name of the target portlet that is defined in the
portlet.xml configuration file.
The StateURI custom tag which is used to create the action URI in the JSP page adds a special action parameter to the PortletURI generated through the response object. This is a string parameter, because adding of complete action classes is deprecated in the Portlet API with WebSphere Portal 5.
In this article, you saw how to extend the well-known state pattern for use in portlet applications with more than one portlet. We discussed a development approach to effectively design your application resulting in clean and easy-to-read code.
The complete implementation for this sample is provided in the download file.
| Name | Size | Download method |
|---|---|---|
| ContactList.zip | 51KB | FTP |
Information about download methods
Hinrich Boog is an IT-Specialist in the IBM e-business Innovation Center in Hamburg, Germany. His main subject areas are WebSphere Portal Server and Web content management. He is a Sun Certified Web Component Developer. You can reach Hinrich at hboog@de.ibm.com .
Marco Seifried is an IT-Specialist in the IBM e-business Innovation Center in Hamburg, Germany. He deals with J2EE architecture and application development, specializing in Websphere Portal Server. You can reach Marco at seifried@de.ibm.com .




