Last Updates | Login      

The big picture

Mentawai has a very simple architecture following the KISS principle. The framework is all based on interfaces so it is extremely flexible. The basic concept is the notion of an Action that executes some task. An action has an Input and an Output. All the information from the web request is contained in the action input. The results produced by an action are placed in the action output so that it can be displayed in the view layer (JSP page, velocity, etc.). An action also has access to Contexts such as Session, Application and Cookies. After the execution, an action should return a Result. For each result you can configure a Consequence such as Forward, Redirect and Chain.

The core interfaces of the Mentawai framework are listed below with a brief explanation:

(Click in the interface to see its javadoc)

org.mentawai.core.Action: It just has setters and getters for the Input, Output, Session, Application, Cookies and Locale. It also defines some standard Results like SUCCESS, ERROR, INDEX, etc. The default implementation is BaseAction.


org.mentawai.core.Input: It provides methods to get values from the input as Object, int, float, double, boolean, etc. It performs the necessary conversions and also have versions that return a default value. It also has methods to return properties of a request (through reflection) and headers of a request. You can also use the method keys() to list all keys in the action input. The default implementation is RequestInput. Below are some examples:


org.mentawai.core.Output: It behaves pretty much like a Map where you can place values by a String key. You can also check if it is empty with the isEmpty() method and get all the keys with the keys() method. The default implementation is ResponseOutput. Below are some examples:


org.mentawai.core.Context: It behaves pretty much like a web application context where you can set attributes by name. A context also supports the reset() method (optional) and the keys() method. Some of its implementations are the SessionContext, ApplicationContext and CookieContext. Below are some examples:


org.mentawai.core.Consequence: A consequence is executed after the action has executed and returned a result. A consequence is an interface that has only the execute() method that receives the action, the HttpServletRequest and the HttpServletResponse. The main consequences implemented by the framework are: Forward (forwards to a JSP page), Redirect (redirects to a JSP), Chain (chains the action with another action) and StreamConsequence (returns a byte stream through the HttpServletResponse). You can implement your own consequences as well.


org.mentawai.core.Filter: A filter is the main building block of the framework. We will talk more about filters in the next chapter, but for now you should know that it is an interface with two methods: destroy() for cleanup and filter() that receives an InvocationChain as a parameter and returns a result. The signature of the filter() method is:


org.mentawai.core.AfterConsequenceFilter: This interface inherits from the Filter interface to add an extra method that is executed after the Consequence of the action is executed. The method signature is:


The big picture is more or less like this:

You don't need to fully understand the Mentawai architecture to start building web applications with it. However it does not hurt to have a good foundation and to really understand how things are working under the hood.

Filters

Filters are the building blocks of Mentawai through which all the main feature of the framework are implemented. A filter wraps or intercepts 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 (InvocationChain) 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 Separation of Concerns pattern, allowing your action to do one thing and do it right! 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.

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.

A filter that gets a Map from the application and places it in the action input:


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.

Through the InvocationChain 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 chain.invoke() 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.

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:


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.

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:


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:


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.

The AfterConsequenceFilter is useful for example for the HibernateFilter so that the hibernate session is closed only after the view layer has been processed and any lazy loading has been done.

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.

Below is an example of an ApplicationManager that is using the CacheFilter and the TimerFilter described above. You can also download by clicking here an application that makes use of both filters. Run this application and you will be surprised by the Mentawai Debug Mode, which is our next topic.


Debug Mode

The Mentawai Debug Mode is an useful feature that lets you know and see what is happening when your action, together with all its filters, gets executed. As we saw in the previous chapter, a filter can alter the action input and output before and after the action gets executed. Wouldn't it be great to see all the filters that are being executed before the action as well as how the input and output look like after each step? That's exactly what the Mentawai Debug Mode will do for you. You can even choose to show the debug information at the bottom of your JSP page or inside your HTML code as a HTML comment. Here is how you set up and turn on the debug mode.

First you need to configure the DebugServletFilter as a servlet filter. This is a servlet filter (from the Servlet API) and not a Mentawai Filter, so we need to get inside the web.xml file. Luckily all you have to do is paste some XML code inside this file. Below is the web.xml file from the example in the previous chapter:


After you setup the DebugServletFilter inside the web.xml file, all you have to do is turn it on in your application manager:


This will make the debug text appears in the bottom of your HTML pages. Not something that you would want in a production site, for example. So you can also output the debug mode as a comment inside your HTML page:


Run your application again and now you will see the debug information of your actions. For the web site http://www.secretcrushonline.com I see the following:

- - - - - - - - - - - - - - - - Mentawai DEBUG - - - - - - - - - - - - - - - -

ActionName = CupidoAction
InnerAction = answerArrow
ActionClass = com.amorsecreto.action.CupidoAction
Browser Locale = en_US
Action Locale = pt_BR
Default Locale = pt_BR


Input:

