Essentials
Get Involved
Documentation
Howto Guides
Development
|
Configuration
|
|
 |
 |
 |
 |
# -------------------------------------------------------------------
#
# S E R V I C E S
#
# -------------------------------------------------------------------
# Classes for Turbine Services should be defined here.
# Format: services.[name].classname=[implementing class]
#
# To specify properties of a service use the following syntax:
# service.[name].[property]=[value]
services.IntakeService.classname= \
org.apache.turbine.services.intake.TurbineIntakeService
# -------------------------------------------------------------------
#
# I N T A K E S E R V I C E
#
# -------------------------------------------------------------------
# The location of the xml file specifying valid inputs
services.IntakeService.xml.path=WEB-INF/conf/intake.xml
tool.request.intake=org.apache.turbine.services.intake.IntakeTool
|
 |
 |
 |
 |
|
|
Xml File
|
|
The following example come from Scarab. These are a couple of
groups from Scarab's intake.xml:
 |
 |
 |
 |
<input-data basePackage="org.tigris.scarab.">
<group name="AttributeValue" key="attv"
mapToObject="om.AttributeValue">
<field name="Value" key="val" type="String">
<rule maxLength="255">Value length cannot be > 255</rule>
<required-message>This module requires data for this
attribute.
</required-message>
</field>
<field name="Url" key="url" type="String" mapToProperty="Value">
<rule maxLength="255">Url length cannot be > 255</rule>
<rule mask="^$|http.+">Please enter an url starting with "http"</rule>
<required-message>This module requires a valid url.</required-message>
</field>
<field name="OptionId" key="optionid" type="NumberKey">
<rule mask="^$|[0-9]+">Please select a valid choice</rule>
<required-message>This module requires that you select an option
for this attribute.
</required-message>
</field>
</group>
<group name="Login" key="login">
<field name="Username" key="u" type="String">
<rule minLength="1">Please enter an email address</rule>
<rule mask=".+@.+\..+">Please enter a valid email address</rule>
</field>
<field name="Password" key="p" type="String">
<rule minLength="1">Please enter a password</rule>
</field>
</group>
</input-data>
|
 |
 |
 |
 |
A group is a set of fields that have been aligned so that they form a
logical unit. The first group includes some of the properties from a
om.AttributeValue business object (BO). This object is a Java Bean
object with get/set methods for each of the properties in the object. In
this case, the object has been auto-generated by Torque from Scarab's
SQL schema.
The group tag has a class attribute which is the name that will be used
within templates and java code to refer to the group. It also contains a
key attribute which will be used in the query parameters. The key is
not referenced in any code, so it can be a short name (even 1 character) as
long as it is uniquely identifies the group from the rest.
An object that the group's fields will map can also be specified. This will
be a default; the individual fields within a group can map to different
objects.
Fields have attributes: name and key which serve similar function to the
group's class and key attributes. It has mapToObject and mapToProperty fields
that can be used to associate a business object to the field for prepopulating
the field as well as assigning the field data to the bean after successful
validation. The field must have a type, which can be simple types such as
String and Integer. It is planned that more complex types, such as
Email, Url, or Date, will be added that will add functionality that is
difficult or not possible with a simple regex mask.
The field can define rule elements. The basic fields include rules for
minimum and maximum, lengths and values, as well as a regex mask.
|
|
Login Example
|
|
 |
 |
 |
 |
<group name="Login" key="login">
|
 |
 |
 |
 |
The name="Login" is a descriptive name for the group. The key="login" is
the value that is used in the web forms to identify the group. The key=
value is not directly referenced. In other words, you do not need to
know it exists unless you are debugging your application. Both of these
attribute values must be unique across all groups in the XML file. Now,
lets look at the fields in the group.
 |
 |
 |
 |
<field name="Username" key="u" type="String">
<rule minLength="1">Please enter an email address</rule>
<rule mask=".+@.+\..+">Please enter a valid email address</rule>
</field>
<field name="Password" key="p" type="String">
<rule minLength="1">Please enter a password</rule>
</field>
|
 |
 |
 |
 |
The name="Username" is the descriptive name for the field. The key="u"
is the value that is used in the web forms to identify the field. Both
of these attributes must be unique across the fields within the group.
The type="String" specifies what the system expects the input for that
field to be (please see the intake.dtd for the allowed values). Within
the field, it is possible to specify one or more rules. These rules
define how Intake should validate web form data. There are minLength,
maxLength and mask attributes to the rule tag. The message inside the
rule tag is a text message which can be used to display an error within
the template.
At this point, it is best to show an example form of how to use Intake
within a Velocity template:
 |
 |
 |
 |
