You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@turbine.apache.org by "Dan K." <da...@YorkU.CA> on 2002/04/15 20:10:45 UTC

my how-to guide on intake for turbine 2.1

Hi,

I have written a how-to guide on using Intake for Turbine 2.1
I don't know if this will be useful to the list but since I've written it
for our project documentation I figured I might as well contribute it to
the Turbine 2.1 project doc so that others can benefit.  I'd welcome
feedback on it if you have any.

Thanks,
Dan

---
/**
 * $Id: intake-how-to.txt,v 1.6 2002/04/15 18:05:35 dkha Exp $
 */

A Simple Turbine 2.1 Intake Example How-to
------------------------------------------

First of all I'd like to note that this document is based on my experience in
using Intake for Turbine 2.1.  I've tried to make it as correct as possible but
I don't guarantee anything.  This has been written as a guide for a new Intake
user and assumes some familiarity with Turbine 2.1.

To use intake, the following steps are required:

1. Create your turbine template with a form.
2. Create the intake.xml file.
3. Create a business object to represent the intake group we are working with
   (this is optional).
4. Create the Turbine Action to handle the form submission.


Step 1. Create your turbine template with a form.
-------------------------------------------------

The first thing to do is the create the form in your template (e.g. a velocity
template file, a .vm file).  Just create the skeleton structure and don't
worry about the field names and values yet.  Note that field names will have
match the names specified in the intake.xml file.  Actually you can do the
opposite (name the fields here first and match them in the intake.xml file) if
you wish, but this guide will do it the aforementioned way.

Now add the following lines above the code for your form and modify it to match
the group and field names in your intake.xml file (perhaps you can come back to
do this step after you've done your intake.xml file).  Here is an example in
a Velocity template for a "login form":

    #set($loginGroup = $intake.LoginGroup.Default)

What this does is to set a Velocity variable called $loginGroup to a default
group object specified by intake.xml.  The $intake variable is the Turbine
Pull Tool instance.  The "LoginGroup" is the name of the group as specified in
the intake.xml file (names must match, and this is not the group's key
attribute.).  The "Default" part obtains a generic default intake group object.

Or if you would like to map the intake group to a business object (for whatever
purpose) then you can do this (read on for more info on what is required to do
this in intake.xml and the corresponding Turbine Action class):

    #set($loginGroup = $intake.LoginGroup.mapTo($mytool.getInstanceLoginForm()))

What this does is to set a Velocity variable called $loginGroup to an new
instance of the LoginForm business object.  It makes use of a custom tool placed
into the Velocity context as "$mytool" (you can make your own tool to
instantiate a new instance of your business object similar to this example).

So, depending on the method you use above, the corresponding Turbine Action
code will need to "cooperate" accordingly.  We'll discuss this later in step 4.

Near the end of the form (before you close the <form> tag) include the
following line:

    $intake.declareGroups()

What this does is to fill in hidden form fields into the form for use by
intake.

In order to use Turbine's Action event system, the submit buttons must adhere
to the naming specification defined by Turbine's Action event system.  See
the

*** IMPORTANT NOTE: ***

If you use $link.setAction('SomeAction').setPage('NextTemplate.vm') in your
form's action attribute like this:

<form name="myForm" method="POST"
        action="$link.setAction('LoginAction').setPage('NextTemplate.vm')">
    ...
</form>

then the form validation won't appear to work (i.e. the user will see the
NextTemplate.vm file instead of the form they were trying to fill out which
failed validation).  To work around this problem, you can omit the
setPage('...') part in your form's action attribute and then have your action
route the user to the next template on validation success OR somehow detect
the current form the user is at and if the validation fails, override the next
template to the current template (which is really just overriding the setPage()
part in the template file specified by the web designer).


Step 2. Create the intake.xml file:
-----------------------------------

The intake.xml file specifies the validation rules required to be satisfied
in order for the form to be accepted.  The file has a "root" XML element of
<input-data> and in that would be <group> elements.

