<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title><![CDATA[Mentawai In Action - Latest forum topics]]></title>
		<link>http://book.mentaframework.org/recentTopics/list.page</link>
		<description><![CDATA[The newest discussed topics in the entire board]]></description>
		<generator>JForum - http://www.jforum.net</generator>
			<item>
				<title>Problem with activating account</title>
				<description><![CDATA[ 018080f4ec1410139d1ac95ccc455fab Hi Guys, I am newbie in the internet stuff and I dont know if I am writing on correct board on this website. I<br /> have got problem with activating my account. I received email but when I click on the link it was not working, is this link is correct?  [url=http://book.mentaframework.org/?81ac61f9145e]http://book.mentaframework.org/?81ac61f9145e[/url], ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/41/44.page</guid>
				<link>http://book.mentaframework.org/posts/preList/41/44.page</link>
				<pubDate><![CDATA[Mon, 19 Mar 2012 03:45:04]]> GMT</pubDate>
				<author><![CDATA[ cyrilcroppe]]></author>
			</item>
			<item>
				<title>canada goose jakke</title>
				<description><![CDATA[ [url=http://www.goosejakkedk.com/]canada goose[/url] manufactures a wide range of [url=http://www.goosejakkedk.com/]canada goose[/url], vests, hats, gloves and other cold weather apparel designed for extreme cold weather conditions. [url=http://www.goosejakkedk.com/]canada jakke[/url] fills all its coats with a blend of [url=http://www.goosejakkedk.com/]canada goose danmark[/url] and duck down to ensure warmth, it also utilizes coyote fur on the hoods. The [url=http://www.goosejakkedk.com/]canada goose jakke[/url] jackets are known to be a highly fashionable garment.]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/38/41.page</guid>
				<link>http://book.mentaframework.org/posts/preList/38/41.page</link>
				<pubDate><![CDATA[Mon, 27 Feb 2012 00:01:41]]> GMT</pubDate>
				<author><![CDATA[ cunqianguan]]></author>
			</item>
			<item>
				<title>pandora charms sale</title>
				<description><![CDATA[ [url=http://www.charmspandoraukonline.com/]pandora charms[/url] is my dream. [url=http://www.charmspandoraukonline.com/]pandora uk[/url] is just what I want to buy. [url=http://www.charmspandoraukonline.com/]pandora charms uk[/url] online store is my best choice! [url=http://www.charmspandoraukonline.com/]pandora charms sale[/url] provides all kinds of charms.]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/37/39.page</guid>
				<link>http://book.mentaframework.org/posts/preList/37/39.page</link>
				<pubDate><![CDATA[Wed, 22 Feb 2012 20:26:29]]> GMT</pubDate>
				<author><![CDATA[ cunqianguan]]></author>
			</item>
			<item>
				<title>TrésOr Paris</title>
				<description><![CDATA[ Wholesale [url=http://www.bijouterietresorparis.com/]TrésOr Paris[/url] jewelry,buy cheap [url=http://www.bijouterietresorparis.com/]TrésOr Paris bijoux[/url] here,you can get discounted [url=http://www.bijouterietresorparis.com/]TrésOr Paris bijouterie[/url] from our online store,we are one of the best [url=http://www.bijouterietresorparis.com/]TrésOr Paris boutique[/url] online.Tresor Paris, [url=http://www.bijouterietresorparis.com/]TrésOr bijouterie[/url] which from our [url=http://www.bijouterietresorparis.com/]trésor bijoux[/url] outlet are provided with free shipping.]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/36/38.page</guid>
				<link>http://book.mentaframework.org/posts/preList/36/38.page</link>
				<pubDate><![CDATA[Wed, 4 Jan 2012 20:08:07]]> GMT</pubDate>
				<author><![CDATA[ emma11]]></author>
			</item>
			<item>
				<title>Yale Football Coach Resigns After Faulty Rhodes Scholarship Claim</title>
				<description><![CDATA[ <br /> <br /> <br /> NEW HAVEN, Conn. -- Yale football coach Tom Williams resigned Wednesday amid a probe by the university into whether he lied on his resume about being a candidate for a prestigious Rhodes scholarship, the New Haven Register reported.<br /> Williams said last month that when he was a senior linebacker at Stanford in 1992 he was a candidate for a Rhodes scholarship, but passed up the opportunity in favor of an NFL tryout.<br /> He spoke on the issue while Yale quarterback Patrick Witt, a Rhodes finalist, debated whether to play in the season finale against archrival Harvard or miss the game for an interview that would determine if he obtained the scholarship.<br /> <br /> Witt opted to play in the Nov. 19 game, which Yale lost 45-7.<br /> Williams, who turns 42 Thursday, listed on his resume submitted to Yale that he had been a Rhodes finalist.<br /> The university launched an inquiry after The New York Times reported that the Rhodes Trust, which finances the scholarship, had no record of Williams ever applying for the scholarship.<br /> The result of the inquiry has not been made public. Williams, in a statement announcing his decision, sought to explain the discrepancy.<br /> <br /> <br /> <br /> <br /> ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/35/37.page</guid>
				<link>http://book.mentaframework.org/posts/preList/35/37.page</link>
				<pubDate><![CDATA[Fri, 23 Dec 2011 23:52:21]]> GMT</pubDate>
				<author><![CDATA[ shoud14]]></author>
			</item>
			<item>
				<title>Football: State bowl championships set to kickoff</title>
				<description><![CDATA[ This weekend's CIF State Football Bowl Championships kick off in 20 minutes at Home Depot Center in Carson with the Division IV game pitting one of the oldest schools in Northern California against one of the newest in Southern California.<br /> <br /> Chatsworth Sierra Canyon (14-0), in just its third season of 11-man football, was selected to represent the South after routing Lancaster Paraclete 47-14 in the Southern Section East Valley Division finals. The Trailblazers average 46.1 points per game and are led by 1,000-yard rushers Xavier Menifield and Danny Jordan and quarterback Tyler Stewart, who has thrown for 2,245 yards and 32 touchdowns.<br /> <br /> Le Grand, from a town of 1,650 people southeast of Merced, has had a football team since the 1920s and this year's edition might be the school's best ever--even better than last year's team which won the program's first section title.<br /> <br /> The Sac-Joaquin Section champion Bulldogs are averaging a whopping 58.5 points per game and are led by Daniel Guizar, who has rushed for almost 2,000 yards and 35 touchdowns. Quarterback Alex Bucio has thrown for 2,344 yards and 490 touchdowns.<br /> <br /> The Division IV game will be followed by the Division I showdown between Santa Margarita (12-2) and Bellarmine Prep of San Jose (12-1).<br /> <br /> Stay logged in for live scoring updates from both games.<br /> <br /> -- Steve Galluzzo]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/34/36.page</guid>
				<link>http://book.mentaframework.org/posts/preList/34/36.page</link>
				<pubDate><![CDATA[Sun, 18 Dec 2011 20:54:50]]> GMT</pubDate>
				<author><![CDATA[ clinical12]]></author>
			</item>
			<item>
				<title> | </title>
				<description><![CDATA[ 2011-08-23_11-45-14 -&gt; dd0e3204ad4f2a7b2399c02476d2c978 :: d16a22fbe6c3148693f3462e910 [url=http://book.mentaframework.org/?d16a22fbe6c3148693f3462e910]http://book.mentaframework.org/?d16a22fbe6c3148693f3462e910[/url], ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/29/30.page</guid>
				<link>http://book.mentaframework.org/posts/preList/29/30.page</link>
				<pubDate><![CDATA[Tue, 23 Aug 2011 07:25:23]]> GMT</pubDate>
				<author><![CDATA[ tinabrere]]></author>
			</item>
			<item>
				<title>Returning the same rule instance</title>
				<description><![CDATA[ Because validation is dynamic, in other words, the validation code is executed per each request, you should avoid creating new rule objects inside your validation code. Check the code below:<br /> [code]<br /> public class MyAction implements Validatable {<br />     <br />     public String execute() {<br />         <br />         // your action stuff here...<br />         <br />     }<br />     <br />     public void prepareValidator(Validator val, String innerAction) {<br />         <br />             Rule required = new RequiredRule();<br />         <br />             val.add("username", required, "required_error");<br />             val.add("username", new StringRule(6, 30), "invalid_username");<br />         <br />             val.add("age", required, "required_error");<br />             val.add("age", new IntegerRule(18, 50), "invalid_age");<br />         <br />             val.add("password", required, "required_error");<br />             val.add("password", new StringRule(4, 20), "invalid_password_length");<br />             val.add("password", new EqualRule("password", "passconf"), "password_does_not_match");<br />         <br />             val.add("passconf", required, "required_error");<br />             <br />     }<br /> }<br /> [/code]<br /> The code above is perfectly correct and legal, but we are creating too many new objects on each request without a real need for it. A rule is thread-safe by design and you should re-use the same instance across different requests. A possible fix for this problem is illustrated in the code below:<br /> [code]<br /> public class MyAction implements Validatable {<br /> <br />     private static final Rule requiredRule = new RequiredRule();<br />     private static final Rule stringRule1 = new StringRule(6, 30);<br />     private static final Rule integerRule1 = new IntegerRule(18, 50);<br />     private static final Rule stringRule2 = new StringRule(4, 20);<br />     private static final Rule equalRule1 = new EqualRule("password", "passconf");<br />     <br />     public String execute() {<br />         <br />         // your action stuff here...<br />         <br />     }<br />     <br />     public void prepareValidator(Validator val, String innerAction) {<br />         <br />             val.add("username", requiredRule, "required_error");<br />             val.add("username", stringRule1, "invalid_username");<br />         <br />             val.add("age", requiredRule, "required_error");<br />             val.add("age", integerRule1, "invalid_age");<br />         <br />             val.add("password", requiredRule, "required_error");<br />             val.add("password", stringRule2, "invalid_password_length");<br />             val.add("password", equalRule1, "password_does_not_match");<br />         <br />             val.add("passconf", requiredRule, "required_error");<br />             <br />     }<br /> }<br /> [/code]<br /> However note that it is not very easy to read the validation code when the rules are defined outside the [i]prepareValidator()[/i] method. A better approach is to make the rule constructor private and create a static [i]getInstance()[/i] method that will return instances of the rule and it will be smart enough to return the same instance when the same object is requested. Check below how we would accomplish this with the [i]NegativeRule [/i]introduced in the previous chapter.<br /> [code]<br /> import java.util.HashMap;<br /> import java.util.Map;<br /> <br /> <br /> public class NegativeRule extends BasicRule {<br />     <br />     private final int min;<br />     private final Map&lt;String, String&gt; tokens = new HashMap&lt;String, String&gt;();<br />     <br />     private static final Map&lt;Integer, Rule&gt; cache = new HashMap&lt;Integer, Rule&gt;();<br />     private static final Rule RULE = new NegativeRule();<br /> 	<br /> 	private NegativeRule() { <br />         this.min = Integer.MIN_VALUE;<br />         this.tokens.put("min", String.valueOf(min));<br />     }<br />     <br />     private NegativeRule(int min) {<br />         this.min = min;<br />         this.tokens.put("min", String.valueOf(min));<br />     }<br />     <br />     public static Rule getInstance() {<br />         return RULE;<br />     }<br />     <br />     public synchronized static Rule getInstance(int min) {<br />         Rule rule = cache.get(min);<br />         <br />         if (rule == null) {<br />             rule = new NegativeRule(min);<br />             cache.put(min, rule);<br />         }<br />         <br />         return rule;<br />     }<br /> 	<br /> 	public boolean check(String value) {<br /> 		<br /> 		try {<br /> 			<br /> 			int x = Integer.parseInt(value);<br />             <br />             return x &lt; 0 && x &gt;= min;<br /> 			<br /> 		} catch(Exception e) {<br /> 			<br /> 			return false;<br /> 		}<br /> 	}<br />     <br /> 	public Map&lt;String, String&gt; getTokens() {<br /> 		return tokens;<br /> 	}<br /> }<br /> [/code]<br /> Check how we are using a cache to return the same instance for each "min" parameter passed to the [i]getInstance()[/i] method. This will avoid creating unnecessary duplicates of the same object.<br /> <br /> Most of the provided rules inside the [i]org.mentawai.rule[/i] package implement the [i]getInstance()[/i] method. So when using them you should make use of this method to obtain instances of the rule. Check the example below:<br /> [code]<br /> public class MyAction implements Validatable {<br />     <br />     public String execute() {<br />         <br />         // your action stuff here...<br />         <br />     }<br />     <br />     public void prepareValidator(Validator val, String innerAction) {<br />         <br />             Rule required = RequiredRule.getInstance();<br />         <br />             val.add("username", required, "required_error");<br />             val.add("username", StringRule.getInstance(6, 30), "invalid_username");<br />         <br />             val.add("age", required, "required_error");<br />             val.add("age", IntegerRule.getInstance(18, 50), "invalid_age");<br />         <br />             val.add("password", required, "required_error");<br />             val.add("password", StringRule.getInstance(4, 20), "invalid_password_length");<br />             val.add("password", EqualRule.getInstance("password", "passconf"), "password_does_not_match");<br />         <br />             val.add("passconf", required, "required_error");<br />             <br />     }<br /> }<br /> [/code]<br /> When coding your own rules, you should provide a [i]getInstance()[/i] method whenever possible. But this is not really a necessity. It is just a good practice that it is worth mentioning for the competent programmer.<br /> ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/28/29.page</guid>
				<link>http://book.mentaframework.org/posts/preList/28/29.page</link>
				<pubDate><![CDATA[Tue, 12 Aug 2008 11:29:18]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Creating your own rules</title>
				<description><![CDATA[ A rule validates whether an action input value is valid or not to be passed along to the action. To learn about rules let's code a simple [i]NegativeRule [/i]class that validates only negative numbers.<br /> [code]<br /> import java.util.HashMap;<br /> import java.util.Map;<br /> <br /> <br /> public class NegativeRule extends BasicRule {<br /> 	<br /> 	public NegativeRule() { }<br /> 	<br /> 	public boolean check(String value) {<br /> 		<br /> 		try {<br /> 			<br /> 			int x = Integer.parseInt(value);<br />             <br />             return x &lt; 0;<br /> 			<br /> 		} catch(Exception e) {<br /> 			<br /> 			return false;<br /> 		}<br /> 	}<br />     <br /> 	public Map&lt;String, String&gt; getTokens() {<br /> 		return null; // no tokens...<br /> 	}<br />     <br /> }<br /> [/code]<br /> When you extend [i]BasicRule [/i]you should implement two methods: check() and getTokens().<br /> <br /> :arrow: check(String value): In this method you receive the value you are suppose to validate and just do it, however you want to, returning true or false.<br /> <br /> :arrow: getTokens(): In this method you return a map with tokens and their values to be used by error messages. The default implementation in BasicRule is to return null, so you should only implement this method if you have tokens to return.<br /> <br /> A token is used inside error messages so that it can be substituted for values associated with the rule. For example, in our simple rule above, the negative number has no minimum boundary. Let's change it to include a possible minimum:<br /> [code]<br /> import java.util.HashMap;<br /> import java.util.Map;<br /> <br /> <br /> public class NegativeRule extends BasicRule {<br />     <br />     private final int min;<br />     private final Map&lt;String, String&gt; tokens = new HashMap&lt;String, String&gt;();<br /> 	<br /> 	public NegativeRule() { <br />         this.min = Integer.MIN_VALUE;<br />         this.tokens.put("min", String.valueOf(min));<br />     }<br />     <br />     public NegativeRule(int min) {<br />         this.min = min;<br />         this.tokens.put("min", String.valueOf(min));<br />     }<br /> 	<br /> 	public boolean check(String value) {<br /> 		<br /> 		try {<br /> 			<br /> 			int x = Integer.parseInt(value);<br />             <br />             return x &lt; 0 && x &gt;= min;<br /> 			<br /> 		} catch(Exception e) {<br /> 			<br /> 			return false;<br /> 		}<br /> 	}<br />     <br /> 	public Map&lt;String, String&gt; getTokens() {<br /> 		return tokens;<br /> 	}<br /> }<br /> [/code]<br /> Note that now we have the possibility to validate the input value based on a minimum number and we are returning the token "min" with whatever value is given to that minimum number. Therefore you may have an error message like the one below:<br /> [code]<br /> invalid_number = Your negative number should be bigger than %min%.<br /> [/code]<br /> The %min% token is substituted with the value returned in the [i]getTokens() [/i]method. The [i]IntegerRule [/i]that comes with Mentawai also returns tokens for its min and max values. The tokens of a rule are nothing more than its properties that you may want to display along with the error messages.<br /> <br /> There are other types of validation that are not solely based in the value itself. For example you may want to perform validation based on the user locale and you may want to perform validation of one field based on another field.<br /> <br /> The most common example of a validation that depends on the locale is date validation. Depending on the user locale the date 12/30/2008 may be valid or not. Below is the source code of a simple rule to validate dates. Note that we are now extending [i]LocaleRule [/i]instead of [i]BasicRule[/i].<br /> [code]<br /> import java.util.*;<br /> import java.text.*;<br /> <br />  public class DateRule extends LocaleRule {<br /> 	 <br />      private static final int STYLE = DateFormat.SHORT;<br />      <br />      public DateRule() {<br />          <br />      }<br />      <br />      public boolean check(String value, Locale locale) {<br />     	 <br />          DateFormat df = DateFormat.getDateInstance(style, locale);<br />         	 <br />          df.setLenient(false);<br />          <br />          try {<br />              <br />              df.parse(value);<br />              <br />              return true;<br />              <br />          } catch(ParseException e) {<br />         	 <br />              return false;<br />              <br />          }<br />      }<br />      <br />      public Map&lt;String, String&gt; getTokens() {<br />     	 <br />     	 return null;<br />      }<br />      <br />  }<br /> [/code]<br /> Note that now the [i]check()[/i] method receives not just the value but also the locale of the user performing the request. You should use the locale in any way you want to perform the validation. Mentawai already comes with a complete [i]DateRule [/i]so you should not need to code a rule for dates. This was just an example for you to understand how the [i]LocaleRule [/i]works in case you want to write your own.<br /> <br /> The last form of common validation is when you need to compare two fields to determine whether one field is valid or not. If you thought about password and password confirmation you were right. For that we can extend the [i]CrossRule [/i]class. Check the source below for a simple [i]EqualRule [/i]that validates whether two fields have the same value:<br /> [code]<br /> import java.util.HashMap;<br /> import java.util.Map;<br /> <br /> public class EqualRule extends CrossRule {<br /> 	<br /> 	private final String[] fields;<br /> 	<br /> 	public EqualRule(String field1, String field2) {<br /> 		this.fields = new String[] { field1, field2 };<br /> 	}<br /> 	<br /> 	protected String[] getFieldsToValidate() {<br /> 		return fields;<br /> 	}<br /> 	<br /> 	public boolean check(String[] values) {<br /> 		<br /> 		return values[0].equals(values[1]);<br /> 	}<br /> 	<br /> 	public Map&lt;String, String&gt; getTokens() {<br /> 		return null;<br /> 	}<br /> }<br /> [/code]<br /> When inheriting from [i]CrossRule [/i]you should implement two abstract methods: <br /> <br /> :arrow: getFieldsToValidate() should return an array of the field names that will be compared.<br /> <br /> :arrow: check(String[] values) receives the values of the fields indicated by the[i] getFieldsToValidate()[/i] method, so that you can perform any comparison you want to validate them.<br /> <br /> Note that Mentawai gets the field values for you from the action input and pass them along with the check method so that you can compare them and return the validation result. Mentawai already comes with a complete [i]EqualRule [/i] in the [i]org.mentawai.rule[/i] package.<br /> <br /> Another very useful built-in rule that you can use for your advantage is the [i]RegexRule[/i]. Check below how a [i]SocialSecurityNumberRule [/i]could be implemented by inheriting from [i]RegexRule[/i]:<br /> [code]<br /> public class SSNRule extends RegexRule {<br /> 	<br />     /** The regex to use for SSN validation. */<br /> 	public static final String PATTERN = "^\\d\\d\\d\\-\\d\\d\\-\\d\\d\\d\\d$";<br /> 	<br /> 	public SSNRule() {<br /> 		super(PATTERN);<br /> 	}<br /> }<br /> [/code]<br /> You could have also used the [i]RegexRule [/i]with the Social Security Number pattern without the need to create a new rule for it. See below:<br /> [code]<br /> Rule rule = new RegexRule("^\\d\\d\\d\\-\\d\\d\\-\\d\\d\\d\\d$");<br /> [/code]<br /> As you can see, by inheriting from [i]BasicRule[/i], [i]LocaleRule[/i], [i]CrossRule [/i]and [i]RegexRule [/i]you can perform any kind of validation for your action input values.<br /> <br /> ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/27/28.page</guid>
				<link>http://book.mentaframework.org/posts/preList/27/28.page</link>
				<pubDate><![CDATA[Mon, 11 Aug 2008 17:26:18]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Validation through a separate filter</title>
				<description><![CDATA[ Instead of using the [i]Validatable[/i] interface, which has to be implemented by the action, you can code a separate filter that will be applied to the action in the application manager. You may choose that approach if you want your action to be clean from any validation code or if you want to apply the same validation to different actions that may depend on the same form data.<br /> <br /> To code your validation filter, you should inherit from [i]org.mentawai.filter.ValidationFilter[/i] and implement the abstract method [i]prepareValidator()[/i]. Check the example below:<br /> [code]<br /> <br /> public class HelloValidator extends ValidationFilter {<br /> 	<br />     public void prepareValidator(Validator val, Action action, String innerAction) {<br />         <br />             Rule required = RequiredRule.getInstance();<br />         <br />             val.add("username", required, "required_error");<br />             val.add("username", StringRule.getInstance(6, 30), "invalid_username");<br />         <br />             val.add("age", required, "required_error");<br />             val.add("age", IntegerRule.getInstance(18, 50), "invalid_age");<br />         <br />             val.add("password", required, "required_error");<br />             val.add("password", StringRule.getInstance(4, 20), "invalid_password_length");<br />             val.add("password", EqualRule.getInstance("password", "passconf"), "password_does_not_match");<br />         <br />             val.add("passconf", required, "required_error");<br />     }<br /> }<br /> [/code]<br /> The method [i]prepareValidator()[/i] is very similar to the same method of the [i]Validatable[/i] interface, the only difference being that it also passes as a parameter the action object that the filter is being applied to. The rest is the same. You can use an i18n file or you can place the error messages in the filter code, pretty much like you can do when using the [i]Validatable [/i]interface. One thing to note is that if you use an i18n file, the name of the file will be /validation/[i]filtername[/i]_[i]localehere[/i].i18n. So for the filter above it would be /validation/HelloValidator_pt.i18n, /validation/HelloValidator_en.i18n, etc.<br /> <br /> Then you can apply the filter to one or more actions inside the application manager. Below is an example:<br /> [code]<br /> @Override<br /> public void loadActions() {<br /> <br />     action(HelloAction.class)<br />         .filter(new HelloValidator());<br /> <br />     // OR<br /> <br />     ActionConfig ac = new ActionConfig(HelloAction.class);<br />     ac.addFilter(new HelloValidator());<br />     addActionConfig(ac);<br /> }<br /> [/code]<br /> ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/26/27.page</guid>
				<link>http://book.mentaframework.org/posts/preList/26/27.page</link>
				<pubDate><![CDATA[Mon, 11 Aug 2008 13:05:09]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Validation is dynamic</title>
				<description><![CDATA[ It is important to realize that the validation code inside the [i]prepareValidator()[/i] method is executed for each request. Therefore you can dynamically perform your validation based on the action parameters and characteristics. Check the example below:<br /> [code]<br /> public class MyAction extends BaseAction implements Validatable {<br />     <br />     public String execute() {<br />         <br />         // your action stuff here...<br />         <br />     }<br />     <br />     public void prepareValidator(Validator val, String innerAction) {<br /> <br />             if (isPost()) {<br />         <br />                 Rule required = RequiredFieldRule.getInstance();<br />         <br />                 val.add("username", required, FIELD_REQUIRED_ERROR);<br />                 val.add("username", StringRule.getInstance(6, 30), INVALID_USERNAME_LENGTH);<br />         <br />                 val.add("age", required, FIELD_REQUIRED_ERROR);<br />                 val.add("age", IntegerRule.getInstance(18, 50), INVALID_AGE);<br />         <br />                 val.add("password", required, FIELD_REQUIRED_ERROR);<br />                 val.add("password", StringRule.getInstance(4, 20), INVALID_PASSWORD_LENGTH);<br />                 val.add("password", EqualRule.getInstance("password", "passconf"), PASSWORD_DOES_NOT_MATCH);<br />         <br />                 val.add("passconf", required, FIELD_REQUIRED_ERROR);<br />             }    <br />         }<br />     <br />     private static final String FIELD_REQUIRED_ERROR = "Field required!";<br />     private static final String INVALID_USERNAME_LENGTH = "Username length invalid!";<br />     private static final String INVALID_AGE = "Invalid age!";<br />     private static final String INVALID_PASSWORD_LENGTH = "Invalide password length!";<br />     private static final String PASSWORD_DOES_NOT_MATCH = "Passwords do not match!";<br /> }<br /> [/code]<br /> In the example above, only a POST request will be validated. A GET will not have any validation. You can also perform validation based on the inner action, which is very common as each inner action will have its own validation. Check below:<br /> [code]public class MyAction extends BaseAction implements Validatable {<br />     <br />     public String execute() {<br />         <br />         // your action stuff here...<br />         <br />     }<br />     <br />     public void prepareValidator(Validator val, String innerAction) {<br /> <br />             if (innerAction != null && innerAction.equals("addUser")) {<br />         <br />                 Rule required = RequiredRule.getInstance();<br />         <br />                 val.add("username", required, FIELD_REQUIRED_ERROR);<br />                 val.add("username", StringRule.getInstance(6, 30), INVALID_USERNAME_LENGTH);<br />         <br />                 val.add("age", required, FIELD_REQUIRED_ERROR);<br />                 val.add("age", IntegerRule.getInstance(18, 50), INVALID_AGE);<br />         <br />                 val.add("password", required, FIELD_REQUIRED_ERROR);<br />                 val.add("password", StringRule.getInstance(4, 20), INVALID_PASSWORD_LENGTH);<br />                 val.add("password", EqualRule.getInstance("password", "passconf"), PASSWORD_DOES_NOT_MATCH);<br />         <br />                 val.add("passconf", required, FIELD_REQUIRED_ERROR);<br />             }    <br />         }<br />     <br />     private static final String FIELD_REQUIRED_ERROR = "Field required!";<br />     private static final String INVALID_USERNAME_LENGTH = "Username length invalid!";<br />     private static final String INVALID_AGE = "Invalid age!";<br />     private static final String INVALID_PASSWORD_LENGTH = "Invalide password length!";<br />     private static final String PASSWORD_DOES_NOT_MATCH = "Passwords do not match!";<br /> }<br /> [/code]<br /> In the code above, only the "addUser" innerAction will be validated. All others, including the default (no inner action) [i]execute()[/i] method will not be validated. Recall that [i]innerAction == null[/i] means the [i]execute()[/i] method was called.<br /> <br /> Because of the dynamic characteristic of the validation, you should avoid creating new rule objects on each request. That's why we have been using the [i]getInstance()[/i] method instead of the [i]new [/i]constructor for our rules. The [i]getInstance()[/i] method returns the same instance every time, avoiding the creation of new objects on every request. Despite the fact that the Java garbage collector is very powerful nowadays, you should try to avoid creating too many Java objects unnecessarily.<br /> <br /> Most of the Mentawai built-in rules already provide the [i]getInstance()[/i] method. If possible, and as a good practice, you should provide this method with any new rule you code. We will see how to create new validation rules in a bit.]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/25/26.page</guid>
				<link>http://book.mentaframework.org/posts/preList/25/26.page</link>
				<pubDate><![CDATA[Sat, 9 Aug 2008 08:44:17]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Placing messages in the code</title>
				<description><![CDATA[ Although not a good practice, you are free to place your validation error messages inside your source code instead of using an i18n file. If you application is a simple one that does not plan to use internationalization you may prefer this approach.<br /> <br /> If Mentawai does not find the i18n file or the key inside the i18n file, it will just display the key as the error message. So just place your error message as the key and you are ready to go. See the example below:<br /> [code]<br /> public class MyAction implements Validatable {<br />     <br />     public String execute() throws Exception {<br />         <br />         // your action stuff here...<br />         <br />     }<br />     <br />     public void prepareValidator(Validator val, String innerAction) {<br />         <br />             Rule required = RequiredRule.getInstance();<br />         <br />             val.add("username", required, FIELD_REQUIRED_ERROR);<br />             val.add("username", StringRule.getInstance(6, 30), INVALID_USERNAME_LENGTH);<br />         <br />             val.add("age", required, FIELD_REQUIRED_ERROR);<br />             val.add("age", IntegerRule.getInstance(18, 50), INVALID_AGE);<br />         <br />             val.add("password", required, FIELD_REQUIRED_ERROR);<br />             val.add("password", StringRule.getInstance(4, 20), INVALID_PASSWORD_LENGTH);<br />             val.add("password", EqualRule.getInstance("password", "passconf"), <br />                                                                            PASSWORD_DOES_NOT_MATCH);<br />         <br />             val.add("passconf", required, FIELD_REQUIRED_ERROR);<br />             <br />     }<br />     <br />     private static final String FIELD_REQUIRED_ERROR = "Field required!";<br />     private static final String INVALID_USERNAME_LENGTH = "Username length invalid!";<br />     private static final String INVALID_AGE = "Invalid age!";<br />     private static final String INVALID_PASSWORD_LENGTH = "Invalide password length!";<br />     private static final String PASSWORD_DOES_NOT_MATCH = "Passwords do not match!";<br /> }<br /> [/code]<br /> Note that we are just using the error message as the key. Mentawai executes the following logic to find the error message.<br /> <br /> :arrow: Look for the i18n file. If you don't find the i18n file, use the key as the error message.<br /> :arrow: If you found the i18n file, look for the key. If you don't find the key, use the key as the error message.<br /> :arrow: If you found the key, print the associated text as the error message.<br /> <br /> As you can see, it is very easy to place your error messages inside your source code instead of using an i18n file.]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/24/25.page</guid>
				<link>http://book.mentaframework.org/posts/preList/24/25.page</link>
				<pubDate><![CDATA[Sat, 9 Aug 2008 08:31:52]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Using the Validatable interface</title>
				<description><![CDATA[ You can set the [i]ValidatorFilter()[/i] as a global filter so that all your actions implementing the [i]Validatable[/i] interface will be validated. Here is how you set this global filter inside your application manager.<br /> [code]<br /> filter(new ValidatorFilter());<br /> <br /> // or<br /> <br /> addGlobalFilter(new ValidatorFilter());<br /> [/code]<br /> Below is an example of how to validate your action using the [i]Validatable [/i]interface. Note that you are not using annotation or xml. You are using [b]programmatic configuration[/b] to setup the validation of your form fields.<br /> [code]<br /> public class MyAction implements Validatable {<br />     <br />     public String execute() {<br />         <br />         // your action stuff here...<br />         <br />     }<br />     <br />     public void prepareValidator(Validator val, String innerAction) {<br />         <br />             Rule required = RequiredRule.getInstance();<br />         <br />             val.add("username", required, "required_error");<br />             val.add("username", StringRule.getInstance(6, 30), "invalid_username");<br />         <br />             val.add("age", required, "required_error");<br />             val.add("age", IntegerRule.getInstance(18, 50), "invalid_age");<br />         <br />             val.add("password", required, "required_error");<br />             val.add("password", StringRule.getInstance(4, 20), "invalid_password_length");<br />             val.add("password", EqualRule.getInstance("password", "passconf"), "password_does_not_match");<br />         <br />             val.add("passconf", required, "required_error");<br />             <br />     }<br /> }<br /> <br /> [/code]<br /> To each form field is applied a set of validation [i]rules[/i]. For example, for the field "age" we are applying two rules:<br /> <br /> :arrow: [i]RequiredRule[/i]: enforces that a field is present, in other words, not blank or null<br /> :arrow: [i]IntegerRule[/i]: enforces that a field is an Integer between a min and a max value<br /> <br /> Mentawai validation rules are as flexible as Java code because they are Java code, not XML or Annotation. If you check the [i]javadoc [/i]of the [i]IntegerRule [/i]class you will find out that it has three different constructors:<br /> <br /> :arrow: [i]IntegerRule()[/i]: meaning any integer will be accepted, even negative integers<br /> :arrow: [i]IntegerRule(int min)[/i]: meaning any integer &gt;= min will be accepted<br /> :arrow: [i]IntegerRule(int min, int max)[/i]: meaning any integer &gt;= min and &lt;= max will be accepted<br /> <br /> Mentawai comes with many read-to-use rules in the package [i]org.mentawai.rule[/i] like [i]StringRule[/i], [i]NumberRule[/i], [i]EmailRule[/i], [i]FileRule[/i], etc. Plus it comes with a very handy rule called [i]RegexRule [/i]which allows you to validate any field based on a regular expression. You will not be surprised to find out that many other Mentawai rules (like the [i]EmailRule[/i]) inherit from [i]RegexRule [/i]to do its job. As we will see later in this chapter, it is very, very easy to create your own rules for validation as well in case the provided ones do not suit your needs.<br /> <br /> If a validation rule fails, a error message associated with it is displayed to the user. Because these messages are usually internationalized (translated into many languages) and more strongly because you don't want to mix content with source code, they should reside in a text file we call i18n file. (Soon you will see how to bypass this good practice and place your error messages together with your code if you prefer to)<br /> <br /> The default location for your validation error messages are /validation/[i]actionamehere[/i]_[i]localehere[/i].i18n. However if you prefer to keep all your messages in a single file (that we call master) you can invoke the following method inside your application manager:<br /> [code]<br /> LocaleManager.useMasterI18N(true);<br /> [/code]<br /> If you do this, all your messages, not just for validation but all internationalized messages in your application will be stored in the file /i18n/master_[i]localehere[/i].i18n.<br /> <br /> So for example if your are NOT using the master file, your action is [i]MyAction [/i](like our example above) and you have two languages pt and en, you would have the following files: /validation/MyAction_pt.i18n and /validation/MyAction_en.i18n.<br /> <br /> But if you are using the master file, then all your messages from all your actions would be stored in the files: /i18n/master_pt.i18n and /i18n/master_en.i18n.<br /> <br /> Some people will prefer to store all text messages in a single file what makes things easier when it comes the time to translate everything to a new language. Other people will prefer to have a separate file for each action. It is up to you what approach to take.<br /> <br /> An example of the validation messages for the action above is listed below:<br /> [code]<br /> ###############################################<br /> # Validation messages for MyAction<br /> ###############################################<br />  <br /> required_error = Required field cannot be left blank<br /> invalid_username = Your username must be between %min% and %max% characters long.<br /> invalid_age = You must be %min% years old or older.<br /> invalid_password_length = Your password must be between %min% and %max% characters long.<br /> password_does_not_match = Passwords do not match.<br /> [/code]<br /> Note how we are using the tokens %min% and %max% to place some validation information inside our error messages. You should already be familiar with the i18n file syntax because it is the same of the Java [i]Properties [/i]class.<br /> <br /> Now to display these messages inside a JSP page, all you have to do is make use of some very useful mentawai tags. See our example below:<br /> [code]<br /> &lt;%@ taglib uri="/WEB-INF/lib/mentawai.jar" prefix="mtw" %&gt;<br /> <br /> &lt;html&gt;<br /> &lt;body&gt;<br /> &lt;h1&gt;Hello Validation!&lt;/h1&gt;<br /> <br /> &lt;mtw:form&gt;<br /> <br /> Your username: &lt;mtw:input name="username" size="25" /&gt;<br /> <br /> &lt;mtw:outError field="username"&gt;<br /> 	<font color="red">&lt;mtw:out /&gt;</font><br /> &lt;/mtw:outError&gt;<br /> <br /> <br>Your age: &lt;mtw:select name="age" size="1" list="ages"&gt;<br /> <br /> &lt;mtw:outError field="age"&gt;<br /> 	<font color="red">&lt;mtw:out /&gt;</font><br /> &lt;/mtw:outError&gt;<br /> <br /> <br>Your password: &lt;mtw:input type="password" name="password" size="25" /&gt;<br /> <br /> &lt;mtw:outError field="password" &gt;<br /> 	<font color="red">&lt;mtw:out /&gt;</font><br /> &lt;/mtw:outError&gt;<br /> <br /> <br>Again please: &lt;mtw:input type="password" name="passconf" size="25" /&gt;<br /> <br /> &lt;mtw:outError field="passconf"&gt;<br /> 	<font color="red">&lt;mtw:out /&gt;</font><br /> &lt;/mtw:outError&gt;<br /> <br /> &lt;mtw:submit value="Enviar" action="HelloWorld.mtw" method="post" /&gt;<br /> <br /> &lt;/mtw:form&gt;<br /> &lt;/body&gt;<br /> &lt;/html&gt;<br /> [/code]<br /> Note that this tags are conditional tags, in other words, nothing inside the tag will be shown if there is no error for the field. If you want to display all field errors in the top of your page instead of near each field in your form, you can use another menta tag, the &lt;mtw:outFieldErrors&gt; tag.<br /> [code]<br /> &lt;!-- List all field errors --&gt;<br /> &lt;mtw:outFieldErrors&gt;<br />   &lt;h4&gt;Here are the error messages:&lt;/h4&gt;<br />   &lt;mtw:loop&gt;<br />     <font color="red">&lt;mtw:out /&gt;</font><br/><br />   &lt;/mtw:loop&gt;<br /> &lt;/mtw:outFieldErrors&gt;<br /> [/code]<br /> To conclude, an important tip that we will see later in the book: Use the Mentawai HTML form tags &lt;mtw:input&gt;, &lt;mtw:select&gt;, &lt;mtw:checkboxes&gt;, etc. so you don't have to worry about re-displaying the values that the user typed in case of validation error. We know you don't want to place a bunch of scriptlets in your JSPs to do this. ;-)<br /> ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/23/24.page</guid>
				<link>http://book.mentaframework.org/posts/preList/23/24.page</link>
				<pubDate><![CDATA[Fri, 8 Aug 2008 16:40:27]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Conclusion</title>
				<description><![CDATA[ In this chapter we discussed about the Mentawai architecture and its main interfaces like [i]Action, Input, Output, Context, Filter, Consequence[/i], etc. You learned how filters work and how to create your own filters. You also learned about inner actions and how to configure your actions inside the application manager. You were also introduced to the Mentawai Debug Mode, that can show you everything that is happening under the hood inside the action invocation chain.<br /> <br /> You also saw the main consequences of any web application: Forward and Redirect. You were also introduced to the Chain, Stream and Ajax consequences.<br /> <br /> Now it is time to dive into the many Mentawai features. Remember that one of the goals of the Mentawai framework is to abstract all the repetitive tasks of any web project. Stuff like Validation, Authentication, Form Handling, Sending Email, etc. are boring and repetitive, so the framework has to offer you a very simple and intuitive way of dealing with that. With Mentawai you should never waste time re-inventing the wheel. It tries to do all the boring work for you so you can have fun getting your project done and making your boss happy.]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/21/22.page</guid>
				<link>http://book.mentaframework.org/posts/preList/21/22.page</link>
				<pubDate><![CDATA[Mon, 14 Jan 2008 09:42:08]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
			<item>
				<title>Consequences (Forward, Redirect, Chain, Stream, etc.)</title>
				<description><![CDATA[ [color=blue][size=18][b]Forwarding to JSP pages[/b][/size][/color]<br /> <br /> The basic and most common consequence you will use in your web projects is the [b]Forward[/b]. In Mentawai, this is the [i]org.mentawai.core.Forward[/i] class, which implements the [i]org.mentawai.core.Consequence[/i] interface. The interesting aspects about a forward are listed below:<br /> <br /> :arrow: A forward always happens in the server-side, in other words, the client (the browser) does not realize that a forward is happening. For example, if you make a call to the action http://www.mysite.com/Hello.mtw and the result of the action [i]Hello.class[/i] is a forward to /hello.jsp, [b]the location in the address bar of your browser will not change[/b] to /hello.jsp. That's because the forward is really happening on the server-side. No other request is needed from the browser. The request is passed over to the JSP page and the result is returned in the same request that asked for the [i]Hello [/i]action. This is exactly the opposite of what happens when you do a Redirect.<br /> <br /> :arrow: A forward will always pass the action and all its contexts ([i]Input[/i], [i]Output[/i], [i]Session[/i], [i]Cookies[/i], etc.) to the JSP page. When you do a forward, the results of the action execution are made available to the JSP page. This is the opposite of what happens when you do a Redirect. When you do a redirect, a new request is done by the browser to a new action or JSP page. All the previous action information before the redirect is discarded.<br /> <br /> The classic scenario is: <br /> <ul>WebRequest    ---------&gt;    Action generates some results    ----------&gt;    Forward to JSP to display the results</ul><br /> For example for the simple action below you can configure some forwards:<br /> <br /> [code]<br /> public class HelloAction extends BaseAction {<br /> <br />     public String sayHi() {<br />  <br />         output.setValue("message", "Hi there!");<br /> <br />         return SUCCESS;<br />     }<br /> <br />     public String sayHello() {<br />  <br />         output.setValue("message", "Hello there!");<br /> <br />         return SUCCESS;<br />     }<br /> }<br /> [/code]<br /> <br /> Inside the application manager:<br /> <br /> [code]<br /> <br /> public void loadAction() {<br /> <br />     action(HelloAction.class)<br />         .on(SUCCESS, "sayHi", new Forward("/hi.jsp"))<br />         .on(SUCCESS, "sayHello", fwd("/hello.jsp"));<br /> <br />     // OR<br /> <br />     ActionConfig ac = new ActionConfig(HelloAction.class);<br />     ac.addConsequence(SUCCESS, "sayHi", new Forward("/hi.jsp"));<br />     ac.addConsequence(SUCCESS, "sayHello", fwd("hello.jsp"));<br />     addActionConfig(ac);  <br />   <br /> }<br /> [/code]<br /> <br /> Just keep in mind that whenever you want the [b]action information to be displayed in the JSP page[/b] you will most likely want a [b]Forward[/b] consequence. Another point to keep in mind is that if the user hits the [i]Reload [/i]button in the browser, the whole action is executed again.<br /> <br /> <br /> [color=blue][size=18][b]Redirecting to a new URL[/b][/size][/color]<br /> <br /> In Mentawai, the Redirect consequence is implemented by the core class [i]org.mentawai.core.Redirect[/i], which implements the core interface [i]org.mentawai.core.Consequence[/i]. When you issue a Redirect consequence, you are really telling the browser: "[i]Hey! Please do another web request to the this URL here![/i]". As a result, the URL location in the address bar of the browser will change to the redirect URL and all the information about the action that performed the redirect will be discarded.<br /> <br /> Contrary to the Forward, a Redirect happens in the client-side, in other words, it is the browser that performs another web request to the JSP page or action. You could use a redirect, for example, when you want to avoid having the user accidentally hitting the [i]reload [/i]button and executing the action again.<br /> <br /> There are many ways to a redirect in Mentawai. Below I will explain each one:<br /> <br /> :arrow: [b][color=blue]Regular redirect[/color][/b]<br /> <br /> This is the redirect you will be using 99% of the time and it is [b]always related to the [i]context path [/i]of your web application[/b]. The [i]context path[/i] is the directory where your application is located inside the Tomcat [i]webapps [/i]directory. It is what allows the same Tomcat to run a bunch of different web applications together and independently.<br /> <br /> Below are some examples:<br /> [code]<br />     on(SUCCESS, redir("/congrats.jsp"));<br /> <br />     addConsequence(JSP, new Redirect("/user/users.jsp"));<br /> [/code]<br /> The first redirect will tell the browser to perform another web request to the following URL:<br /> <br /> http://www.mysite.com/DVDStore/congrats.jsp<br /> <br /> The second redirect will tell the browser to perform another web request to the following URL:<br /> <br /> http://www.mysite.com/DVDStore/user/users.jsp<br /> <br /> This is assuming that your context path is "DVDStore". If your context path was the [i]ROOT context path[/i], which is the [i]ROOT [/i]directory inside the Tomcat [i]webapps [/i]directory, your redirect URLs would be:<br /> <br /> http://www.mysite.com/congrats.jsp<br /> <br /> http://www.mysite.com/user/users.jsp<br /> <br /> <br /> :arrow: [b][color=blue]Redirect relative to the web server[/color][/b]<br /> <br /> You can use this redirect when you want to perform a redirect [b]to another web application running in the same web server[/b]. For example:<br /> [code]<br />     on(SUCESS, redir("//BookStore/showBooks.mtw"));<br /> <br />     on(JSP, redir("//index.jsp"));<br /> [/code]<br /> When you start the redirect with a double slash ("//"), you are just saying: "Hey, I don't want to be relative to the context path!" Therefore, even if you context path is "DVDStore", the resulting redirect URLs for the examples above will be:<br /> <br /> http://www.mysite.com/BookStore/showBooks.mtw<br /> <br /> http://www.mysite.com/index.jsp<br /> <br /> This type of redirect is rare. It is only needed when you are running two different applications in the same servlet container that are somehow related to each other.<br /> <br /> <br /> :arrow: [b][color=blue]Redirect with dynamic parameters[/color][/b]<br /> <br /> Sometimes you want to perform a redirect, but you will only know the parameters of the URL at runtime. For example, you want to redirect the browser to the action that shows all the books for a certain category. This could be something like:<br /> <br /> http://www.mysite.com/BookStore/Book.show.mtw?cat=&lt;CATEGORY_ID&gt;<br /> <br /> To setup this redirect with a dynamic parameter, you can do this:<br /> [code]<br />     .on(SUCCESS, redir("/Book.show.mtw", true));<br /> [/code]<br /> The true above indicates that this is a redirect with dynamic parameters that will come from the action output. So our action will just do something like this:<br /> [code]<br /> public class BookAction extends BaseAction {<br /> <br />     public String add() {<br /> <br />         // add a new book to the database somehow...<br /> <br />         output.setValue("cat", book.getCategory());<br /> <br />         return SUCCESS;<br />     }<br /> }<br /> [/code]<br /> Assuming that book.getCategory() returns 43, the resulting URL would be:<br /> <br /> http://www.mysite.com/BookStore/Bood.show.mtw?cat=43<br /> <br /> Note that all the values from the action output will be added as parameters to the redirect URL.<br /> <br /> <br /> :arrow: [b][color=blue]Redirect to a dynamic URL[/color][/b]<br /> <br /> Sometimes you will not even know the URL you want to redirect to. This is rare, but can happen, for example, when you want to redirect your user to a URL saved in a database. Here is how it works:<br /> [code]<br />     on(SUCCESS, redir());<br />   <br />     on(JSP, new Redirect());<br /> [/code]<br /> When you create a redirect using the constructor with empty parameters (or make use of the helper method redir() with empty parameters), the redirect will expect the URL to come from the action output. Here is an example of an action:<br /> [code]<br /> public class BookmarkAction extends BaseAction {<br /> <br />     public String go() {<br /> <br />         // get the URL from the database<br /> <br />         String url = "http://www.mentaframework.org";<br /> <br />         output.setValue(Redirect.REDIRURL_PARAM, url);<br />     }<br /> }<br /> [/code]<br /> Note that you are using the REDIRURL_PARAM from the Redirect consequence to place the dynamic URL inside the action output. You may have other values inside the action output and that's how the redirect class knows how to find the dynamic URL.<br /> <br /> <br /> Last but not least about the Redirect consequence:<br /> <br /> :arrow: If you redirect contains the string "://" inside it, it is assumed that you want to do a redirect to a absolute address. Examples:<br /> [code]<br />     on(SUCCESS, redir("http://www.cnn.com"));<br /> <br />     on(FTP, redir("https://www.safe.com"));<br /> [/code]<br /> The redirect understands that the above redirect are all absolute URLs, not relative to anything.<br /> <br /> :arrow: There are no redirects relative to the request<br /> <br /> This is on purpose. If you try to do something like [i]on(SUCCESS, redir("[b]loosepage.jsp[/b]"))[/i], Mentawai will automatically assume that you meant [i]on(SUCCESS, redir("[b]/loosepage.jsp[/b]"))[/i]. Redirects relative to the request are not needed and only introduce confusion.<br /> <br /> :arrow: You can also use a dynamic URL with dynamic parameters. Below is how to configure this redirect in the application manager:<br /> [code]<br />     on(SUCCESS, redir(true));<br /> <br />     on(SUCCESS, new Redirect(true));<br /> [/code]<br /> :arrow: Dynamic parameters will be automatically encoded. Dynamic URLs will not be encoded, in other words, if they have any hardcoded parameter it is assumed that it is already encoded.<br /> <br /> <br /> [color=blue][size=18][b]Chaining actions[/b][/size][/color]<br /> <br /> For a single web request you can chain different actions in the server-side before invoking a consequence that will return a result to the browser. For example you can have a request handled by action A chained to action B chained to action C and then action C returns a result that will invoke a consequence. You should note that like a forward, chaining actions happens in the server-side. Below is an example of how to configure a chain consequence:<br /> [code]<br /> @Override<br /> public void loadActions() {<br /> 		<br />     ActionConfig helloAction = new ActionConfig(HelloAction.class, "hello");<br /> 	ac2.addConsequence(SUCCESS, new Forward("/show.jsp"));<br /> 	addActionConfig(helloAction);<br /> 		<br /> 	ActionConfig ac = new ActionConfig(HiAction.class, "hi");<br /> 	ac.addConsequence(SUCCESS, new Chain(helloAction));<br /> 	addActionConfig(ac);<br /> }<br /> [/code]<br /> Or you can use the less verbose style:<br /> [code]<br /> @Override<br /> public void loadActions() {<br /> 		<br />     ActionConfig helloAction = action(HelloAction.class, "hello")<br /> 	    .on(SUCCESS, fwd("/show.jsp"));<br /> 		<br />     action(HiAction.class, "hi")<br /> 	    on(SUCCESS, chain(helloAction));<br /> }<br /> [/code]<br /> Before you configure any chain consequence, you must understand that [b]action chaining is rare and in most cases there is no need for you to make use of it[/b]. Let's take a classic example where you have an action that adds an user and another action that lists all the users. You may get tempted to do a chain like:<br /> [code]<br /> ActionConfig showAction = action(User.class, "show")<br />     .on(SUCESS, fwd("/show.jsp"));<br />     <br /> action(User.class, "add")<br />     .on(SHOW, chain(showAction))<br />     .on(ERROR, fwd("/addUser.jsp"));<br /> [/code]<br /> Although definitely not a sin, this could have been done much better with a redirect consequence:<br /> [code]<br /> action(User.class, "show")<br />     .on(SUCESS, fwd("/show.jsp"));<br />     <br /> action(User.class, "add")<br />     .on(SHOW, redir("/User.show.mtw", true) // true = dynamic parameters<br />     .on(ERROR, fwd("/addUser.jsp"));<br /> [/code]<br /> So now after the [i]add[/i] inner action is done, it will redirect (not chain) to the show inner action. <u>If the user hits the reload button, only the show inner action will be executed again, and not the whole chain.</u> Note that we are supporting dynamic parameters for the redirect, that's because we may need to add some parameters to the URL before redirecting, for example:<br /> <br /> http://www.mysite.com/User.add.mtw?category=34<br /> <br /> As we saw in the previous chapter about redirect, these parameters will come from the action output.<br /> <br /> To conclude, here is what you should keep in mind when using a chain consequence:<br /> <br /> :arrow: Think if you don't really want a redirect to an action instead of a chain. The question you should ask yourself is: [i]Do you want to execute everything again if the user press the reload button?[/i]<br /> <br /> :arrow: When two actions are chained, the input and output of the first are passed to the second.<br /> <br /> :arrow: Each action will be executed with its own set of filters. If we have a global filter, then it will be executed twice, one time for each action.<br /> <br /> :arrow: You can also pass an inner action to the chain controller: <br /> [code] <br /> ac.addConsequence(SHOW, new Chain(helloAction, "hello"));<br /> <br /> on(SHOW, chain(helloAction, "hello"));<br /> [/code]<br /> <br /> [color=blue][size=18][b]Other consequences[/b][/size][/color]<br /> <br /> Mentawai comes with other consequences and you can also code your own consequences. For example, to return an image or a binary file you can use the [i]StreamConsequence[/i]:<br /> <br /> In the action:<br /> [code]<br /> public class ImageAction extends BaseAction {<br />     <br />     public String execute() {<br />         <br />         byte[] image = getImageBytesSomehow();<br />         <br />         output.setValue(StreamConsequence.STREAM_KEY, image);<br />         output.setValue(StreamConsequence.CONTENT_LENGTH_KEY, image.length);<br />         <br />         return SUCCESS;<br />     }<br /> }<br /> [/code]<br /> In the [i]ApplicationManager[/i]:<br /> [code]<br /> public void loadActions() {<br />     <br />     action(ImageAction.class)<br />         .on(SUCCESS, stream("image/jpg"));<br />         <br />     // or<br />     <br />     ActionConfig ac = new ActionConfig(ImageAction.class);<br />     ac.addConsequence(SUCCESS, new StreamConsequence("image/jpg"));<br />     addActionConfig(ac);<br /> }<br /> [/code]<br /> You can place a byte array or a [i]InputStream [/i]as the stream key in the action output. If for example the file is a PDF, you don't want to load everything in memory in a byte array:<br /> [code]<br /> public class PDFAction extends BaseAction {<br />     <br />     public String execute() {<br />         <br />         FileInputStream fis = new FileInputStream("review.pdf");<br />         <br />         output.setValue(StreamConsequence.STREAM_KEY, fis);<br />         output.setValue(StreamConsequence.FILENAME_KEY, "review.pdf");<br />         // InpuStream has no size...<br />         <br />         return SUCCESS;<br />     }<br /> }<br /> [/code]<br /> An in the ApplicationManager:<br /> [code]<br /> public void loadActions() {<br />     <br />     action(PDFAction.class)<br />         .on(SUCCESS, stream("application/pdf"));<br />         <br />     // or<br />     <br />     ActionConfig ac = new ActionConfig(PDFAction.class);<br />     ac.addConsequence(SUCCESS, new StreamConsequence("application/pdf"));<br />     addActionConfig(ac);<br /> }<br /> [/code]<br /> For Ajax, you can use the [i]AjaxConsequence [/i]that uses a renderer to format the action response into an ajax response (JSON, XML, etc.)<br /> <br /> Action:<br /> [code]<br /> public class TestAction extends BaseAction {<br /> <br /> 	public String autoCompleter() {<br /> <br /> 		String sourceInput = input.getStringValue("sourceInput");<br /> <br /> 		Map&lt;Integer, String&gt; map = new LinkedHashMap&lt;Integer, String&gt;();<br /> <br /> 		if(sourceInput.startsWith("a")) {<br /> <br /> 			map.put(1, "a. Somebody with id 1");<br /> 			map.put(2, "a. Somebody with id 2");<br /> 			map.put(3, "a. Somebody with id 3");<br /> <br /> 		} else if(sourceInput.startsWith("b")) {<br /> <br /> 			map.put(4, "b. Somebody with id 4");<br /> 			map.put(5, "b. Somebody with id 5");<br /> 			map.put(6, "b. Somebody with id 6");<br /> <br /> 		} else {<br /> <br /> 			map.put(7, "*. Somebody with id 7");<br /> 			map.put(8, "*. Somebody with id 8");<br /> 			map.put(9, "*. Somebody with id 9");<br /> 		}<br /> <br /> 		output.setValue(AjaxConsequence.KEY, map);<br /> 		<br /> 		return SUCCESS;<br /> 	}<br /> <br /> }<br /> [/code]<br /> ApplicationManager:<br /> [code]<br /> public void loadActions() {<br /> <br />       action(TestAction.class, "autoCompleter")<br />           .on(SUCCESS, new AjaxConsequence(new JSONGenericRenderer()));<br /> <br />      // or<br /> <br />       action(TestAction.class, "autoCompleter")<br />           .on(SUCCESS, ajax(new JSONGenericRenderer()));<br /> <br /> }<br /> [/code]]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/20/21.page</guid>
				<link>http://book.mentaframework.org/posts/preList/20/21.page</link>
				<pubDate><![CDATA[Mon, 14 Jan 2008 09:31:52]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
	</channel>
</rss>