(1) <form action="$link.setPage("Login.vm")" method="POST" name="login" >
(2) <input type="hidden" name="action" value="Login">
(3) #if ($data.Parameters.nextTemplate)
(4) <input type="hidden" name="nextTemplate"
value="$data.Parameters.nextTemplate">
#else
(5) <input type="hidden" name="nextTemplate" value="Start.vm">
#end
<p>
Email Address:
(6) #set ( $loginGroup = $intake.Login.Default )
(7) #if ( !$loginGroup.Username.isValid() )
(8) $loginGroup.Username.Message<br>
#end
(9) <input name= "$loginGroup.Username.Key"
value="$!loginGroup.Username" size="25" type="text">
</p>
<p>
Password:
(10) #if ( !$loginGroup.Password.isValid() )
(11) $loginGroup.Password.Message<br>
#end
(12) <input name= "$loginGroup.Password.Key"
value="" size="25" type="text"
onChange="document.login.submit();">
</p>
(13) <input type="submit" name="eventSubmit_doLogin" value="Login">
(14) $intake.declareGroups()
</form>
|
 |
 |
 |
 |
The example above shows quite a few different concepts with regards to
web application design, so lets break them down a bit, starting from the
top. Each of the important lines have been numbered for easy reference.
-
Create the <form> tag. Within it, we use the $link object to
create a URI for the template "Login.vm". In other words, when the
button is clicked, the page will submit upon itself.
-
Set the Action to execute to be "Login". This can either be a hidden
input field or be defined with the
$link.setPage().setAction("Login") method
-
Check to see if there is a "nextTemplate" defined in the
GET/POST/PATH_INFO information. On success, the Action can use the
nextTemplate field to decide what page to show next.
-
If (3), then create a hidden input tag that holds the value for
nextTemplate.
-
If not (3), then set the nextTemplate to be the "Start.vm" page.
-
This retrieves the default Login Group object from Intake. What this
means is that the group "Login" as defined in Scarab's intake.xml is
represented as an object.
-
It is then possible to query the object to confirm if the
information within it is valid.
-
This will display the invalid error message as defined in the
intake.xml <rule> definitions.
-
Here we define a form input text field. The $loginGroup.Username.Key
specifies an Intake system generated key. The value attribute
$!loginGroup.Username will tell Intake to either display an empty
String or display the previous form submission.
-
Repeat the same procedure as for the Username field.
-
Repeat the same procedure as for the Username field.
-
A bit of JavaScript will cause the form to submit itself if one hits
tab after entering the password.
-
eventSubmit_doLogin is special. It tells Turbine to execute the
doLogin method in the Action. This is based on the Action Events
system.
-
$intake.declareGroups() tells Intake to add a couple hidden input
fields to the page output. These fields represent the Groups that
were used in the template.
Below is an example of the HTML that is sent to the browser after the
page has been requested:
 |
 |
 |
 |
<form action="http://foo:8080/scarab/servlet/scarab/template/Login.vm"
method="POST" name="login" >
<input type="hidden" name="action" value="Login">
<input type="hidden" name="nextTemplate" value="Start.vm">
<p>
Email Address:
<input name= "login_0u"
value="" size="25" type="text">
</p>
<p>
Password:
<input name= "login_0p"
value="" size="25" type="text" onchange="document.login.submit();">
</p>
<input type="submit" name="eventSubmit_doLogin" value="Login">
<input type="hidden" name="intake-grp" value="login"></input>
<input type="hidden" name="login" value="_0"></input>
</form>
|
 |
 |
 |
 |
Some notes to consider:
-
The _0 signifies the "default" group.
-
The login_0u signifies the login group combined with the _0 and the
"u" is from the intake.xml file for the field "Username".
-
The two hidden input fields are what is generated from the
$intake.declareGroups()
The Java Action code which handles the submission of the form looks like this:
 |
 |
 |
 |
public void doLogin( RunData data, Context context ) throws Exception
{
IntakeTool intake = (IntakeTool)context
.get(ScarabConstants.INTAKE_TOOL);
if ( intake.isAllValid() && checkUser(data, context) )
{
String template = data.getParameters()
.getString(ScarabConstants.NEXT_TEMPLATE,
TurbineResources.getString("template.homepage", "Start.vm") );
setTemplate(data, template);
}
else
{
// Retrieve an anonymous user
data.setUser (TurbineSecurity.getAnonymousUser());
setTemplate(data,
data.getParameters()
.getString(ScarabConstants.TEMPLATE, "Login.vm"));
}
}
/**
Checks to make sure that the user exists, has been confirmed.
*/
public boolean checkUser(RunData data, Context context)
throws Exception
{
User user = null;
IntakeTool intake = (IntakeTool)context
.get(ScarabConstants.INTAKE_TOOL);
try
{
String username = null;
String password = null;
try
{
Group login = intake.get("Login", IntakeTool.DEFAULT_KEY);
username = login.get("Username").toString();
password = login.get("Password").toString();
}
catch ( Exception e )
{
throw new TurbineSecurityException(
"Login information was not supplied.");
}
// Authenticate the user and get the object.
user = TurbineSecurity.getAuthenticatedUser( username, password );
...
}
}
|
 |
 |
 |
 |
