Extending the state pattern for multi-portlet applications

This article describes how to extend the state pattern to multi-portlet applications and provides techniques to effectively design these applications. It then shows how to implement multi-portlet applications and provides an implementation example for WebSphere Portal V5. The implementation is deployed in the WebSphere Portal Test environment for IBM WebSphere Studio Application Developer.

Share:

Hinrich Boog (hboog@de.ibm.com ), IT-Specialist, IBM

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 (SEIFRIED@uk.ibm.com), IT-Specialist, IBM

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 .



02 October 2003

Introduction

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:

  1. Websphere Studio Application Developer Version 5.0.1
  2. Portal Toolkit V5.0.0.0
  3. WebSphere Portal Test Environment (installed with the Portal Toolkit)
  4. WebSphere Portal Server V5.0.0.0 (installed with the WebSphere Portal Test Environment)
  5. 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.


Introducing the scenario

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:

ContactListPortlet

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.

ContactListDetailPortlet

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
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
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
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.

Setting up the database

First, set up the Cloudscape database to store your persistent data of the contact list.

  1. Open a command prompt and go to the directory application Developer Home\runtimes\portal_v50\shared\app\cloudscape\bin.
  2. Set the classpath by calling setCP.bat.
  3. Open the cView Cloudscape tool by calling cview.bat in the same directory.
  4. Create a new database in the directory c:\temp\db called contactList.
    Select File -> New -> Database and enter C:\temp\db\contactList as a Name.
    Click OK, and the database is created.
  5. Now create a new table named ADDRESS.
  6. Create columns in the table with the following properties:
    Name Type Nullable Length Auto increment
    OIDINTNON/AYES
    LASTNAMEVARCHARYES255
    FIRSTNAMEVARCHARYES255
    TITLEVARCHARYES32
    PHONEVARCHARYES32
    ADDRESSVARCHARYES128
    ZIPVARCHARYES10
    CITYVARCHARYES32
    COUNTRYVARCHARYES32
    EMAILVARCHARYES128
    COMPANYVARCHARYES32

    The database should look like this:

    Figure 4. Database for persistent contact list data
    Database for persistent conact list data
  7. Now you can enter some data into the tables.
  8. 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.

  1. 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.
  2. Name the server MyPortal. For the Server Type, select WebSphere Portal Version 5.0 - Test Environment.
  3. After you have created the server, double-click on it and the server configuration opens in Application Developer.
  4. 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.
  5. Add a new data source. Select the Cloudscape JDBC Provider and Version 5.0 data source.
  6. De-select the box for container managed persistence and name the data source ds1.
    Figure 5. Specifying the data source
    Specifying the data source
  7. 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
    Server configuration settings

Setting up the sample project

Next you will get your Application Developer ready to import the sample project provided in the download section.

  1. Open the Application Developer Portlet Wizard and create an empty portlet.
  2. Name the project ContactList and leave the default settings for the EAR file. Use J2EE Version 1.3 / WebSphere Portal 5 and click Finish.
  3. Save the ContactList.zip file on your local hard drive and unzip the contents to some place in your file system.
  4. In the file system, copy the com directory in the Web-inf\source directory to the Java Source directory of your workspace project (typically application Developer Home\workspace\ContactList).
  5. Copy the contents of the Web-inf directory except the source directory to the Web-inf directory of your workspace project.
  6. Copy the jsp directory into the Web Content folder of your workspace project.
  7. 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.
  8. Right-click on the ContactList project and choose Run on Server.
  9. 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
Running the sample portal application

Implementation details

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.


Conclusion

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.


Download

DescriptionNameSize
Code sampleContactList.zip  ( HTTP | FTP )51KB

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
ArticleID=13728
ArticleTitle=Extending the state pattern for multi-portlet applications
publish-date=10022003