Google

Saturday, April 28, 2007

Handeling "page not found" using Struts

While surfing web, Most of us have encountered 404- Page not found message. Any resource you request; If it does not exist on server you would get such an error. In struts applications when you request for x.do and if there is no Action-mapping defined in struts-config.xml file for ActionForward x; You would get such an error.

Unknown ActionMapping
In struts you can define one ActionMapping which will receive all requests for which no ActionMappins is defined. It is called "Unknown ActionMapping".
<action
name="/debug"
unknown="true"
forward="/pages/debug.jsp/>

Notably one can also do some NLP or spell correction to seek for resource user might be looking for and can ask to give that resource. This helps improving user experience while surfing your site.

Labels: , , ,

Friday, April 13, 2007

Why ActionForm is not an interface?

There are few reasons why Action Form is not an interface.

Extensibility
Adding a new method in interface (in next version of struts) will break earlier application's form bean. While in case of base class one can add new method as default implementation which doesn't break earlier applications to use new version.

If Action Form is an interface, people using struts would be tempted to use their business objects as Action Forms which can cause following problems.

Action Form is implemented to accept any value from HTML form and then validate those properties, If any of them are found to be incorrect; can be corrected on the fly. While business objects are not designed to buffer invalid data so programmer cannot change incorrect values on the fly instead they will get an exception.

Some business objects are designed to start transactions, lock resources like database while they are used. In that case; even if input fields from HTML form are invalid, resources will be locked and transactions will start which is illegal usage of resources.

Auto population mechanism of struts is designed to populate object first and then validate. In that case if business objects are used as Action Form and a property of a business object is meant to change system state, Invalid value may affect system and application in turn. So using one layer of ActionForm will block such invalid property values.

Labels: , , ,

Ways of Extending ActionForm

There are two different flavors of Action Form exist.

Action Form as a Java Bean

In this implementation of Action Form developer will have to define a property in Action Form class for each input defined in HTML form. There will also be getter and setter for each of those properties. This concept of having properties and getter and setters for all properties is a concept of Java Bean.

Action Form as a map