Intake is retrieved from the context and asked whether all the inputs
that it knows about were valid. If not the login form will be quickly
reshown and error messages will be given. If the data is valid, the
field data is extracted manually in this case, as the Intake fields do
not map directly to a bean object. The next example will use the
group.setProperties() method to directly assign Intake's field data to
the matching beans.
|
|
Attribute Value example
|
|
 |
 |
 |
 |
<group name="AttributeValue" key="attv"
mapToObject="om.AttributeValue">
|
 |
 |
 |
 |
The name="AttributeValue" is simply a descriptive name for the group.
The key="attv" is the value that is used in the web forms to identify
the group. Both of these attributes must be unique across all groups in
the XML file. The mapToObject="om.AttributeValue" is an optional
attribute. This specifies what Java Bean object that this group maps to.
If a mapToObject is not specified, then it is possible to use Intake to
retrieve the values of the data directly instead of getting it from a
populated object. This will be covered in detail further on.
 |
 |
 |
 |
<field name="Value" key="val" type="String">
<rule maxLength="255">Value length cannot be > 255</rule>
<required-message>This module requires data for this
attribute.
</required-message>
</field>
<field name="Url" key="url" type="String" mapToProperty="Value">
<rule maxLength="255">Url length cannot be > 255</rule>
<rule mask="^$|http.+">Please enter an url starting with "http"</rule>
<required-message>This module requires a valid url.</required-message>
</field>
|
 |
 |
 |
 |
The fields within a group relate to the form fields on a web page. At
this point, it is probably best to show an example rather than
explaining in detail what each part of the field tag is. Therefore,
using the fields above in a simple example, one might have a form with a
text entry box that allows you to edit a Url. The filename is:
"EditUrl.vm".
 |
 |
 |
 |
#set ( $action = $link.setPage("EditUrl.vm").setAction("SaveUrl") )
<form action="$action"
method="post">
#set ( $attributeValue = $issue.AttributeValue("URL") )
#set ( $group = $intake.AttributeValue.mapTo($attributeValue) )
Enter Url:
<input type="text" name="$group.Url.Key" value="$!group.Url.Value">
<input type="submit" name="eventSubmit_doSave" value="Submit>
$intake.declareGroups()
</form>
|
 |
 |
 |
 |
To explain the template above, the first #set is done simply for
convenience. The second #set is part of Scarab. It uses the $issue
object to retrieve a "URL" AttributeValue object for a particular issue.
The next #set tells Intake to map that object to the AttributeValue
group. What it does is tell Intake to create an AttributeValue Group
object which has been mapped to the AttributeValue retrieved from the
$issue object. This Group object represents the XML file <group>
as a Java object.
Moving down further into the example, there is the <input> field
which has a name and value attributes. The $group.Url.Key tells Intake
to retrieve the key information for the field. This would evaluate to
"attv_0url". What this is a combination of the group key (attv), a "_0"
is the result of retrieving the "$intake.AttributeValue.Default" and the
"url" is the field key. The value attribute would evaluate to just an
empty String the first time around. The $intake.declareGroups() is a
special method that will create a hidden input field that declares which
groups have been added to the page. We will discuss that in more detail
further down.
View source on the HTML page after executing the template and this is
what the form above would look like:
 |
 |
 |
 |
<form action="http://server/s/servlet/s/template/EnterUrl.vm/action/EnterUrlAction"
method="post">
Enter Url:
<input type="text" name="attv_0url" value="">
<input type="submit" name="eventSubmit_doEnter" value="Submit>
<input type="hidden" name="attv" value="_0">
<input type="hidden" name="intake-grp" value="attv">
</form>
|
 |
 |
 |
 |
When the form is submitted to the server (the user clicks the submit
button), the following code in the EnterUrlAction.java class is executed.
 |
 |
 |
 |
