| <?xml version="1.0"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you 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>"Simple" Intake How-to for Turbine 2.1</title> |
| </properties> |
| |
| <body> |
| <section name="Introduction"> |
| <p> |
| First of all I'd like to note that this document is based on my |
| experience in using Intake for Turbine 2.1. I've tried to make |
| it as correct as possible but I don't guarantee anything. This |
| has been written as a guide for a new Intake user and assumes |
| some familiarity with Turbine 2.1. |
| </p> |
| <p> |
| To use intake, the following steps are required: |
| |
| <ol> |
| <li>Create your turbine template with a form.</li> |
| <li>Create the intake.xml file.</li> |
| <li>Create a business object to represent the intake group |
| we are working with (this is optional).</li> |
| <li>Create the Turbine Action to handle the form |
| submission.</li> |
| </ol> |
| </p> |
| <p> |
| Some additional information concerning removing Intake group |
| information from the request is included at the bottom of this |
| document. |
| </p> |
| </section> |
| |
| <section name="Step 1: Create your turbine template with a form"> |
| <p> |
| The first thing to do is the create the form in your template |
| (e.g. a velocity template file, a .vm file). Just create the |
| skeleton structure and don't worry about the field names and |
| values yet. Note that field names will have to match the names |
| specified in the intake.xml file. Actually you can do the |
| opposite (name the fields here first and match them in the |
| intake.xml file) if you wish, but this guide will do it the |
| former way. |
| </p> |
| <p> |
| Now add the following lines above the code for your form and |
| modify it to match the group and field names in your intake.xml |
| file (perhaps you can come back to do this step after you've |
| done your intake.xml file). Here is an example in a Velocity |
| template for a "login form": |
| </p> |
| <source><![CDATA[ |
| #set($loginGroup = $intake.LoginGroup.Default) |
| ]]></source> |
| <p/> |
| <p> |
| What this does is to set a Velocity variable called $loginGroup |
| to a default group object specified by intake.xml. The $intake |
| variable is the Turbine Pull Tool instance (IntakeTool). The |
| "LoginGroup" is the name of the group as specified in the |
| intake.xml file (names must match, and this is not the group's |
| key attribute.). The "Default" part obtains a generic default |
| intake group object. Or in other words, this resolves to |
| IntakeTool.get(String groupName) with the groupName being |
| "LoginGroup". Also, you can re-write the statement as |
| $intake.get("LoginGroup").getDefault() in your template. |
| </p> |
| <p> |
| Or if you would like to map the intake group to a business |
| object (for whatever purpose) then you can do this (read on |
| for more info on what is required to do this in intake.xml and |
| the corresponding Turbine Action class): |
| </p> |
| <source><![CDATA[ |
| #set($loginGroup = $intake.LoginGroup.mapTo($mytool.getInstanceLoginForm())) |
| ]]></source> |
| <p/> |
| <p> |
| What this does is to set a Velocity variable called $loginGroup |
| to an instance of the LoginForm business object (and if the |
| returned object has values in its fields and appropriate |
| "getter" methods then this would prepopulate the intake group |
| with the values. A good usage example of this is when you |
| would like to prepopulate the form with values from the |
| database and want to use intake to validate the form). It |
| makes use of a custom tool placed into the Velocity context as |
| "$mytool" (you can make your own tool to instantiate an instance |
| of your business object similar to this example). |
| </p> |
| <p> |
| So, depending on the method you use above, the corresponding |
| Turbine Action code will need to "cooperate" accordingly. |
| We'll discuss this later in step 4. |
| </p> |
| <p> |
| Near the end of the form (before you close the "form" tag) |
| include the following line: |
| </p> |
| <source><![CDATA[ |
| $intake.declareGroups() |
| ]]></source> |
| <p/> |
| <p> |
| What this does is to fill in hidden form fields into the form |
| for use by intake. |
| </p> |
| <p> |
| In order to use Turbine's Action event system, the submit buttons |
| must adhere to the naming specification defined by |
| <a href="http://turbine.apache.org/turbine-2/howto/action-event-howto.html"> |
| Turbine's Action event system</a>. |
| </p> |
| |
| <subsection name="*** IMPORTANT NOTE ***"> |
| <p> |
| If you use |
| $link.setAction('SomeAction').setPage('NextTemplate.vm') |
| in your form's action attribute like this: |
| </p> |
| <source><![CDATA[ |
| <form name="myForm" method="POST" |
| action="$link.setAction('LoginAction').setPage('NextTemplate.vm')"> |
| ... |
| </form> |
| ]]></source> |
| <p/> |
| <p> |
| then the form validation won't appear to work (i.e. the user |
| will see the NextTemplate.vm file instead of the form they |
| were trying to fill out which failed validation). To work |
| around this problem, you can omit the setPage('...') part |
| in your form's action attribute and then have your action |
| route the user to the next template on validation success |
| OR somehow detect the current form the user is at and if |
| the validation fails, override the next template to the |
| current template (which is really just overriding the |
| setPage() part in the template file specified by the web |
| designer). |
| </p> |
| </subsection> |
| </section> |
| |
| <section name="Step 2: Create the intake.xml file"> |
| <p> |
| The intake.xml file specifies the validation rules required to |
| be satisfied in order for the form to be accepted. The file has |
| a "root" XML element of "input-data" and in that would be |
| "group" elements. |
| </p> |
| <p> |
| Here is an example of the element (with no other sub-elements): |
| </p> |
| <source><![CDATA[ |
| <!DOCTYPE input-data SYSTEM |
| "http://turbine.apache.org/dtd/intake_2_3.dtd"> |
| <input-data basePackage="ca.yorku.devteam.inca.clients.skeleton."> |
| ...group elements goes here... |
| </input-data> |
| ]]></source> |
| <p/> |
| <p> |
| Notice the basePackage attribute (optional) points to the |
| skeleton package with an extra period at the end. This |
| attribute specifies the package that contains the java objects |
| the "group" and "field" elements can optionally map to. |
| The trailing period is REQUIRED. |
| </p> |
| |
| <subsection name="<group> elements"> |
| <p> |
| Each group element represents a collection of field information you'd like to |
| validate in your form. For example, on a login page you would have a form for |
| the user to input their username and password, and as well as a login button. |
| This entire form would be grouped as a group in the intake.xml file. |
| </p> |
| <p> |
| Here is an example of a group with no other elements (not useful yet): |
| </p> |
| <source><![CDATA[ |
| <group name="LoginGroup" key="loginGroupKey" mapToObject="LoginForm"> |
| ...field elements goes here... |
| </group> |
| ]]></source> |
| <p/> |
| <p> |
| A group element can have the following attributes: |
| |
| <ul> |
| <li>"name" attribute |
| <ul> |
| <li> |
| the name of the group, is required, and must |
| be unique across the entire intake.xml file. |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| <ul> |
| <li>"key" attribute |
| <ul> |
| <li> |
| the key of the group, is required, and must |
| be unique across the entire intake.xml file. |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| <ul> |
| <li>"mapToObject" attribute |
| <ul> |
| <li> |
| optional, used if you want to map the form |
| to a business object. Note that the field |
| names specified later by the "field" element |
| in the group should match the field names of |
| the business object with appropriate get/set |
| methods. See the "field" tag examples to |
| find how to override this default behaviour. |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </p> |
| <p> |
| For a complete list of valid attributes of the group |
| element, please see the |
| <a href="http://turbine.apache.org/turbine-2/services/intake-service.html"> |
| intake-service document</a> on the Turbine web site. |
| </p> |
| </subsection> |
| |
| <subsection name="<field> elements"> |
| <p> |
| Each group element can contain any number of "field" |
| elements. Each field element will correspond to a field in |
| the form. The name and key of each field will be used in |
| the form code in the template so make sure the names and |
| keys match in both files (intake.xml and the template file). |
| </p> |
| <p> |
| Here is an example of a field with no other elements (not |
| too useful yet): |
| </p> |
| <source><![CDATA[ |
| <field name="Username" key="loginUsernameKey" type="String" |
| mapToProperty="Username"> |
| ...rule elements goes here... |
| </field> |
| ]]></source> |
| <p/> |
| <p> |
| A field element can have the following attributes: |
| |
| <ul> |
| <li>"name" attribute |
| <ul> |
| <li> |
| the name of the field, is required, and must |
| be unique across the entire group element. |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| <ul> |
| <li>"key" attribute |
| <ul> |
| <li> |
| the key of the field, is required, and must |
| be unique across the entire group element. |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| <ul> |
| <li>"type" attribute |
| <ul> |
| <li> |
| required, the type of the field so that |
| intake will know what to expect. Valid |
| types I know of are: String, Integer (I |
| believe these map to the corresponding Java |
| types). Please see the intake.dtd for the |
| allowed values. |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| <ul> |
| <li>"mapToProperty" attribute |
| <ul> |
| <li> |
| optional, used if you want to map the form |
| to a business object. Note that the field |
| names specified in this "field" element |
| should match the field name of the business |
| object with appropriate get/set methods. |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </p> |
| <p> |
| For a complete list of valid attributes of the field |
| element, please see the |
| <a href="http://turbine.apache.org/turbine-2/services/intake-service.html"> |
| intake-service document</a> on the Turbine web site. |
| </p> |
| </subsection> |
| |
| <subsection name="<rule> elements"> |
| <p> |
| In each field element, you can have rules defined. The |
| supported rule elements for Intake in Turbine 2.1 are: |
| </p> |
| <source><![CDATA[ |
| <rule name="required" value="true">Error message for required failed</rule> |
| <rule name="minLength" value="4">Error message for required min length failed</rule> |
| <rule name="maxLength" value="9">Error message for required max length failed</rule> |
| <rule name="mask" value="^[0-9]+$">Error message for regular expression failed</rule> |
| <rule name="notANumberMessage">Error message for Number fields when the entry is not a number</rule> |
| |
| ]]></source> |
| <p/> |
| <p> |
| For more info on the supported rules, please see the |
| <a href="http://turbine.apache.org/turbine-2/services/intake-service.html"> |
| intake-service document</a> on the Turbine web site: |
| </p> |
| </subsection> |
| </section> |
| |
| <section name="Step 3: Create a business object to represent the intake group we are working with (this is optional)."> |
| <p> |
| The business object is basically a Java class that has get and |
| set methods for each of the object's fields, and these get and |
| set method names should match the field names specified in the |
| intake.xml file (whether we stay with the default behaviour of |
| matching the field names in intake.xml and the business object |
| or we use the mapToProperty attribute in the "field" element). |
| Note it is required to use the mapToObject property in the group |
| element to use this feature. |
| </p> |
| <p> |
| The business object also has to implement the |
| org.apache.turbine.om.Retrievable interface. The Retrievable |
| was designed to work with a database so the methods |
| get/setQueryKey doesn't make much sense if your business object |
| isn't based on a database model. For my use, I just force the |
| key to be "_0" which is the default key used by Intake (as of |
| Turbine 2.1). You could, of course, implement it as a normal |
| data field to allow the template to set the query key and then |
| in the Action to get the query key. But then you'll have to |
| keep track of the key you use in both the template file and |
| Action class (the benefit would be that you'll be able to use |
| more than 1 business object in the same template if you get/set |
| the different query keys). |
| </p> |
| <p> |
| Here is an example of how to use the setQueryKey() and |
| getQueryKey() methods of the business object that implements |
| the Retrievable interface: |
| </p> |
| <p> |
| In the template file, e.g. myform.vm: |
| </p> |
| <source><![CDATA[ |
| #set($loginForm = $mytool.getLoginFormInstance()) |
| $loginForm.setQueryKey("abc") |
| #set($loginGroup = $intake.LoginGroup.mapTo($loginForm)) |
| ]]></source> |
| <p/> |
| <p> |
| In the Action class: |
| </p> |
| <source><![CDATA[ |
| // This key has to match the one in the template |
| String key = "abc"; |
| Group group = intake.get("LoginGroup", key); |
| ]]></source> |
| <p/> |
| </section> |
| |
| <section name="Step 4: Create the Turbine Action to handle the form submission."> |
| <p> |
| Depending on the method you use, the code in the action will |
| need to obtain the corresponding group object from intake. The |
| following examples will demonstrate the ideas. |
| </p> |
| <p> |
| Here is an example the code in a Turbine Action, using intake |
| without mapping to a business object (vanilla method): |
| </p> |
| <source><![CDATA[ |
| /** |
| * Performs user login |
| */ |
| public void doLogin(RunData data, Context context) |
| throws Exception { |
| // Get intake group |
| IntakeTool intake = |
| (IntakeTool)context.get("intake"); |
| |
| // Notice how this gets the group named "LoginGroup" as defined in |
| // the intake.xml file, and gets it using the default key |
| // IntakeTool.DEFAULT_KEY (which is "_0"). |
| Group group = intake.get("LoginGroup", IntakeTool.DEFAULT_KEY); |
| |
| // Check if group fields are valid and if they are not, then return. |
| // Intake will handle the validation error and display the |
| // corresponding error messages to the user but if you use the setPage() |
| // mechanism to get the "next template" then you must now set the |
| // template to be the same one as the user was filling out. Otherwise |
| // the user will just see the next template. See the "important note" |
| // in step 1. |
| if (!group.isAllValid()) { |
| Log.debug("Group elements INVALID"); |
| setTemplate(data, "Login.vm"); |
| return; |
| } else { |
| // If all is validated then you can set the next template and/or |
| // continue processing...it's up to you. You can also use |
| // setPage() in the template file to set the next template to show |
| // on successful validation. |
| setTemplate(data, "LoginSuccess.vm"); |
| } |
| |
| // This gets the value of the "Username" field from the group object |
| String username = (String)group.get("Username").getValue(); |
| String password = (String)group.get("Password").getValue(); |
| |
| // Now you will be able to use the username and password variable in |
| // the rest of the Turbine Action. |
| ... |
| } |
| ]]></source> |
| <p/> |
| <p> |
| Here is example code in a Turbine Action, using the intake |
| group's default mapToObject setting (this is the same whether |
| or not you use the field's mapToProperty attribute): |
| </p> |
| <source><![CDATA[ |
| /** |
| * Performs user login |
| */ |
| public void doLogin(RunData data, Context context) |
| throws Exception { |
| // Get intake group |
| IntakeTool intake = |
| (IntakeTool)context.get("intake"); |
| Group group = intake.get("LoginGroup", IntakeTool.DEFAULT_KEY); |
| |
| // Check if group fields are valid and if they are not, then return. |
| // Intake will handle the validation error and display the |
| // corresponding error messages to the user but if you use the setPage() |
| // mechanism to get the "next template" then you must now set the |
| // template to be the same one as the user was filling out. Otherwise |
| // the user will just see the next template. See the "important note" |
| // in step 1. |
| if (!group.isAllValid()) { |
| Log.debug("Group elements INVALID"); |
| setTemplate(data, "Login.vm"); |
| return; |
| } else { |
| // If all is validated then you can set the next template and/or |
| // continue processing...it's up to you. You can also use |
| // setPage() in the template file to set the next template to show |
| // on successful validation. |
| setTemplate(data, "LoginSuccess.vm"); |
| } |
| |
| // Instaniate a business object that represents the form |
| LoginForm loginForm = new LoginForm(); |
| |
| // Set the properties of the form given the field data in the group |
| // (i.e. populate the business object) |
| group.setProperties(loginForm); |
| |
| // Now the business object is populated accordingly. You can use it |
| // for whatever purpose in the rest of the Turbine Action. |
| ... |
| } |
| ]]></source> |
| <p/> |
| </section> |
| <section name="Removing Intake information from the request"> |
| <p> |
| Intake data is retained in the request in order to allow for the |
| possibility that it will be re-presented to the user on the next |
| page. Normally this is desirable behaviour - there may have been |
| an error in the data so you want to redisplay it. There is a |
| possibility however that you might want to reuse the same group |
| on either the same or a different page after fully processing |
| the data; in this case it may be undesirable to redisplay the |
| previously entered data. The prime example of this is where a |
| page includes a repeating group of records and provides an |
| opportunity to add a further record using the default group, |
| returning to the same page after each record is added. In this |
| situation you will find that the default group needs to be |
| removed from the request, otherwise the data entered on the |
| previous page will be redisplayed. |
| </p> |
| <p> |
| Intake allows for this by providing a way of removing the data |
| that is no longer appropriate to display. Simply: |
| </p> |
| <source><![CDATA[ |
| intake.remove(group); |
| ]]></source> |
| <p/> |
| <p> |
| ... where "intake" is a reference to your IntakeTool and "group" |
| is a reference to the group you wish to remove from the |
| request. You would do this after the new record had been |
| validated and added to the database. |
| </p> |
| <p> |
| It will be rare that you actually need to do this - it is |
| required only in situations where the same group is used on |
| subsequent pages after the data has been fully processed (it |
| should be pretty obvious when this is the case). |
| </p> |
| </section> |
| </body> |
| </document> |