empty

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Filter = org.mentawai.filter.AuthenticationFilter@145eca6


Input:

empty

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Filter = org.mentawai.filter.ValidatorFilter@1b3c169


Input:

empty

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Filter = org.mentawai.filter.ConnectionFilter@108fbd4


Input:

empty

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Filter = IoCFilter


Input:

empty

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Filter = DIFilter: tryField=true


Input:

empty

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Filter = org.mentawai.filter.InjectionFilter@dcc20c


Input:

conn = com.mchange.v2.c3p0.impl.NewProxyConnection@efa9fb
loc = pt_BR
userDAO = com.amorsecreto.dao.mysql.MySQLUserDAO@179fb8d

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Action = answerArrow()

Input:

conn = com.mchange.v2.c3p0.impl.NewProxyConnection@efa9fb
loc = pt_BR
userDAO = com.amorsecreto.dao.mysql.MySQLUserDAO@179fb8d

Output:

empty

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Result = jsp

Consequence = Forward to /answerArrow.jsp

Total Time = 1ms

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



Mentawai Web Framework - Version:1.11 Build:20070911

Inner Actions

In Mentawai an action is a piece of code that gets executed when the Mentawai controller receives a HTTP request from the browser. As we have seen before, this can be a class that extends BaseAction, a class that implements Action or any regular POJO (Plain Old Java Object).

By default, if you make a request to http://www.mysite.com/HelloAction.hello.mtw, the controller understands that you want to call the hello() method of the HelloAction class. You can also omit the method part, like in http://www.mysite.com/HelloAction.mtw and the controller assumes that you want to call the method execute() from the HelloAction class.

Mentawai uses the term inner action for the hello() method. An action class such as HelloAction.java can have many inner actions inside it. These inner actions are nothing more than the instance methods of the action class.

For example, we may have an action class like this:


We say that the LoginAction has no inner actions. The LoginAction class is the action itself, in other words, you can call it with the following URL:

http://www.mysite.com/LoginAction.mtw

You can also call it like this, although it would not make much sense:

http://www.mysite.com/LoginAction.execute.mtw

Now we can add a new method to the LoginAction, in other words, we are adding an inner action to the LoginAction class.


An now to call the inner action sayHello you would use the following URL:

http://www.mentaframework.org/HelloAction.sayHello.mtw

It is important to understand the inner action concept because some methods take a String as the innerAction parameter. For example, we can make our action implement the Validatable interface, to setup some validation code:


Note that for the execute method, we consider that there is no inner action, so the innerAction is null and not "execute". The execute() method is kind of the natural method of an action class, in other words, it is the method that gets executed when no inner action is specified in the request URL.

The only way to get the innerAction parameter to be equal to "execute" is to call the action with the following URL: http://www.mysite.com/HelloAction.execute.mtw, which does not make much sense. If you want to call the "execute" method, you should make a request like: http://www.mysite.com/HelloAction.mtw, and the innerAction will be null.

Setting up actions

This chapter is important because it will show you all the ways you can use to setup your actions in the application manager. If you decide not to configure anything, then Mentawai will use its conventions, for example a request to http://www.mysite.com/HelloAction.hello.mtw will call the hello() method of the HelloAction class. The default consequence for the action will be a forward to the /HelloAction/hello.jsp.

As we have discussed in earlier chapters, sometimes there is no way out and you have to configure your actions. This chapter will show you how to do it.


Note that we are adding a global filter that will be applied to all actions. We are also adding a filter specific to the action (VOFilter). Two consequences (one for JSP and one for SUCCESS) and a global consequence for the result LOGIN are being added as well.

No inner action was specified, so by default this configuration will be considered for all inner actions inside UserAction.class. The following actions will be executed with the filters and consequences configured above:

http://www.mysite.com/User.mtw
http://www.mysite.com/User.add.mtw
http://www.mysite.com/User.del.mtw

Basically all inner actions inside the UserAction class will have the configuration specified for the UserAction class. Now let's get more specific.

You can add consequences and filters specific for a single inner action. Let's add a filter and a consequence specific for the add inner action, in other words, for requests to http://www.mysite.com/User.add.mtw:


So for our example, we will have the following filters being executed, in the following order:

AuthenticationFilter -> VOFilter -> AuthorizationFilter -> UserAction.add

Note that global filters are always executed first, then comes the action specific filters, then comes the inner action specific filters.

For consequences, the rule is simple:

First try to get a consequence specific to the inner action. If not found, try to get a consequence specific to the action. If not found, try to get a global consequence. If still not found, go by the Mentawai conventions: forward to /User/add.jsp.

You can get even more specific creating a whole ActionConfig object just for the inner action you want to configure. The filters and consequences you define will be applied only for the inner action specified in the action config. Below is an example:


