Master Series: Tracking Portal Page States with IBM Web Experience Factory (WEF)


Adam Kewley Davalen

 by Adam Kewley

Once in a while during product development we run into scenarios where we need to extend the functionality of IBM Web Experience Factory (WEF) & IBM WebSphere Portal above and beyond what’s supported out of the box. The product goes a long way to make things easier to develop with but it’s impossible (and impractical) to expect it to cover every scenario. Fortunately we can usually rely on custom API and sample workarounds to get us through. This article will discuss one such scenario: Tracking Portal Page states with WEF.

In general a portlet isn’t supposed to know (or care) which page it is placed on. It also shouldn’t worry which page the user was on previously. Due to this construct, it’s not always easy to tell when a portlet is being reloaded or when it’s processing a request from a form action.

In some instances however, a project may require a portlet to refresh itself when a user navigates back to that page. A client may wish that an input form resets itself despite what the JSR specification may state. IBM provides a few API classes that expose the page structure. We’ve used them in the past to get the unique page name as well as generate a portal navigation menu inside of a portlet. In this segment we will discuss how to implement your own portlet page tracker which will not only be able to tell when  page changed, but also track whether or not a portlet has registered this page change.

The WebSphere Portal API provides the ModelUtil and NavigationNode classes to gain access to the page models within the portal. Using the following sample code, we can obtain the unique name of the current portal page:

ModelUtil util = ModelUtil.from( webAppAccess.getHttpServletRequest(), webAppAccess.getHttpServletResponse() );

NavigationNode node = ( NavigationNode ) util.getNavigationSelectionModel().getSelectedNode(); 

String uniquePageName = node.getContentNode().getObjectID().getUniqueName().trim();

If we know which page we are currently on we can also keep track of the prior page we were on. This requires a bit of planning. One key aspect of this solution is assuring that the page tracking logic exists on all portal pages. If you only apply the tracker portlet to a few key pages your tracker will lose its state and you may end up missing page state changes. Every page that’s visible within the portal will need to contain the tracker portlet. There are a couple of ways to handle this.

Some Portals may contain a header portlet which exists on all pages. This header portlet can be modified to include the page tracking logic as well. Optionally if you have no use for a common header/footer/filter portlet, you can create a hidden portlet that is placed on the page but uses a Portal Theme skin which hides the portlet altogether. This allows the portlet to execute without visually impacting your portal project.

The Page tracker also needs a bit of custom logic to track the current state. A shared variable of type String named currentPage will contain the last registered page name for the session. An event handler that is setup for “OnRequest” events will use the portal page logic to determine whether or not the API pageName differs from the value stored in the currentPage variable. Using this logic we can now identify when a user switches portal pages.

public void updatePageTracker( WebAppAccess webAppAccess ) {

final String newPage = getCurrentPage( webAppAccess );

final String currentPage = webAppAccess.getVariables().getString( “currentPageVar” );

 

if ( currentPage == null || newPage.equals( currentPage ) ) {

    Vector<String> pageRegistry;

    pageRegistry = (Vector)webAppAccess.getVariables().getObject( “pageRegistryVar” );

 

    if ( pageRegistry == null ) {

        pageRegistry = new Vector<String>(); // Initialize

        webAppAccess.getVariables().setObject( “pageRegistryVar”, pageRegistry );

    }

    webAppAccess.getVariables().setString( “currentPageVar”, newPage );

    pageRegistry.clear(); // remove registered portlets.

}

}                                                                                                                                                                                                             

The Page Tracker solution isn’t as useful however if the portlets on the page are not able to individually discern whether or not this page change took place. We can get around this by using a bit of java and a second shared variable (Object) called pageRegistry. This xml variable should include multiple elements that contain the name of registered portlet instances for a given page. We don’t care which portlets should be on a given page, only that the portlet adds itself to the registry.

The additional java code would include a method:

public boolean hasPageChanged( WebAppAccess webAppAccess ) {

 

Vector<String> pageRegistry;

pageRegistry =(Vector)webAppAccess.getVariables().getObject(“pageRegistryVar” );

 

boolean isRegistered = false;

final String portletID = webAppAccess.getInstanceID();

 

if (  pageRegistry.contains( portletID ) )

{

    isRegistered = true;

}

else

{

    pageRegistry.add( portletID );

}

return isRegistered;

}

