jvanzyl     01/05/12 22:04:44

  Modified:    xdocs/howto criteria-howto.xml python-howto.xml
                        sybase-howto.xml
  Added:       xdocs/howto security-howto.xml webmacro-site-howto.xml
  Log:
  - more corrections
  - fixing source tags in python howto
  
  Revision  Changes    Path
  1.2       +3 -3      jakarta-turbine/xdocs/howto/criteria-howto.xml
  
  Index: criteria-howto.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-turbine/xdocs/howto/criteria-howto.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- criteria-howto.xml        2001/05/13 04:21:31     1.1
  +++ criteria-howto.xml        2001/05/13 05:04:44     1.2
  @@ -3,7 +3,7 @@
   <document>
   
    <properties>
  -  <title>Advanced Criteria</title>
  +  <title>Criteria Howto</title>
     <author email="[EMAIL PROTECTED]">Cameron Riley</author>
    </properties>
   
  @@ -12,8 +12,8 @@
   
      <p>
        For a basic description and examples of the Criteria Object with Peers please 
  -     view the <a href="peers.html">Peers</a> and <a href="advpeers.html">Advanced 
Peers</a> 
  -     documents. This document intends to show more advanced techniques using 
Criteria, 
  +     view the <a href="/howto/peers-howto.html">Peers Howto</a> 
  +     document. This document intends to show more advanced techniques using 
Criteria, 
        such as comparators and joins. As always, for more information on the methods 
        available in the Criteria Object, view the javadocs.
      </p>
  
  
  
  1.2       +14 -6     jakarta-turbine/xdocs/howto/python-howto.xml
  
  Index: python-howto.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-turbine/xdocs/howto/python-howto.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- python-howto.xml  2001/05/13 04:21:31     1.1
  +++ python-howto.xml  2001/05/13 05:04:44     1.2
  @@ -58,14 +58,16 @@
       <p>
           Now we need to edit the TurbineResources.properties.  Add the following
           keys to your application's properties:
  -        <source>
  +    </p>
  +        <source><![CDATA[
           services.AssemblerBrokerService.assembler.screen=
           org.apache.turbine.util.assemblerbroker.python.PythonScreenFactory
           services.AssemblerBrokerService.assembler.action=
           org.apache.turbine.util.assemblerbroker.python.PythonActionFactory
   
           services.AssemblerBrokerService.python.path=/path/to/python
  -        </source>
  +        ]]></source>
  +    <p>
           The first two registers the Python Assembler Factories with the
           AssemblerBrokerService.  The last line tells the Python interpreter
           where to find all the .py files for your application.
  @@ -73,7 +75,8 @@
       <p>
           In the root of your services.AssemblerBrokerService.python.path
           you need to add a file named config.py that looks like this:
  -        <source>
  +    </p>
  +        <source><![CDATA[
               import java
   
               from java.io import *
  @@ -93,7 +96,9 @@
               from org.apache.turbine.util             import RunData
               from org.webmacro.servlet                import WebContext
               from org.apache.turbine.services.security   import TurbineSecurity
  -        </source>
  +        ]]></source>
  +        
  +      <p>
           JPython sometimes gets a bit confused with the Servlet Engine
           classloader, which forces us to call sys.add_package for each java
           package that we wish to use in our Python code.  You also need to
  @@ -136,13 +141,16 @@
           test.wm file (I assumer everybody knows how to do this).  Now create a
           test.py and place it in the python-path/screens directory.  It should
           look something like this:
  -        <source>
  +    </p>
  +        <source><![CDATA[
  +
               class Subjectslist(WebMacroSiteScreen):
                  def doBuildTemplate (self,data):
                       context = self.getContext(data)
                       context.put ("me","Leon")
                       context.put ("text","Python is cool");
  -        </source>
  +        ]]></source>
  +    <p>
           For more information about the self parameter see the Python docs.  You
           can call any java code that you would normally be able to use (just
           remember to add it to conf.py) including database, services, etc. You
  
  
  
  1.2       +1 -1      jakarta-turbine/xdocs/howto/sybase-howto.xml
  
  Index: sybase-howto.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-turbine/xdocs/howto/sybase-howto.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- sybase-howto.xml  2001/05/13 04:21:31     1.1
  +++ sybase-howto.xml  2001/05/13 05:04:44     1.2
  @@ -32,7 +32,7 @@
   <LI>Generate your application with the TDK as normal.</LI>
   <LI>Edit the project properties as instructed by the TDK.</LI>
   <LI>
  -Before you run 'build-project.sh init' you will need to create the
  +Before you run 'build.sh init' you will need to create the
   database.  Automatic database creation for Sybase does not currently
   work, so the database must be created first.
   </LI>
  
  
  
  1.1                  jakarta-turbine/xdocs/howto/security-howto.xml
  
  Index: security-howto.xml
  ===================================================================
  <?xml version="1.0"?>
  
  <document>
   <properties>
    <title>Turbine Services</title>
    <author email="[EMAIL PROTECTED]">Cameron Riley</author>
   </properties>
  
  <body>
  
  <section name="Turbine Security">
  
  <p>
  The Turbine Security includes a <a href="services/security-service.html">Security 