Here is an example of the element (with no other sub-elements):
<input-data basePackage="ca.yorku.devteam.inca.clients.inca_auth.om.">
    ...group elements goes here...
</input-data>


Each group element represents a collection of field information you'd like to
validate in your form.  For example, on a login page you would have a form for
the user to input their username and password, and as well as a login button.
This entire form would be grouped as a group in the intake.xml file.

Here is an example of a group with no other elements (not useful yet):

    <group name="LoginGroup" key="loginGroupKey"
        mapToObject="LoginForm">
        ...field elements goes here...
    </group>

The group element can have the following attributes:

"name" attribute:
    - the name of the group, is required, and must be unique across the
      entire intake.xml file.
"key" attribute:
    - the key of the group, is required, and must be unique across the
      entire intake.xml file.
"mapToObject" attribute:
    - optional, used if you want to map the form to a business object.
      Note that the field names specified later by the <field> element in the
      group should match the field names of the business object with appropriate
      get/set methods.  See the <field> tag examples to find how to override
      this default behaviour.

For a complete list of valid attributes in the group element, please see the
intake-service document on the Turbine web site:
http://jakarta.apache.org/turbine/turbine-2/services/intake-service.html


Each group element can contain any number of <field> elements.  Each field
element will correspond to a field in the form.  The name and key of each
field will be used in the form code in the template so make sure the names and
keys match in both files (intake.xml and the template file).

Here is an example of a field with no other elements (not too useful yet):

    <field name="Username" key="loginUsernameKey" type="String"
            mapToProperty="Username">
        ...rule elements goes here...
    </field>

The field element can have the following attributes:

"name" attribute:
    - the name of the field, is required, and must be unique across the
      entire group element.
"key" attribute:
    - the key of the field, is required, and must be unique across the
      entire group element.
"type" attribute:
    - required, the type of the field so that intake will know what to expect.
      Valid types I know of are: String, Integer (I believe these map to
      Java types).  Please see the intake.dtd for the allowed values.
"mapToProperty=" attribute:
    - optional, used if you want to map the form to a business object.
      Note that the field names specified later by the <field> element in the
      group should match the field names of the business object with appropriate
      get/set methods.  See the <field> tag examples to find how to override
      this default behaviour.

For a complete list of valid attributes in the field element, please see the
intake-service document on the Turbine web site:
http://jakarta.apache.org/turbine/turbine-2/services/intake-service.html


In each field element, you can have rules defined.  The supported rule elements
for Intake in Turbine 2.1 are:
<rule name="required" value="true">Error message for required failed</rule>
<rule name="minLength" value="4">Error message for required min length failed</rule>
<rule name="maxLength" value="9">Error message for required max length failed</rule>
<rule name="mask" value="^[0-9]+$">Error message for regular expression failed</rule>

For more info on the supported rules, please see the intake-service document
on the Turbine web site:
http://jakarta.apache.org/turbine/turbine-2/services/intake-service.html



Step 3. Create a business object to represent the intake group we are working
    with (this is optional).
-----------------------------------------------------------------------------

The business object is basically a Java class that has get and set methods for
each of the object's fields, and these get and set method names should match
the field names specified in the intake.xml file (whether we stay with the
default behaviour of matching the field names in intake.xml and the business
object or we use the mapToProperty attribute in the <field> element).  Note
it is required to use the mapToObject property in the group element to use this
feature.

The business object also has to implement the org.apache.turbine.om.Retrievable
interface.  The Retrievable was designed to work with a database so the
methods get/setQueryKey doesn't make much sense if your business object isn't
based on a database model.  For my use, I just force the key to be "_0"
which is the default key used by Intake (as of Turbine 2.1).  You could, of
course, implement it as a normal data field to allow the template to set
the query key and then in the Action to get the query key.  But then you'll
have to keep track of the key you use in both the template file and Action
class (the benefit would be that you'll be able to use more than 1 business
object in the same template if you get/set the different query keys).

