Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

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.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Building a Portlet within the Model-View-Controller Paradigm using WebSphere Portal

Michael Kwong (mkwong@us.ibm.com), Software Engineer, IBM Silicon Valley Lab in San Jose, California
Michael Kwong is a software engineer at the IBM Silicon Valley Lab in San Jose, California. His interests include Web applications and portlet programming, search technologies, knowledge management, and the development process. He holds a BSc, MSc, and PhD in Electrical Engineering from Stanford University. You can reach Michael at mkwong@us.ibm.com .
Laurence England (englandl@us.ibm.com), Software Architectect , IBM Silicon Valley Lab in San Jose, California
Laurence England is a software architectect at the IBM Silicon Valley Lab in San Jose, California. He has been involved with several projects, including WebSphere Portal Development Community, WebSphere Studio Enterprise Developer, and WebSphere Asset Analyzer. In his spare time, he participates in ultra-marathons. You can reach Larry at englandl@us.ibm.com .

Summary:  This article describes a portlet implementation and design within a Model-View-Controller (MVC) paradigm in the context of WebSphere Portal 4.1. WebSphere Portal supports MVC by using Listeners to handle events generated through user actions, and JSPs to generate views.

Date:  30 Oct 2002
Level:  Intermediate

Activity:  8383 views
Comments:  

© Copyright International Business Machines Corporation 2002. All rights reserved.

Introduction

IBM ® WebSphere® Portal 4.1 (hereafter called Portal) lets you build portals by combining software components known as portlets. Developers can build portlets independently of one another, and reuse and combine them to build different portals. This results in a flexible, open, and extensible framework so that developers can build portals for enterprises of all sizes. Each of these portals in turn provides a single point of access to the applications, content, processes, and people within the organization.

Model-View-Controller (MVC) is a well-known programming practice that isolates the application logic, the data store, and its presentation from one another, so that developers can enhance and modify each of these pieces independently, with minimal impact to the rest of the code. WebSphere Portal supports MVC by using Listeners (Controller) to handle events generated through user actions, and JSPs to generate views. Information is exchanged between these different components as attributes (name/value pairs) in the PortletRequest, PortletSession, or PortletData objects.

However, in a straightforward portlet implementation, these attributes function as global variables with no type checking. Furthermore, a single listener is used to handle all possible actions generated by all views (or screens) of the portlet. Consequently, for portlets with complicated designs involving many view transitions, the portlet code can quickly degenerate into an unmanageable mess that is difficult to debug and extend.

This article describes a portlet implementation and design within a fully realized MVC paradigm in the context of Portal 4.1. The portlet views can be developed and modified independently. Session and persistent portlet data are properly encapsulated to ensure maintainability of the software as the portlet code evolves.


A typical portlet in WebSphere Portal

This first section discusses a basic portlet design. Figure 1 shows the typical program flow for a WebSphere Portal portlet. To generate the portlet display, the doView method of the portlet is called. The portlet generates the HTML code by retrieving the current portlet state from the appropriate attribute in the PortletRequest, PortletSession, and/or PortletData objects. Based on the current portlet state, an appropriate JSP file that implements a particular view for the portlet is then invoked. The HTML tags are streamed to and rendered by the browser, letting the user interact with the user interface. When the user clicks on an appropriate user interface element, an HTTP request is sent back to Portal, which calls the actionPerformed method of the ActionListener object registered to handle ActionEvents for the portlet.


Figure 1. Program flow in a typical portlet application
Diagram of a program flow in a typical portlet application

Since a portlet is implemented using a servlet, the user (application) state cannot be stored in member variables. Instead, Portal provides:

  • PortletRequest objects to pass transient information pertaining to the current request/event between various software components
  • PortletSession objects to store user attributes or portlet states that need to persist for as long as the user is logged on
  • PortletData objects to store persistent application data on a per portlet basis (this lets you implement a dashboard-style portlet, which you can configure to automatically display user specified information/view on login)

The API for storing attributes and data in all three objects are similar. You can set the value of an attribute using:

setAttribute 
   session.setAttribute("attributeName", "attributeValue");  

