Sunday 21 July 2013

Hibernate

1.   Hibernate Entities

A Hibernate entity consists of:
  • A simple POJO class
  • A mapping strategy (aka. chosen implementation)
  • Hibernate APIs.

2.   Hibernate implementations

Hibernate supports several implementations to map POJO classes to a storage, and thus define ORM mappings:
Some implementations require to add in the code of the POJO class some code support, like in the case of JPA and Annotation mapping, while others associate the entity elsewhere, like in the case of hbm.xml mappings.

3.   Example-1: Mapping strategy using the hbm.xml file

The "hbm.xml" mapping strategy consists of the following:
  • Session Configuration file - Configures the Hibernate session factory. Usually it is called "hibernate.cfg.xml"
  • Entities - POJO classes that represent the database tables
  • Mapping files - Maps POJO entities to Database tables. Usually they are called "<class-name>.hbm.xml"
  • Optionally Session Factory helper infrastructure classes
  • Optionally Logging configuration

3.1   Session Factory Configuration file

SessionFactory is a global factory responsible for a particular database.

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>
    <!-- Database connection settings -->
    <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"></property>

    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>

    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>

    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>

    <!-- Disable the second-level cache -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>

    <!-- Drop and re-create the database schema on startup -->
    <property name="hbm2ddl.auto">update</property>

    <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>

  </session-factory>
</hibernate-configuration>
Note: The "hbm2ddl.auto" option turns on automatic generation of database schemas directly into the database.
Lets examine the configuration file:

  • First of all we start from a template:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>

  </session-factory>
</hibernate-configuration>

  • We add database connection settings:
    <!-- Database connection settings -->
    <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"></property>


  • We add connection pool settings:
    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>


Caution: The built-in Hibernate connection pool is in no way intended for production use. It lacks several features found on any decent connection pool.

  • We define Hibernate's SQL dialect:
    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>


The "dialect" property element specifies the particular SQL variant Hibernate generates.

  • We define the session context strategy:
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>


  • We define the cache policy
    <!-- Disable the second-level cache -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>


  • We define the log level of the executed queries:
    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>


  • We define a helper property for developement, to ease the association relationships: 
    <!-- Drop and re-create the database schema on startup -->
    <property name="hbm2ddl.auto">update</property>


The "hbm2ddl.auto" option turns on automatic generation of database schemas directly into the database.

  • And lastly we define the mapping file(s) for persistent classes:
    <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>


3.2   Entity class

The Event class below is just a simple POJO class:

package org.hibernate.tutorial.domain;


import java.util.Date;

public class Event {
  private Long id;
  private String title;
  private Date date;

  public Event() {}

  public Long getId() {
    return id;
  }

  private void setId(Long id) {
    this.id = id;
  }

  public Date getDate() {
    return date;
  }

  public void setDate(Date date) {
    this.date = date;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }
}

Lets examine the class:
  • id - The id property holds a unique identifier value for a particular event. We do not want to manually assign it a unique value, but prefer it to be generated automatically by the infrastructure. Hence it has a private setter method and a public getter method.
  • title - Maps to a db table column in the "hbm.xml" mapping file
  • date - Maps to a db table column in the "hbm.xml" mapping file.

3.3   Event.hbm.xml

<?xml version="1.0"?>
  <!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="org.hibernate.tutorial.domain">
  <class name="Event" table="EVENTS">
    <id name="id" column="EVENT_ID">
      <generator class="native"/>
    </id>
    <property name="date" type="timestamp" column="EVENT_DATE"/>
    <property name="title"/>
  </class>
</hibernate-mapping>

Lets examine the mapping file:
  • First of all it begins with a template:
  <?xml version="1.0"?>     <!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

  <hibernate-mapping package="org.hibernate.tutorial.domain">
    [...]
  </hibernate-mapping>

  • Then we add association to a database table:

  <class name="Event" table="EVENTS">
  </class>
The above association tells Hibernate how to persist and load object of class Event to the table EVENTS. Each instance is now represented by a row in that table.
  • We map the unique identifier property to the tables primary key. We configure Hibernate's identifier generation strategy for a surrogate primary key column:

    <id name="id" column="EVENT_ID">
      <generator class="native"/>
    </id>
In the above code we chose a generation strategy of "native", which offers a level of portability depending on the configured database dialect.
Note: "native" is no longer consider the best strategy in terms of portability. There are specifically 2 bundled enhanced generators:
  • org.hibernate.id.enhanced.SequenceStyleGenerator
  • org.hibernate.id.enhanced.TableGenerator
