| <?xml version="1.0"?> |
| <!-- |
| /* |
| * Copyright 2001-2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| --> |
| |
| <document> |
| |
| <properties> |
| <title>Turbine Services - Intake Service</title> |
| </properties> |
| |
| <body> |
| |
| <section name="Intake Service"> |
| |
| <p> |
| 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="http://db.apache.org/torque/">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> |
| |
| <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"> |
| |
| <source><![CDATA[ |
| # ------------------------------------------------------------------- |
| # |
| # 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 |
| ]]></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> |
| |
| <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> |
| |
| <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 name="AttributeValue" key="attv" |
| mapToObject="om.AttributeValue"> |
| <field name="Value" key="val" type="String"> |
| <rule name="maxLength" value="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 name="maxLength" value="255">Url length cannot be > 255</rule> |
| <rule name="mask" value="^$|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 name="mask" value="^$|[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 name="minLength" value="1">Please enter an email address</rule> |
| <rule name="mask" value=".+@.+\..+">Please enter a valid email address</rule> |
| </field> |
| <field name="Password" key="p" type="String"> |
| <rule name="minLength" value="1">Please enter a password</rule> |
| </field> |
| </group> |
| |
| </input-data> |
| ]]></source> |
| |
| <p> |
| 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 |
| 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. |
| </p> |
| <p> |
| 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. |
| </p> |
| <p> |
| 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. |
| </p> |
| <p> |
| The field can define rule elements. The basic fields include rules for |
| minimum and maximum, lengths and values, as well as a regex mask. |
| </p> |
| |
| </section> |
| |
| <section name="Login Example"> |
| |
| <source><![CDATA[ |
| <group name="Login" key="login"> |
| ]]></source> |
| |
| <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> |
| |
| <source><![CDATA[ |
| <field name="Username" key="u" type="String"> |
| <rule name="minLength" value="1">Please enter an email address</rule> |
| <rule name="mask" value=".+@.+\..+">Please enter a valid email address</rule> |
| </field> |
| <field name="Password" key="p" type="String"> |
| <rule name="minLength" value="1">Please enter a password</rule> |
| </field> |
| ]]></source> |
| |
| <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: |
| |
| (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> |
| ]]></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> |
| |
| <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"> |
| |
| <input type="hidden" name="intake-grp" value="login"></input> |
| <input type="hidden" name="login" value="_0"></input> |
| |
| </form> |
| ]]></source> |
| |
| <p> |
| 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 Java Action code which handles the submission of the form looks like this: |
| </p> |
| |
| <source><![CDATA[ |
| public void doLogin( RunData data, Context context ) throws Exception |
| { |
| IntakeTool intake = (IntakeTool) context.get("intake"); |
| |
| 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 ); |
| |
| ... |
| } |
| } |
| ]]></source> |
| |
| <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> |
| |
| </section> |
| |
| <section name="Attribute Value example"> |
| |
| <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 name="maxLength" value="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 name="maxLength" value="255">Url length cannot be > 255</rule> |
| <rule name="mask" value="^$|http.+">Please enter an url starting with "http"</rule> |
| <required-message>This module requires a valid url.</required-message> |
| </field> |
| ]]></source> |
| |
| <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> |
| |
| <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 name="maxLength" value="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 name="maxLength" value="255">Url length cannot be > 255</rule> |
| <rule name="mask" value="^$|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> |
| 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> |
| The template: |
| </p> |
| |
| <source><![CDATA[ |
| #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> |
| ]]></source> |
| |
| <p> |
| 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. |
| </p> |
| <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())); |
| |
| 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); |
| } |
| } |
| } |
| </source> |
| |
| <p> |
| 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. |
| </p> |
| |
| |
| <source><![CDATA[ |
| Dan Diephouse wrote: |
| > |
| > I want to validate a form that updates my business object properties |
| > with intake. I got the latest cvs of turbine-2 repository and built a |
| > new distribution of the turbine jar. I can easily use intake to add |
| > validate items I add to my databse, but I'm running in to a snag when |
| > trying to modify them. I've defined by business object in the intake |
| > validation file. I use the following code to update my item: |
| > |
| > IntakeTool intake = (IntakeTool) context.get("intake"); |
| > |
| > ParameterParser pp = data.getParameters(); |
| > |
| > if ( intake.isAllValid() ) { |
| > Job j = new Job(); |
| > j.setNew(false); |
| > group.setProperties(j); |
| > |
| > JobPeer.doUpdate(j); |
| > |
| > Error--> data.getParameters().add("jobid", j.getJobId().toString()); |
| > data.setMessage("Job updated."); |
| > } else { |
| > data.setMessage("There was an error updating the job. |
| > Check below for further information."); |
| > } |
| > |
| > It runs OK, until I try and retrieve the JobId. I get a Null Pointer |
| > exception. Is there something I'm doing wrong here? Or is this a bug? |
| > Do I need to specify that this is not a new object to intake? I would |
| > include my template, but there are lots of fields so its really long. |
| > But here's a little summary with most fields gone: |
| > |
| > #set ( $job = $basecamp.getJob() ) - This gets a job from a pull tool |
| > #set ( $jobGroup = $intake.Job.mapTo($job) ) |
| > <input type=hidden name="$jobGroup.JobId.Key" |
| > value="$jobGroup.JobId.Value"> |
| > |
| > #if ( !$jobGroup.Title.isValid() ) |
| > $jobGroup.Title.Message<br> |
| > #end |
| > <input type=text name="$jobGroup.Title.Key" |
| > value="$!jobGroup.Title.Value" size="50"> |
| > . |
| > . |
| > . |
| > . |
| > $intake.declareGroups() |
| > |
| > Thanks, |
| > |
| > Dan Diephouse |
| |
| This is not how i usually do things, but I guess it could work. One |
| thing that is wrong is that you are using mapTo(job) in the template and |
| then in the action you are using IntakeTool.DEFAULT_KEY. Unless |
| job.getQueryKey() returns "_0", this combination is not going to work. |
| Print out data.getParameters().toString() in the action to see what the |
| parameters look like. |
| |
| Here is what I consider a normal course of events: |
| |
| 1. In the template: |
| |
| $job = $foo.Job |
| #set ( $jobGroup = $intake.Job.mapTo($job) ) |
| |
| (This job is can be a new Job or one that is already saved.) |
| |
| 2. In the action: |
| |
| // get the same (not necessarilary the same java Object, but has the |
| exact same attribute values) job |
| Job job = foo.getJob() |
| Group group = intake.get("Job", job.getQueryKey()); |
| group.setProperties(job); |
| |
| It appears as though you are trying to map the parameters given for one |
| job to another job. |
| |
| john mcnally |
| ]]></source> |
| |
| </section> |
| |
| <section name="Default Values for fields"> |
| |
| <p> |
| If you want to use input fields which should default to non-empty values for, |
| new objects, you can use the defaultValue field: |
| </p> |
| |
| <source><![CDATA[ |
| <group name="test" key="test"> |
| <field name="Value" key="val" type="String" defaultValue="preset"> |
| </field> |
| </group> |
| ]]></source> |
| |
| <p>If you set up a form like this:</p> |
| |
| <source><![CDATA[ |
| #if($!dz) |
| #set ($frm = $intake.test.mapTo($t)) |
| $frm.Mode. |
| #else |
| #set ($frm = $intake.test.default ) |
| #end |
| |
| <FORM NAME="entryForm"> |
| <INPUT type="text" name="$frm.get("val").Key" value="$!frm.get("val")"> |
| </FORM> |
| ]]></source> |
| |
| <p> |
| then you can either map your form to the fields of the $t object or to the default values, which, for |
| the val Field is the string 'preset'. |
| </p> |
| |
| </section> |
| |
| <section name="Empty fields"> |
| <p> |
| Sometimes you have form fields which are not required (can be left |
| empty) but should be mapped onto a non null value in your bean. This |
| is especially true if you use string fields in conjunction with |
| "required" columns in a database. For this case, you can preset an |
| "empty" value for each field which is used if a field is missing or |
| empty in the form parameters returned by the browser. If you don't set |
| this, the default is "null". |
| </p> |
| |
| <source><![CDATA[ |
| <group name="test" key="test"> |
| <field name="Value" key="val" type="String" emptyValue=""/> |
| </group> |
| ]]></source> |
| |
| <p>This would return the empty String (not a null value) for the "val" field |
| if the user does not enter anything. Without the emptyValue parameter, intake |
| would assign the null value to the bean field.</p> |
| |
| </section> |
| |
| </body> |
| |
| </document> |