You can play with the order of the filters with some methods like ActionConfig.addFilterFirst(), that will add a filter to be executed BEFORE the global filters. You can also make your action implement the GlobalFilterFree interface, to signal to the controller that it does not want any global filters. And you can also add a global filter that will be executed LAST, in other words, after all other filters have been executed. This will be rare cases, when for some very particular scenario you need to take more control in the invocation chain of filters.

Below are some examples of these rare methods:



Consequences (Forward, Redirect, Chain, Stream, etc.)

Forwarding to JSP pages

The basic and most common consequence you will use in your web projects is the Forward. In Mentawai, this is the org.mentawai.core.Forward class, which implements the org.mentawai.core.Consequence interface. The interesting aspects about a forward are listed below:

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 Hello.class is a forward to /hello.jsp, the location in the address bar of your browser will not change 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 Hello action. This is exactly the opposite of what happens when you do a Redirect.

A forward will always pass the action and all its contexts (Input, Output, Session, Cookies, 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.

The classic scenario is:

For example for the simple action below you can configure some forwards:


Inside the application manager:


Just keep in mind that whenever you want the action information to be displayed in the JSP page you will most likely want a Forward consequence. Another point to keep in mind is that if the user hits the Reload button in the browser, the whole action is executed again.

Redirecting to a new URL

In Mentawai, the Redirect consequence is implemented by the core class org.mentawai.core.Redirect, which implements the core interface org.mentawai.core.Consequence. When you issue a Redirect consequence, you are really telling the browser: "Hey! Please do another web request to the this URL here!". 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.

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 reload button and executing the action again.

There are many ways to a redirect in Mentawai. Below I will explain each one:

Regular redirect

This is the redirect you will be using 99% of the time and it is always related to the context path of your web application. The context path is the directory where your application is located inside the Tomcat webapps directory. It is what allows the same Tomcat to run a bunch of different web applications together and independently.

Below are some examples:


The first redirect will tell the browser to perform another web request to the following URL:

http://www.mysite.com/DVDStore/congrats.jsp

The second redirect will tell the browser to perform another web request to the following URL:

http://www.mysite.com/DVDStore/user/users.jsp

This is assuming that your context path is "DVDStore". If your context path was the ROOT context path, which is the ROOT directory inside the Tomcat webapps directory, your redirect URLs would be:

http://www.mysite.com/congrats.jsp

http://www.mysite.com/user/users.jsp

Redirect relative to the web server

You can use this redirect when you want to perform a redirect to another web application running in the same web server. For example:


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:

http://www.mysite.com/BookStore/showBooks.mtw

http://www.mysite.com/index.jsp

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.

Redirect with dynamic parameters

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:

http://www.mysite.com/BookStore/Book.show.mtw?cat=

To setup this redirect with a dynamic parameter, you can do this:


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:


Assuming that book.getCategory() returns 43, the resulting URL would be:

http://www.mysite.com/BookStore/Bood.show.mtw?cat=43

Note that all the values from the action output will be added as parameters to the redirect URL.

Redirect to a dynamic URL

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:


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:


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.

Last but not least about the Redirect consequence:

If you redirect contains the string "://" inside it, it is assumed that you want to do a redirect to a absolute address. Examples:


The redirect understands that the above redirect are all absolute URLs, not relative to anything.

There are no redirects relative to the request

This is on purpose. If you try to do something like on(SUCCESS, redir("loosepage.jsp")), Mentawai will automatically assume that you meant on(SUCCESS, redir("/loosepage.jsp")). Redirects relative to the request are not needed and only introduce confusion.

You can also use a dynamic URL with dynamic parameters. Below is how to configure this redirect in the application manager:


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.

Chaining actions

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:


Or you can use the less verbose style:


Before you configure any chain consequence, you must understand that action chaining is rare and in most cases there is no need for you to make use of it. 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:


Although definitely not a sin, this could have been done much better with a redirect consequence:


So now after the add inner action is done, it will redirect (not chain) to the show inner action. If the user hits the reload button, only the show inner action will be executed again, and not the whole chain. 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:

http://www.mysite.com/User.add.mtw?category=34

As we saw in the previous chapter about redirect, these parameters will come from the action output.

To conclude, here is what you should keep in mind when using a chain consequence:

Think if you don't really want a redirect to an action instead of a chain. The question you should ask yourself is: Do you want to execute everything again if the user press the reload button?

When two actions are chained, the input and output of the first are passed to the second.

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.

You can also pass an inner action to the chain controller:


Other consequences

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 StreamConsequence:

In the action:


In the ApplicationManager:


You can place a byte array or a InputStream 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:


An in the ApplicationManager:


For Ajax, you can use the AjaxConsequence that uses a renderer to format the action response into an ajax response (JSON, XML, etc.)

Action:


ApplicationManager:


Conclusion

In this chapter we discussed about the Mentawai architecture and its main interfaces like Action, Input, Output, Context, Filter, Consequence, 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.

You also saw the main consequences of any web application: Forward and Redirect. You were also introduced to the Chain, Stream and Ajax consequences.

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.