Making Managed Beans Aware of the JSF Lifecycle

An event that runs when a JSF page is being loaded should be useful for initialization stuff. In my project team several developers use bean constructors to do such things which I think is a bad practice. Although I prefer the getters to do initializations, I’ve added a onPageLoad event to our application for people who prefer the constructors. It is similiar to Shale view mapper, the managed bean and the page name must be mapped in order to run the event. There are two things needed to do the job, a phaselistener and an interface to mark the managed beans. PhaseListener runs maps the viewId to the managed bean and executes the onPageLoad event.

public class PageLoadListener implements PhaseListener {

  protected final static Log logger = LogFactory.getLog(PageLoadListener.class);

  public void afterPhase(PhaseEvent phaseEvent) {
    FacesContext facesContext = phaseEvent.getFacesContext();
    String viewId = phaseEvent.getFacesContext().getViewRoot().getViewId();
    System.out.println(viewId);

    if (viewId.endsWith(".jsf")) {
      String managedBeanName = getManagedBeanNameFromView(viewId);
      Object object = facesContext.getApplication().createValueBinding("#{" + managedBeanName + "}").getValue(facesContext);
      if (object == null)
        logger.error("OnPageLoad cannot be executed, no such managed bean:"+ managedBeanName);
      else {
        ILifeCycleAware lifeCycleAwareBean = (ILifeCycleAwareobject;
        lifeCycleAwareBean.onPageLoad();
      }
    }
  }

  public void beforePhase(PhaseEvent phaseEvent) {
    
  }

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

  public String getManagedBeanNameFromView(String viewId) {
    String pageName = viewId.substring(1, viewId.length() 4);
    return "pc_" + StringUtils.capitalize(pageName);
  }

}
      

And the interface that makes the managed bean aware of the lifecycle.

public interface ILifeCycleAware {
  public void onPageLoad();
}
      

For example there is a page called index.jsp, and it is referred as the virtual mapping /index.jsf. Phaselistener extracts the index token and gives the mapping pc_Index. Also the managed bean class Index.java implements ILifeCycleAware interface and overrides the onPageLoad event. Then phaselistener executes this event. Finally the backing bean of index.jsp is declared in faces-config.xml as;

  <managed-bean>
  <managed-bean-name>pc_Index</managed-bean-name>
  <managed-bean-class>barca.Index</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
 </managed-bean>

 The good thing is more events can be added like the ones in Shale, eg prerender, preprocess and etc. So you can execute similiar events and make the managed beans aware of the lifecycle.

12 Responses to Making Managed Beans Aware of the JSF Lifecycle

  1. Belletti says:

    Usage of “pc_” prefix for backing bean names is a good practice from IBM. All hail IBM.

  2. Cagatay says:

    A good alternative for onLoad, but doesn’t seem to be extendable. What if I need more events like prerender etc.

  3. Octoberdan says:

    Will this work if a bean is lost because of a session timing out?

  4. Cagatay says:

    I guess so since JSF will create a new instance when it is referred for the first time.

  5. Deepak says:

    Hi!

    I’m trying out this technique to do some init work in my managed bean. but phaseEvent.getFacesContext().getViewRoot() returns null. Any idea why this would happen?

    Rgds,
    Deepak

  6. bansi says:

    Hi Cagatay
    I have used the above technique to retrieve incoming Http Request Header Variables . As suggested i have onPageLoad event defined in MyPhaseListener & Backing Bean. But the header variables are returning NULL values. Am i missing anything here.

    Here are snippets of code
    ————–

    ————–

    ————–
    faces-config.xml
    ————– com.mycompany.MyPhaseListener


    pc_GreetingList
    com.mycompany.TestJsfBean
    request


    testJsfBean

    com.mycompany.TestJsfBean

    request
    testSpringBean com.mycompany.TestSpringBean #{testSpringBean}

    Can i have two references to TestJsfBean with different names as shown above. Hope this is not the mistake i am making

    ————–
    MyPhaseListener.java
    ————–
    public void afterPhase(PhaseEvent pe)
    {
    System.out.println(“after – ” + pe.getPhaseId().toString());

    FacesContext facesContext = pe.getFacesContext();
    String viewId = pe.getFacesContext().getViewRoot().getViewId();
    System.out.println(“ViewId =”+viewId);

    if (viewId.endsWith(“.jsp”)) {
    String managedBeanName = getManagedBeanNameFromView(viewId);
    Object object = facesContext.getApplication().createValueBinding(“#{” + managedBeanName + “}”).getValue(facesContext);
    if (object == null)
    logger.error(“OnPageLoad cannot be executed, no such managed bean:”+ managedBeanName);
    else {
    ILifeCycleAware lifeCycleAwareBean = (ILifeCycleAware) object;
    lifeCycleAwareBean.onPageLoad();
    }
    }
    ————–
    TestJsfBean.java
    ————–
    public void onPageLoad() {
    Map requestHeaderMap = new HashMap();

    requestHeaderMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();

    System.out.println(“Hash Map Size in TestJsfBean:”+requestHeaderMap.size());

    String bemsId = (String)requestHeaderMap.get(“BOEINGBEMSID”);
    System.out.println(“In TestJsfBean:”+bemsId);
    //return bemsId;
    }
    ————–
    ILifeCycleAware
    ————–
    package com.mycompany;

    public interface ILifeCycleAware {
    public void onPageLoad();

    }

  7. bansi says:

    I dont have problem with accessing requestParameterMap in PhaseListener (RESTORE_VIEW). But please note i am not able to access it in the Backing Bean method i.e. onPageLoad()

    The reason i am doing this is i would like to store my Http Request Header variables in Backing Bean method based on which i will perform some business logic & then accordingly i will render my first jsp page of the application

    The Phase Id is RENDER_RESPONSE in afterPhase() method from where the onPageLoad() method is called i.e

    lifeCycleAwareBean.onPageLoad();

    Please let me know if i am missing something or taking a wrong path. I would appreciate your quick response. Also can i have different bean names refering to same bean class in faces-config.xml i.e.

    pc_GreetingList

    com.mycompany.TestJsfBean

    request

    testJsfBean

    com.mycompany.TestJsfBean

    request

    Pl note pc_GreetingList and testJsfBean are two different bean names refering to same bean class com.mycompany.TestJsf Bean

  8. ceaseoleo says:

    I have tried this method out as well.. it appears the view root is always returning the previous page’s view root /page1 -> page2 -> page3

    when going to page 3 i get page2 in the view root.

  9. ceaseoleo says:

    the solution is without adding to your navigation rule, this will not work.

  10. Martin says:

    Hi, I actually would like to know how you maintain this wonderfully formatted source code within a wordpress page. Seems at least that you are pasting from an eclipse editor.
    What wordpress plugin are you using. I have tried several with only disappointing results!

    Thanks
    Martin

  11. cagataycivici says:

    Hi Martin, Check this out: http://www.java2html.de/