Friday, December 7, 2007

Changing View JSP In doView Of A Portlet With JSF

I'm playing around with JBoss portal server, Portlets and JSF these days and I had to change the view of a portlet when a value in database changed. The value is changed from another portlet and the portlet I was developing had to look for the change every time it was rendered and reset it self if the value had changed. Looked simple enough but I had to waste a good part of a day to find a good solution.

I'm new to all these technologies and depend on Google to find me solutions but I couldn't find anything that helped me to do this with Sun Reference Implementation of JSF. I found one that described how to do it in IBM implementation of JSF which obviously didn't work on Sun RI. The problem is you just can't redirect to a JSP in the doView method if you are using JSF. I tried to do it by overriding the doView method in FacesPortlet.

Then I found this article on JSF Central which described how to redirect a user to a login page if the user is not logged in and that's exactly what I wanted. All I had to do was

  1. Write a PhaseListener and in the beforePhase method do my database check and set the view ID to my start page view id if the value had changed.
  2. Change the getPhaseId method to return PhaseId.RENDER_RESPONSE which makes the PhaseListner fire every time a page is rendered. The PhaseId.RESTORE_VIEW event is not fired every time a portlet is rendered.
  3. Configure the PhaseListener in faces-config.xml
That was it, pretty easy and would have been if I knew a little bit more about JSF :)

public class DBPhaseListener implements PhaseListener {

public void beforePhase(PhaseEvent event) {
FacesContext fc = event.getFacesContext();

System.out.println("Current View ID" + fc.getViewRoot().getViewId());
if (changed()) {
System.out.println("Changing view");
NavigationHandler nh = fc.getApplication().getNavigationHandler();
nh.handleNavigation(fc, null, "main");
}
}

private boolean changed() {
// code to check db changes
}

public void afterPhase(PhaseEvent event) {
}

public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
}


And the faces-config.xml

<faces-config>
<lifecycle>
<phase-listener>com.test.DBPhaseListener</phase-listener>
</lifecycle>

<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>main</from-outcome>
<to-view-id>/WEB-INF/jsp/index.jsp</to-view-id>
</navigation-case>
</navigation-rule>

<!-- rest of the faces-config -->
</faces-config>

Don' forget to click the +1 button below if this post was helpful.