For further discussion, see Section 28.4, “Identifier generation”
  • Lastly, we need to tell Hibernate about the remaining entity class properties. By default, no properties of the class are considered persistent:

    <property name="date" type="timestamp" column="EVENT_DATE"/>
    <property name="title"/>

In the snippet above, Hibernate will also search for getDate(), setDate(), getTitle() and setTitle() methods.

Note: The date property mapping include the "column" attribute. Hibernate by default uses the property name as the column name. The word "date" is reserved, and thus it needs to map it to a different name.
Note: The date property mapping include the "type" attribute.  Hibernate will try to determine the correct conversion and mapping type itself if the "type" attribute is not present in the mapping. In this case Hibernate cannot know if the "date" property should map to a SQL date, timestamp, or time column, and thus we need to define it the "type" property.

3.4   Optionally Session Factory Helper Infrastructure Classes

Hibernate is controlled and started by a org.hibernate.SessionFactory object. It is a thread-safe global object that is instantiated once. It is used to obtain org.hibernate.Session instances, that represents a single-threaded unit of work.


You (the Hibernate architect) need to store the org.hibernate.SessionFactory somewhere for easy access in application code.

Example: SessionFactory utility
package org.hibernate.tutorial.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
  private static final SessionFactory sessionFactory = buildSessionFactory();

  private static SessionFactory buildSessionFactory() {
    try {
      // Create the SessionFactory from hibernate.cfg.xml
      return new Configuration().configure().buildSessionFactory();
    }
    catch (Throwable ex) {
      // Make sure you log the exception, as it might be swallowed
      System.err.println("Initial SessionFactory creation failed." + ex);
      throw new ExceptionInInitializerError(ex);
    }
  }

  public static SessionFactory getSessionFactory() {
    return sessionFactory;
  }
}

We create a HibernateUtil helper class that takes care of startup and makes accessing the org.hibernate.SessionFactory more convenient. This class not only produces the global org.hibernate.SessionFactory reference in its static initializer; it also hides the fact that it uses a static Singleton.

In an application server we can use instead JNDI lookup for convenience.

If you give the org.hibernate.SessionFactory a name in your configuration, Hibernate will try to bind it to JNDI under that name after it has been built.

Another, better option is to use a JMX deployment and let the JMX-capable container instantiate and bind a HibernateService to JNDI. Such advanced options are discussed later.

3.5   Optionally Logging Configuration

You need to configure a logging system. Hibernate uses commons logging and provides two choices:
Most developers prefer Log4j: From the Hibernate distribution you can copy the "log4j.properties" file from the "etc/" directory to your "src" directory, next to "hibernate.cfg.xml".

4. Loading and storing objects

Lets create a startup point for our application - a class with a main() method - the EventManager class :

package org.hibernate.tutorial;


import org.hibernate.Session;
import java.util.*;
import org.hibernate.tutorial.domain.Event;
import org.hibernate.tutorial.util.HibernateUtil;

public class EventManager {

  public static void main(String[] args) {
    EventManager mgr = new EventManager();
    if (args[0].equals("store")) {
      mgr.createAndStoreEvent("My Event", new Date());
    }
    HibernateUtil.getSessionFactory().close();
  }

  private void createAndStoreEvent(String title, Date theDate) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
    Event theEvent = new Event();
    theEvent.setTitle(title);
    theEvent.setDate(theDate);
    session.save(theEvent);
    session.getTransaction().commit();
  }
}