This method should be called in an onRequest event handler by each portlet which wishes to make use of the page tracking logic. The method can be used in a conditional check to see if the portlet should update itself.

So now that we have the basic solution for tracking page changes and portlets that can identify when a page change has occurred, we’ll outline a couple uses for this solution.

#1 Updating Portlet on Page Change

When switching portal pages, initialized portlets are simply given render requests. It is assumed that the portlet will render its last known state. By using the page tracking logic, an event handler can be triggered to make a service operation call and obtain new data. If you need to update the portlet, then be sure to call the webAppAccess.resetCurrentPage( String page ) method which will force the portlet to update the page during a render request.

#2 Filtering Events

WEF events are broadcast events that will trigger event handlers in portlets that exist on any accessible page in the portal. This means that if you have a global filter event, every portlet that listens to this filter event will act when the filter event is fired regardless of whether or not they are on the current page. This will only occur if the portlet has been initialized for that session. Portlets residing on pages that you have not yet visited will not listen for the event. This of course can cause performance issues because you now have any portlet listening to this event acting during a single request. The page tracking logic can be inserted in the event handler to determine whether the event handler should execute or not. Example:

public boolean isValidPageEvent( WebAppAccess webAppAccess )

{

Vector<String> pageRegistry

pageRegistry = (Vector)webAppAccess.getVariables().getObject( “pageRegistryVar” );

return ( pageRegistry.contains( webAppAccess.getInstanceID() ) );                       

}

 

Adding a conditional logic to your event handler will prevent this portlet form executing if it doesn’t need to.

#3 Returning to an Initial Portlet State.

If you have a portlet that you wish to return to an original page after navigating away and back to this portal page, you can use the event handler to swap pages. Just use the webAppAccess.resetCurrentPage method to change the active page during a render request.

#4 Resetting a Portlet.

This is a bit tricky, and there are other ways to accomplish this, but you can also reset session data for a given portlet as well.

In conclusion it is possible to track the state of portlets as well as the page that the portal is being rendered on. By using some java and a few builders you can add a framework which can aid in performance tuning of WEF events as well as handling data refreshes and portlet resets.

Closing Thoughts:

  1. The code in this segment is provided as a sample and not production ready.
  2. The solution assumes that portlets are rendering individually and not using parallel portlet rendering.
  3. The sample also assumes that the portlet tracking the page changes renders before the other portlets render. The “page tracker” portlet should be the first portlet (top most) rendered on the page, and the portlets that make use of the page tracker should come after.
  4. This sample utilizes the public_spi.jar Jar file.
  5. The java source code for this sample can be downloaded here.

About the Author: Adam Kewley has been working with IBM Web Experience Factory (WEF) for over 10 years. He began his career working with the WEF development team itself. Over time he moved from software QA to Development, L3 support lead (assisting the IBM customer support team), and finally on to consulting. He has led several engagements and has been pulled in the past to put out fires and address deliverable roadblocks ensuring success for a client. Adam is currently employed at Davalen as the WEF lead and architect and is a resident of southern New Hampshire.

————————————————————————————————————————————
This article is from our monthly resource e-Newsletter. Did you miss it in your inbox? Visit our eNewsletter archives for past editions or if you want to receive our monthly newsletter automatically, simply write to Ruth O’Keefe and request to be added to our E-Newsletter list. You can also view other articles in the Master Series by clicking here.

2 comments on “Master Series: Tracking Portal Page States with IBM Web Experience Factory (WEF)

  1. Nice article. Easy to read and it will be valuable to many. I did not know that WEF Events worked across pages if the portlet had already been initialized. I thought only wires could be used for that. Interesting.

    • Thanks! Yes they can work cross pages, but generally do not use them for that purpose. The cross-page portlet will not listen for the event if you have not initialized the portlet yet (ie viewed it in the same session), and it will not change the page. They can be useful for setting filter events however.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s