Tuesday, July 22, 2008

Problem Statement and Source Files


Theory without examples can be hard to grasp and less useful. So just making a small problem and corresponding files. Lets see
Problem statement: Given an online reporting application. There is a form that posts certain parameters and displays reports accordingly. Let us say that there are two basic parameters: report type and date range. Report type may be word, pdf, text. Date range consists of a from and a to time. Further user has an option to specify current time as the to time. Our form bean would look something like this:

package myPackage;

public class MyFormBean{
private String reportType;
//date in format dd/MM/yyyy HH:mm
privateDate fromDate;
private Date toDate;
private boolean useCurrentTime=true;

//.......
//public getters and setters for fields
//.......
}

Reports are denoted by a simple interface:
package myPackage;

public interface Report{
String getFileUrl();
String getType();
Date getCreationTime();
}
Reports are fetched using this interface:
package myPackage;

public interface DataBaseUtil{
List<Report> getReports(MyFormBean myFormBean);
}
which may have some implementation like:
package myPackage;

public class DataBaseUtilImpl{
private static DataBaseUtilImpl singleInst = new DataBaseUtilImpl();
private DataBaseUtilImpl(){}

public static DataBaseUtilImpl getInstance(){ return singleInst ; }

public List<Report> getReports(MyFormBean myFormBean){
//process command object to get a list of reports
}
}
The controller will be injected something like this in the config file:


 <bean id="reportFormController" class="myPackage.ReportFormController">
<property name "dataBaseUtil" ref="DataBaseUtilBean"/>
<property name="formView" value="reportInput"/>
<property name="bindOnNewForm" value="true"/>
<property name="successView" value="reportOutput"/>
<property name="validator" ref="myValidator"/>
<property name="commandName" value="reportFormBean"/>
<property name="commandClass" value="myPackage.MyFormBean"/>
</bean>
The actual form controller will look something like:

package myPackage;

import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.text.*;

public class ReportFormController extends SimpleFormController {
private DataBaseUtil dataBaseUtil;

public void setDataBaseUtil(DataBaseUtil dbUtil){
this.dataBaseUtil = dbUtil;
}

public DataBaseUtil getDataBaseUtil(){
return this.dataBaseUtil;
}

/*Override so as string inputs in the form bind directly to date in command object*/
@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder dataBinder) throws Exception{
DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
df.setLenient(false);
dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(df,false));
super.initBinder(request,dataBinder);
}


@Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,Object command, BindException bindException)throws Exception{
//handle submit request
ReportFormBean repFormBean = (ReportFormBean ) command;

List<Report> reps ;

if(dataBaseUtil != null)
reps = dataBaseUtil.getReports(repFormBean);
else
reps = new ArrayList<Report>();

ModelAndView mv = showForm(request, response, bindException);

mvmodel.put("REPORTS", reps);

return mv;
}
}
From next post we will start exploring some practical problems using these files as our base.

Monday, July 14, 2008

Testing a SimpleFormController

Testing a SimpleFormController using JUnit and JMock was a small challenge I came across. After hitting a number of hurdles I managed to write tests that were meaningful and worked. Following points noted for people on similar quest :):

  1. Keep handy JMock Cheat Sheet , especially the Methods and Expectations part
  2. Use MockHttpServletResponse, MockHttpServletRequest and MockHttpSession in the package org.springframework.mock.web to mock web response, request and session respectively.
  3. Remember you can construct post requests and get requests with your MockHttpServletRequest using: MockHttpServletRequest mockRequest = new MockHttpServletRequest("POST","myUrl"); and MockHttpServletRequest mockRequest = new MockHttpServletRequest("GET","myUrl");
  4. Finally use ModelAndView modelAndView = myController.handleRequest(mockRequest, mockResponse);
  5. Use JUnit asserts to verify ModelAndView as per your expectations

Generally your controller will follow this path: receive request-process-return ModelAndView to render. Processing may involve using the command object and passing values to the backend for processing. In your controller tests do NOT attempt to check backend- just mock it. Focus on checking the controller. A combination of expectations and asserts is your best bet to do the testing thoroughly. Let us explore a small example based on these principles in our next post.

Thursday, July 3, 2008

Conditional Form Binding

Form binding is a useful feature in Spring. However I needed to turn on or off form binding depending on certain conditions. Golden question, how to do it...

1. In the controller constructor (or in XML config for DI) call setBindOnNewForm(true);
2. Do NOT call/set setSessionForm(true);
3. Override suppressBinding and return true or false according to your condition. true will suppress form binding.

@Override
protected boolean suppressBinding(HttpServletRequest request){
boolean myCondition = false;
//some checks on myCondition depending on request params
return myCondition ;
}

Tuesday, July 1, 2008

Date Binding on SimpleFormController using initBinder

If you wish to bind an input date field in your web form directly to a Date property in your command object, you will need to override the initBinder method of the SimpleFormController. Following maps a date in dd/MM/yyyy format on the front-end to backend and vice-versa.

@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder dataBinder) throws Exception{
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
df.setLenient(false);
dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(df,false));
super.initBinder(request,dataBinder);
}

Your valang validators can help you put some crisp checks on date if need be. Remember dd/mm/yyyy and dd/MM/yyyy are NOT same.

Thursday, June 26, 2008

SimpleFormController and Validation

While making your spring application you may come across the need to use a SimpleFormController. If so, there may be questions and confusions. The spring javadoc has some good documentation. Try this cheat sheet too if you are short on time or wish to revise your SimpleFormController knowledge:

SimpleFormController Cheat Sheet

After you get the controller running, you may want to validate your form. Besides using Validator class in the spring framework you may want to explore some configurable validation options. Check springmodules validation:

Spring Modules Validation

This gives you pointers on using Jakarta Commons and valang. I found valang much-much better than using either commons or the spring Validator class for server side validations. For client side validation I still need to make this thing work correctly as my jsp code generates the form on fly using tags. And tags and valang client side thingy dont gel well together. Will post a solution if I find one :).

And remember that expressions given for valang bean are like assertions. So the following check to make sure that a particular field should NOT be null is WRONG

{ myParam : myParam IS NULL : 'This param should not be null.' }

This, in effect says that your param SHOULD be null. So, the correct rule will be:

{ myParam : myParam IS NOT NULL : 'This param should not be null.' }

Your expressions should evaluate to true in order to avoid error. Remember that and you will be happy. Valang allows pretty complex and rigorous test conditions not possible with jakarata commons. Not easily. It is simpler, sweeter and downright good.

Saturday, February 9, 2008

The Beginning

There are a million people writing on Java. Why write more? Mainly to chronicle my learnings for personal and public use.

Java is vast. And when I say Java, I include J2EE, designing applications using Java and following things related to it. So where to begin? I will be mainly writing on multi-threading, spring, hibernate, junit, jmock and design patterns. It is not really meant to be a tutorial (not yet). Just sharing my learning and chronicling the same over time.

I will begin with spring.

The best place to start learning is the spring website at: http://www.springframework.org/documentation . I absolutely adore this light-weight, non-intrusive, well-designed framework. The reasons I will leave you to discover for converting you to a spring believer is not my intention. The framework consists of several modules which can be used independently. Again, I am not listing them but will mention as I write about them. This should not affect any article as various spring modules can be used independently.

I also refer Spring in Action by Craig Wells with Ryan Breidenbach. Lets see where we end up!