You can retrieve the value of the attribute elsewhere using:

getAttribute 
   session.getAttribute("attributeName");  

In both cases, attributeName is the string name of the attribute.

One problem with this approach is that the attributes in the PortletRequest, PortletSession, and PortletData objects function as global variables for the portlet. The portlet code ends up peppered throughout with the getAttribute and setAttribute method calls. Firstly, it is not possible to perform compile time checking of the attribute name. A typo in the attribute name anywhere in the code would lead to run-time bugs that might escape testing. For example, an attribute name might be accidentally reused for completely different purposes. Secondly, the lack of encapsulation means that changes to the attribute naming convention will result in global code changes throughout, resulting in code that is fragile and difficult to maintain.

Another problem results from the use of a single ActionListener to handle ActionEvents associated with all views. A typical actionPerformed method of the ActionListener contains an if-then-else structure for handling the different cases.

   DefaultPortletAction action = (DefaultPortletAction)event.getAction(); 
   ...... 
   if ("View1_Action1".equals(action.getName())) { 
      ...... 
   } else if ("View1_Action2"Equals(action.getName())) { 
      ...... 
   } else if ("View2_Action1"Equals(action.getName())) { 
      ...... 
   } else if ...... { 
      ...... 
   }

Consequently, the actionPerformed method becomes an increasingly long routine that you would need to modify whenever a new view is added (or when an existing one is changed). Also, by mixing logic implementing functions that are completely unrelated, the program flow becomes more difficult to follow, leading to "spaghetti" code that is hard to maintain, extend, and change.


CMVC portlet from the WebSphere Portal Development Community Builder

The WebSphere Portal Development Community Builder is a set of portlets that work together to support the software development process. For the beginner, a set of portlets (many with source code) provides examples of how customer shops can integrate their own software into the portal framework. The CMVC portlet (Figure 2) is a sample portlet that provides integration to CMVC, an IBM internal source configuration management and defect tracking tool. It supports at-a-glance monitoring of defect status of different projects using lists and graphs. For the purposes of this article, it serves as a good example of a portlet with a reasonably complicated set of views and how you can apply the Model-View-Control paradigm to manage this complexity.


Figure 2. Two CMVC portlets side-by-side, displaying a graphical and a table view
Screen capture of two CMVC portlets side-by-side, displaying a graphical and a table view

Managing session and persistent state

For the CMVC portlet, a lightweight, transient object, CMVCPortletSession, is used for encapsulating the state of the portlet. You can create a CMVCPortletSession object anywhere in the code by passing to its constructor the PortletRequest object (which also provides access to the PortletSession and PortletData objects). All of the state information managed by CMVCPortletSession are stored in an appropriate attribute of the PortletRequest, PortletSession, or PortletData objects. Access to the data is encapsulated by CMVCPortletSession and associated classes, which provides an object-oriented API for accessing the state data by other software components.


Figure 3. UML diagram showing CMVCPortletSession and the associated subobjects. In this diagram, only a representative subset of the classes is shown.
UML diagram showing CMVCPortletSession and the associated subobjects

Figure 3 shows the UML diagram of CMVCPortletSession and the associated subobjects. The state information is organized into logical subobjects (ViewManager, CMVCService, and DefectHistoryManager) to make it more manageable. ViewManager manages the state transitions among the various portlet views: password (which is not shown), defect list, graphical (for current defect distribution, historical defect count, and historical defect run rate), edit, and the error view. CMVCService maintains information about the CMVC family, release, and component to monitor, and provides an API for accessing the back-end CMVC server. Finally, DefectHistoryManager is used to retrieve the historical defect count data generated by a background daemon process and stored in XML format.