Lets examine the class above:

    • We define a "main" entry point for the class:


      public static void main(String[] args) {
        EventManager mgr = new EventManager();
        if (args[0].equals("store")) {
          mgr.createAndStoreEvent("My Event", new Date());
        }
        HibernateUtil.getSessionFactory().close();
      }


      The main method receives an argument of the requested operation (args[0])

    • We define the "createAndStoreEvent()" method. It does the following:
      • Get a sessin for the current operation
      • Begin a transaction for the current operation
      • Create a new Event object
      • Persist it on the session object, i.e. hand it over to Hibernate. At that point, Hibernate takes care of the SQL and executes an INSERT on the database.
      • Commit the transaction












































    Primary-Key / Unique-Identifier Generation Strategy

    All persistent entity classes need to hold a unique identifier value. This identifier is designated a generation strategy, either a default one, or specific one defined by the Hibernate architect. There mainly two types of generation strategy:
    • Without generation strategy (Default) - The id is assigned manually by the programmer
    • With generation strategy - The id is created automatically by the Hibernate infrastructure.
    Hibernate supports several generation strategies. It supports database generated, globally unique, as well as application assigned, identifiers. Identifier value generation is also one of Hibernate's many extension points and you can plugin in your own strategy.

    The idea behind these generators is to port the actual semantics of the identifer value generation to the different databases. For example, the org.hibernate.id.enhanced.SequenceStyleGenerator mimics the behavior of a sequence on databases which do not support sequences by using a table.

    Visible Scopes

    Hibernate can access public, private, and protected accessor methods fields directly.

    Constructors

    Each entity requires a no-argument constructor, with a visibility of package or public.

    Document-Type Definition (DTD)

    Hibernate DTD file is included in hibernate-core.jar (and also in hibernate3.jar, if using the distribution bundle).

    Hibernate Types

    The types declared and used in the mapping files (the "type" property) are not Java data types or SQL database types. These types are  Hibernate mapping types. Hibernate will try to determine the correct conversion and mapping type itself if the type attribute is not present in the mapping. In some cases this automatic detection using Reflection on the Java class might not have the default you expect or need. For example, in the case of a "date" property, Hibernate cannot know if the property, which is of java.util.Date, should map to a SQL date, timestamp, or time column.

    Sunday 14 July 2013

    Spring MVC

    MVC - Model, View, Controller

    • Model - The data of the application (database, web-service, csv file, etc...)
    • View - The view of the data (JSP, XML, HTML, etc...)
    • Controller - The flow of the application (Which page to display, how to display it, etc...)
    To implement a controller you need to register it with a Spring DispatcherServlet instance.

    An application is made with the following components:
    • One or more controllers
    • A view component such as a JSP
    • A configuration that wires the components together through  XML or annotations
    Example-1:
    package com.cap.news.web; 

    import java.util.List; 
    import javax.servlet.http.HttpServletRequest; 
    import javax.servlet.http.HttpServletResponse; 
    import org.springframework.web.servlet.ModelAndView; 
    import org.springframework.web.servlet.mvc.AbstractController; 
    import com.mycap.mynews.core.MyNewsService; 
    import com.mycap.mynews.core.NewsArticle;

    /** 
    * The HomePageController builds the data model to display on
    * the home page. It contains a list of articles. 
    */ 

    public class extends AbstractController { 
    // Service for business methods 
    private GeekNewsService service; 

    /** 
    * Set the object for presentation (ModelAndView)
    */ 
    @Override 
    protected ModelAndView handleRequestInternal(
          HttpServletRequest req,
          HttpServletResponse res) 
           throws Exception {
    List<NewsArticle> articles = 
        service.getArticles(); 
    return new ModelAndView( "home", "articles", articles ); 

    /** 
    * Injected by Spring 
    * @param service
    */ 
    public void setGeekNewsService( GeekNewsService service ) { 
      this.service = service; 
    }

    The HomePageController extends Spring's AbstractController, which provides simple servlet-like functionality. It implements a single method -- handleRequestInternal() -- which accepts HttpServletRequest and HttpServletResponse objects, just as a servlet's service() method would. You could read parameters from the HttpServletRequest, but later I'll show you an easier alternative. The purpose of the AbstractController is to invoke business functionality and to generate a ModelAndViewobject from it.
    The ModelAndView object is a container that hosts the model and provides insight to Spring's view resolver about how to locate the view. It is created with three parameters:
    • viewName - Tells the view resolver to show the page identified by "viewName" 
    • modelName - An identifier for the model that will be accessed from the view
    • modelObject - The model itself.
    Every Spring MVC application is mapped to a servlet that provides MVC functionality: the DispatcherServlet:
    <servlet>
      <servlet-name>news</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>

    The servlet needs to be mapped to a URI pattern. Lets map all "htm" extensions to it:
    <servlet-mapping>
      <servlet-name>news</servlet-name>
      <url-pattern>*.htm</url-pattern>
    </servlet-mapping> 

    Next, you need to map the MVC beans. By default, Spring MVC looks for them  in an XML file whose name starts with the servlet name followed by -servlet.xml, and location in the WEB-INF directory.
    The XML file will contain:
    • The controller
    • The URL mapping strategy (to map URLs to controllers)
    • The view resolver
    Listing 2. news-servlet.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

      <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
          <props>
            <prop key="/home.htm">homePageController</prop>
          </props>
        </property>
      </bean>

      <bean id="homePageController" class="com.cap.news.web.HomePageController">
        <property name="newsService" ref="newsService" />
      </bean>

      <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
          <value>/</value>
        </property>
        <property name="suffix">
          <value>.jsp</value>
        </property>
      </bean>
    </beans>

    The news-servlet.xml file defines the following elements:
    • HomePageController with the name homePageController. It injects the newsService bean into it, which is created in another Spring mapping file
    • urlMapping bean
    • viewResolver bean.

    Handler mappings

    Maps incoming web requests to appropriate handlers.
    There are some handler mappings you can use out of the box, for example, the SimpleUrlHandlerMapping or the BeanNameUrlHandlerMapping.
    A HandlerMapping provides a HandlerExecutionChain. It contains the handler that matches the incoming request, and optionally other handler interceptors (HandlerInterceptor) that are applied to the request. The DispatcherServlet, which is the entry point of URLs to Spring MVC, will hand over requests to the handler mapping, which in turn provides an appropriate HandlerExecutionChain. Then the DispatcherServlet will execute the handler and interceptors in the chain (if any).

    Handler mappings (HandlerMapping) are configurable and can optionally contain interceptors (HandlerInterceptor), that are executed before and/or after the actual handler was executed. They can react not only on the URL of the request but also on a state of the session.
    The two most common handler mappings are BeanNameUrlHandlerMapping and SimpleUrlHandlerMapping. They share the following properties:
    • interceptors: the list of interceptors to use. See Section 13.4.3, “Intercepting requests - the HandlerInterceptor interface”
    • defaultHandler: the default handler to use. 
    • order: based on the value of the order property, Spring will sort the available handler mappings and apply the first matching handler (see the org.springframework.core.Ordered interface). 
    • alwaysUseFullPath: A boolean property (default: false). if true, the full path within the current servlet context is used (e.g. /testing/viewPage.html); If false, the path within the current servlet mapping is used (e.g. /viewPage.html). 
    • urlDecode: A boolean property (default: true). 
    • lazyInitHandlers: A boolean property (default: false). allows for lazy initialization of singleton handlers. 

    BeanNameUrlHandlerMapping

    Maps incoming HTTP requests to names of beans, defined in the web application context. Example: To insert an account with an already provided form controller (see Section 13.3.4, “Command controllers”) we could map the HTTP request with the URL http://samples.com/editaccount.form to the appropriate Controller as follows:

    <beans>
      <bean id="handlerMapping"
            class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
        <bean name="/editaccount.form"
              class="org.springframework.web.servlet.mvc.SimpleFormController">
          <property name="formView" value="account"/>
          <property name="successView" value="account-created"/>
          <property name="commandName" value="account"/>
          <property name="commandClass" value="samples.Account"/>
      </bean>
    <beans>

    All incoming requests for the URL /editaccount.form will now be handled by the form Controller in the source listing above. Of course we have to define a servlet-mapping in web.xml as well, to let through all the requests ending with .form.

    <web-app>
      ...
      <servlet>
        <servlet-name>sample</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <!-- maps the sample dispatcher to *.form -->
      <servlet-mapping>
        <servlet-name>sample</servlet-name>
        <url-pattern>*.form</url-pattern>
      </servlet-mapping>
      ...
    </web-app>


    SimpleUrlHandlerMapping

    A configurable mapping that has Ant-style path matching capabilities (see org.springframework.util.PathMatcher class).
    Example:
    Configure the web.xml to enable all requests ending with .html and .form to be handled by the sample dispatcher servlet.






    <web-app>
      ...
      <servlet>
        <servlet-name>sample</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
      </servlet>

      <!-- maps the sample dispatcher to *.form -->
      <servlet-mapping>
        <servlet-name>sample</servlet-name>
        <url-pattern>*.form</url-pattern>
      </servlet-mapping>

      <!-- maps the sample dispatcher to *.html -->
      <servlet-mapping>
        <servlet-name>sample</servlet-name>
        <url-pattern>*.html</url-pattern>
      </servlet-mapping>
      ...
     </web-app>



    Configure the handler mapping to:
    • Route the requests for 'help.html' in any directory to the 'helpController', which is a UrlFilenameViewController (See Section 13.3, “Controllers”).
    • Route the requests for a resource beginning with 'view', and ending with '.html' in the directory 'ex' to the 'helpController'.
    • Two further mappings are also defined for 'editAccountFormController'.


    <beans>
      <!-- no 'id' required, HandlerMapping beans are automatically detected by the DispatcherServlet -->
      <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
          <value> /*/account.form=editAccountFormController /*/editaccount.form=editAccountFormController /ex/view*.html=helpController /**/help.html=helpController </value>
        </property>
      </bean>
      <bean id="helpController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
      <bean id="editAccountFormController" class="org.springframework.web.servlet.mvc.SimpleFormController">
        <property name="formView" value="account"/>
        <property name="successView" value="account-created"/>
        <property name="commandName" value="Account"/>
        <property name="commandClass" value="samples.Account"/>
      </bean>
    <beans>

    Intercepting requests - the HandlerInterceptor interface

    Useful when you want to apply specific functionality to certain requests.
    Interceptors must implement org.springframework.web.servlet.HandlerInterceptor, which defines three methods that should provide enough flexibility to do all kinds of pre- and post-processing:

    • One that will be called before the actual handler will be executed
    • One that will be called after the handler is executed
    • One that is called after the complete request has finished.
    Note: The preHandle(..) method returns a boolean value. You can use this method to break or continue the processing of the execution chain. When this method returns true, the handler execution chain will continue, when it returns false, the DispatcherServlet assumes the interceptor itself has taken care of requests (and, for example, rendered an appropriate view) and does not continue executing the other interceptors and the actual handler in the execution chain.
    Example: An interceptor that intercepts all requests and reroutes the user to a specific page if the time is not between 9 a.m. and 6 p.m.





    <beans>
      <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="interceptors">
          <list>
            <ref bean="officeHoursInterceptor"/>
          </list>
        </property>
        <property name="mappings">
          <value> /*.form=editAccountFormController /*.view=editAccountFormController </value>
        </property>
      </bean>
      <bean id="officeHoursInterceptor" class="samples.TimeBasedAccessInterceptor">
        <property name="openingTime" value="9"/>
        <property name="closingTime" value="18"/>
      </bean>
    <beans>


    package samples;

    public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
      private int openingTime;
      private int closingTime;
      public void setOpeningTime(int openingTime) {
        this.openingTime = openingTime;
      }
      public void setClosingTime(int closingTime) {
        this.closingTime = closingTime;
      }
      public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Calendar cal = Calendar.getInstance();
        int hour = cal.get(HOUR_OF_DAY);
        if (openingTime <= hour < closingTime) {
          return true;
        }
        else {
          response.sendRedirect("http://host.com/outsideOfficeHours.html");
          return false;
        }
      }
    }

    Any request coming in, will be intercepted by the TimeBasedAccessInterceptor, and if the current time is outside office hours, the user will be redirected to a static html file, saying, for example, he can only access the website during office hours.
    As you can see, Spring has an adapter class (the cunningly named HandlerInterceptorAdapter) to make it easier to extend the HandlerInterceptor interface.




    Controller Types

    • AbstractController - Provides basic controller functionality. All other controllers extends this controller.
    • MultiActionController - Supports the aggregation of multiple request-handling methods into one controller, which then allows you to group related functionality together. It is capable of mapping requests to method names and then invoking the correct method to handle a particular request.
    • Command controllers - Dynamically bind parameters from HttpServletRequest to data objects. First, lets examine what command controllers are available straight out of the box.
      • AbstractCommandController - Provides writing you own command controller, and binding request parameters to a data object you specify. it also offers validation features and lets you specify what to do with the command object that has been populated with request parameter values.
      • AbstractFormController - Offers form submission support. Using this controller you can model forms and populate them using a command object you retrieve in the controller. The AbstractFormController binds the fields of the form, validates the command object, and hands the object back to the controller to take the appropriate action. Supported features are: invalid form submission (resubmission), validation, and normal form workflow. Use this controller if you need forms, but don't want to specify what views you're going to show the user in the application context.
      • SimpleFormController - Provides more support when creating a form with a corresponding command object. It let's you specify a command object, a viewname for the form, a viewname for page you want to show the user when form submission has succeeded, and more.
      • AbstractWizardFormController - This is an abstract wizard controller that you should extend in order to write your own form controller. You should implement the validatePage(), processFinish() and processCancel() methods.