public void doEnter( RunData data, Context context ) throws Exception
{
IntakeTool intake = (IntakeTool)context
.get(ScarabConstants.INTAKE_TOOL);
// check to see if the fields are valid
if ( intake.isAllValid() )
{
// get the "AttributeValue" Group
AttributeValue av = new AttributeValue();
Group group = intake.get("AttributeValue", IntakeTool.DEFAULT_KEY);
group.setProperties (av);
// now av is properly populated with the form data
}
}
|
 |
 |
 |
 |
If the form fields are invalid as a result of not matching one of the
rules that are defined in the fields in the XML file, then the action
does nothing and the page is displayed again.
Back to explaining the fields, lets look at the example again:
 |
 |
 |
 |
<field name="Value" key="val" type="String">
<rule maxLength="255">Value length cannot be > 255</rule>
<required-message>This module requires data for this
attribute.
</required-message>
</field>
<field name="Url" key="url" type="String" mapToProperty="Value">
<rule maxLength="255">Url length cannot be > 255</rule>
<rule mask="^$|http.+">Please enter an url starting with "http"</rule>
<required-message>This module requires a valid url.</required-message>
</field>
|
 |
 |
 |
 |
|
|
Multiple groups of the same class in one form
|
|
This example uses a form from Scarab that assigns values to various
attribute's that are relevant for an issue (bug). Attributes include
summary, operating system, platform, assigned to, etc. Some of the
attributes are required, but not all.
The template:
 |
 |
 |
 |
#set ( $action = $link.setPage("entry,Wizard3.vm").setAction("ReportIssue")
.addPathInfo("nextTemplate", "entry,Wizard4.vm") )
#set ($user = $scarabR.User)
#set ($module = $user.CurrentModule)
#set ($issue = $user.ReportingIssue)
<form method="get" action="$action">
<hr><br>Please fill in the following:<br><br>
#foreach ( $attVal in $issue.OrderedModuleAttributeValues )
#set ( $attrInput = $intake.AttributeValue.mapTo($attVal) )
#if ( $attVal.Attribute.AttributeType.ValidationKey )
#set ( $field = $attVal.Attribute.AttributeType.ValidationKey )
#elseif ($attVal.Attribute.AttributeType.Name == "combo-box" )
#set ( $field = "OptionId" )
#else
#set ( $field = "Value" )
#end
#if ( $attVal.isRequired() )
$attrInput.get($field).setRequired(true)
<b>*</b>
#end
$attVal.Attribute.Name:
#if ($attVal.Attribute.AttributeType.Name == "combo-box" )
<font color="red">
#attrValueErrorMsg ( $attVal $field )
</font>
<br>
#attrValueSelect ($attVal $field "")
#else
<font color="red">
#attrValueErrorMsg ( $attVal $field )
</font>
<br>
#if ($attVal.Attribute.AttributeType.Name == "long-string" )
<textarea name= "$attrInput.Value.Key" cols="40"
rows="5">$!attrInput.Value</textarea>
#else
<input name= "$attrInput.Value.Key"
value="$!attrInput.Value" size="20" type="text">
#end
<br><br>
#end
#end
<p>
<input type="submit"
name="eventSubmit_doEnterissue" value="Submit Issue">
$intake.declareGroups()
</form>
|
 |
 |
 |
 |
The main new thing added here is that the $intake group is mapped to a business
object. A business object that is to be used in this way is expected to
implement the Retrievable interface, which provides a method to get a
String key which uniquely identifies the object.
The action:
 |
 |
 |
 |
public void doEnterissue( RunData data, Context context )
throws Exception
{
IntakeTool intake = (IntakeTool)context
.get(ScarabConstants.INTAKE_TOOL);
// Summary is always required.
ScarabUser user = (ScarabUser)data.getUser();
Issue issue = user.getReportingIssue();
AttributeValue aval = (AttributeValue)issue
.getModuleAttributeValuesMap().get("SUMMARY");
Group group = intake.get("AttributeValue", aval.getQueryKey());
Field summary = group.get("Value");
summary.setRequired(true);
issue.setVocabulary(new Vocabulary(summary.toString()));
if ( intake.isAllValid() )
{
Iterator i = issue.getModuleAttributeValuesMap()
.values().iterator();
while (i.hasNext())
{
aval = (AttributeValue)i.next();
group = intake.get("AttributeValue", aval.getQueryKey());
if ( group != null )
{
group.setProperties(aval);
}
}
if ( issue.containsMinimumAttributeValues() )
{
issue.save();
String template = data.getParameters()
.getString(ScarabConstants.NEXT_TEMPLATE,
"entry,Wizard3.vm");
setTemplate(data, template);
}
}
}
|
 |
 |
 |
 |
The action shows how the business object or action can let intake know if
a field is required. It also shows how multiple groups of the same class
can be added to a template and then the information is easily passed on
to an associated bean.
|
|
|