| <!DOCTYPE html> |
| <!-- |
| | Generated by Apache Maven Doxia Site Renderer 1.9.2 from xdocs/howto.xml at 21 September 2021 |
| | Rendered using Apache Maven Fluido Skin 1.9 |
| --> |
| <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| <meta name="generator" content="Apache Maven Doxia Site Renderer 1.9.2" /> |
| <meta name="author" content="Jeffery Painter" /> |
| <meta name="author" content="John McNally" /> |
| <meta name="author" content="Jon S. Stevens" /> |
| <meta name="author" content="Eric Pugh" /> |
| <title>Fulcrum Intake – Fulcrum Intake Service</title> |
| <link rel="stylesheet" href="./css/apache-maven-fluido-1.9.min.css" /> |
| <link rel="stylesheet" href="./css/site.css" /> |
| <link rel="stylesheet" href="./css/print.css" media="print" /> |
| <script src="./js/apache-maven-fluido-1.9.min.js"></script> |
| </head> |
| <body class="topBarDisabled"> |
| <div class="container-fluid"> |
| <header> |
| <div id="banner"> |
| <div class="pull-left"><a href="../../" id="bannerLeft" title="Apache Turbine"><img src="../../images/turbine-project.png" alt="Apache Turbine"/></a></div> |
| <div class="pull-right"></div> |
| <div class="clear"><hr/></div> |
| </div> |
| |
| <div id="breadcrumbs"> |
| <ul class="breadcrumb"> |
| <li id="publishDate">Last Published: 21 September 2021<span class="divider">|</span> |
| </li> |
| <li id="projectVersion">Version: 2.0.1-SNAPSHOT</li> |
| <li class="pull-right"><span class="divider">|</span> |
| <a href="../" title="Fulcrum">Fulcrum</a></li> |
| <li class="pull-right"><span class="divider">|</span> |
| <a href="../../" title="Turbine">Turbine</a></li> |
| <li class="pull-right"><a href="https://www.apache.org" class="externalLink" title="Apache">Apache</a></li> |
| </ul> |
| </div> |
| </header> |
| <div class="row-fluid"> |
| <header id="leftColumn" class="span2"> |
| <nav class="well sidebar-nav"> |
| <ul class="nav nav-list"> |
| <li class="nav-header">Overview</li> |
| <li><a href="index.html" title="Main"><span class="none"></span>Main</a></li> |
| <li class="active"><a href="#"><span class="none"></span>Howto</a></li> |
| <li class="nav-header">Project Documentation</li> |
| <li><a href="project-info.html" title="Project Information"><span class="icon-chevron-right"></span>Project Information</a></li> |
| <li><a href="project-reports.html" title="Project Reports"><span class="icon-chevron-right"></span>Project Reports</a></li> |
| <li class="nav-header">Apache</li> |
| <li><a href="https://www.apache.org/" class="externalLink" title="Apache Website"><span class="none"></span>Apache Website</a></li> |
| <li><a href="https://www.apache.org/licenses/" class="externalLink" title="License"><span class="none"></span>License</a></li> |
| <li><a href="https://www.apache.org/foundation/how-it-works.html" class="externalLink" title="How the ASF works"><span class="none"></span>How the ASF works</a></li> |
| <li><a href="https://www.apache.org/foundation/sponsorship.html" class="externalLink" title="Sponsorship"><span class="none"></span>Sponsorship</a></li> |
| <li><a href="https://www.apache.org/foundation/thanks.html" class="externalLink" title="Thanks"><span class="none"></span>Thanks</a></li> |
| <li><a href="https://www.apache.org/security/" class="externalLink" title="Security"><span class="none"></span>Security</a></li> |
| </ul> |
| </nav> |
| <div class="well sidebar-nav"> |
| <hr /> |
| <div id="poweredBy"> |
| <div class="clear"></div> |
| <div class="clear"></div> |
| <div class="clear"></div> |
| <a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy"><img class="builtBy" alt="Built by Maven" src="./images/logos/maven-feather.png" /></a> |
| </div> |
| </div> |
| </header> |
| <main id="bodyColumn" class="span10" > |
| |
| |
| |
| |
| <section> |
| <h2><a name="Intake_Service"></a>Intake Service</h2> |
| |
| |
| <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 class="externalLink" 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. Intake can be used |
| standalone by any application that supports Avalon components. However it |
| has extensive integration with the <a class="externalLink" href="http://turbine.apache.org/">Turbine</a> |
| application framework. This HowTo focuses on using it with Turbine. |
| </p> |
| |
| |
| <p> |
| The visual picture of where Intake fits into a Turbine web application |
| looks something like this: |
| </p> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| ------------------ |
| HTML Form |
| ------------------ |
| Intake |
| ------------------ |
| Business Objects <- e.g. Torque Generated |
| ------------------ |
| Peers <- e.g. Torque Generated |
| ------------------ |
| RDBMS |
| ------------------ |
| </pre></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. Intake also supports the input of localized values and |
| does the right thing based on the Locale the user requested. Lastly, Intake can |
| provide 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> |
| <h2><a name="Usage"></a>Usage</h2> |
| |
| <p> |
| Intake is implemented as a Avalon component. Access to it is provided by |
| a Turbine Pull Tool. One or more XML specifications are 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 class="source"><pre class="prettyprint"> |
| import org.apache.fulcrum.intake.model.*; |
| import org.apache.turbine.services.intake.IntakeTool; |
| </pre></div> |
| |
| </section> |
| |
| <section> |
| <h2><a name="Xml_File"></a>Xml File</h2> |
| |
| |
| <p> |
| The following example comes from <a class="externalLink" href="http://scarab.tigris.org/">Scarab</a>. These are a couple of |
| groups from Scarab's intake.xml: |
| </p> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| <input-data xmlns="http://turbine.apache.org/schema/intake/4.0" 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 &gt; 255</rule> |
| <rule name="required" value="true">This module requires data for |
| this attribute. |
| </rule> |
| </field> |
| <field name="Url" key="url" type="String" mapToProperty="Value"> |
| <rule name="maxLength" value="255">Url length cannot be &gt; 255</rule> |
| <rule name="mask" value="^$|http.+">Please enter an url starting with "http"</rule> |
| <rule name="required" value="true">This module requires a valid url.</rule> |
| </field> |
| <field name="OptionId" key="optionid" type="NumberKey"> |
| <rule name="mask" value="^$|[0-9]+">Please select a valid choice</rule> |
| <rule name="required" value="true">This module requires that you select |
| an option for this attribute. |
| </rule> |
| </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> |
| </pre></div> |
| |
| |
| <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 <code>name</code> attribute which is the name that will be used |
| within templates and java code to refer to the group. It also contains a |
| <code>key</code> 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: <code>name</code> and <code>key</code> which serve |
| similar function to the group's <code>name</code> and <code>key</code> |
| attributes. It has <code>mapToObject</code> and <code>mapToProperty</code> 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 <code>type</code> out of the following |
| supported types: |
| </p> |
| <ul> |
| |
| <li><code>boolean</code></li> |
| |
| <li><code>BigDecimal</code> This field type supports localization.</li> |
| |
| <li><code>int</code></li> |
| |
| <li><code>float</code> This field type supports localization.</li> |
| |
| <li><code>FileItem</code></li> |
| |
| <li><code>String</code> (default)</li> |
| |
| <li><code>DateString</code></li> |
| |
| <li><code>double</code> This field type supports localization.</li> |
| |
| <li><code>short</code></li> |
| |
| <li><code>long</code></li> |
| |
| <li><code>custom</code> Custom field types can be defined by using this type. |
| The class name of the customized field must be given in the <code>fieldClass</code> |
| attribute then. The custom class must extend the class |
| <code>org.apache.fulcrum.intake.model.Field</code>. This way, more |
| complex types, such as Email, Url, or Date, can be added that add functionality |
| that is difficult or not possible with a simple regex mask.</li> |
| </ul> |
| The field types supporting localization will parse the given strings from the |
| request using the locale from the parser to allow the entry of floating point numbers with |
| localized decimal separators. |
| |
| |
| <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> |
| <h2><a name="Login_Example"></a>Login Example</h2> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| <group name="Login" key="login"> |
| </pre></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 class="source"><pre class="prettyprint"> |
| <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> |
| </pre></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 class="source"><pre class="prettyprint"> |
| (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> |
| </pre></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> |
| </p> |
| <ol style="list-style-type: decimal"> |
| |
| <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> |
| Below is an example of the HTML that is sent to the browser after the |
| page has been requested: |
| </p> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| <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> |
| </pre></div> |
| |
| |
| <p> |
| Some notes to consider: |
| </p> |
| |
| |
| <ol style="list-style-type: decimal"> |
| |
| <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> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| public void doLogin( PipelineData pipelineData, Context context ) throws Exception |
| { |
| // get a reference to the run data object |
| RunData data = (RunData) pipelineData; |
| |
| IntakeTool intake = (IntakeTool) context.get("intake"); |
| |
| 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")); |
| } |
| } |
| |
| /** |
| 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 ); |
| |
| ... |
| } |
| } |
| </pre></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> |
| |
| </section> |
| |
| <section> |
| <h2><a name="Attribute_Value_example"></a>Attribute Value example</h2> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| <group name="AttributeValue" key="attv" |
| mapToObject="om.AttributeValue"> |
| </pre></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 class="source"><pre class="prettyprint"> |
| <field name="Value" key="val" type="String"> |
| <rule name="maxLength" value="255">Value length cannot be &gt; 255</rule> |
| <rule name="required" value="true">This module requires data for |
| this attribute. |
| </rule> |
| </field> |
| <field name="Url" key="url" type="String" mapToProperty="Value"> |
| <rule name="maxLength" value="255">Url length cannot be &gt; 255</rule> |
| <rule name="mask" value="^$|http.+">Please enter an url starting with "http"</rule> |
| <rule name="required" value="true">This module requires a valid url.</rule> |
| </field> |
| </pre></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 class="source"><pre class="prettyprint"> |
| #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> |
| </pre></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 class="source"><pre class="prettyprint"> |
| <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> |
| </pre></div> |
| |
| |
| <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> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| public void doEnter( PipelineData pipelineData, 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></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 class="source"><pre class="prettyprint"> |
| <field name="Value" key="val" type="String"> |
| <rule name="maxLength" value="255">Value length cannot be &gt; 255</rule> |
| <rule name="required" value="true">This module requires data for |
| this attribute. |
| </rule> |
| </field> |
| <field name="Url" key="url" type="String" mapToProperty="Value"> |
| <rule name="maxLength" value="255">Url length cannot be &gt; 255</rule> |
| <rule name="mask" value="^$|http.+">Please enter an url starting with "http"</rule> |
| <rule name="required" value="true">This module requires a valid url.</rule> |
| </field> |
| </pre></div> |
| |
| </section> |
| |
| <section> |
| <h2><a name="Multiple_groups_of_the_same_class_in_one_form"></a>Multiple groups of the same class in one form</h2> |
| |
| |
| <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> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| #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> |
| </pre></div> |
| |
| |
| <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> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| public void doEnterissue( PipelineData pipelineData, Context context ) |
| throws Exception |
| { |
| // get a reference to the run data object |
| RunData data = (RunData) pipelineData; |
| |
| 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); |
| } |
| } |
| } |
| </pre></div> |
| |
| |
| <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> |
| |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| 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 |
| </pre></div> |
| |
| </section> |
| |
| <section> |
| <h2><a name="Default_values_for_fields"></a>Default values for fields</h2> |
| |
| |
| <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> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| <group name="test" key="test"> |
| <field name="Value" key="val" type="String" defaultValue="preset"> |
| </field> |
| </group> |
| </pre></div> |
| |
| |
| <p>If you set up a form like this:</p> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| #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> |
| </pre></div> |
| |
| |
| <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> |
| <h2><a name="Empty_fields"></a>Empty fields</h2> |
| |
| <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> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| <group name="test" key="test"> |
| <field name="Value" key="val" type="String" emptyValue=""/> |
| </group> |
| </pre></div> |
| |
| |
| <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> |
| |
| <section> |
| <h2><a name="Display_attributes_for_fields"></a>Display attributes for fields</h2> |
| |
| <p> |
| The Intake DTD allows additional attributes that can help you in your |
| template. The <code>displayName</code> can be used to provide a label |
| for the given field. The <code>displaySize</code> can be used to define |
| the displayed size of the field (either numerical or as a CSS-style). |
| The Intake tool $intake provides these values as |
| <code>$field.DisplayName</code> and <code>$field.DisplaySize</code>, |
| respectively. |
| </p> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| <group name="test" key="test"> |
| <field name="Value" key="val" type="String" |
| displayName="Test Value" |
| displaySize="150px" |
| /> |
| </group> |
| </pre></div> |
| |
| |
| <p>This could be used in the template like this:</p> |
| |
| |
| <div class="source"><pre class="prettyprint"> |
| #set ($tg = $intake.test.Default) |
| |
| $tg.Value.DisplayName: |
| <input type="text" name="$tg.Value.Key" value="$!tg.Value.HTMLString" |
| style="width:${tg.Value.DisplaySize};" /> |
| </pre></div> |
| |
| </section> |
| |
| <section> |
| <h2><a name="Custom_validators"></a>Custom validators</h2> |
| |
| <p> |
| Fields can have custom validators through the help of the |
| <code>validator</code> attribute. If the validator class is not |
| qualified (i.e. has no package) the package |
| <code>org.apache.turbine.services.intake.validator</code> is |
| assumed. Validator classes must implement the |
| <code>org.apache.turbine.services.intake.validator.Validator</code> |
| interface. If the validator needs initialization from the list |
| of constraints (based on the <code>rule</code> elements in the |
| definition file), it also must implement |
| <code>org.apache.turbine.services.intake.validator.InitableByConstraintMap</code>. |
| It is recommended to extend one of the existing validator classes |
| which live in the <code>org.apache.turbine.services.intake.validator</code> |
| package. In this validator class, override <code>assertValidity(String)</code>, |
| don't forget to call <code>super.assertValidity(testValue)</code> and add |
| your own checks to the validator. |
| </p> |
| |
| <p> |
| For validator classes extending <code>DefaultValidator</code> |
| the most important method to implement is <code>assertValidity()</code>. |
| There are two signatures of this method. If you just need to compare |
| the value entered to a list of database entries, for example, it |
| is sufficient to implement <code>assertValidity(String)</code>. The |
| default code handles multi-valued fields and other stuff for you. If |
| you want to do advanced checks and comparisons, you need to implement |
| <code>assertValidity(Field)</code>. Here you can check for locale, |
| associated group and values of other fields in the same group. See |
| the following section for examples. |
| </p> |
| |
| </section> |
| |
| <section> |
| <h2><a name="Validating_dependent_fields"></a>Validating dependent fields</h2> |
| |
| <p> |
| Sometimes it is necessary to validate fields not only against a set of |
| constant rules but also against the values of other fields in the same |
| form or group. For these cases, Intake provides the helper class |
| <code>FieldReference</code>. It provides additional rules to compare |
| fields to other fields: |
| </p> |
| |
| <table border="0" class="table table-striped"> |
| |
| <tr class="a"> |
| |
| <th>Rule Name</th> |
| |
| <th>Comparison</th> |
| |
| <th>Rule Value</th> |
| </tr> |
| |
| <tr class="b"> |
| |
| <td>less-than</td> |
| |
| <td align="center"><</td> |
| |
| <td><name of other field></td> |
| </tr> |
| |
| <tr class="a"> |
| |
| <td>greater-than</td> |
| |
| <td align="center">></td> |
| |
| <td><name of other field></td> |
| </tr> |
| |
| <tr class="b"> |
| |
| <td>less-than-or-equal</td> |
| |
| <td align="center"><=</td> |
| |
| <td><name of other field></td> |
| </tr> |
| |
| <tr class="a"> |
| |
| <td>greater-than-or-equal</td> |
| |
| <td align="center">>=</td> |
| |
| <td><name of other field></td> |
| </tr> |
| </table> |
| |
| <p> |
| Two examples of implementations of these comparison rules are |
| available as <code>DateRangeValidator</code> and |
| <code>IntegerRangeValidator</code>. An example on how to use these |
| is shown below. |
| </p> |
| |
| <div class="source"><pre class="prettyprint"> |
| <group name="DateRange" key="dr"> |
| <field name="DateFrom" key="dmin" type="DateString"> |
| <rule value="MM/dd/yyyy" name="format">Invalid format</rule> |
| </field> |
| <field name="DateTo" key="dmax" type="DateString" |
| validator="DateRangeValidator"> |
| <rule value="MM/dd/yyyy" name="format">Invalid format</rule> |
| <rule value="DateFrom" name="greater-than"> |
| To-Date must be greater than From-Date</rule> |
| </field> |
| </group> |
| </pre></div> |
| |
| </section> |
| |
| |
| |
| |
| </main> |
| </div> |
| </div> |
| <hr/> |
| <footer> |
| <div class="container-fluid"> |
| <div class="row-fluid"> |
| <p>© 2005–2021 |
| <a href="https://www.apache.org/">The Apache Software Foundation</a> |
| </p> |
| </div> |
| </div> |
| </footer> |
| </body> |
| </html> |