This article supercedes an article by a similar name. It was updated to be consistent with the IBM WebSphere Portal Version 5.0 Portlet API, and to remove references to deprecated methods and classes. Specifically, the pattern implementation was modified to remove references to the deprecated class org.apache.jetspeed.portlet.DefaultPortletAction and to the deprecated methods:org.apache.jetspeed.portlet.PortletURI.addAction(PortletAction)
and org.apache.jetspeed.portlet.event.ActionEvent.getAction().
The example implementation in part 2 is now a J2EE 1.3 application, and it uses WebSphere Portal V5 development tooling.
WebSphere portlet developers have typically relied on the IBM Portlet API as the basis for their implementation. This API exposes the components needed to develop fully functional portlets. However, it does not provide assistance to implement a well-designed page navigation model. When creating complex portlets, a developer must handle the view navigation within the portlet, and consider how to efficiently use action events and listeners to respond to user action events, such as clicking on a button or a link.
The state pattern design discussed here provides a good approach to portlet application design to help organize page transitions and to implement a separation of responsibilities in the Model-View-Controller (MVC) design pattern. If you choose to program portlets using the IBM Portal API you need to use an approach like this.
This paper describes a pattern implementation. The recommended framework solution for portlet development is Struts. The Jakara Struts project, an Apache Software Foundation open-source project, provides a framework to address these same issues of MVC design and page control flow. It also provides support for exception handling, error handling, input validation, forms, and internationalization. Applications can be written using the Struts framework and deployed as a portlet. For a corresponding example implementation using Struts, see Developing and Deploying a Struts Application as a WebSphere Portal V5 Portlet.
Portlet development guidelines and example implementations provide a good understanding of the Portlet API. However, implementing complex process control is outside the scope of the API. Without a well-designed approach to implementing control logic you end up creating portlets that contain a fair amount of code dedicated to simply addressing the intent of a user's request. Besides being repetitive, this code makes the portlet much harder to read because you need to wade through the control logic to get to the real work of the portlet. The control logic is also prone to error because it relies on aspects, such as string name matching to hook an event to a listener, or a listener action, to behavior in the portlet method. It can also complicate the business logic because the implementation of the control function can resemble the business logic.
To solve these problems with control logic, you can consider your application to be a collection of portlet actions and states. Then, given a well-defined approach to state transitions, you can remove the cumbersome control logic code from within the portlet application. This article discusses how you can apply this same approach to state management for portlet development, and to create a reusable state pattern to address this problem generically.
Problems with the standard implementation approach
Consider a simple MVC-based portlet which retrieves a list of items from a database and presents the list to the user. When the user selects an item, a detailed view is displayed showing specific information about the selected item. This detailed view could involve another request to the database. The important point here is that a requirement exists to follow two different control flows.
In the first step, the controller must call the business objects to create the appropriate beans, which are passed to a Java™ Server Page (JSP) to be rendered in the main view. In the second step, the controller retrieves an indicator of the selected item from the user's request and then calls the business objects to create the appropriate bean, which is passed to a different JSP to render in a detailed view.
In the MVC implementation, the view components are clearly different; two different JSPs exist for the two views. You might need to access different business model components to generate the beans needed for each request. The controller function would need to know:
- What business methods to call
- What beans to generate
- Where to put those beans on the request object
- How to invoke the appropriate JSP
This is where the code becomes cumbersome. In the case of servlet programming, you might choose to implement these as separate servlets, so that the controller function for each request is naturally separated by the service method of each appropriate servlet class. If you prefer to use a dispatcher approach instead of a separate servlet implementation, then you would have to use a framework, such as Struts, to implement a similar MVC design.
This is a complicated task because you do not have the option of using multiple portlet classes to implement one portlet. You are not able to address a portlet class directly. The same service method of the same portlet handles all HTTP requests sent back to the portlet. Consequently, you need to implement control code to:
- Determine which action is being requested
- What processing needs to occur
- What state to leave the portlet in
- What to render back to the user
The components of a state pattern implementation
Applying the state pattern to portlets lets you cleanly implement process control. You use the following components in the state pattern, as shown in Figure 1.
Figure 1. The interaction diagram for the state pattern.
This is the main portlet class. It is
portlet-independent, and would typically include all of
the portlet-specific code. This class serves as a dispatcher to
support action and state classes where the portlet code resides.
StateManagerPortlet implements the actionPerformed,doView, doEdit,
doHelp, and doConfigure methods.
The actionPerformed
method simply gets the current instance of the action class and
dispatches to its actionPerformed method. Similarly, the do methods
get the current state object and dispatch to its perform method.
Therefore, the StateManagerPortlet does not need to know anything
about the current portlet implementation and does not have a large
number of ifs and checks to determine where processing should
continue. As long as you are familiar with the flow between states
and actions, the processing occurs properly, without your having
to code much extraneous control logic.
In WebSphere Portal V4.2
the method to add an Action class instance to a PortelURI was deprecated.
This API was useful because you could retrieve your Action subclass instance
from the PortletEvent object and dispatch to it's actionPerformed method as
part of our state transition. The recommended replacement API is to use
a string instead of an Action to add to the PortletURI and retreive from the
Portlet Event. This class provides the mapping from the given string
to an Action class instance.
Classes that implement this interface implement
an actionPerformed method. This method performs any action necessary
to implement the function required by the action request. However,
the function implemented is specific to the action event being
invoked. An individual actionPerformed method for a specific action
class contains code only for that particular action. This method
also sets the current state for further processing. In this flow
process, an action is called, which performs work specific to its
function and then sets the state for the next transition.
This class provides the inital states for each of the supported portlet modes.
Classes that implement this interface will implement a perform method. This method gets called from the do methods of the StateManagerPortlet, and contains the code that would normally reside in these methods. Again, this code is specific to the state of the class it resides in, and therefore avoids additional clutter.
Typically, the state's perform method invokes a JSP to render
its results. The user interface might let the user set other actions within
the portlet. The JSP associates an action class with each of these
actions on the page. When a user invokes one of these actions,
the appropriate action class instance is invoked from the StateManagerPortlet
actionPerformed method, and state transition occurs. The State
class is not responsible for state management and transition.
Applying the state pattern results in a cleaner
implementation, and, as you move between portlet modes, the state
is always remembered. When you use the actionPerformed method to
retrieve form data and hold it in session, you avoid problems
with form data not getting reposted when the the portal page is
refreshed.
With this pattern, you can easily determine where and
when you want data to be retrieved from the source, and when it
should be retrieved from cache. Because actionPerformed methods are not
invoked on portal page refreshes, you can place data access
code in the action state and cache them there. The state classes
can use data from cache in order to avoid multiple trips to get data, when
the portal page is refreshed.
Consider the following scenario. You have a portlet that presents a list of items on the main page to the user; the user can select one item to get more detailed information, which is presented on another page. The user is also able to to add, edit, and delete items. The data is persisted in a database. In this example, the items are contacts, as in an address book.
From a visual perspective, an implementation of the above scenario can have the following pages:
- Main view page - Displays the list of contacts with an option to select one contact for more information
- Detail view page - Displays the selected contact's information
- Main edit page - Displays the list of contacts with options to add, delete, or modify
- Add entry page - Displays a form to get the contact information to be added
- Modify entry page - Displays a similar form with the existing data inserted for modification
In this case, you do not have an explicit page to delete an entry. The user can select a contact entry to delete from the main edit page. There is no confirmation page or successful execution page. Entry deletion processing occurs, and the main edit page is refreshed. If an error occurs, an appropriate message displays, but under normal processing, there is no view associated with this action.
Assume you want the Main and Detail
view pages available to users who have view permission for the portlet;
you want add, edit, and delete capabilities available to users who have
edit permission for the portlet. In this case, the Main and Detail
view pages are controlled from the doView portlet method. The
remaining pages are controlled from the doEdit method.
First, consider the doView method. Using standard
portlet programming techniques, you can implement it as follows:
public void doView(PortletRequest request, PortletResponse response)
throws PortletException, IOException {
String oid = request.getParameter("selectedContact");
if (oid == null) {
// Main view processing goes here
portletContext.include("main_view.jsp", request, response);
else {
// Detail view processing goes here
portletContext.include("detail_view.jsp", request, response);
}
} |
However, you realize that if you attempt to retrieve
the selectedContact index from the HTTP request on every refresh,
then, when your portlet is refreshed as a result of the portal
page being refreshed, the form data is lost and this implementation
returns the portlet to the main view - even if the user was working
with a different portlet on the page. Therefore, you use an action
listener to get the selected contact value and set it on session
so that future refreshes can get the correct value and preserve
the appropriate page setting.
Now the doView code looks like the
code below; the actionPerformed
method, implemented in the action listener, retrieves the appropriate value
and puts it on session. Of course, you also need to specify the
action event on the portlet URI so that the listener is called.
public void doView(PortletRequest request, PortletResponse response)
throws PortletException, IOException {
PortletSession session = request.getPortletSession(false);
if (session != null) {
String oid = (String)session.getAttribute("oid");
if (oid == null) {
// Main view processing goes here
// URI and action listener for showing the contact details
PortletURI portletURI = response.createURI();
portletURI.addAction("detailRequest");
request.setAttribute("detailURI", portletURI.toString());
portletContext.include("main_view.jsp", request, response);
else {
// Detail view processing goes here
// Get bean for given OID
session.removeAttribute("oid");
portletContext.include("detail_view.jsp", request, response);
}
}
else
response.getWriter().println("You must log in first");
}
public void actionPerformed(ActionEvent event) throws PortletException {
String actionName = event.getActionString();
PortletRequest request = event.getRequest();
// Show the contact detail view. Get the contact oid number
// of the selected contact and put it on the session object
if (actionName.equals("detailRequest")) {
String oid = request.getParameter("selectedContact");
request.getSession(true).setAttribute("oid", oid);
}
} |
There is quite a bit of code here to simply manage the page transitions between the main view and detail views. You have not yet written any code for the application's business logic. There are many opportunities for bugs to be introduced into this code. Also, you need to implement component pieces in various places to make the process flow successfully; often these components rely on string matching to hook up an event with an appropriate action or set and read a flag in the code that manages process control.
Including the additional actions to add, edit,
and modify the control code would make the code more cumbersome.
The following code source shows the actionPerformed method for this
implementation. This does not display the corresponding code in
the doEdit method that needs to set portletURI with the appropriate
action, interrogate the event flags, and set and remove data and flags
from session.
public void actionPerformed(ActionEvent event) throws PortletException {
String actionName = event.getActionString();
PortletRequest request = event.getRequest();
PortletSession session = request.getPortletSession();
// Show the contact detail view. Get the contact oid number
// of the selected contact and put it on the session object
if (actionName.equals("detailRequest")) {
String oid = request.getParameter("selectedContact");
session.setAttribute("oid", oid);
}
// Handle the request to go to the add view
if (actionName.equals("ADD_REQUEST")) {
session.setAttribute("NEXT_EDIT_PAGE", "ADD_PAGE");
}
// Handle the request to go to the edit view
if (actionName.equals("EDIT_REQUEST")) {
session.setAttribute("NEXT_EDIT_PAGE", "MODIFY_PAGE);
}
// Handle the reqeust to delete content
if (actionName.equals("DELETE_REQUEST"))
ContactsManager.getInstance().(deleteContact(request));
// Handle the Add Content event
if (actionName.equals("ADD_CONTACT"))
ContactsManager.getInstance().addContact(request));
// Handle the Modify Content event
if (actionName.equals("EDIT_CONTACT"))
ContactsManager.getInstance().modifyContact(request));
} |
How does this change with the state pattern?
How can you improve this implementation? First,
keep in mind that this application represents a collection of application
actions and states. An action is a class that implements the action
interface, and literally handles the processing for a specific application
task or action. This is a portion of application code that today
exists in the actionPerformed method of the actionListener class;
only this portion is specific to a single action event.
A state is a class that implements the state interface and represents the effect of the portlet as a result of applying an action. This class typically has a visual component.
Such an application would typically contain the following:
Actions:
- Show Main Page
- Show Detail Page
- Show Main Edit Page
- Show Add Contact Page
- Add a Contact
- Show Modify Contact Page
- Modify a Contact
- Delete a Contact
States:
- Main View Page
- Detail View Page
- Main Edit Page
- Add Contact Page
- Modify Contact Page
Now, determine the state transitions available for this application. The transitions are managed by applying the appropriate actions to the current state, which results in the application entering another specific state.
Figure 2. A state diagram
With this understanding of the portlet, you can
create this application using the state pattern. The application
is built using a common structure for state transition that lets
you eliminate the excessive if statements with string
matching and multiple flags being set.
How does the state pattern work?
The code below shows the simple processing in
the doView method in the StateManagerPortlet class. The other do
methods would be similar. You could easily collapse this processing
to the service method. In this case, you would look for the state
object from session using the portlet mode as the key. It is displayed
this way because you would typically code to the do methods and the
comparison would be more familiar. Also, you would extract the default
state into a properties file or another initialization parameter
to remove the connection to this class.
Public void doView(PortletRequest request, PortletResponse response)
throws PortletException, IOException {
// Ensure we are logged in
PortletSession session = request.getPortletSession();
User user = request.getUser();
if (session == null) || user == null)
throw new MessageException("Login to the portal first");
// Get the portlet state object from session, if not there get the initial
// state for the mode.
State nextState = (State) session.getAttribute(request.getMode().toString());
if (nextState == null)
nextState = InitialStateManager.getInitialState(request.getMode());
// Dispatch to state handler
nextState.performView(request, response,
getPortletConfig().getContext());
} |
The code below shows the simple processing in
the actionPerformed method of the StateManagerPortlet class. Again,
this method simply gets the action class instance identified by the
action name string and invokes its actionPerformed method.
Public void actionPerformed(ActionEvent event) throws PortletException {
// Execute the perform action method for the event
PortletContext portletContext = getPortletConfig().getContext();
PortletRequest request = event.getRequest();
// Get the action handler class and dispatch
String actionClassName = event.getActionString();
Action action = ActionClassManager.getAction(actionClassName);
// Dispatch to that class event handler; register the next state
action.actionPerformed(request, portletContext);
action.setState(request);
} |
Then, the actionPerformed method of the action
classes performs normal processing and also puts the proper state
on the session for appropriate flow control. Keep in mind that the
action and state classes in general have no or very few fields.
So, there is minimal expense in adding them to the session object.
Because no changes are needed to implement this
pattern in the portlet do methods, you do not show the state classes
perform method equivalents. However, you may extend the pattern
here to include a refresh method for the state. The refresh method
would logically extract the application code that is responsible
for portlet data retrieval, so that you can isolate the logic needed
to determine if a portlet refresh causes the source data to refresh
or be retrieved from a cache.
Before the state class is asked by the StateManagerPortlet to write an HTML fragment to the response (or invoke a JSP to do this), the StateManagerPortlet can ask the state class to refresh itself. In the refresh method, you can include logic to refresh or re-retrieve data for the display.
For example, a portlet that displays volatile data may need to go back to the data source each time the screen is refreshed. You would include the logic to do this in the refresh method. On the other hand, a portlet that displays stable information would more likely put the data access logic in the initial state lazy initialization logic and cache the results. The refresh method for this type of stable data state would do nothing.
Because business logic in the refresh method could cause a transition to a different state (including an error state), you could extend the state pattern to allow for state transitions from within states.
As WebSphere Portal becomes the preferred platform for enterprise portal applications, it becomes increasingly more critical to have well-defined frameworks and patterns for portlet development. This article discussed the need for a pattern to manage complex application page flow within a portlet, which results in efficient processing and clean code that lets you easily debug, maintain, and enhance an application.




