joerg       2003/07/30 08:20:10

  Modified:    src/documentation/xdocs/userdocs/flow tutor.xml
  Log:
  made it valid: there was a 'n' between <header/> and <body/>
  code formatting
  
  Revision  Changes    Path
  1.3       +226 -189  
cocoon-2.1/src/documentation/xdocs/userdocs/flow/tutor.xml
  
  Index: tutor.xml
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/documentation/xdocs/userdocs/flow/tutor.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- tutor.xml 27 Jul 2003 15:59:55 -0000      1.2
  +++ tutor.xml 30 Jul 2003 15:20:10 -0000      1.3
  @@ -1,5 +1,5 @@
   <?xml version="1.0" encoding="UTF-8"?>
  -<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN" 
"../../dtd/document-v10.dtd">
  +<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN" 
"document-v10.dtd">
   
   <document>
     <header>
  @@ -8,44 +8,40 @@
         <person name="Ovidiu Predescu" email="[EMAIL PROTECTED]"/>
       </authors>
     </header>
  -n
     <body>
   
  -<s1 title="Tutorial: A Gentle Introduction to Flowscript">
  -<p>In this tutorial, we will create a simple number guessing game using 
Cocoon's Flowscript engine.</p>
  -
  -<p>
  -After you have Cocoon 2.1 deployed and running, go to where you have Cocoon 
deployed and create a new subdirectory named <code>game</code>. Cocoon's 
default main sitemap will automatically mount the sitemap in the 
subdirectory.</p>
  -
  -<p>Create the following <code>sitemap.xmap</code> in the new 
