<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title><![CDATA[Latest posts for the topic "Filters"]]></title>
		<link>http://book.mentaframework.org/posts/list/3.page</link>
		<description><![CDATA[Latest messages posted in the topic "Filters"]]></description>
		<generator>JForum - http://www.jforum.net</generator>
			<item>
				<title>Filters</title>
				<description><![CDATA[ Filters are the building blocks of Mentawai through which all the main feature of the framework are implemented. A filter [i]wraps[/i] or [i]intercepts[/i] an action so that it can change everything about the action before it is actually executed. A filter always gets executed before the action, but as we will see in a moment it can also modify the action after it has been executed. For a single action you will usually have a stack of filters ([i]InvocationChain[/i]) being executed before the action. You can define global filters that will be applied on all actions or you can define action specific filters that will be applied only on that action. Filters are powerful, simple and flexible. They favor the [url="http://en.wikipedia.org/wiki/Separation_of_Concerns"][b]Separation of Concerns[/b][/url] pattern, allowing your action to [b]do one thing and do it right[/b]! For example, there is no need for your action code to get convoluted with validation code, file upload code, connection pooling code, etc. This can and should be abstracted outside your action through filters.<br /> <br /> Mentawai comes with many ready-to-use filters, but you should understand how they work and how to build your own filters. Building filters are very simple and you should have this weapon ready to kill unnecessary complexity in your code. Let's start coding some filters.<br /> <br /> A filter that gets a Map from the application and places it in the action input:<br /> <br /> [code]<br /> <br /> import org.mentawai.core.*;<br /> <br /> import java.util.*;<br /> <br /> public class CacheFilter implements Filter {<br />     <br />     private static final String KEY = "cache";<br />     <br />     public String filter(InvocationChain chain) throws Exception {<br />         <br />         Action action = chain.getAction();<br />         <br />         Context application = action.getApplication();<br />         <br />         Map&lt;String, Object&gt; cache = (Map&lt;String, Object&gt;) application.getAttribute(KEY);<br />         <br />         if (cache != null) {<br />             <br />             Input input = action.getInput();<br />             <br />             input.setValue(KEY, cache);<br />             <br />         }<br />         <br />         return chain.invoke(); // next filter or the action<br />     }<br /> <br />     public void destroy() { }<br /> }<br /> <br /> <br /> <br /> [/code]<br /> <br /> This was a somewhat unrealistic example as your action can just access the application context and get the cache map itself. However it is useful to understand the basic functionality of filters.<br /> <br /> Through the [i]InvocationChain[/i] object passed as a parameter to the filter you can get the action before it has been executed. Having the action, you can now access its Input, Output and contexts such as the Application context. After the filter is done, it should call [i]chain.invoke()[/i] unless it wants to halt the action execution. The invoke method will call the next filter in the filter stack or the action if there are no more filters in the stack. It returns the action result (String) which will be in turn returned by the filter.  <br /> <br /> There will be cases when you do want to block the access to the action, for example when you are using an authentication filter. An authentication filter may look like the filter below:<br /> <br /> [code]<br /> import org.mentawai.core.*;<br /> <br /> public class AuthenticationFilter implements Filter {<br />     <br />     public static final String LOGIN = "login";<br />     <br />     public String filter(InvocationChain chain) throws Exception {<br />  <br />         Action action = chain.getAction();       <br />         <br />         Context session = action.getSession();<br />         <br />         if (session.hasAttribute("user")) {<br />             <br />             return chain.invoke();<br />             <br />         }<br />         <br />         return LOGIN;<br />     }<br />     <br />     public void destroy() { }<br /> }<br /> [/code]<br /> <br /> In the filter above we are checking if the use is logged in the system, before allowing the action to be executed. If we find an object in the session for the key "user" we assume that the user is logged and call invoke(). If the user is not logged than we return the result LOGIN which may redirect the browser to a login page.<br /> <br /> A filter can modify the action before and also after the action has been executed. Check the example below which calculates the total time the action has taken to execute:<br /> <br /> [code]<br /> import org.mentawai.core.*;<br /> <br /> import java.util.Date;<br /> <br /> public class TimerFilter implements Filter {<br />     <br />     public String filter(InvocationChain chain) throws Exception {<br />         <br />         Action action = chain.getAction();<br />         <br />         Output output = action.getOutput();<br />         <br />         output.setValue("timeBefore", new Date()); // before the action execution...<br />         <br />         long now = System.currentTimeMillis();<br />         <br />         String result = chain.invoke();<br />         <br />         long totalTime = System.currentTimeMillis() - now;<br />         <br />         output.setValue("timeAfter", new Date()); // after the action execution...<br />         <br />         output.setValue("totalTime", totalTime);<br />         <br />         return result;<br />     }<br /> <br />     public void destroy() { }<br /> <br /> }<br /> [/code]<br /> <br /> Note how we are modifying the action output before and after the action has been executed. Another possibility is to use the AfterConsequenceFilter, which inherits from the Filter interface, to perform some task after the consequence has been executed. Let's change our TimerFilter to compute the time it takes for the consequence to execute:<br /> <br /> [code]<br /> package examples.helloworld.filter;<br /> <br /> import org.mentawai.core.*;<br /> <br /> import java.util.Date;<br /> <br /> public class TimerFilter implements AfterConsequenceFilter {<br />     <br />     public String filter(InvocationChain chain) throws Exception {<br />         <br />         Action action = chain.getAction();<br />         <br />         Output output = action.getOutput();<br />         <br />         output.setValue("timeBefore", new Date().toString()); // before the action execution...<br />         <br />         long now = System.currentTimeMillis();<br />         <br />         String result = chain.invoke();<br />         <br />         long totalTime = System.currentTimeMillis() - now;<br />         <br />         output.setValue("timeAfter", new Date().toString()); // after the action execution...<br />         <br />         output.setValue("totalTime", totalTime);<br />         <br />         // save the initial time for the consequence here...<br />         <br />         Input input = action.getInput();<br />         <br />         input.setValue("initialTime", System.currentTimeMillis());<br />         <br />         return result;<br />     }<br />     <br />     public void afterConsequence(Action action, Consequence c, boolean conseqExecuted, boolean actionExecuted, String result) {<br />         <br />         if (!conseqExecuted) {<br />             <br />             System.out.println("There was an error executing the consequence!");<br />             <br />         } else {<br />             <br />             Input input = action.getInput();<br />         <br />             Long initialTime = (Long) input.getValue("initialTime");<br />             <br />             long totalTime = System.currentTimeMillis() - initialTime.longValue();<br />             <br />             System.out.println("The total time for the consequence was: " + totalTime);<br />         }<br />     }<br />     <br />     public void destroy() { }<br /> }<br /> [/code]<br /> <br /> Why didn't we place the total consequence time in the action output as well, so that we could show it in the JSP page? That's because after the consequence is executed the JSP page is history. The page was already processed so placing new things in the action output will not do us any good. That's why we chose to use the System.out to display the total consequence time.<br /> <br /> The [i]AfterConsequenceFilter [/i]is useful for example for the [i]HibernateFilter [/i]so that the hibernate session is closed only after the view layer has been processed and any lazy loading has been done.<br /> <br /> Filters can do many other things as we will see in later chapters. It can do input validation, handle exceptions, open transactions, inversion of control, etc. Filters prepare everything for the action, so that when it is time for the action to get executed, everything is ready, organized and beautiful.<br /> <br /> Below is an example of an ApplicationManager that is using the CacheFilter and the TimerFilter described above. You can also download by [url="http://www.mentaframework.org/mentainaction/HelloMentawai/HelloWorld3.war"]clicking here[/url] an application that makes use of both filters. Run this application and you will be surprised by the [b][color=blue]Mentawai Debug Mode[/color][/b], which is our next topic.<br /> <br /> [code]<br /> package examples.helloworld;<br /> <br /> import java.util.HashMap;<br /> import java.util.Map;<br /> <br /> import org.mentawai.core.Context;<br /> <br /> import examples.helloworld.action.HelloMenta;<br /> import examples.helloworld.filter.CacheFilter;<br /> import examples.helloworld.filter.TimerFilter;<br /> <br /> public class ApplicationManager extends org.mentawai.core.ApplicationManager {<br />    <br />    @Override<br />    public void init(Context application) {<br /> <br />       setDebugMode(true);<br />       <br />       Map&lt;String, Object&gt; cache = new HashMap&lt;String, Object&gt;();<br />       <br />       application.setAttribute("cache", cache);<br />    }<br /> 	<br /> 	@Override<br /> 	public void loadActions() {<br />       <br />       addGlobalFilter(new TimerFilter());<br />       <br />       addGlobalFilter(new CacheFilter());<br /> 		<br /> 		action(HelloMenta.class)<br /> 			.on(ERROR,   redir("/index.jsp"));<br /> 		<br /> 	}<br /> }<br /> [/code]<br /> ]]></description>
				<guid isPermaLink="true">http://book.mentaframework.org/posts/preList/11/11.page</guid>
				<link>http://book.mentaframework.org/posts/preList/11/11.page</link>
				<pubDate><![CDATA[Thu, 27 Dec 2007 14:43:43]]> GMT</pubDate>
				<author><![CDATA[ saoj]]></author>
			</item>
	</channel>
</rss>