For performance reasons, the information is not retrieved from PortletSession and PortletData until it is needed (lazy evaluation). For example, the getters and setters for the CMVC family are implemented as follows:

    public String getFamily() { 
      if (this.family == null) { 
	this.family = 
	  (String)getData().getAttribute(getUserID() + ":" + CMVC_FAMILY_VAR); 
	if (this.family == null) { 
	  final String defaultStr = properties.getCMVCFamily(); 
	  this.family = defaultStr; 
	  try { 
	    setFamily(this.family); 
	  } catch (Exception ex) { 
	  } 
	} 
      } 
      return this.family; 
    } 
 
    public void setFamily(String family) 
      throws IOException { 
      this.family = family; 
      PortletData data = getData(); 
      try { 
        data.setAttribute(getUserID() + ":" + CMVC_FAMILY_VAR, this.family); 
        data.store(); 
      } catch (AccessDeniedException ex) { 
      } 
      ...... 
    }

The getter methods first check to see if the member variable used to cache the corresponding attribute in the CMVCPortletSession has been initialized. If not, it tries to retrieve the value of the attribute from the PortletData (or the PortletSession) object. If the attribute does not yet exist, the getter method initializes it to a default value. Since CMVCPortletSession is transient and recreated for every servlet invocation, it could directly reference objects (such as the PortletRequest) that do not persist across HTTP requests. Note that the user ID is included in the attribute name to work around the fact that for some versions of WebSphere Portal, PortletData is not unique for each user.

You can then access the user state through the well-defined interface of the CMVCPortletSession object, without regard to whether the state is actually stored in the PortletSession or in the PortletData through an object-oriented API. Not only does this help avoid the proliferation of the getAttribute and setAttribute calls and the resulting lack of compile time checking for the attribute names, but also the rest of the portlet code does not need to know the details of where the data is stored. The portlet developer can freely change the storage location (from PortletSession to PortletData for example, or even to an XML file or a customized database table) without impacting the rest of the code. Keep in mind, though, that changing the storage location could change the lifetime (and hence the semantics) of the attribute. Data stored in PortletSession is valid while the user session is valid. Data stored in PortletData is persistent for the entire lifetime of a given concrete portlet instance.

Generating portlet views and event handling

The CMVC portlet employs a fully realized MVC paradigm. Figure 4 shows a UML diagram of the classes implementing the edit view based on a previously established MVC framework. To add a new view/screen to the portlet, the portlet developer must implement:

  • A new CMVCView subclass that generates the appropriate HTML tags (either by invoking an appropriate JSP file, or through direct Writer calls) for the browser to display
  • A FormModel subclass used by the new CMVCView subclass to access necessary information for generating the display
  • A CMVCEvent subclass that represents actions that can be associated with the view; it provides utility routines for extracting event parameters from the PortletRequest
  • A CMVCListener subclass that is responsible for handling any events generated by the user for the view

In MVC terms, the CMVCView classes generate the view, the CMVCListener classes act as the controller, and the FormModel classes provide the model for the view, encapsulating the view information to be displayed.


Figure 4. UML diagram showing the MVC classes associated with the edit view
UML diagram showing the MVC classes associated with the edit view

A key benefit of this architecture is that you can add and maintain each of the views (edit, defect list, graph, password input, and error reporting) independently of one other, as long as the interfaces defined by the framework are implemented. The standard interfaces let you treat the classes implementing the different views in a similar way, thereby simplifying the dispatch code.

The sequence diagram shown in Figure 5a and 5b below shows the generation of the edit view. The doEdit method of the CMVC portlet uses the ViewManager to retrieve the EditView object. This in turn is used for generating the HTML UI. FormModel, the parent of EditViewModel, provides convenience functions to generate the HTML tags. Throughout this process, transient CMVCPortletSession objects are generated as needed for extracting state information.


Figure 5. Sequence diagrams showing the generation of the edit view. (a) Overall flow with the outputHTML details omitted.
Sequence diagram showing the overall flow of the generation of the edit view with the outputHTML details omitted

Figure 5b. Details of output HTML
Sequence diagram showing the details of outputHTML

Events are handled and dispatched as follows. WebSphere Portal provides a mechanism for attaching event objects to an encoded URL:

PortletURI uri = response.createURI(); 
uri.addAction(event);

The URI can then be converted into a string that is appropriate for the href attribute of the <a> tag or the action attribute of the <form> tag.