subdirectory:</p>
  -
  -<source><![CDATA[
  -
  +    <s1 title="Tutorial: A Gentle Introduction to Flowscript">
  +      <p>In this tutorial, we will create a simple number guessing game using
  +         Cocoon's Flowscript engine.</p>
  +      <p>After you have Cocoon 2.1 deployed and running, go to where you have
  +        Cocoon deployed and create a new subdirectory named 
<code>game</code>.
  +        Cocoon's default main sitemap will automatically mount the sitemap in
  +        the subdirectory.</p>
  +      <p>Create the following <code>sitemap.xmap</code> in the new 
subdirectory:</p>
  +      <source><![CDATA[
   <?xml version="1.0" encoding="UTF-8"?>
   <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0";>
   
   <map:components>
  -    <map:generators default="file">
  -        <!-- in this example we use JXTemplateGenerator to insert 
  -            Flow variables in page content -->
  -        <map:generator label="content,data" 
  -           logger="sitemap.generator.jxt" name="jxt" 
  -            src="org.apache.cocoon.generation.JXTemplateGenerator"/>
  -    </map:generators>
  -    <map:flow-interpreters default="JavaScript"/>
  -    <map:transformers default="xslt"/>
  -    <map:serializers default="html"/>
  -    <map:matchers default="wildcard"/>
  -    <map:selectors default="browser">
  -      <map:selector name="exception" 
  -        src="org.apache.cocoon.selection.XPathExceptionSelector">
  -        <exception name="invalid-continuation" 
  - class="org.apache.cocoon.components.flow.InvalidContinuationException"/>
  -        <exception class="java.lang.Throwable" unroll="true"/>
  -      </map:selector>
  -    </map:selectors>
  -    <map:actions/>
  -    <map:pipes default="caching"/>
  +  <map:generators default="file">
  +    <!-- in this example we use JXTemplateGenerator to insert
  +         Flow variables in page content -->
  +    <map:generator label="content,data" logger="sitemap.generator.jxt"
  +                   name="jxt" 
src="org.apache.cocoon.generation.JXTemplateGenerator"/>
  +  </map:generators>
  +  <map:flow-interpreters default="JavaScript"/>
  +  <map:transformers default="xslt"/>
  +  <map:serializers default="html"/>
  +  <map:matchers default="wildcard"/>
  +  <map:selectors default="browser">
  +    <map:selector name="exception" 
src="org.apache.cocoon.selection.XPathExceptionSelector">
  +      <exception name="invalid-continuation"
  +                 
class="org.apache.cocoon.components.flow.InvalidContinuationException"/>
  +      <exception class="java.lang.Throwable" unroll="true"/>
  +    </map:selector>
  +  </map:selectors>
  +  <map:actions/>
  +  <map:pipes default="caching"/>
   </map:components>
   
   <map:views/>
  @@ -53,227 +49,268 @@
   <map:action-sets/>
   
   <map:flow language="javascript">
  -    <!-- Flow will use the javascript functions defined in game.js -->
  -    <map:script src="flow/game.js"/>
  +  <!-- Flow will use the javascript functions defined in game.js -->
  +  <map:script src="flow/game.js"/>
   </map:flow>
   
   <map:pipelines>
  - <map:component-configurations>
  +  <map:component-configurations>
       <global-variables/>
  -</map:component-configurations>
  +  </map:component-configurations>
   
  -<map:pipeline>
  +  <map:pipeline>
       <!-- no filename: call main() in game.js -->
       <map:match pattern="">
  -        <map:call function="main"/>
  +      <map:call function="main"/>
       </map:match>
   
       <!-- use JXtemplate to generate page content -->
       <map:match pattern="*.jxt">
  -        <map:generate type="jxt" src="documents/{1}.jxt"/>
  -        <map:serialize type="xhtml"/>
  +      <map:generate type="jxt" src="documents/{1}.jxt"/>
  +      <map:serialize type="xhtml"/>
       </map:match>
   
       <!-- .kont URLs are generated by the Flow system for continuations -->
       <map:match pattern="*.kont">
  -        <map:call continuation="{1}"/>
  +      <map:call continuation="{1}"/>
       </map:match>
  -    
  +
       <!-- handle invalid continuations -->
   
       <!-- this style of handling invalidContinuation is now deprecated: -->
       <!-- this URI will never be called automatically anymore. -->
       <!-- see handle-errors below -->
       <map:match pattern="invalidContinuation">
  -        <map:generate src="documents/invalidContinuation.xml"/>
  -        <map:serialize type="xml"/>
  +      <map:generate src="documents/invalidContinuation.xml"/>
  +      <map:serialize type="xml"/>
       </map:match>
   
       <!-- the new non-hardcoded way of handling invalidContinuation -->
       <map:handle-errors>
  -        <map:select type="exception">
  -            <map:when test="invalid-continuation">
  -                <map:generate src="documents/invalidContinuation.html"/>
  -                <map:serialize type="xhtml"/>
  -            </map:when>
  -        </map:select>
  +      <map:select type="exception">
  +        <map:when test="invalid-continuation">
  +          <map:generate src="documents/invalidContinuation.html"/>
  +          <map:serialize type="xhtml"/>
  +        </map:when>
  +      </map:select>
       </map:handle-errors>
  -
  -</map:pipeline>
  +  </map:pipeline>
   
   </map:pipelines>
  +
   </map:sitemap>
   ]]></source>
  -<p>
  -Inside the new subdirectory, create two more directories, 
<code>documents/</code> and <code>flow/</code>. </p>
  -<p>
  -Inside <code>documents/</code>, you will store the "views" -- pages to send 
to the player. Create the file <code>guess.jxt</code>, which will be the page 
the player will enter their guess: 
  -</p>
  -<source><![CDATA[
  +      <p>Inside the new subdirectory, create two more directories,
  +        <code>documents/</code> and <code>flow/</code>.</p>
  +      <p>Inside <code>documents/</code>, you will store the "views" -- pages 
to
  +        send to the player. Create the file <code>guess.jxt</code>, which 
will
  +        be the page the player will enter their guess:</p>
  +      <source><![CDATA[
   <?xml version="1.0"?>
   <html xmlns:jx="http://apache.org/cocoon/templates/jx/1.0";>
   <head>
  -    <title>cocoon flow number guessing game</title>
  +  <title>cocoon flow number guessing game</title>
   </head>
   <body>
  -    <h1>Guess the Number Between 1 and 10</h1>
  -    <h2>${hint}</h2>
  -    <h3>You've guessed ${guesses} times.</h3>
  -
  -    <form method="post" action="${continuation.id}.kont">
  -        <input type="text" name="guess"/>
  -        <input type="submit"/>        
  -    </form>
  +  <h1>Guess the Number Between 1 and 10</h1>
  +  <h2>${hint}</h2>
  +  <h3>You've guessed ${guesses} times.</h3>
  +  <form method="post" action="${continuation.id}.kont">
  +    <input type="text" name="guess"/>
  +    <input type="submit"/>
  +  </form>
   </body>
   </html>
   ]]></source>
  -<p>
  -You'll also need a page to display when the person chooses the correct 
number. Name it <code>success.jxt</code> (Again in <code>documents/</code>): 
  -</p>
  -<source><![CDATA[
  +      <p>
  +        You'll also need a page to display when the person chooses the 
correct
  +        number. Name it <code>success.jxt</code> (Again in 
<code>documents/</code>):
  +      </p>
  +      <source><![CDATA[
   <?xml version="1.0"?>
  -
   <html xmlns:jx="http://apache.org/cocoon/templates/jx/1.0";>
   <head>
  -    <title>cocoon flow number guessing game</title>
  +  <title>cocoon flow number guessing game</title>
   </head>
   <body>
  -    <h1>Success!</h1>
  -
  -    <h2>The number was: ${random}</h2>
  -    <h3>It took you ${guesses} tries.</h3>
  -    
  -    <p><a href="./">Play again</a></p>
  +  <h1>Success!</h1>
  +  <h2>The number was: ${random}</h2>
  +  <h3>It took you ${guesses} tries.</h3>
  +  <p><a href="./">Play again</a></p>
   </body>
   </html>
   ]]></source>
  -<p>
  -You may notice some strange codes inside the files -- namely things like 
<code>${random}</code> and <code>${guesses}</code> . They look like variables, 
and they will be replaced with values when the pages are sent to the client. 
This is where the <link href="jxtemplate.html">JXTemplateGenerator</link> comes 
in. 
  -</p>
  -<p>
  -Inside <code>flow/</code>, you will store the code that actually controls 
how this application runs. In the "MVC" pattern, the Flow is the "Controller", 
and it is very powerful. 
  -</p>
  -<p>
  -Create the following file named <code>game.js</code>: 
  -</p>
  -<source><![CDATA[
  +      <p>
  +        You may notice some strange codes inside the files -- namely things 
like
  +        <code>${random}</code> and <code>${guesses}</code>. They look like
  +        variables and they will be replaced with values when the pages are
  +        sent to the client. This is where the
  +        <link href="jxtemplate.html">JXTemplateGenerator</link> comes in.
  +      </p>
  +      <p>
  +        Inside <code>flow/</code> you will store the code that actually 
controls
  +        how this application runs. In the "MVC" pattern the Flow is the
  +        "Controller" and it is very powerful.
  +      </p>
  +      <p>
  +        Create the following file named <code>game.js</code>:
  +      </p>
  +      <source><![CDATA[
   function main() {
   
  -    var random =  Math.round( Math.random() * 9 ) + 1;
  +  var random =  Math.round( Math.random() * 9 ) + 1;
   
  -    var hint = "No hint for you!"
  -    var guesses = 0;
  +  var hint = "No hint for you!"
  +  var guesses = 0;
   
  -    while (true) {
  +  while (true) {
   
  -        cocoon.sendPageAndWait("guess.jxt", { "random" : random, 
  -                                 "hint" : hint, "guesses" : guesses} );
  -
  -        var guess = parseInt( cocoon.request.get("guess") );
  -        guesses++;
  -        
  -        if (guess) {
  -            if (guess > random) {
  -                hint = "Nope, lower!"
  -            } else if (guess < random) {
  -                hint = "Nope, higher!"
  -            } else {
  -                break;
  -            }
  -        }
  +    cocoon.sendPageAndWait("guess.jxt", { "random" : random, "hint" : hint,
  +                                          "guesses" : guesses} );
  +
  +    var guess = parseInt( cocoon.request.get("guess") );
  +    guesses++;
  +
  +    if (guess) {
  +      if (guess > random) {
  +        hint = "Nope, lower!"
  +      } else if (guess < random) {
  +        hint = "Nope, higher!"
  +      } else {
  +        break;
  +      }
       }
  +  }
   
  -    cocoon.sendPage("success.jxt", {"random" : random, 
  -                       "guess" : guess, "guesses" : guesses} );
  +  cocoon.sendPage("success.jxt", {"random" : random, "guess" : guess,
  +                                  "guesses" : guesses} );
   }
   ]]></source>
  -<p>
  -Alright, now let's follow the execution of this Flow and pipeline: The 
player accesses the URL <code>http://host/cocoon/game/</code> and the 
&lt;map:match pattern=""&gt; matches, and starts the pipeline. 
  -</p>
  -<p>
  -The function <code>main()</code> which is referenced in 
<code>flow/game.js</code> is called, and a new Continuation object is created. 
Without getting into too much detail, the state of the Javascript code is 
saved, and can be recalled any number of times. 
  -</p>
  -<p>
  -
  -We now enter the code in <code>game.js</code>: 
  -</p>
  -<p>
  -A random number between 1 and 10 is chosen.
  -</p>
  -<p> 
  -Variables containing a hint for the player and the player's current number 
of guesses are initialized.
  -The Flow now enters the <code>while(true)</code> loop which basically keeps 
the game going until the player guesses the correct number. 
  -</p> 
  -<p>
  -We now get to the following line, where things start to get interesting: 
  -</p>
  -<source>
  +      <p>
  +        Alright, now let's follow the execution of this Flow and pipeline: 
The
  +        player accesses the URL <code>http://host/cocoon/game/</code> and the
  +        &lt;map:match pattern=""&gt; matches, and starts the pipeline.
  +      </p>
  +      <p>
  +        The function <code>main()</code> which is referenced in
  +        <code>flow/game.js</code> is called and a new Continuation object is
  +        created. Without getting into too much detail the state of the 
Javascript
  +        code is saved and can be recalled any number of times.
  +      </p>
  +      <p>We now enter the code in <code>game.js</code>:</p>
  +      <p>A random number between 1 and 10 is chosen.</p>
  +      <p>
  +        Variables containing a hint for the player and the player's current
  +        number of guesses are initialized. The Flow now enters the
  +        <code>while(true)</code> loop which basically keeps the game going 
until
  +        the player guesses the correct number.
  +      </p>
  +      <p>We now get to the following line, where things start to get 
interesting:</p>
  +      <source>
   cocoon.sendPageAndWait("guess.jxt", { "random" : random, "hint" : hint, 
"guesses" : guesses} );
   </source>
  -<p>
  -The Flow layer sends the contents of the URI "guess.jxt" which is matched in 
the sitemap (see above). We also pass an inline Javascript object, containing 
three key/value pairs, one named "random" which contains the value of the 
variable random as initialized above, and so on for hint and guesses. The keys 
are substituted later down the line, when the JXTemplateGenerator comes into 
play. 
  -</p>
  -<p>
  -We could also do the following: 
  -</p>
  -<source>
  +      <p>
  +        The Flow layer sends the contents of the URI "guess.jxt" which is 
matched
  +        in the sitemap (see above). We also pass an inline Javascript object,
  +        containing three key/value pairs, one named "random" which contains 
the
  +        value of the variable random as initialized above, and so on for 
hint and
  +        guesses. The keys are substituted later down the line, when the
  +        <code>JXTemplateGenerator</code> comes into play.
  +      </p>
  +      <p>We could also do the following:</p>
  +      <source>
   cocoon.sendPageAndWait("guess.jxt", { "foo" : random } );
   </source>
  -<p>
  -In this case, the value of random would be able to be substituted in our 
JXTemplate, but under the name "foo"" instead -- we'd just have to make sure we 
have the correct keyname in our template. 
  -</p>
  -<p>
  -The Flow Layer also does another interesting thing: it halts the execution 
of the Javascript! Through the magic of continuations, the Flow Layer is able 
to resume execution of the script at the exact line in which it left off. This 
creates some very powerful situations with respect to web programming, and 
forces the reader to think very differently about how web applications are 
designed. 
  -</p>
  -<p>
  -Picking back up in the script execution, the client is sent through the 
pipeline matching "guess.jxt". Referring back to the sitemap, we match *.jxt, 
and run the file through the JXTemplateGenerator, which substitutes the 
keynames for the values sent from the <link 
href="api.html#sendPageAndWait">cocoon.sendPageAndWait()</link> function. 
  -</p>
  -<p>
  -One thing to note is in the form which is sent back to Cocoon when the 
player submits the guess: 
  -</p>
  -<source><![CDATA[
  +      <p>
  +        In this case, the value of random would be able to be substituted in 
our
  +        JXTemplate, but under the name "foo" instead -- we'd just have to 
make
  +        sure we have the correct keyname in our template.
  +      </p>
  +      <p>
  +        The Flow Layer also does another interesting thing: it halts the
  +        execution of the Javascript! Through the magic of continuations the 
Flow
  +        Layer is able to resume execution of the script at the exact line in
  +        which it left off. This creates some very powerful situations with
  +        respect to web programming, and forces the reader to think very
  +        differently about how web applications are designed.
  +      </p>
  +      <p>
  +        Picking back up in the script execution, the client is sent through
  +        the pipeline matching "guess.jxt". Referring back to the sitemap, we
  +        match *.jxt, and run the file through the JXTemplateGenerator, which
  +        substitutes the keynames for the values sent from the
  +        <link href="api.html#sendPageAndWait">cocoon.sendPageAndWait()</link>
  +        function.
  +      </p>
  +      <p>
  +        One thing to note is in the form which is sent back to Cocoon when 
the
  +        player submits the guess:
  +      </p>
  +      <source><![CDATA[
   <form method="post" action="${continuation.id}.kont">
   ]]></source>
  -<p>
  -Here, ${continuation.id} is resolved to a unique identifier which points to 
the current continuation. One can think of this somewhat of a session ID. 
  -</p>
  -<p>
  -When the player submits the form, it is submitted to a unique URL which 
contains the continuation ID, plus ".kont", which we end up matching in the 
sitemap: 
  -</p>
  -<source><![CDATA[
  -
  +      <p>
  +        Here, ${continuation.id} is resolved to a unique identifier which 
points
  +        to the current continuation. One can think of this somewhat of a 
session ID.
  +      </p>
  +      <p>
  +        When the player submits the form, it is submitted to a unique URL 
which
  +        contains the continuation ID, plus ".kont", which we end up matching 
in
  +        the sitemap:
  +      </p>
  +      <source><![CDATA[
   <map:match pattern="*.kont">
  -    <map:call continuation="{1}"/>
  +  <map:call continuation="{1}"/>
   </map:match>
   ]]></source>
  -<p>
  -When Cocoon sees a URL like this, it attempts to restart the continuation 
with the specified ID, and we re-enter the Javascript code where we left off 
previously. 
  -</p>
  -<p>
  -
  -We are now back in the Javascript at the line after <link 
href="api.html#sendPageAndWait">sendPageAndWait()</link>. We create a new 
variable (an int), which we get from the POST request that was sent by the 
form. Notice in the form we had <code>&lt;input type="text" 
name="guess"/&gt;</code> and in the Javascript we get the request parameter by 
using <code>cocoon.request.get("guess");</code> 
  -</p>
  -<p>
  -Now we increment the player's guess count, and we test to see if they 
guessed the correct number. If the guess was too high, we set the hint variable 
telling them to guess lower, and we fall through the bottom of the while loop, 
and we send the guess form back to the player. 
  -</p>
  -<p>
  -If the guess was too low, we tell them to guess higher, and we fall through 
the loop as well, sending the player the form again. 
  -</p>
  -<p>
  -If the guess was correct, we break out of the main loop and send the player 
to a different view, this time to "success.jxt", and we give the template not 
only their number and the random number (pointless, yes, because they were the 
same), but also the number of guesses to tell the player how good or bad at 
guessing numbers they are. 
  -</p>
  -<p>
  -The main point of interest in the Flow script at this point is the use of 
<code>sendPage()</code> instead of <code>sendPageAndWait()</code>. 
<code>sendPage()</code> works exactly the same, except, yes, you guessed it, we 
don't halt execution of code, and keep processing. 
  -</p>
  -<p>
  -At this point, there's no more code left and the game is over, and the Flow 
stops. 
  -</p>
  -<p>
  -Another thing to note is the &lt;map:handle-errors&gt; tag in the sitemap. 
Previously, when a continuation which did not exist was called, the Flow layer 
would automatically redirect to the URI "invalidContinuation". Now, the Flow 
layer throws an <code>InvalidContinuationException</code>, and you can now 
handle it as described in the handle-errors tag. 
  -</p>
  -<p>
  -And that's it! You have now just made your very first application using the 
Flow layer. 
  -</p>
  +      <p>
  +        When Cocoon sees a URL like this, it attempts to restart the 
continuation
  +        with the specified ID and we re-enter the Javascript code where we 
left
  +        off previously.
  +      </p>
  +      <p>
  +        We are now back in the Javascript at the line after
  +        <link href="api.html#sendPageAndWait">sendPageAndWait()</link>. We 
create
  +        a new variable (an int), which we get from the POST request that was 
sent
  +        by the form. Notice in the form we had
  +        <code>&lt;input type="text" name="guess"/&gt;</code> and in the 
Javascript
  +        we get the request parameter by using 
<code>cocoon.request.get("guess");</code>.
  +      </p>
  +      <p>
  +        Now we increment the player's guess count and we test to see if they
  +        guessed the correct number. If the guess was too high, we set the 
hint
  +        variable telling them to guess lower, we fall through the bottom of
  +        the while loop and we send the guess form back to the player.
  +      </p>
  +      <p>
  +        If the guess was too low, we tell them to guess higher, we fall 
through
  +        the loop as well sending the player the form again.
  +      </p>
  +      <p>
  +        If the guess was correct, we break out of the main loop and send the
  +        player to a different view, this time to "success.jxt", and we give 
the
  +        template not only their number and the random number (pointless, yes,
  +        because they were the same), but also the number of guesses to tell 
the
  +        player how good or bad at guessing numbers they are.
  +      </p>
  +      <p>
  +        The main point of interest in the Flow script at this point is the 
use of
  +        <code>sendPage()</code> instead of <code>sendPageAndWait()</code>.
  +        <code>sendPage()</code> works exactly the same, except, yes, you 
guessed
  +        it, we don't halt execution of code and keep processing.
  +      </p>
  +      <p>At this point there's no more code left and the game is over and 
the Flow stops.</p>
  +      <p>
  +        Another thing to note is the &lt;map:handle-errors&gt; tag in the 
sitemap.
  +        Previously, when a continuation which did not exist was called, the 
Flow
  +        layer would automatically redirect to the URI "invalidContinuation". 
Now,
  +        the Flow layer throws an <code>InvalidContinuationException</code> 
and
  +        you can now handle it as described in the handle-errors tag.
  +      </p>
  +      <p>
  +        And that's it! You have now just made your very first application 
using
  +        the Flow layer.
  +      </p>
       </s1>
     </body>
   </document>
  
  
  

Reply via email to