Action Form is a mapping between HTML form properties and business object corresponding to that form. The map can be used to trap all parameters passed without defining any of the properties in advance. Each field is just another entry on the Map. This can save developers effort a bit where developer will have to define two methods (public void setvalue(String key, Object value and public Object getValue(String key) instead of getter and setters of each property of the form.

DynaActionForm

Declaring simple properties in the usual way add up to a lot of work in a larger application.To create conventional JavaBean ActionForm, You need to code a field, a getter, and a setter; A lot of infrastructure just to say get this and set that. It would be faster if we could just declare the Java Bean properties instead to code each one and system takes care of defining getter and setters of those properties. DynaActionForms are designed for the purpose. You could just define an Action Form in struts-config.xml file and declare what all properties it holds and Struts takes care of rest of things. It is actually based on DynaBean component of the Jakarta Commons.

There is one difference in reset method of Action Form in DynaActionForm implementation and Map based or Java Bean based implementation.

In case of DynaActionForm implementation; reset method will set all properties to its initial values which are defined in struts-config.xml while defining Action Form. while in case of other two implementation reset method will set all properties to their default values which depend on type of a property.

Labels: , , ,

Thursday, April 12, 2007

Sample application of struts

Any Struts application comprises of following different components. I have taken Simple Register User application to explain all those components.
  1. struts-config.xml (Configuration file)
  2. ActionServlet
  3. Action Class
  4. Action Form class
  5. Action Forward
  6. web.xml

struts-config.xml is a configuration file which maps requests to Action and Action Form classes depending on URI received in request. And forwards response to a view component depending Action Forward received from Action class.

<struts-config>
<form-beans>

<form-bean
name="registerForm"
type="app.RegisterForm"/>

</form-beans>

<action-mappings>

<action
path="/register"
type="app.RegisterAction"
name="RegisterForm"
scope="request"
validate="true"
input="/register.jsp">
<forward name="success" path="/success.html"/>
<forward name="failure" path="/failure.html"/>
</action>

</action-mappings>
</struts-config>


ActionServlet
is a controller component which reads struts-config object and controls whole work flow. Most of the time we use default ActionSErvlet implementation but one can also extend ActionServlet class to customize work flow.

Action class uses helper classes to request parameter to perform any action and returns response to ActionServlet in form of Action Forward.

package app;

import org.apache.struts.action.*;
import javax.servlet.http.*;
import java.io.*;

public class RegisterAction extends Action{

public ActionForward execute(ActionMapping mapping,ActionForm form,
HttpServletRequest req, HttpServletResponse res){

RegisterForm refisterForm = (RegisterForm)form;

String userName = rf.getUserName();
String password1 = rf.getPassword1();
String password2 = rf.getPAssword2();

if(password1.equals(password2)){
if(User exists in database){
Throw exception;
mapping.findForward("failure");
}
mapping.findForward("success");
}
mapping.findForward("failure");
}
}

Action Form class defines all properties defined in form and getter and setter methods for those properties.

package app;

import org.apache.struts.action.*;

public class RegisterForm extends ActionForm{

private String userName;
private String password1;
private String password2;

public String getUserName(){ return userName;}
public String getPassword1(){ return password1;}
public String getPassword2(){ return password2;}

public void setUserName(String userName){ this.userName = userName;}
public void setUserName(String password1){ this.password1 = password1;}
public void setUserName(String password2){ this.password2 = password2;}

public ActionWrrors validate(ActionMapping mapping, HttpServletRequest req){
ActionErrors errors = new ActionWrrors();

if((userName= =null) || (userName.length()<1)){> errors.add("userName",new ActionError("error.userName.required")); if((password1= =null) || (password1.length()<1)){>
errors.add("password1",new ActionError("error.password1.required"));
if((password2= =null) || (password2.length()<1)){>
errors.add("password2",new ActionError("error.password2.required"));

return errors;
}
}

ActionForward is the object which Action class uses to return ActionResult to ActionServlet and then depending on that result ActionServlet forwards response to any of the view component.

web.xml is a web application deployment descriptor file. User Needs to map request to ActionServlet instance and pass struts-config.xml file as a parameter to ActionServlet instance. Struts also has a tag library which needs to be configured in web.xml file.

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>
/WEB-INF/conf/struts-config.xml

<
/param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-nameaction</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

<taglib>
<taglib-uri>/tags/struts-beans</taglib-uri>
<taglib-location>/WEB-INF/lib/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-html</taglib-uri>
<taglib-location>/WEB-INF/lib/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-logic</taglib-uri>
<taglib-location>/WEB-INF/lib/struts-.tld</taglib-location>
</taglib>

Apart from this user needs to define success.html and failure.html pages and register.do file which is HTML form to enter userName, password1 and password2.

Labels: , ,

Sunday, April 8, 2007

Introduction of struts MVC framework

Struts is a Java based web application framework which works on MVC design pattern. The project was created by Craig McClanahan in May 2000 and it is widely accepted and used Java framework.

The reason behind struts widely accepted is, ITs MVC framework. Struts clearly differentiates between different tiers of web applications. Model, View and Controller.

When request comes to server, web application container which could be Tomcat or weblogic or JBoss forwards request to ActionServlet. ActionServlet delegates request to one of the Action classes. Action classes generally have business logic defined or they call to helper classes which have implemented business logic.

Action class based on request performs business logic and forwards request to another Action class or returns to ActionServlet with ActionForward.

ActionForward is another Action URI, which is mapped to a JSP page which displays data.

So Action class works as Model, JSPs wok as View and ActionServlet works as controller which decides which Action class to instantiate based on request and then based on ActionForward decides on which JSP to be called. Other than that Struts also allows you to use Velocity or Tiles at view layer to make view layer more manageable.

Total work flow of struts framework:
  1. A client requests for a resource with URI that matches with the Action URI pattern defined in deployment descriptor file (web.xml).
  2. The web application container passes the request to ActionServlet.
    • ActionServlet gets instantiated when application is deployed. It reads struts-config.xml file and creates a configuration object. This configuration object is used to map request with resources like ActionForm bean or Action class.
    • That is why when struts-config.xml file changes, we need to redeploy the whole application so as to create a new configuration object.
  3. ActionServlet looks for mapping for the path, If no mapping is found it throws an exception.
  4. If the mapping specifies a form bean, the ActionServlet sees if there is one already or creates one. If the bean already is play, It resets and populates it from HTTP request.
  5. If the mapping has validate is set to true and Action bean has defined validate method, then it performs validation. If validation fails then servlet forwards request to input property of Action mapping with an error message.
  6. Then servlet finds the Action type from mapping and instantiates Action class and calls to perform or execute method of Action class.
  7. Action class has a business logic implementation or it uses classes known as helper classes which has implementation of business logic.
  8. The Action returns ActionForward to ActionServlet. ActionForward is another URI which is a JSP page in most cases. ActionServlet then forwards request to that JSP page which render response for the request and sends it to browser.
This is a detailed work flow of a typical struts application. Keep in touch i will be writing on Action classes and ActionFormBeans and other configuration in my next posts.

Labels: , ,