views:

2870

answers:

1

Hey all,

I have a JSF application that consists of two JSPs: login.jsp & main.jsp.

I have the following faces-config.xml:

<lifecycle>
  <phase-listener>package.programs.scorecard.beans.EventBean</phase-listener>
</lifecycle>
<managed-bean>
  <managed-bean-name>FormBean</managed-bean-name>
  <managed-bean-class>package.programs.scorecard.beans.FormBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
  <managed-bean-name>DataBean</managed-bean-name>
  <managed-bean-class>package.programs.scorecard.beans.DataBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
  <managed-bean-name>EventBean</managed-bean-name>
  <managed-bean-class>package.programs.scorecard.beans.EventBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

And the following web.xml:

<welcome-file-list>
  <welcome-file>faces/login.jsp</welcome-file>
  <welcome-file>faces/index.jsp</welcome-file>
  <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>/faces/*</url-pattern>
</servlet-mapping>

I have a couple of components on login.jsp that update properties in DataBean on a commandLink click. Upon successful completion, the user is navigated to /main.jsp.

I notice that when I click the commandLink, the method executes BEFORE the bean is updated. This results in all of my bean properties to be null when the method executes because the values from my form are not being applied to the bean.

From what I understood of the JSF life cycle, the "Update Model Values" should always be executed before "Invoke Application" unless "immediate=true" is specified, which it is not for my commandLink.

I have been trying to debug this for a couple of hours this morning, and I welcome any suggestions or insights.

UPDATE: I have investigated this issue thoroughly and have concluded that the drop down component I was utilizing has a bug in it that should be fixed in the next release. My solution was to use a regular h:selectOneMenu in lieu of the third party component, and it works like a charm:

<h:selectOneMenu id="ddlManager" value="#{DataBean.managerId}">
    <f:selectItems value="#{DataBean.managerList}" />
</h:selectOneMenu>

Where managerList is a list of SelectItem objects.

+2  A: 

This is not a solution - it is an example that might help you diagnose the problem. Of course, you may be doing this already - I see you've implemented a phase listener.

Bean:

public class LoginBean implements Serializable {

    private String user;
    private String password;

    public String getPassword() {
     return password;
    }

    public String getUser() {
     return user;
    }

    public void setPassword(String password) {
     System.out.println("Update Password: " + password);
     this.password = password;
    }

    public void setUser(String user) {
     System.out.println("Update User: " + user);
     this.user = user;
    }

    public String login() {
     if ("user".equals(user) && "password".equals(password)) {
      // ok
      System.out.println("Login OK");
      return "loggedIn";
     } else {
      System.out.println("Login Failed");
      FacesContext context = FacesContext.getCurrentInstance();
      FacesMessage message = new FacesMessage(
        "Invalid user name or password");
      context.addMessage(null, message);
      return null;
     }
    }

}

View:

<f:view>
 <h:form>
  login:
  <h:inputText value="#{loginBean.user}" />
  <h:inputSecret value="#{loginBean.password}" />
  <h:commandButton value="login" action="#{loginBean.login}" />
  <h:messages />
 </h:form>
</f:view>

faces-config.xml:

<?xml version="1.0" encoding="UTF-8"?>

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
    version="1.2">
    <managed-bean>
     <managed-bean-name>loginBean</managed-bean-name>
     <managed-bean-class>login.LoginBean</managed-bean-class>
     <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
    <navigation-rule>
     <display-name>login</display-name>
     <from-view-id>/login.jsp</from-view-id>
     <navigation-case>
      <from-outcome>loggedIn</from-outcome>
      <to-view-id>/label.jsp</to-view-id>
     </navigation-case>
    </navigation-rule>
    <lifecycle>
     <phase-listener>login.PhaseListenerImpl</phase-listener>
    </lifecycle>
</faces-config>

Phase listener:

public class PhaseListenerImpl implements PhaseListener {

    public void afterPhase(PhaseEvent event) {
     System.out.println("AFTER: " + event.getPhaseId());
    }

    public void beforePhase(PhaseEvent event) {
     System.out.println("BEFORE: " + event.getPhaseId());
    }

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

}

The expected log output for a matching username and password would be:

BEFORE: RESTORE_VIEW(1)
AFTER: RESTORE_VIEW(1)
BEFORE: APPLY_REQUEST_VALUES(2)
AFTER: APPLY_REQUEST_VALUES(2)
BEFORE: PROCESS_VALIDATIONS(3)
AFTER: PROCESS_VALIDATIONS(3)
BEFORE: UPDATE_MODEL_VALUES(4)
Update User: user
Update Password: password
AFTER: UPDATE_MODEL_VALUES(4)
BEFORE: INVOKE_APPLICATION(5)
Login OK
AFTER: INVOKE_APPLICATION(5)
BEFORE: RENDER_RESPONSE(6)
AFTER: RENDER_RESPONSE(6)
McDowell
Thanks, @McDowell. See the updated question...I found out the solution was in the component I was using. I took your advice and stepped through the whole life cycle and couldn't figure it out. Thank you, my friend.
KG