jon 01/05/11 19:13:19
Modified: docs/services intake-service.html
xdocs/services intake-service.xml
Log:
added a ton of docs and clarifications. going to check this in now so that
others can contribute to it...
-jon
Revision Changes Path
1.14 +704 -170 jakarta-turbine/docs/services/intake-service.html
Index: intake-service.html
===================================================================
RCS file: /home/cvs/jakarta-turbine/docs/services/intake-service.html,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- intake-service.html 2001/05/11 21:12:00 1.13
+++ intake-service.html 2001/05/12 02:13:18 1.14
@@ -13,6 +13,8 @@
<meta name="author" value="John
McNally">
<meta name="email" value="[EMAIL PROTECTED]">
+ <meta name="author" value="Jon S. Stevens">
+ <meta name="email" value="[EMAIL PROTECTED]">
<title>Turbine - Turbine Services - Intake</title>
</head>
@@ -154,10 +156,59 @@
<tr><td>
<blockquote>
<p>
- Intake uses an xml specification to perform input validation and
-mapping input data to a bean's properties. The code is still under
-development and so if a feature appears missing, jump in and add it.
+Intake uses an xml specification to perform web form input validation
+and mapping input data to a bean's properties. In other words, Intake
+will allow a web application to take web form input, validate it and
+then map the data to an object. Tools like the <a href="../torque.html">Torque</a>
help provide mapping of Objects to the
+database and Intake helps map web form data to Objects.
</p>
+ <p>
+The visual picture of where Intake fits into a Turbine web application
+looks something like this:
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+------------------
+ HTML Form
+------------------
+ Intake
+------------------
+ Business Objects <- Torque Generated
+------------------
+ Peers <- Torque Generated
+------------------
+ RDBMS
+------------------
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+There are several advantages to using Intake. First off, it provides for
+a centralized management system for dealing with form data. All of the
+configuration of Intake is done through a single XML file. Next, Intake
+is good for validating the form data. Intake provides the ability to do
+regular expression matching in order to make sure that form fields
+contain the data that they should contain. For example, if someone
+should only enter a number into a form field, it can be validated with a
+regular expression. Lastly, Intake can provides a centralized source for
+error messages. If the validation fails, the error message defined in
+the XML file can be shown to the user.
+</p>
</blockquote>
</td></tr>
</table>
@@ -190,11 +241,20 @@
#
# To specify properties of a service use the following syntax:
# service.[name].[property]=[value]
+
+services.IntakeService.classname= \
+org.apache.turbine.services.intake.TurbineIntakeService
-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
</pre></td>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
</tr>
@@ -217,11 +277,42 @@
<tr><td>
<blockquote>
<p>
-Intake is implemented as a service and a pull tool. An xml specification
-is parsed during the service initialization and used by the pull tool
-while processing request data and generating the response.
-The following examples come from <a href="http://scarab.tigris.org">Scarab</a>
- </p>
+Intake is implemented as a Turbine Service and a Pull Tool. An XML
+specification is parsed during the service initialization and used by
+the pull tool while processing request data and generating the response.
+</p>
+ <p>
+Intake is made available in the Velocity context with the default value
+of $intake. The name of the variable that is used is what is configured
+for the tool. For example, the current configuration is "tool.request.intake".
+To change the name of the variable to "foo", it would be "tool.request.foo".
+</p>
+ <p>
+Intake is made available in Java code by adding the following imports to
+the top of a .java file:
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+import org.apache.turbine.services.intake.IntakeTool;
+import org.apache.turbine.services.intake.model.*;
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
</blockquote>
</td></tr>
</table>
@@ -234,8 +325,9 @@
<tr><td>
<blockquote>
<p>
-Here are a couple groups from Scarab's intake.xml:
- </p>
+The following example come from <a href="http://scarab.tigris.org/">Scarab</a>.
These are a couple of
+groups from Scarab's intake.xml:
+</p>
<div align="left">
<table cellspacing="4" cellpadding="0" border="0">
<tr>
@@ -246,29 +338,31 @@
<tr>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
<td bgcolor="#ffffff"><pre>
-
<input-data basePackage="org.tigris.scarab.">
-<group class="AttributeValue" key="attv"
+
+<group name="AttributeValue" key="attv"
mapToObject="om.AttributeValue">
- <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>
- <field name="Value" key="val"
type="String">
- <rule maxLength="255">Value length cannot be &gt;
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 &gt;
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="Value" key="val" type="String">
+ <rule maxLength="255">Value length cannot be &gt;
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 &gt;
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 class="Login" key="login"
mapToObject="om.ScarabUser">
- <field name="Username" key="u" type="String"
mapToProperty="Username">
+<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>
@@ -278,7 +372,6 @@
</group>
</input-data>
-
</pre></td>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
</tr>
@@ -290,12 +383,12 @@
</table>
</div>
<p>
-In the above, fields have been grouped so that they form a logical unit.
-The first group includes some of the properties from an AttributeValue business
-object. The Value property in the BO can take many types of inputs. The Url
-field also maps to the same Value property but can check for valid url
-syntax. The second group maps to a User object, but can also be viewed as a
-group that contains the fields for a single html form.
+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.
</p>
<p>
The group tag has a class attribute which is the name that will be used
@@ -334,8 +427,34 @@
</td></tr>
<tr><td>
<blockquote>
- <p>
-The template:
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+<group name="Login" key="login">
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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.
</p>
<div align="left">
<table cellspacing="4" cellpadding="0" border="0">
@@ -347,42 +466,203 @@
<tr>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
<td bgcolor="#ffffff"><pre>
-
-<form action="$link.setPage("Login.vm")"
method="POST" name="login" >
- <input type="hidden" name="action"
value="Login">
- #if ($data.Parameters.nextTemplate)
- <input type="hidden" name="nextTemplate"
value="$data.Parameters.nextTemplate">
- #else
- <input type="hidden" name="nextTemplate"
value="Start.vm">
- #end
+<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>
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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.
+</p>
+ <p>
+At this point, it is best to show an example form of how to use Intake
+within a Velocity template:
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+(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:
- #set ( $login = $intake.Login.Default )
+(6) #set ( $loginGroup = $intake.Login.Default )
- #if ( !$login.Username.isValid() )
- $login.Username.Message<br>
- #end
- <input name= "$login.Username.Key"
- value="$!login.Username" size="25"
type="text">
+(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>
- Enter your email address.<br>
-<br>
+<p>
Password:
- #if ( !$login.Password.isValid() )
- $login.Password.Message
- #end
- <br>
- <input name= "$login.Password.Key"
- value="" size="25" type="text"
onChange="document.login.submit();">
+(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>
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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.
+</p>
+ <p>
+<ol>
+ <li>
+ 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.
+ </li>
+ <li>
+ 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
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ If (3), then create a hidden input tag that holds the value for
+ nextTemplate.
+ </li>
+ <li>
+ If not (3), then set the nextTemplate to be the "Start.vm" page.
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ It is then possible to query the object to confirm if the
+ information within it is valid.
+ </li>
+ <li>
+ This will display the invalid error message as defined in the
+ intake.xml <rule> definitions.
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ Repeat the same procedure as for the Username field.
+ </li>
+ <li>
+ Repeat the same procedure as for the Username field.
+ </li>
+ <li>
+ A bit of JavaScript will cause the form to submit itself if one hits
+ tab after entering the password.
+ </li>
+ <li>
+ eventSubmit_doLogin is special. It tells Turbine to execute the
+ doLogin method in the Action. This is based on the Action Events
+ system.
+ </li>
+ <li>
+ $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.
+ </li>
+</ol>
+</p>
+ <p>
+Below is an example of the HTML that is sent to the browser after the
+page has been requested:
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+<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>
-Enter your password.<br>
+<p>
+Password:
+ <input name= "login_0p"
+ value="" size="25" type="text"
onchange="document.login.submit();">
+</p>
+
<input type="submit" name="eventSubmit_doLogin"
value="Login">
-$intake.declareGroups()
-</form>
+<input type="hidden" name="intake-grp"
value="login"></input>
+<input type="hidden" name="login"
value="_0"></input>
+
+</form>
</pre></td>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
</tr>
@@ -394,20 +674,24 @@
</table>
</div>
<p>
-In the template above, $intake is provided as a Pull Tool, which provides
-access to the groups/fields. $intake.Login gets the Login group. The fields
-are then accessed using the names from the xml file. The key attribute
-is used in the <input name="">, while the Field's toString() method is
-used to populate the <input value=""> (At least for the username, we do
-not want to prepopulate the password form field.) Error messages for invalid
-input can also be seen in the event the form is reshown. Finally it
-is important to call $intake.declareGroups() right before the ending
-form tag. This will add extra hidden fields to notify intake which groups
-are present, when the form is submitted.
+Some notes to consider:
</p>
+ <ol>
+ <li>
+ The _0 signifies the "default" group.
+ </li>
+ <li>
+ The login_0u signifies the login group combined with the _0 and the
+ "u" is from the intake.xml file for the field "Username".
+ </li>
+ <li>
+ The two hidden input fields are what is generated from the
+ $intake.declareGroups()
+ </li>
+</ol>
<p>
-The action:
- </p>
+The Java Action code which handles the submission of the form looks like this:
+</p>
<div align="left">
<table cellspacing="4" cellpadding="0" border="0">
<tr>
@@ -418,62 +702,245 @@
<tr>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
<td bgcolor="#ffffff"><pre>
+public void doLogin( RunData data, Context context ) throws Exception
+{
+ IntakeTool intake = (IntakeTool)context
+ .get(ScarabConstants.INTAKE_TOOL);
+
+ if ( intake.isAllValid() &amp;&amp; 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"));
+ }
+}
- public void doLogin( RunData data, Context context ) throws Exception
+/**
+ 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
{
- IntakeTool intake = (IntakeTool)context
- .get(ScarabConstants.INTAKE_TOOL);
-
- if ( intake.isAllValid() && checkUser(data, context) )
+ String username = null;
+ String password = null;
+ try
{
- String template = data.getParameters()
- .getString(ScarabConstants.NEXT_TEMPLATE,
- TurbineResources.getString("template.homepage",
"Start.vm") );
- setTemplate(data, template);
+ Group login = intake.get("Login", IntakeTool.DEFAULT_KEY);
+ username = login.get("Username").toString();
+ password = login.get("Password").toString();
}
- else
+ catch ( Exception e )
{
- // Retrieve an anonymous user
- data.setUser (TurbineSecurity.getAnonymousUser());
- setTemplate(data,
- data.getParameters()
- .getString(ScarabConstants.TEMPLATE, "Login.vm"));
+ throw new TurbineSecurityException(
+ "Login information was not supplied.");
}
-
+
+ // Authenticate the user and get the object.
+ user = TurbineSecurity.getAuthenticatedUser( username, password );
+
+ ...
}
+}
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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.
+</p>
+ </blockquote>
+ </td></tr>
+ </table>
+ <table border="0" cellspacing="0"
cellpadding="2" width="100%">
+ <tr><td bgcolor="#525D76">
+ <font color="#ffffff" face="arial,helvetica,sanserif">
+ <a name="Attribute Value example"><strong>Attribute Value
example</strong></a>
+ </font>
+ </td></tr>
+ <tr><td>
+ <blockquote>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+<group name="AttributeValue" key="attv"
+ mapToObject="om.AttributeValue">
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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.
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+<field name="Value" key="val" type="String">
+ <rule maxLength="255">Value length cannot be &gt;
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 &gt;
255</rule>
+ <rule mask="^$|http.+">Please enter an url starting with
"http"</rule>
+ <required-message>This module requires a valid
url.</required-message>
+</field>
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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".
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+#set ( $action =
$link.setPage("EditUrl.vm").setAction("SaveUrl") )
+<form action="$action"
+ method="post">
+
+#set ( $attributeValue = $issue.AttributeValue("URL") )
+#set ( $group = $intake.AttributeValue.mapTo($attributeValue) )
- /**
- 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);
+Enter Url:
+<input type="text" name="$group.Url.Key"
value="$!group.Url.Value">
- 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.");
- }
+<input type="submit" name="eventSubmit_doSave"
value="Submit>
- // Authenticate the user and get the object.
- user = TurbineSecurity.getAuthenticatedUser( username, password );
+$intake.declareGroups()
+</form>
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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.
+</p>
+ <p>
+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.
+</p>
+ <p>
+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.
+</p>
+ <p>
+View source on the HTML page after executing the template and this is
+what the form above would look like:
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+<form
action="http://server/s/servlet/s/template/EnterUrl.vm/action/EnterUrlAction"
+ method="post">
- ...
- }
- </pre></td>
+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>
+</pre></td>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
</tr>
<tr>
@@ -484,13 +951,83 @@
</table>
</div>
<p>
-Here intake is retrieved from the context and asked whether all the
-inputs were valid. If not the login form will be reshown and error
-messages will be given. If the data is valid the field data is extracted
-manually in this case, as the 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.
+When the form is submitted to the server (the user clicks the submit
+button), the following code in the EnterUrlAction.java class is executed.
</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+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
+ }
+}
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
+ <p>
+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.
+</p>
+ <p>
+Back to explaining the fields, lets look at the example again:
+</p>
+ <div align="left">
+ <table cellspacing="4" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#ffffff"><pre>
+ <field name="Value" key="val" type="String">
+ <rule maxLength="255">Value length cannot be &gt;
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 &gt;
255</rule>
+ <rule mask="^$|http.+">Please enter an url starting with
"http"</rule>
+ <required-message>This module requires a valid
url.</required-message>
+ </field>
+</pre></td>
+ <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ <tr>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
+ <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif"
width="1" height="1" vspace="0" hspace="0" border="0"/></td>
+ </tr>
+ </table>
+ </div>
</blockquote>
</td></tr>
</table>
@@ -507,7 +1044,7 @@
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.
- </p>
+</p>
<p>
The template:
</p>
@@ -521,7 +1058,6 @@
<tr>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
<td bgcolor="#ffffff"><pre>
-
#set ( $action =
$link.setPage("entry,Wizard3.vm").setAction("ReportIssue")
.addPathInfo("nextTemplate", "entry,Wizard4.vm") )
#set ($user = $scarabR.User)
@@ -583,7 +1119,6 @@
$intake.declareGroups()
</form>
-
</pre></td>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
</tr>
@@ -613,49 +1148,48 @@
<tr>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
<td bgcolor="#ffffff"><pre>
- 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()));
+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() )
+ if ( intake.isAllValid() )
+ {
+ Iterator i = issue.getModuleAttributeValuesMap()
+ .values().iterator();
+ while (i.hasNext())
{
- 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() )
+ aval = (AttributeValue)i.next();
+ group = intake.get("AttributeValue", aval.getQueryKey());
+ if ( group != null )
{
- issue.save();
+ group.setProperties(aval);
+ }
+ }
+
+ if ( issue.containsMinimumAttributeValues() )
+ {
+ issue.save();
- String template = data.getParameters()
- .getString(ScarabConstants.NEXT_TEMPLATE,
- "entry,Wizard3.vm");
- setTemplate(data, template);
- }
+ String template = data.getParameters()
+ .getString(ScarabConstants.NEXT_TEMPLATE,
+ "entry,Wizard3.vm");
+ setTemplate(data, template);
}
}
-
- </pre></td>
+}
+</pre></td>
<td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1"
height="1" vspace="0" hspace="0" border="0"/></td>
</tr>
<tr>
1.4 +542 -180 jakarta-turbine/xdocs/services/intake-service.xml
Index: intake-service.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine/xdocs/services/intake-service.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- intake-service.xml 2001/04/23 20:13:42 1.3
+++ intake-service.xml 2001/05/12 02:13:18 1.4
@@ -5,6 +5,7 @@
<properties>
<title>Turbine Services - Intake</title>
<author email="[EMAIL PROTECTED]">John McNally</author>
+ <author email="[EMAIL PROTECTED]">Jon S. Stevens</author>
</properties>
<body>
@@ -12,13 +13,47 @@
<section name="Intake Service">
<p>
- Intake uses an xml specification to perform input validation and
-mapping input data to a bean's properties. The code is still under
-development and so if a feature appears missing, jump in and add it.
+Intake uses an xml specification to perform web form input validation
+and mapping input data to a bean's properties. In other words, Intake
+will allow a web application to take web form input, validate it and
+then map the data to an object. Tools like the <a
+href="../torque.html">Torque</a> help provide mapping of Objects to the
+database and Intake helps map web form data to Objects.
</p>
-</section>
+<p>
+The visual picture of where Intake fits into a Turbine web application
+looks something like this:
+</p>
+
+<source><![CDATA[
+------------------
+ HTML Form
+------------------
+ Intake
+------------------
+ Business Objects <- Torque Generated
+------------------
+ Peers <- Torque Generated
+------------------
+ RDBMS
+------------------
+]]></source>
+<p>
+There are several advantages to using Intake. First off, it provides for
+a centralized management system for dealing with form data. All of the
+configuration of Intake is done through a single XML file. Next, Intake
+is good for validating the form data. Intake provides the ability to do
+regular expression matching in order to make sure that form fields
+contain the data that they should contain. For example, if someone
+should only enter a number into a form field, it can be validated with a
+regular expression. Lastly, Intake can provides a centralized source for
+error messages. If the validation fails, the error message defined in
+the XML file can be shown to the user.
+</p>
+
+</section>
<section name="Configuration">
@@ -34,54 +69,84 @@
#
# To specify properties of a service use the following syntax:
# service.[name].[property]=[value]
+
+services.IntakeService.classname= \
+org.apache.turbine.services.intake.TurbineIntakeService
-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
]]></source>
</section>
+<section name="Usage">
+<p>
+Intake is implemented as a Turbine Service and a Pull Tool. An XML
+specification is parsed during the service initialization and used by
+the pull tool while processing request data and generating the response.
+</p>
- <section name="Usage">
- <p>
-Intake is implemented as a service and a pull tool. An xml specification
-is parsed during the service initialization and used by the pull tool
-while processing request data and generating the response.
-The following examples come from <a href="http://scarab.tigris.org">Scarab</a>
- </p>
- </section>
+<p>
+Intake is made available in the Velocity context with the default value
+of $intake. The name of the variable that is used is what is configured
+for the tool. For example, the current configuration is "tool.request.intake".
+To change the name of the variable to "foo", it would be "tool.request.foo".
+</p>
- <section name="Xml File">
+<p>
+Intake is made available in Java code by adding the following imports to
+the top of a .java file:
+</p>
- <p>
-Here are a couple groups from Scarab's intake.xml:
- </p>
<source><![CDATA[
+import org.apache.turbine.services.intake.IntakeTool;
+import org.apache.turbine.services.intake.model.*;
+]]></source>
+
+</section>
+
+<section name="Xml File">
+
+<p>
+The following example come from <a
+href="http://scarab.tigris.org/">Scarab</a>. These are a couple of
+groups from Scarab's intake.xml:
+</p>
+<source><![CDATA[
<input-data basePackage="org.tigris.scarab.">
-<group class="AttributeValue" key="attv"
+
+<group name="AttributeValue" key="attv"
mapToObject="om.AttributeValue">
- <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>
- <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="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 class="Login" key="login" mapToObject="om.ScarabUser">
- <field name="Username" key="u" type="String" mapToProperty="Username">
+<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>
@@ -91,16 +156,17 @@
</group>
</input-data>
-
]]></source>
+
<p>
-In the above, fields have been grouped so that they form a logical unit.
-The first group includes some of the properties from an AttributeValue business
-object. The Value property in the BO can take many types of inputs. The Url
-field also maps to the same Value property but can check for valid url
-syntax. The second group maps to a User object, but can also be viewed as a
-group that contains the fields for a single html form.
+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.
</p>
+
<p>
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
@@ -128,155 +194,453 @@
minimum and maximum, lengths and values, as well as a regex mask.
</p>
- </section>
+</section>
- <section name="Login Example">
+<section name="Login Example">
+<source><![CDATA[
+<group name="Login" key="login">
+]]></source>
+
<p>
-The template:
+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.
</p>
<source><![CDATA[
+<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>
+]]></source>
-<form action="$link.setPage("Login.vm")" method="POST" name="login" >
- <input type="hidden" name="action" value="Login">
- #if ($data.Parameters.nextTemplate)
- <input type="hidden" name="nextTemplate" value="$data.Parameters.nextTemplate">
- #else
- <input type="hidden" name="nextTemplate" value="Start.vm">
- #end
+<p>
+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.
+</p>
+
+<p>
+At this point, it is best to show an example form of how to use Intake
+within a Velocity template:
+</p>
+
+<source><![CDATA[
+(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:
- #set ( $login = $intake.Login.Default )
+(6) #set ( $loginGroup = $intake.Login.Default )
- #if ( !$login.Username.isValid() )
- $login.Username.Message<br>
- #end
- <input name= "$login.Username.Key"
- value="$!login.Username" size="25" type="text">
+(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>
- Enter your email address.<br>
-<br>
+<p>
Password:
- #if ( !$login.Password.isValid() )
- $login.Password.Message
- #end
- <br>
- <input name= "$login.Password.Key"
- value="" size="25" type="text" onChange="document.login.submit();">
+(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>
+]]></source>
+
+<p>
+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.
+</p>
+
+<p>
+<ol>
+ <li>
+ 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.
+ </li>
+ <li>
+ 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
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ If (3), then create a hidden input tag that holds the value for
+ nextTemplate.
+ </li>
+ <li>
+ If not (3), then set the nextTemplate to be the "Start.vm" page.
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ It is then possible to query the object to confirm if the
+ information within it is valid.
+ </li>
+ <li>
+ This will display the invalid error message as defined in the
+ intake.xml <rule> definitions.
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ Repeat the same procedure as for the Username field.
+ </li>
+ <li>
+ Repeat the same procedure as for the Username field.
+ </li>
+ <li>
+ A bit of JavaScript will cause the form to submit itself if one hits
+ tab after entering the password.
+ </li>
+ <li>
+ eventSubmit_doLogin is special. It tells Turbine to execute the
+ doLogin method in the Action. This is based on the Action Events
+ system.
+ </li>
+ <li>
+ $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.
+ </li>
+</ol>
+</p>
-Enter your password.<br>
+<p>
+Below is an example of the HTML that is sent to the browser after the
+page has been requested:
+</p>
+
+<source><![CDATA[
+<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">
-$intake.declareGroups()
-</form>
+<input type="hidden" name="intake-grp" value="login"></input>
+<input type="hidden" name="login" value="_0"></input>
+
+</form>
]]></source>
<p>
-In the template above, $intake is provided as a Pull Tool, which provides
-access to the groups/fields. $intake.Login gets the Login group. The fields
-are then accessed using the names from the xml file. The key attribute
-is used in the <input name="">, while the Field's toString() method is
-used to populate the <input value=""> (At least for the username, we do
-not want to prepopulate the password form field.) Error messages for invalid
-input can also be seen in the event the form is reshown. Finally it
-is important to call $intake.declareGroups() right before the ending
-form tag. This will add extra hidden fields to notify intake which groups
-are present, when the form is submitted.
+Some notes to consider:
</p>
-
- <p>
-The action:
- </p>
+<ol>
+ <li>
+ The _0 signifies the "default" group.
+ </li>
+ <li>
+ The login_0u signifies the login group combined with the _0 and the
+ "u" is from the intake.xml file for the field "Username".
+ </li>
+ <li>
+ The two hidden input fields are what is generated from the
+ $intake.declareGroups()
+ </li>
+</ol>
- <source>
+<p>
+The Java Action code which handles the submission of the form looks like this:
+</p>
- public void doLogin( RunData data, Context context ) throws Exception
+<source><![CDATA[
+public void doLogin( RunData data, Context context ) throws Exception
+{
+ IntakeTool intake = (IntakeTool)context
+ .get(ScarabConstants.INTAKE_TOOL);
+
+ if ( intake.isAllValid() && checkUser(data, context) )
{
- 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
{
- String template = data.getParameters()
- .getString(ScarabConstants.NEXT_TEMPLATE,
- TurbineResources.getString("template.homepage", "Start.vm") );
- setTemplate(data, template);
+ Group login = intake.get("Login", IntakeTool.DEFAULT_KEY);
+ username = login.get("Username").toString();
+ password = login.get("Password").toString();
}
- else
+ catch ( Exception e )
{
- // Retrieve an anonymous user
- data.setUser (TurbineSecurity.getAnonymousUser());
- setTemplate(data,
- data.getParameters()
- .getString(ScarabConstants.TEMPLATE, "Login.vm"));
+ throw new TurbineSecurityException(
+ "Login information was not supplied.");
}
-
+
+ // Authenticate the user and get the object.
+ user = TurbineSecurity.getAuthenticatedUser( username, password );
+
+ ...
}
+}
+]]></source>
- /**
- 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);
+<p>
+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.
+</p>
- 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.");
- }
+</section>
- // Authenticate the user and get the object.
- user = TurbineSecurity.getAuthenticatedUser( username, password );
+<section name="Attribute Value example">
- ...
- }
- </source>
+<source><![CDATA[
+<group name="AttributeValue" key="attv"
+ mapToObject="om.AttributeValue">
+]]></source>
+
+<p>
+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.
+</p>
+
+
+<source><![CDATA[
+<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>
+]]></source>
<p>
-Here intake is retrieved from the context and asked whether all the
-inputs were valid. If not the login form will be reshown and error
-messages will be given. If the data is valid the field data is extracted
-manually in this case, as the 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.
+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".
</p>
+<source><![CDATA[
+#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>
+]]></source>
+
+<p>
+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.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+View source on the HTML page after executing the template and this is
+what the form above would look like:
+</p>
+
+<source><![CDATA[
+<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>
+]]></source>
+
+<p>
+When the form is submitted to the server (the user clicks the submit
+button), the following code in the EnterUrlAction.java class is executed.
+</p>
+
+<source><![CDATA[
+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
+ }
+}
+]]></source>
+
+<p>
+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.
+</p>
+
+<p>
+Back to explaining the fields, lets look at the example again:
+</p>
+
+<source><![CDATA[
+ <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>
+]]></source>
+
</section>
<section name="Multiple groups of the same class in one form">
- <p>
+<p>
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.
- </p>
+</p>
<p>
The template:
</p>
<source><![CDATA[
-
#set ( $action = $link.setPage("entry,Wizard3.vm").setAction("ReportIssue")
.addPathInfo("nextTemplate", "entry,Wizard4.vm") )
#set ($user = $scarabR.User)
@@ -338,7 +702,6 @@
$intake.declareGroups()
</form>
-
]]></source>
<p>
@@ -350,51 +713,50 @@
<p>
The action:
</p>
-
- <source>
- 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()));
+<source>
+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() )
+ if ( intake.isAllValid() )
+ {
+ Iterator i = issue.getModuleAttributeValuesMap()
+ .values().iterator();
+ while (i.hasNext())
{
- 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() )
+ aval = (AttributeValue)i.next();
+ group = intake.get("AttributeValue", aval.getQueryKey());
+ if ( group != null )
{
- issue.save();
+ group.setProperties(aval);
+ }
+ }
+
+ if ( issue.containsMinimumAttributeValues() )
+ {
+ issue.save();
- String template = data.getParameters()
- .getString(ScarabConstants.NEXT_TEMPLATE,
- "entry,Wizard3.vm");
- setTemplate(data, template);
- }
+ String template = data.getParameters()
+ .getString(ScarabConstants.NEXT_TEMPLATE,
+ "entry,Wizard3.vm");
+ setTemplate(data, template);
}
}
-
- </source>
+}
+</source>
<p>
The action shows how the business object or action can let intake know if
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]