Multiple session or multi-window problem and solution where multiple class uses a same form extended from SimpleFormController of Spring MVC

May 8, 2008

Problem:
Lets think of a scenario, we are running a hospital management system. We need to search for patient’s record, doctor’s record, medicine stock record and many other things. Where searching criteria are completely different to each other. In order to implement the OO pattern, we develop a common search class and different command class for different type of search. Following figure illustrates the scenario:

If have created separate bean for Medicine, Doctor and Patient with Search class and define the separate command class for medicine, doctor and Patient. Works fine if you run all these separately. But Open a search page for Doctor then open a search page for Medicine in new window or tab and now press search button for doctor. What happens? You got the search result for Medicine though you suppose to get search result for Doctor.

Observation:
This is one of the most interesting problem of session related task in Spring MVC. Lets go into tail. SimpleFormController of Spring MVC extended from AbstractFromController of spring MVC this contains a method called getFormSessionAttributeName(). The spring framework source code 2.5 returns a string from this method in following way.

protected String getFormSessionAttributeName() {
return getClass().getName() + ".FORM." + getCommandName();
}

This is called 2 times, one while showing the form and one while submitting the form. If your class name is GeneralSearch and package name is net.project.web.search then this method will return the attribute name as net.project.web.search.GeneralSearch.FORM.command. The form kept in session by this name for both searching by different command class of Doctor and Medicine because you have set setSessionForm=true by. Now how do you expect to distinguish both form while submitting it in onSubmit() method? It always replace the old command class by the newest command class thats why in method onSubmit(), out preferred command object is not retrieved accurately.

Solution:
All that we need to do in this case is to make sure the form session attribute name is different for two different command class in our whole search system. You can pass a hidden value
into into your .jsp or .ftl and add it with form session attribute name to make a different session name for each search. You can override the method getFormSessionAttributeName and add the value with the attribute name that is different for each form like following

protected String getFormSessionAttributeName( HttpServletRequest request) {
String sessionId = ServletRequestUtils.getStringParameter( request, "sessionId", null);
if (sessionId!=null) {
return (super.getFormSessionAttributeName(request) + "." +sessionId);
}
return super.getFormSessionAttributeName();
}

You can pass a specific session id as the hidden variable and retrieve it by httpServletRequest and add it with the session attribute name while showing and submitting the form. That will help you to enable to work with multiple session and multi window.

By: Md. Shahjalal


Workflow of SimpleFormController of Spring MVC

February 27, 2008

The entire life cycle of a HTML form is handled by SimpleFormController of Spring MVC. The tasks of form viewing, validation, submission are maintained in complex but magical way by this Class. The parent class (AbstractFomController) stopped its functionality up to form viewing where as this class run to the end for doing extra works of form submission. There are a lot of method works across the class to perform a solid support to the system but few of those play key roles and a developer should know to work with it. Following section will cover these things:

isFormSubmission(): Checkout is the HTTP request is for form viewing or submitting. For post method it returns true. In fact, this method leads to one of two main stream of form view and form submit. This act as the divider for two flow.

formBackingObject(): Creates instance of the form object. By default it follows the the class set by method setCommandClass(). You can configure it in your servlet.xml’s bean property by
<property name=”commandClass”>
<value>project.db.beanClass</value>
</property>
This is not final so that you can add extra things with it. For example, for saving a form in DB we maintain a id as primary key which starts from 1. Then you can add a checking of id>0 or not find out its a new form or old form.

initBinder(): This method called after the instance of the form is created and the controller creates the data binder. Programmer used to override this method to register custom PropertyEditors for a form. Suppose, to bind date, time related things with the form object. If there is no binding like these, this method do nothing(By default).

setBindOnNewForm(): While you have the dataBinder instance is ready, you are allowed to perform biding parameters comes with initial HTTP GET request. The action is fixed by the bindOnNewForm property set by this method.

isSessionForm(): Determines the form is in the session or not. If so, it store the form in the session. By setting setSessionForm() = true one can let the controller to enable this feature. Many ORM tool supports reattaching, or merging, a detached bean. So setSessionForm() to true gives lot advantages to developers. But mind it, it takes a lot of memory too. At the form submission cycle(by HTTP POST request) if the method returns true, the form will be retrieved from session and remove it from session for farther work. But in case of any error in form submission process, the form will be placed back into session.

isValidateOnBinding(): If true then run all the validations of the form. This is too important for the controller so by default set to true and marked final. Only way to change it is through setValidateOnBinding() method.

suppressValidate(): If coder needs more controlled validation over the form after binding variables are welcome to use this method. It allows to choose on a request-by-request basis whether or not to run through the validations.. By default it is false. It may be confusing that why should you use a request-by-request validation for the form though you have method like onBindAndValidate() activated later. Think of a scenario where you validate all for update, insert, delete e.t.c for form submission. A delete operation do not need to perform non empty fields, can directly delete from DB. So, one can handle delete by suppressValidation.

referenceData(): At the end of process of form viewing it collect reference data by this method. For example, once need to show all the state list of a country in a drop down list. In this method one can provide the list in a map for displaying in the form. These are called auxiliary object for the form. After this the Controller assemble the full model with the form object, any possible errors from potential binding, and the model from referenceData(). It will then send this combined model to the View fixed by formView property of the bean in servlet.xml file. The from will lead to a successful view.

onBindAndValidate(): The callback method allows to perform any custom validation logic or general logic after binding and validation. After this method the controller look for any error occurs or not. If error then the form will be stored in the session (where setSessionForm() == ture) and show the original form otherwise successfully complete form submission method.

By: Md. Shahjalal

References:
1. Expert Spring MVC and Web Flow
2. wikipedia


Follow

Get every new post delivered to your Inbox.