Contextual PortletMode changes using the JBoss Portlet Bridge

10 December 2009

Java | portal | portlets | seam |

By default, the JSR-301/329 portlet bridge manages your navigation history during PortletMode changes. Meaning that, if the user is clicking around in the portlet "view" mode and decides to click the help icon (help mode), the user should be directed to the place where he left off in help mode - and vice versa. Of course, if the user has never been in help mode during the current session, he will go to the default help viewId.

Why use portlet modes instead of javascript widgets?

First I would like to give you a little justification of the beauty of this feature. Some people will argue the point of "Why do you need different modes like, Help and Edit?", when you could add some cool "javascript of the week" that would dynamically display what you intended to present in one of the given modes. Well, you could develop your interactions either way but it really isn't a question of why. It's a question of "How?". How do you want users to interact with your applications? And since you have already made the decision to invest in a portal solution, why not use the features that are built in and that stay consistent across the entire UI? Any UI Developer or Interaction Designer will tell you that adding cool javascript widgets adds another layer of complexity and maintenance, thus adding to developer time and bottom line ROI. In addition, when you develop any servlet based application to work within a portal environment, you are properly separating your concerns when you use these modes (without even realizing it in most cases). You are presenting distinguished flows for different trains of thought and making it easier for users to accomplish the task at hand.

The Usecase

Ok, off the soap box and onto the use case. Let's say your user is filling out a beloved expense report. It's probably one of his top 5 things that he loves most about his job ;) Seriously, his IT department just launched a new intranet portal using the latest and greatest GateIn platform and they completely revamped their old Seam application that was used for expense report submissions to run as a portlet.

So, Joe User starts to fill out his expense report in a 6 step wizard. He gets through the first few steps and arrives at a screen asking for his cost center and other details that he has no idea about. Behold the beautiful question mark(help mode) in the top right hand corner of his portlet window! Joe clicks the button and sees exactly the information he needs, and he also sees a link at the bottom of the screen that says “add this to the form”. Joe clicks it, and is returned to his expense report with all of the details pre-populated in his form. Not only was the help screen easy to understand, but it was just a basic .xhtml page that can be templated and maintained by any UI developer without any special javascript kung fu.

The next screen (in view mode), asks him to itemize each receipt and expense. Since he took a trip to Euro-land, all of his receipts are in Euros. And since he recently just got his internet privileges suspended (and no, he won't tell us why) he has no idea what the current conversion rates are. Once again, Joe clicks the help button and is presented with a clickable table of currency options. Not only that, but the finance department has placed some important notifications on this page via CMS. Joe reads the notifications and clicks on "Euros" and is taken back to a modified input table that auto converts his itemized euro(€) values to USD($).

As you can see, these are just random examples of possibilities of detecting PortletMode changes with GateIn, Seam, and RichFaces. The real beauty of this code is detecting the actual mode change and providing contextual help. This is not currently provided by the bridge as a default behavior, so here is the code to do it:

The Code

First create a simple session bean with the following code. This will allow us to get a handle on the current mode.

private String mode; public String getMode() { Object responseObject = FacesContext.getCurrentInstance().getExternalContext().getRequest(); if (responseObject instanceof RenderRequest) {

RenderRequest renderRequest = (RenderRequest)responseObject; if(renderRequest.getPortletMode().toString().equals(mode)){ mode = null; }else{ mode = renderRequest.getPortletMode().toString(); }

} return mode; } public String getFromView() { PortletSession portletSession = (PortletSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false); String viewId = (String)portletSession.getAttribute("javax.portlet.faces.viewIdHistory.view");

viewId = viewId.substring(0,viewId.indexOf("?")); return viewId; } public void setMode(String mode) {

this.mode = mode; }

Next add something similar to this in pages.xml

 <page view-id="/expenseWizard/*" action="#{mode.getMode()}"> 
 <rule if-outcome="help" if="#{mode.getFromView() == '/expenseWizard/step3.xhtml'}"> 
 <render view-id="/helpPages/step3help.xhtml"/> 
 <rule if-outcome="help" if="#{mode.getFromView() == '/expenseWizard/step4.xhtml'}"> 
 <render view-id="/helpPages/step4help.xhtml"/>