Service</a> 
  as well as Actions and Screens that can be extended in the Templating Services.
  </p>
  
  </section>
  
  
  <!-- Start -->
  
  
  <section name="Users, Groups, Roles and Permissions">
  
  <p>
  The default Relational Database schema that Turbine uses for the database security 
  service, and which the TDK is generated with upon initialisation, includes the 
  data structure for the managing of permissions. 
  The default or core schema can be viewed at;
  </p>
  
  <p>
  <ul><a href="turbine-schema.html">Turbine Core Schema</a></ul>
  </p> 
  
  <p>
  The main tables are TURBINE_GROUP, TURBINE_USER, TURBINE_ROLE and 
TURBINE_PERMISSION. 
  The Permissions are the individual actions a user is allowed to take in the system. 
  The Role is a container for the Permissions, in other words a Role can be made of 
  many Permissions. User is an account that is interaction with the System and the 
Group 
  is a something that a User would want to do something in. In the Turbine mailing 
lists 
  it has often been described in the same way as a project. In a project you have 
fulfill 
  a role, however a User doesnt "belong" to a project they merely have a role in that 
  project ( or group ). In this manner too a User can have many Roles within the one 
  Group. For instance a User may have the Role Developer in the Group, but may also 
have 
  the Role of Administrator as well. While initially confusing at first, as there 
  are no group-user or role-user containers, it is a flexible system and strong system.
  </p>
  
  </section>
  
  
  <section name="Access Control Lists">
  
  <p>
  A User's interaction through the system is controlled by the Permissions they are 
  able to partake in. The AccessControlLists manage this information and present it 
via 
  RunData and User Interfaces to the application. The RunData interface through the 
  getACL() method presents the AccessControlList Object.
  </p>
  
  <source>
  
   //get the AccessControlList Object 
   //from RunData
   AccessControlList acl = data.getACL();
  
   //check if the User ( from the http request )
   //has permission to view the invoices
   if( acl.hasPermission("viewinvoice") )
   {
      data.setMessage("You have permission to view the invoices.");
      setTemplate(data, "Invoice.vm");
   }
   else
   {
      data.setMessage("You do not have Permission to view the Invoices");
      setTemplate(data, "UnauthorizedRequest.vm");
   }
  
  </source>
  
  <p>
  This will check if the User has permission to view this in the Global Group which 
  is useful for managing Anonymous Users as well as logged in Users across your 
  application. If however you need stronger security, such as only allowing users that 
  have logged in, and have a Role in a specific Group, the Permission will need to be 
  matched to the Group and User. As an example, assume one of your groups is 
"Accounting" 
  and the Invoice information is only to be viewed by Usersthat have a Role in 
Accounting 
  as well as the Permission "viewinvoice", the above method would be re-written; 
  </p>
  
  <source><![CDATA[
  
   //get the User from RunData
   User user = data.getUser();
  
  
   //get the AccessControlList Object 
   //from RunData
   AccessControlList acl = data.getACL();
  
   //check if the User has logged in,
   //has a role in the group and
   //has permission to view the invoices
   if( user.hasLoggedIn() &&
       acl.hasPermission("viewinvoice", "Accounting") )
   {
      data.setMessage("You have permission to view the invoices.");
      setTemplate(data, "Invoice.vm");
   }
   else
   {
      data.setMessage("You do not have Permission to view the Invoices");
      setTemplate(data, "UnauthorizedRequest.vm");
   }
  
  ]]></source>
  
  <p>
  If instead the Permission could be across any of the Roles the User has, the 
  method acl.hasPermission(String permission, GroupSet groups), can be used. As 
  always check the Javadocs for more detail.
  </p>
  
  
  
  </section>
  
  <section name="Templates and Logging In">
  
  <p>
  Managing Anonymous Users and Logged In Users poses problems in applications for 