Here is an example of how to use the setQueryKey() and getQueryKey() methods
of the business object that implements the Retrievable interface:

In the template file, e.g. myform.vm:
    #set($loginForm = $mytool.getLoginFormInstance())
    $loginForm.setQueryKey("abc")
    #set($loginForm = $intake.LoginGroup.mapTo($loginForm))

In the Action class:
    // This key has to match the one in the template
    String key = "abc";
    Group group = intake.get("LoginGroup", key);


Step 4. Create the Turbine Action to handle the form submission.
----------------------------------------------------------------

Depending on the method you use, the code in the action will need to obtain
the corresponding group object from intake.  The following examples will
demonstrate the ideas.

Here is an example the code in a Turbine Action, using intake without mapping
to a business object (vanilla method):

    /**
     * Performs user login
     */
    public void doLogin(RunData data, Context context)
            throws Exception {
        // Get intake group
        IntakeTool intake =
                (IntakeTool)context.get(IncaAuthConstants.INTAKE_TOOL);

        // Notice how this gets the group named "LoginGroup" as defined in
        // the intake.xml file, and gets it using the default key
        // IntakeTool.DEFAULT_KEY (which is "_0").
        Group group = intake.get("LoginGroup", IntakeTool.DEFAULT_KEY);

        // Check if group fields are valid and if they are not, then return.
        // Intake will handle the validation error and display the
        // corresponding error messages to the user but if you use the setPage()
        // mechanism to get the "next template" then you must now set the
        // template to be the same one as the user was filling out.  Otherwise
        // the user will just see the next template.  See the "important note"
        // in step 1.
        if (!group.isAllValid()) {
            Log.debug("Group elements INVALID");
            setTemplate(data, "Login.vm");
            return;
        } else {
            // If all is validated then you can set the next template and/or
            // continue processing...it's up to you.  You can also use
            // setPage() in the template file to set the next template to show
            // on successful validation.
            setTemplate(data, "LoginSuccess.vm");
        }

        // This gets the value of the "Username" field from the group object
        String username = (String)group.get("Username").getValue();
        String password = (String)group.get("Password").getValue();

        // Now you will be able to use the username and password variable in
        // the rest of the Turbine Action.
        ...
    }


Here is example code in a Turbine Action, using the intake group's default
mapToObject setting (this is the same whether or not you use the field's
mapToProperty attribute):

    /**
     * Performs user login
     */
    public void doLogin(RunData data, Context context)
            throws Exception {
        // Get intake group
        IntakeTool intake =
                (IntakeTool)context.get(IncaAuthConstants.INTAKE_TOOL);
        Group group = intake.get("LoginGroup", IntakeTool.DEFAULT_KEY);

        // Check if group fields are valid and if they are not, then return.
        // Intake will handle the validation error and display the
        // corresponding error messages to the user but if you use the setPage()
        // mechanism to get the "next template" then you must now set the
        // template to be the same one as the user was filling out.  Otherwise
        // the user will just see the next template.  See the "important note"
        // in step 1.
        if (!group.isAllValid()) {
            Log.debug("Group elements INVALID");
            setTemplate(data, "Login.vm");
            return;
        } else {
            // If all is validated then you can set the next template and/or
            // continue processing...it's up to you.  You can also use
            // setPage() in the template file to set the next template to show
            // on successful validation.
            setTemplate(data, "LoginSuccess.vm");
        }

        // Instaniate a business object that represents the form
        LoginForm loginForm = new LoginForm();

        // Set the properties of the form given the field data in the group
        // (i.e. populate the business object)
        group.setProperties(loginForm);

        // Now the business object is populated accordingly.  You can use it
        // for whatever purpose in the rest of the Turbine Action.
        ...
    }


The end.

This document was written by Dan Kha


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>