Dynamic Navigation In most web applications, navigation is  not static. The page flow does not just depend on which button you click but  also on the inputs that you provide. For example, submitting a login page may  have two outcomes: success or failure. The outcome depends on a  computation namely, whether the username and password are legitimate.  To implement dynamic navigation, the  submit button must have a method expression, such  as    <h:commandButton label="Login" action="#{loginController.verifyUser}"/>  In our example, loginController  references a bean of some class, and that class must have a method named  verifyUser.  A method expression in an  action attribute has no parameters. It can have  any return type. The return value is converted to a string by calling  toString.    Note          |    In JSF 1.1, an action method was required to  have return type String. In JSF 1.2, you  can use any return type. In particular, using enumerations is a useful  alternative since the compiler can catch typos in the action  names.  |     Here is an example of an action method:    String verifyUser() {      if (...)         return "success";      else         return "failure";   }  The method returns an outcome string such as "success"  or "failure". The navigation handler uses the  returned string to look up a matching navigation rule.    Note          |    An action method may return null to indicate that the same page should be  redisplayed.  |     In summary, here are the steps that are  carried out whenever the user clicks a command button whose action attribute is a method expression:   -  
The specified bean is  retrieved.   -  
The referenced method is called.   -  
The resulting string is passed to the navigation handler. (As  explained under "The  Navigation Algorithm" on page 87,  the navigation handler also receives the method expression string.)    -  
The navigation handler looks up the next page.    Thus, to implement branching behavior, you  supply a reference to a method in an appropriate bean class. You have wide  latitude about where to place that method. The best approach is to find a class  that has all the data that you need for decision making.  Next, we work through this  process in an actual application. Our sample program presents the user with a  sequence of quiz questions (see Figure 3-1).             When the user clicks the "Check Answer"  button, the application checks whether the user provided the correct answer. If  not, the user has one additional chance to answer the same problem (see Figure 3-2).              After two wrong  answers, the next problem is presented (see Figure 3-3).             And, of course, after a correct answer,  the next problem is presented as well. Finally, after the last problem, a  summary page displays the score and invites the user to start over (see Figure 3-4).             Our application has two classes. The  Problem class, shown in Listing 3-1,  describes a single problem, with a question, an answer, and a method to check  whether a given response is correct.  The QuizBean class describes a  quiz that consists of a number of problems. A QuizBean instance also keeps track of the current problem and the  total score of a user. You will find the complete code in Listing 3-2.   Listing 3-1.  javaquiz/src/java/com/corejsf/Problem.java        1. package com.corejsf;   2.   3. public class Problem {   4.    private String question;   5.    private String answer;   6.   7.    public Problem(String question, String answer) {   8.       this.question = question;   9.       this.answer = answer;  10.    }  11.  12.    public String getQuestion() { return question; }  13.  14.    public String getAnswer() { return answer; }  15.  16.    // override for more sophisticated checking  17.    public boolean isCorrect(String response) {  18.       return response.trim().equalsIgnoreCase(answer);  19.    }  20. }
  |    In this example, the QuizBean  is the appropriate class for holding the navigation methods. That bean has all  the knowledge about the user's actions, and it can determine which page should  be displayed next.   Listing 3-2.  javaquiz/src/java/com/corejsf/QuizBean.java        1. package com.corejsf;   2.   3. public class QuizBean {   4.    private int currentProblem;   5.    private int tries;   6.    private int score;   7.    private String response;   8.    private String correctAnswer;   9.  10.    // here, we hardwire the problems. In a real application,   11.    // they would come from a database  12.    private Problem[] problems = {  13.       new Problem(  14.          "What trademarked slogan describes Java development? Write once, ...",  15.          "run anywhere"),  16.       new Problem(  17.          "What are the first 4 bytes of every class file (in hexadecimal)?",  18.          "CAFEBABE"),  19.       new Problem(  20.          "What does this statement print? System.out.println(1+\"2\");",  21.          "12"),  22.       new Problem(  23.          "Which Java keyword is used to define a subclass?",  24.          "extends"),  25.       new Problem(  26.          "What was the original name of the Java programming language?",  27.          "Oak"),  28.       new Problem(  29.          "Which java.util class describes a point in time?",  30.          "Date")  31.    };  32.  33.    public QuizBean() { startOver(); }  34.  35.    // PROPERTY: question  36.    public String getQuestion() {  37.       return problems[currentProblem].getQuestion();  38.    }  39.  40.    // PROPERTY: answer  41.    public String getAnswer() { return correctAnswer; }  42.  43.    // PROPERTY: score  44.    public int getScore() { return score; }  45.  46.    // PROPERTY: response  47.    public String getResponse() { return response; }  48.    public void setResponse(String newValue) { response = newValue; }  49.  50.    public String answerAction() {  51.       tries++;  52.       if (problems[currentProblem].isCorrect(response)) {  53.          score++;  54.          nextProblem();  55.          if (currentProblem == problems.length) return "done";  56.          else return "success";  57.       }  58.       else if (tries == 1) {  59.          return "again";  60.       }  61.       else {  62.          nextProblem();  63.          if (currentProblem == problems.length) return "done";  64.          else return "failure";  65.       }  66.    }  67.  68.    public String startOverAction() {  69.       startOver();  70.       return "startOver";  71.    }  72.  73.    private void startOver() {  74.       currentProblem = 0;  75.       score = 0;  76.       tries = 0;  77.       response = "";  78.    }  79.  80.    private void nextProblem() {  81.       correctAnswer = problems[currentProblem].getAnswer();  82.       currentProblem++;  83.       tries = 0;  84.       response = "";  85.    }  86. }     
  |    Have a glance at the code inside the answerAction method  of the QuizBean class. The method returns one of  the strings "success" or "done" if the user answered the  question correctly, "again" after the first wrong answer, and  "failure" or "done" after the second wrong try.         public String answerAction() {       tries++;       if (problems[currentProblem].isCorrect(response)) {          score++;          if (currentProblem == problems.length - 1) {             return "done";          }          else {             nextProblem();             return "success";          }       }       else if (tries == 1) {          return "again";       }       else {          if (currentProblem == problems.length - 1) {             return "done";          }          else {             nextProblem();             return "failure";          }       }    }       We attach the answerAction method  expression to the buttons on each of the pages. For example, the  index.jsp page contains the following  element:    <h:commandButton value="Check answer" action="#{quiz.answerAction}"/>  Here, quiz is the QuizBean instance that is defined in  faces-config.xml.  Figure  3-5 shows the directory structure of the  application. Listing  3-3 shows the main quiz page index.jsp. The  success.jsp and failure.jsp pages  are omitted. They differ from index.jsp only in the message at the top  of the page.           The done.jsp page in Listing 3-4  shows the final score and invites the user to play again. Pay attention to the  command button on that page. It looks as if we could use static navigation,  since clicking the "Start over" button always returns to the index.jsp  page. However, we use a method expression:    <h:commandButton value="Start over" action="#{quiz.startOverAction}"/>  The  startOverAction method carries out useful work  that needs to take place to reset the game. It resets the score and reshuffles  the response items:     public String startOverAction() {       startOver();       return "startOver";    }  In general, action methods have two  roles:     Note          |    As you will see in Chapter  7, you can also attach action listeners to  buttons. When the user clicks the button, the code in the  processAction method of the action listener is  executed. However, action listeners do not interact with the navigation  handler.  |     Listing  3-5 shows the application configuration  file with the navigation rules.  Because we selected our outcome  strings so that they uniquely determine the successor web page, we can use a  single navigation rule:    <navigation-rule>      <navigation-case>         <from-outcome>success</from-outcome>         <to-view-id>/success.jsp</to-view-id>      </navigation-case>      <navigation-case>         <from-outcome>again</from-outcome>         <to-view-id>/again.jsp</to-view-id>      </navigation-case>      ...   </navigation-rule>   Figure 3-6 shows the transition  diagram.             Finally, Listing 3-6 shows the message  strings.   Listing 3-3.  javaquiz/web/index.jsp        1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.   5.    <f:view>   6.       <head>    7.          <title><h:outputText value="#{msgs.title}"/></title>   8.       </head>   9.       <body>  10.          <h:form>  11.             <p>  12.                <h:outputText value="#{quiz.question}"/>  13.             </p>  14.             <p>  15.                <h:inputText value="#{quiz.response}"/>  16.             </p>  17.             <p>  18.                <h:commandButton value="#{msgs.answerButton}"   19.                   action="#{quiz.answerAction}"/>  20.             </p>  21.          </h:form>  22.       </body>  23.    </f:view>  24. </html>     
  |    Listing 3-4.  javaquiz/web/done.jsp        1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.       <body>   9.          <h:form>  10.             <p>  11.                <h:outputText value="#{msgs.thankYou}"/>  12.                <h:outputFormat value="#{msgs.score}">   13.                   <f:param value="#{quiz.score}"/>  14.                </h:outputFormat>  15.             </p>  16.             <p>  17.                <h:commandButton value="#{msgs.startOverButton}"  18.                   action="#{quiz.startOverAction}"/>  19.             </p>  20.          </h:form>  21.       </body>  22.    </f:view>  23. </html>     
  |     Listing 3-5.  javaquiz/web/WEB-INF/faces-config.xml        1. <?xml version="1.0"?>   2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   5.         http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"   6.    version="1.2">   7.    <navigation-rule>   8.       <navigation-case>   9.          <from-outcome>success</from-outcome>  10.          <to-view-id>/success.jsp</to-view-id>   11.          <redirect/>  12.       </navigation-case>  13.       <navigation-case>  14.          <from-outcome>again</from-outcome>  15.          <to-view-id>/again.jsp</to-view-id>  16.       </navigation-case>  17.       <navigation-case>  18.          <from-outcome>failure</from-outcome>  19.          <to-view-id>/failure.jsp</to-view-id>  20.       </navigation-case>  21.       <navigation-case>  22.          <from-outcome>done</from-outcome>  23.          <to-view-id>/done.jsp</to-view-id>  24.       </navigation-case>  25.       <navigation-case>  26.          <from-outcome>startOver</from-outcome>  27.          <to-view-id>/index.jsp</to-view-id>  28.       </navigation-case>  29.    </navigation-rule>  30.    <managed-bean>  31.       <managed-bean-name>quiz</managed-bean-name>  32.       <managed-bean-class>com.corejsf.QuizBean</managed-bean-class>  33.       <managed-bean-scope>session</managed-bean-scope>  34.    </managed-bean>  35.  36.    <application>  37.       <resource-bundle>  38.          <base-name>com.corejsf.messages</base-name>  39.          <var>msgs</var>  40.       </resource-bundle>  41.    </application>  42. </faces-config>      
  |     Listing 3-6.  javaquiz/src/java/com/corejsf/messages.properties        1. title=A Java Trivia Quiz   2. answerButton=Check Answer   3. startOverButton=Start over   4. correct=Congratulations, that is correct.   5. notCorrect=Sorry, that was not correct. Please try again!   6. stillNotCorrect=Sorry, that was still not correct.   7. correctAnswer=The correct answer was: {0}.   8. score=Your score is {0}.   9. thankYou=Thank you for taking the quiz.
  |    |