Tuesday, May 5, 2009

Static Navigation with JavaServer Pages JSF

So, we have seen how a basic request-response cycle happens within a JSF application. During a typical web based interaction, a web client submits a form, which invokes a ‘doXYZ’ method on a managed bean, and the managed bean returns a String from its do method which essentially describes the result of the client-server interaction. Given this String, which in our Rock Paper Scissors game was either the word “win”, “lose”, “tie” or failure, the JSF framework then looks at the appropriate navigation-rule in the faces-config.xml file to figure out which should be rendered for the client.

 

<navigation-rule>
        <from-view-id>/index.jsp</from-view-id>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>youwin</from-outcome>
            <to-view-id>/win.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>youlose</from-outcome>
            <to-view-id>/lose.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>tie</from-outcome>
            <to-view-id>/tie.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>failure</from-outcome>
            <to-view-id>/failure.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>

 

However, not every client-server interaction needs the facilities of a managed bean. Sometimes a web based interaction simply isn’t dynamic. Sometimes you just want to send a user back to a given page in your site. For example, when a user lands on the win, lose, tie or failure JSP page, we’d like to provide a link that asks them if they want to play again. An easy way to do this would by simply having a command button that does not specify a managed bean, but instead, directly describes a navigation outcome by its action attribute (do note that the commandButton needs to be placed within the JSF <h:form> tag):

<h:form>
<h:commandButton value="Play Again?" action="playAgain"/>
</h:form>

 

So, in this case we have a JSF commandButton with the action attribute set to playAgain. We can then simply create a navigation rule indicating that when the win.jsp generates an action of “playAgain”, then the Java ServerFaces framework should send the client to the index.jsp page. The following is the static navigation-rule for the win.jsp as it would need to appear in the faces-config.xml file.

 

<navigation-rule>

    <from-view-id>/win.jsp</from-view-id>
    <navigation-case>
        <from-outcome>playAgain</from-outcome>
        <to-view-id>/index.jsp</to-view-id>
    </navigation-case>

</navigation-rule>

 

Alternatively, on the lose.jsp page, we could use a commandLink, as opposed to a commandButton, to issue the playAgain action to the JSF framework:

<h:form>
<h:commandLink action="playAgain" >
    <h:outputText value="Would you like to play again?"/>
</h:commandLink>
</h:form>

The commandLink is a little more involved, as it requires a nested outputText tag, but in the grand scheme of things, it’s not all that much work. The navigation rule for the lose.jsp would be as follows:

<navigation-rule>

    <from-view-id>/lose.jsp</from-view-id>
    <navigation-case>
        <from-outcome>playAgain</from-outcome>
        <to-view-id>/index.jsp</to-view-id>
    </navigation-case>

</navigation-rule>

Heck, we could even put BOTH a commandLink and a commandButton on the tie.jsp:

 

<h:commandLink action="playAgain" >
    <h:outputText value="Would you like to play again?"/>
</h:commandLink>
<br/>
<h:commandButton value="Play Again?" action="playAgain"/>
</h:form>

The navigation rule entry in the faces-config.xml file for the tie.jsp would be remarkably similar to the win and lose JSP entries:

<navigation-rule>

    <from-view-id>/tie.jsp</from-view-id>
    <navigation-case>
        <from-outcome>playAgain</from-outcome>
        <to-view-id>/index.jsp</to-view-id>
    </navigation-case>

</navigation-rule>

 

Of course, you’re probably seeing a dizzying trend here with static page navigation entries that look eerily the same. Well, if you’re starting to think that there must be some way to simplify a common navigation strategy before the faces-config.xml file becomes a mile long, well, you’d be right.

 

If you have a common from-outcome that might be generated by any number of pages in your application, you can create one, single, navigation-rule that uses a ‘slash/wildcard’ in the from-view-id:

  <from-view-id>/*</from-view-id>

With this configured, any action on any page in your JSF application that triggers the playAction will automatically forward to the page specified in the to-view-id element. So, rather than coding another navigation-rule for the failure.jsp page, let’s just add in the default navigation rule:

<navigation-rule>

    <from-view-id>/*</from-view-id>
    <navigation-case>
        <from-outcome>playAgain</from-outcome>
        <to-view-id>/index.jsp</to-view-id>
    </navigation-case>

</navigation-rule>

Now, after adding a command link to the failure.jsp, we can take advantage of the default navigation case, rather than specifying another entry in the faces-config.xml file:

<h:form>
<h:commandLink action="playAgain" >
    <h:outputText value="Please try again..."/>
</h:commandLink>
</h:form>

If you really wanted to get persnickety, you could just delete the navigation rules dealing with the win, lose and tie JSP pages. I’m going to leave them in just as a reference.

 

<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">

<faces-config>

    <application>
        <locale-config>
            <default-locale>es</default-locale>
            <supported-locale>en</supported-locale>
            <supported-locale>fr</supported-locale>
        </locale-config>
    </application>
    <managed-bean>
        <managed-bean-name>rpsbean</managed-bean-name>
        <managed-bean-class>com.mcnz.jsf.bean.RPSBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>

    <navigation-rule>
        <from-view-id>/index.jsp</from-view-id>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>youwin</from-outcome>
            <to-view-id>/win.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>youlose</from-outcome>
            <to-view-id>/lose.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>tie</from-outcome>
            <to-view-id>/tie.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-action>#{rpsbean.doRockPaperScissorsGame}</from-action>
            <from-outcome>failure</from-outcome>
            <to-view-id>/failure.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>

    <navigation-rule>
        <from-view-id>/win.jsp</from-view-id>
        <navigation-case>
            <from-outcome>playAgain</from-outcome>
            <to-view-id>/index.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>
    <navigation-rule>
        <from-view-id>/lose.jsp</from-view-id>
        <navigation-case>
            <from-outcome>playAgain</from-outcome>
            <to-view-id>/index.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>
    <navigation-rule>
        <from-view-id>/tie.jsp</from-view-id>
        <navigation-case>
            <from-outcome>playAgain</from-outcome>
            <to-view-id>/index.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>
    <navigation-rule>

    <from-view-id>/*</from-view-id>
    <navigation-case>
        <from-outcome>playAgain</from-outcome>
        <to-view-id>/index.jsp</to-view-id>
    </navigation-case>

</navigation-rule>

</faces-config>

No comments:

Post a Comment

Followers