managing 
  the Secure/Strong parts of the application and the Unsecure/Weak parts of the 
  application. In Turbine, the Action and Screen components make managing this process 
  quite simple. Assume the only Velocity Template allowed to be viewed without being 
  logged in is the actual Login.vm template. As this is the only Screen that 
  needs to be Unsecure/Weak we can manage this via the parent of Login Screen.
  </p>
  
  
  <source>
  
  package com.mycompany.modules.screens;
  
  //parent which allows Users to view the screen
  public class WeakScreen extends VelocityScreen
  {
  
      //nothing to check that the User 
      //can view this screen   
      protected void doBuildTemplate( RunData data, Context context ) 
          throws Exception
      {
          //call to Super
          super.doBuildTemplate(data, context);
      }
  
  }
  
  package com.mycompany.modules.screens;
  
  //the java component of the Login Velocity Template
  public class Login extends WeakScreen
  {
  
      //nothing to check that the User 
      //can view this screen   
      protected void doBuildTemplate( RunData data, Context context ) 
          throws Exception
      {
          context.put("date",new Date());
  
          //call to Super
          super.doBuildTemplate(data, context);
      }
  
  }
  
  
  
  
  </source>
  
  <p>
  Note that there is nothing in that method which checks that the User has logged in. 
  On the other hand, for the Secure or Strong Actions and Screens we would want a 
  check to ensure that the User has logged in.
  </p>
  
  <source>
  
  package com.mycompany.modules.screens;
  
  //Strong screen which checks for login
  public class StrongScreen extends VelocityScreen
  {
  
      //check that User has Logged in before bothering
      //to add anything to the context.   
      protected void doBuildTemplate( RunData data ) 
          throws Exception
      {
  
          if (data.getUser().hasLoggedIn())   
          {   
              doBuildTemplate( data, TurbineVelocity.getContext( data ) );
          }
          else
          {
              //send the User to the Login Template
              data.setMessage("Please Login first!");
              setTemplate(data,"Login.vm");
          }
      }
  
  }
  
  
  package com.mycompany.modules.screens;
  
  //as an example use the Invoices again
  public class Invoice extends StrongScreen
  {
  
      //can view this screen   
      protected void doBuildTemplate( RunData data, Context context ) 
          throws Exception
      {
          context.put("invoice",new Invoice());
  
          //call to Super
          super.doBuildTemplate(data, context);
      }
  
  
  }
  
  
  </source>
  
  
  <p>
  In the latter example, before the Screen populates the Context it will check for the 
  User being logged in by the doBuildTemplate(data) method in the parent. If the test 
  fails, the context isnt created for the Invoice screen. Another way to manage this 
  is to seperate the screens into two packages, com.mycompany.modules.screens.unsecure 
  and com.mycompany.modules.screens.secure and have a Default.java Screen in each 
  of the packages mimicing the above approaches.
  </p>
  
  </section>
  
  
  
  
  
  </body>
  </document>
  
  
  
  1.1                  jakarta-turbine/xdocs/howto/webmacro-site-howto.xml
  
  Index: webmacro-site-howto.xml
  ===================================================================
  <?xml version="1.0"?>
  
  <document>
   <properties>
    <title>WebMacro Site</title>
    <author email="[EMAIL PROTECTED]">Turbine Documentation Team</author>
   </properties>
  
  <body>
  
  <section name="WebMacro Site">
  
  <p>
  In Turbine, we have excellent integration with the template tool
  <a href="http://www.webmacro.org/";>WebMacro</a>,
  we call this WebMacroSite building. The reason why we want to wrap Turbine
  around WebMacro instead of using it on its own is to provide a completely
  MVC model for building web applications where the framework has control
  over the authentication, security, connection pool, etc and WebMacro is
  simply used as the View portion of the MVC model. Turbine is responsible
  for helping you manage all the different templates as well so that you
  can easily construct a site that both designers and engineers can work
  together on (<strong>that is our primary goal!</strong>). The reason why this is
  good is that it will help you design and build web applications that have
  more functionality and less duplication of code since Turbine is fully
  re-usable.
  </p>
  
  <p>
  Knowledge of how WebMacro works and what a WebMacro Context object is
  are required for understanding this documentation. This documentation also
  assumes that you are using a Servlet API 2.2 and higher serlvet engine
  such as <a href="http://jakarta.apache.org/tomcat/";>Tomcat</a> because
  we are now targeting towards using WAR archives. Although, this should
  work with older servlet engines as well...it just may be slightly harder
  for you to setup. You should also be familiar with the rest of the Turbine
  documentation that is referenced on the <a href="index.html">index page</a>.
  </p>
  
  <p>
  Here is a brief description of the way that the system works: all requests
  are passed through the Turbine Servlet. The servlet is then responsible
  for brokering the request, building up the Context object and then calling
  WebMacro's template engine to process your template document and return
  the results. Pretty simple. Now, lets move on to some more detailed
  instructions...:-)
  </p>
  
  </section>
  
  <section name="Screens">
  
  <p>
  Lets start off with a simple WebMacro Screen to get things rolling
  so you can see how powerful things are. You should compile this class into
  your <em>WEB-INF/classes</em> directory.
  </p>
  
  <source><![CDATA[
  
  // WebMacro Stuff
  import org.webmacro.*;
  import org.webmacro.servlet.*;
  import org.webmacro.util.*;
  
  // Turbine Stuff
  import org.apache.turbine.util.RunData;
  import org.apache.turbine.modules.screens.WebMacroSiteScreen;
  
  public class HelloWorld extends WebMacroSiteScreen
  {
      public void doBuildTemplate( RunData data, Context context )
          throws Exception
      {
          // the context object has already been setup for you!
          context.put ("hello", "this is a test...");
      }
  }
  ]]></source>
  
  <p>
  Ok, as you can see, you do not even need to return a value from your method!
  You simply stuff objects into the WebMacro Context and that is it! Next,
  you will want to create a .wm template of the same name as your class:
  HelloWorld.wm...within that template you will put the BODY portion of your
  page. In other words, there is no reason to put the header/footer into
  this file since that will be built seperately (more documentation on that
  futher down...). You should save this document in your <em>templates/screens/</em>
  directory.
  </p>
  
  <source><![CDATA[
  <p>
      <font color="red">
          $hello of the emergency broadcast station.
      <font>
  </p>
  ]]></source>
  
  <p>
  When you request a URL like this:
  </p>
  
  <p>
  http://www.server.com/servlet/Turbine/template/HelloWorld.wm
  </p>
  
  <p>
  What that will do is cause the system to first execute the HelloWold.java
  class (if it exists) and then it will call WebMacro's template engine directly
  and execute the HelloWorld.wm template and then return the results back
  to you.
  </p>
  
  <p>
  <em>NOTE:</em> Turbine capitalizes the first letter in the class file name
  before looking for the matching class in the classpath.  This allows you to
  follow (somewhat) normal class naming guidelines. For example:
  </p>
  
  <p>
  index.wm and Index.wm both map to Index.class
  
  roleeditor.wm maps to Roleeditor.class
  
  role_editor.wm maps to Role_editor.class
  </p>
  
  <p>
  The result will be a fully formed HTML document with the <em>$hello</em>
  replaced with the value: "this is a test...". If you want to make the URI
  above shorter or easier to read, you could simply re-write things using
  <a href="http://www.apache.org/docs/mod/mod_rewrite.html";>mod_rewrite</a>.
  For example, by removing the "<em>/servlet/Turbine/template</em>" portion
  of the URI.
  </p>
  
  <p>
  As you can see, this is much easier than doing servlet after servlet
  because it removes a lot of the setup and other things that could potentially
  go wrong. It also makes the individual template files easier to manage
  and more re-usable because there isn't any surrounding page layout mixed
  in with the page.
  </p>
  
  <p>
  If you want to do something that is more complicated than this that
  is reflected across all of your Screens, then you should write a class
  that is a subclass of WebMacroSiteScreen and then put your specific code
  in there. For example, if you wanted a security method to be called automaticially
  without having to normally call super() to get it from an overridden method
  in the superclass, you could have something like this (semi-pseudo untested
  code):
  </p>
  
  <source><![CDATA[
  
  // WebMacro Stuff
  import org.apache.webmacro.Context;
  
  // Turbine Stuff
  import org.apache.turbine.util.RunData;
  import org.apache.turbine.modules.screens.WebMacroSiteScreen;
  
  public abstract class SecureScreen extends WebMacroSiteScreen
  {
      protected boolean doCheckSecurity(RunData data)
          throws Exception
      {
          if (data.isSecure())
              return true;
          else
              return false;
      }
  
      /*
       * override the doBuild() method of the
       * TemplateScreen to always check security first
       */
      public void doBuild(RunData data, Context context) throws Exception
      {
          if ( !this.doCheckSecurity(data))
          {
              // set the template and screen to be different or do
              // some other short circuit code here
          }
          doBuildTemplate(data, context);
          return super.buildTemplate(data, context);
      }
  }
  ]]></source>
  
  <p>
  What this would do is override the doBuild() method in TemplateScreen (which
  is the base class that WebMacroSiteScreen subclasses from) and have it
  always do a security check before displaying the content. The benefit of
  this is that all you need to do to add security to your screen is to simply
  subclass this class instead of WebMacroSiteScreen. There is also no need
  to remember to call super() since the doBuild() method will be called for
  you automaticially by Turbine. You can start to see how Turbine is simply
  an extension of the servlet framework itself. For example, the Servlet
  Engine will call HttpServlet's service() method for you, just like Turbine
  will call your doBuild() method for you. Tight integration with tools like
  WebMacro just make things even cleaner. :-)
  </p>
  
  <p>
  One other feature in this system is that if you are not building up
  a Context object that is specific for your screen, then you do not need
  to create a Java class to match the template file. You simply create the
  .wm template and put it in a directory and call it with the same URI described
  above. This is really useful when you have a static site of content that
  you are converting to be dynamic and you only want to do small portions
  of it at any one time. You can also do the opposite of this which is to
  only create a Java class file and no template file. You can do this by
  simply overriding the doBuild() method in TemplateScreen and returning
  your results directly instead of attempting to build a template. Later,
  when you want to add a template and remove the HTML code, you can change
  the doBuild() into a doBuildTemplate(), build the Context object up and
  you are done. Cool!
  </p>
  
  <p>
  Here is an example of having templates in subdirectories and making
  links to each of them...
  </p>
  
  <p>
  Create a directory structure like this:
  </p>
  
  <p>
  WEB-INF/templates/screens/admin/
  Put <em>index.wm</em> into the <em>screens/</em> directory.
  Put <em>UserAdmin.wm</em> into the <em>screens/admin/</em> directory.
  </p>
  
  <p>
  In index.wm, if you want to link to UserAdmin.wm, you would add something
  like this to the HTML:
  </p>
  
  <source><![CDATA[
  
  <a href="$link.setPage("admin,UserAdmin.wm")</font>">User Admin Screen</a>
  
  ]]></source>
  
  <p>
  As you can see above, I used a "," instead of a "/". You can use either
  one here. The above will create a fully formed URI with the session information
  encoded into the link if the clients brower has cookies turned off.
  </p>
  
  </section>
  
  <section name="Layout and Navigations">
  
  <p>
  Now that you know how to create simple Screens, you are probably wondering
  where the layout and navigation portions of the page come from and how
  you control that. If you were not wondering that, then shame on you. :-)
  Essentially, it is the same exact procedure as before except you subclass
  WebMacroSiteLayout and WebMacroSiteNavigation instead. Again, it is possible
  to not have Java class files always match up with the template and in most
  cases, you probably won't need to have a user defined Context in the Layout.
  </p>
  
  <p>
  Below is an example Layout. It will be searched for in the templates/layouts
  directory structure and also takes advantage of the same template path
  lookup code as described below:
  </p>
  
  <source><![CDATA[
  
  #if ( $data.getMessage() )</font>
  {
      $data.getMessage()
  }
  
  <table width="100%">
  
  <tr>
      <td>$navigation.setTemplate("/default_top.wm")</td>
  </tr>
  <tr>
      <td>$screen_placeholder</td>
  </tr>
  <tr>
      <td>$navigation.setTemplate("/default_bottom.wm")</td>
  </tr>
  
  </table>
  
  ]]></source>
  
  <p>
  The variable <em>$screen_placeholder</em> is important here because that
  is where the output from your Screen will be placed. WebMacroSiteLayout
  is responsible for taking care of this. The other variables are for including
  your Navigations into the system. The benefit of all of this is that it
  enforces the View portion of the MVC model because the "body" and "navigation"
  portions of your page simply becomes a variable that you can plug into
  any number of Layouts and in any location. If you want to write code so
  that the Layout is determined by a variable in the database or in the HTTP
  request or whever, all you need to do is write your own WebMacroSiteLayout
  and override some of the methods in there to determine the layout based
  on your own conditions instead of the system default conditions.
  </p>
  
  </section>
  
  <section name="How the templates are found">
  
  <p>
  Since everything is keyed off the template variable, if
  <em>data.getParameters().getString("template")</em>
  returns <em>/about_us/directions/driving.wm</em>, the search for the Screen
  class is as follows (in order):
  <ol>
  <li>
  about_us.directions.Driving</li>
  
  <li>
  about_us.directions.Default</li>
  
  <li>
  about_us.Default</li>
  
  <li>
  Default</li>
  
  <li>
  WebMacroSiteScreen</li>
  </ol>
  </p>
  
  <p>
  If the template variable does not exist, then <em>WebMacroSiteScreen</em>
  will be executed and <em>templates/screens/index.wm</em> will be executed.
  If <em>index.wm</em> is not found or if the template is invalid or WebMacro
  execution throws an exception of any reason, then <em>templates/screens/error.wm</em>
  will be executed.
  </p>
  
  <p>
  For the Layouts and Navigations, the following paths will be searched
  in the layouts and navigations template subdirectories (in order):
  </p>
  
  <p>
  <ol>
  <li>
  /about_us/directions/driving.wm</li>
  
  <li>
  /about_us/directions/default.wm</li>
  
  <li>
  /about_us/default.wm</li>
  
  <li>
  /default.wm</li>
  </ol>
  </p>
  
  </section>
  
  <section name="Actions">
  
  <p>
  Actions happen when you have an <em>action</em> parameter defined in the
  URI. For example:
  </p>
  
  <p>
  <u>http://www.server.com/servlet/Turbine/template/HelloWorld/action/UpdateWorld</u>
  In this case, what happens is that the class UpdateWorld class (located
  in your <em>WEB-INF/classes/PACKAGE/actions/</em> directory) is executed
  first before anything. Then your HelloWorld class (located in your 
WEB-INF/classes/PACKAGE/screens/
  directory) is executed. Then your template (for screen/navigation/layout)
  HelloWorld.wm is executed. The point of an action is that it should perform
  some sort of "action" on your system. Usually, this means storing some
  information from a POST request into a database or sending email or something
  of that nature. Actions themselves do not return results, but may set a
  message with data.setMessage(). They can also short circuit the system
  by changing the Template and Screen to be executed. You might want to do
  that if there is an error with the form data and you want to re-display
  the same page again. Unlike most of the rest of the modules (ie: Screens,
  Navigations, Layouts), there is no corresponding WebMacro template file
  for an Action.
  </p>
  
  <source><![CDATA[
  
  // WebMacro Stuff
  import org.apache.webmacro.Context;
  
  // Turbine Stuff
  import org.apache.turbine.util.RunData;
  import org.apache.turbine.modules.actions.WebMacroAction;
  
  public class AddUser extends WebMacroAction
  {
      public void doPerform( RunData data, Context context ) throws Exception
      {
          if ( data.getParameter.getString("username",null) == null)
          {
              data.setMessage("Username does not exist");
              setTemplate ( data, "AddUser.wm" );
              return;
          }
  
          // store user info into database
          data.setMessage("Information stored!");
          setTemplate( data, "MainMenu.wm");
  
          // stuff something into the WebMacro Context
          context.put ("variable", "foo");
      }
  }
  
  ]]></source>
  
  <p>
  In the very basic example Action above, a check is performed to make sure
  that
  the form data contained a "username" variable. If there is no data, the
  template is changed back to the "AddUser" template and the processing is
  stopped with an error message that can be easily displayed in the template.
  If the processing finishes, then the MainMenu.wm template will be shown
  and the message can be displayed.
  </p>
  
  </section>
  
  <section name="Action Event">
  
  <p>
  There is also a new feature of Turbine that the WebMacroSiteAction takes
  advantage of, it is called <a href="action-event.html">Action Event</a>.
  Please click the link and read more documentation about it. This is an
  excellent way to write your actions because now they are entirely event
  driven based on which button was clicked in the HTML form.
  </p>
  
  </section>
  
  </body>
  </document>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to