Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

2.5. Seam pageflow: the numberguess example

For Seam applications with relatively freeform (ad hoc) navigation, JSF/Seam navigation rules are a perfectly good way to define the page flow. For applications with a more constrained style of navigation, especially for user interfaces which are more stateful, navigation rules make it difficult to really understand the flow of the system. To understand the flow, you need to piece it together from the view pages, the actions and the navigation rules.
Seam allows you to use a jPDL process definition to define pageflow. The simple number guessing example shows how this is done.

2.5.1. Understanding the code

The example is implemented using one JavaBean, three JSP pages and a jPDL pageflow definition. Let's begin with the pageflow:
<pageflow-definition name="numberGuess">
   
   <start-page name="displayGuess" view-id="/numberGuess.jsp">
      <redirect/>
      <transition name="guess" to="evaluateGuess">
          <action expression="#{numberGuess.guess}" />
      </transition>
   </start-page>
   
   <decision name="evaluateGuess" expression="#{numberGuess.correctGuess}">
      <transition name="true" to="win"/>
      <transition name="false" to="evaluateRemainingGuesses"/>
   </decision>
   
   <decision name="evaluateRemainingGuesses" expression="#{numberGuess.lastGuess}">
      <transition name="true" to="lose"/>
      <transition name="false" to="displayGuess"/>
   </decision>
   
   <page name="win" view-id="/win.jsp">
      <redirect/>
      <end-conversation />
   </page>
   
   <page name="lose" view-id="/lose.jsp">
      <redirect/>
      <end-conversation />
   </page>
   
</pageflow-definition>
  1. The <page> element defines a wait state where the system displays a particular JSF view and waits for user input. The view-id is the same JSF view id used in plain JSF navigation rules. The redirect attribute tells Seam to use post-then-redirect when navigating to the page. (This results in friendly browser URLs.)
  2. The <transition> element names a JSF outcome. The transition is triggered when a JSF action results in that outcome. Execution will then proceed to the next node of the pageflow graph, after invocation of any jBPM transition actions.
  3. A transition <action> is just like a JSF action, except that it occurs when a jBPM transition occurs. The transition action can invoke any Seam component.
  4. A <decision> node branches the pageflow, and determines the next node to execute by evaluating a JSF EL expression.
Example 2.18. 

Here is what the pageflow looks like in the JBossIDE pageflow editor:
Now that we have seen the pageflow, it is very, very easy to understand the rest of the application!
Here is the main page of the application, numberGuess.jsp:
<%@ taglib uri="https://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="https://java.sun.com/jsf/core" prefix="f"%>
<html>
<head>
<title>Guess a number...</title>
</head>
<body>
<h1>Guess a number...</h1>
<f:view>
    <h:form>
        <h:outputText value="Higher!" rendered="#{numberGuess.randomNumber>numberGuess.currentGuess}" />
        <h:outputText value="Lower!" rendered="#{numberGuess.randomNumber<numberGuess.currentGuess}" />
        <br />
        I'm thinking of a number between <h:outputText value="#{numberGuess.smallest}" /> and 
        <h:outputText value="#{numberGuess.biggest}" />. You have 
        <h:outputText value="#{numberGuess.remainingGuesses}" /> guesses.
        <br />
        Your guess: 
        <h:inputText value="#{numberGuess.currentGuess}" id="guess" required="true">
            <f:validateLongRange
                maximum="#{numberGuess.biggest}" 
                minimum="#{numberGuess.smallest}"/>
        </h:inputText>
        <h:commandButton type="submit" value="Guess" action="guess" />
        <br/>
        <h:message for="guess" style="color: red"/>
    </h:form>
</f:view>
</body>
</html>
Example 2.19. 

Notice how the command button names the guess transition instead of calling an action directly.
The win.jsp page is predictable:
<%@ taglib uri="https://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="https://java.sun.com/jsf/core" prefix="f"%>
<html>
<head>
<title>You won!</title>
</head>
<body>
<h1>You won!</h1>
<f:view>
    Yes, the answer was <h:outputText value="#{numberGuess.currentGuess}" />.
    It took you <h:outputText value="#{numberGuess.guessCount}" /> guesses.
    Would you like to <a href="jboss_application_server_numberGuess.seam">play again</a>?
  </f:view>
</body>
</html>
Example 2.20. 

As is lose.jsp (which I can't be bothered copy/pasting). Finally, the JavaBean Seam component:
@Name("numberGuess")
@Scope(ScopeType.CONVERSATION)
public class NumberGuess {
   
   private int randomNumber;
   private Integer currentGuess;
   private int biggest;
   private int smallest;
   private int guessCount;
   private int maxGuesses;
   
   @Create 
   @Begin(pageflow="numberGuess")
   public void begin()
   {
      randomNumber = new Random().nextInt(100);
      guessCount = 0;
      biggest = 100;
      smallest = 1;
   }
   
   public void setCurrentGuess(Integer guess)
   {
      this.currentGuess = guess;
   }
   
   public Integer getCurrentGuess()
   {
      return currentGuess;
   }
   
   public void guess()
   {
      if (currentGuess>randomNumber)
      {
         biggest = currentGuess - 1;
      }
      if (currentGuess<randomNumber)
      {
         smallest = currentGuess + 1;
      }
      guessCount ++;
   }
   
   public boolean isCorrectGuess()
   {
      return currentGuess==randomNumber;
   }
   
   public int getBiggest()
   {
      return biggest;
   }
   
   public int getSmallest()
   {
      return smallest;
   }
   
   public int getGuessCount()
   {
      return guessCount;
   }
   
   public boolean isLastGuess()
   {
      return guessCount==maxGuesses;
   }

   public int getRemainingGuesses() {
      return maxGuesses-guessCount;
   }

   public void setMaxGuesses(int maxGuesses) {
      this.maxGuesses = maxGuesses;
   }

   public int getMaxGuesses() {
      return maxGuesses;
   }

   public int getRandomNumber() {
      return randomNumber;
   }
}
  1. The first time a JSP page asks for a numberGuess component, Seam will create a new one for it, and the @Create method will be invoked, allowing the component to initialize itself.
  2. The @Begin annotation starts a Seam conversation (much more about that later), and specifies the pageflow definition to use for the conversation's page flow.
Example 2.21. 

As you can see, this Seam component is pure business logic! It doesn't need to know anything at all about the user interaction flow. This makes the component potentially more reuseable.

 
 
  Published under the terms of the Open Publication License Design by Interspire