When the user clicks on the link or submits the form, WebSphere Portal transfers control to the actionPerformed method of the ActionListener registered for the CMVC portlet. The ActionListener implementation then calls the getListenerClass() method of CMVCEvent to obtain an instance of the appropriate CMVCListener subclass for handling the current event. The processEvent method of the CMVCListener object is then invoked.

  public void actionPerformed(ActionEvent event) 
    throws PortletException { 
    CMVCEvent cmvcEvent = (CMVCEvent)event.getAction(); 
    CMVCListener listener = cmvcEvent.getListenerClass(); 
    listener.processEvent(cmvcEvent, event.getRequest()); 
  }

Currently, for simplicity, the CMVC portlet assumes a one-to-one correspondence between the CMVCEvent and the CMVCListener subclasses (there is only one handler registered with each event). Note that by implementing an event-listener registry and the corresponding dispatch mechanism, you can extend this scheme so that you have multiple listeners for each event.

The CMVCListener first casts the CMVCEvent that is passed to it to the proper subclass, and retrieves information about the event by calling the appropriate methods on the event object. This information can be used to extract data for the model, update the state in the CMVCPortletSession object, and determine the next view/screen to transition to. The transition from one view to the next is managed through the ViewManager object in CMVCPortletSession, which maintains a reference to the CMVCView that is appropriate for the current view. Access the current CMVCView object through the getViewType and setViewType methods.

Figure 6 shows the sequence diagram of how the EditFormEvent and EditFormListener objects cooperate to handle events associated with the EditView. When a user event takes place, WebSphere Portal passes control to the actionPerformed method of the portlet, which in turn queries the event for the appropriate CMVCListener object (an EditFormListener in this case) to handle the event, and passes control to its processEvent method. The EditFormListener object then coordinates with the CMVCPortletSession object to handle the event.


Figure 6. Sequence diagram showing the dispatch of events for the edit view
Showing diagram showing the dispatch of events for the edit view

Understanding the CMVC portlet design

There is a another way to look at this design. Design Patterns by E. Gamma et al. describes commonly used object-oriented designs and provides useful terminology for discussing software architectures. Design patterns lie behind the design of the CMVC portlet MVC architecture. CMVCPortletSession and associated objects play the role of mediator in the Mediator pattern, so that various objects (for example, the CMVCView and CMVCListener objects) can share information without becoming coupled to one another.

At the same time, the reference to the view objects in CMVCPortletSession represent states for the portlet UI. The ViewManager plays the role of the context in the State pattern.


Conclusion

Portlet programming is a relatively new field. A straightforward application of the existing PortletAPI, while effective for simple portlets, might not result in portlet designs and implementations that are extensible and maintainable. Principles such as data abstraction and encapsulation, and the Model-View-Controller paradigm are just as important, if not more important, in portlet and Web applications as they are in thick client applications. However, they are not always consistently applied in practice. It is our hope that by sharing our experience in portlet implementation, we play a part in establishing portlet design patterns that will prove useful in portlet programming.

Currently, the developer hand-codes the CMVCPortletSession, CMVCView, CMVCEvent, and CMVCListener objects. While it is easy to adapt this framework for other portlets, you could also generalize and automate the dispatch and transition mechanism in a similar style to Apache Struts. Developing such an MVC framework for portlets will be a boon to portlet development in general.

Top of page


About the authors

Michael Kwong is a software engineer at the IBM Silicon Valley Lab in San Jose, California. His interests include Web applications and portlet programming, search technologies, knowledge management, and the development process. He holds a BSc, MSc, and PhD in Electrical Engineering from Stanford University. You can reach Michael at mkwong@us.ibm.com .

Laurence England is a software architectect at the IBM Silicon Valley Lab in San Jose, California. He has been involved with several projects, including WebSphere Portal Development Community, WebSphere Studio Enterprise Developer, and WebSphere Asset Analyzer. In his spare time, he participates in ultra-marathons. You can reach Larry at englandl@us.ibm.com .

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


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. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

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.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=13922
ArticleTitle=Building a Portlet within the Model-View-Controller Paradigm using WebSphere Portal
publish-date=10302002
author1-email=mkwong@us.ibm.com
author1-email-cc=
author2-email=englandl@us.ibm.com
author2-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers