Sunday, January 16, 2011

Design Patterns in Java (Java EE) - Model View Controller (aka MVC)

MVC Concept

MVC pattern is quite simple and very useful pattern for context representation. Representation can be of any kind (text based consoles - OBERON OS for example, or modern GWT based applications).

Please download sample code from my google code repository.

MVC approach divides components into three kinds:
Model that holds model of data we wish to represent, it represents the business logic of an application. It encapsulate business rules into components (JavaBeans in JSP/Servlets MVC application).
View that present data on screen (render model). Model is rendered in such way that it enable interaction with model data and model operations.
Controller that react to user input and based on what is selected it make decisions for making specific calls on model components (update model for example) and selecting appropriate view for displaying updated or existing data.

Because of limitations of web architecture (page are refreshed only when use request them), we cannot use push model of MVC. With this model data has "power" to updates model. For example if you have two simultaneous users that are accessing same web page and same data, if one of them update part of the data, that update will be available immediately to other user. We all know that this does not happen, but there are some tweaks (please see this oracle description for techniques that enable this - long polling, etc.).

Ok, but what can we do to have full functional MVC design in our JEE application. We can (as many framework do) use pull model design concept. With this model view pulls data from model as user initiate request. Or you can wait for WebSocket to be properly (by complying to HTML5 spec.) implemented by all browser vendors and as we know until now, all browser are beautifully aligned with W3C spec, so no problem here! :)
Note: If you still want to use some of cutting edge HTML5 stuff, please use libraries (like jQuery, prototype) right away because then when HTML5 spec changes (and it will!) you just need to upgrade you library. :)
I will also do some tutorials later on jQuery (maybe jQuery mobile?) and full fat client JavaScript application that can leverage HTML5 stuff.

Whatever strategy we use, MVC architecture still delivers its key benefits. This are:

  • Each component has clear responsibility;
  • models contain no view-specific code;
  • view contain no control code or data-access code and concentrate on data display;
  • controllers create and updates models, they do not depend on particular view implementations.

MVC using JSP and servlets

Servlet are good at data processing (reading data, communication with database, invoking business service). JSPs on other hand are good at presentation of data (building HTML to present result of request). So it is natural to combine these two Java EE core concepts for MVC implementation.

The original request is handled by servlet. The servlet invokes the business services (we can use Spring for initializing business service object, but it will be overkill for this example) components which will perform data access and create beans to represent the result (this is the model). Then the server decides which JSP page is appropriate to present those particular result and forwards the request there (this is where JSP pages play they part - view). Servlet decide what business logic code applies and which JSP page should preset (so servlet is the controller).

Simple (but really simple) MVC example

In this example some user will chose product to buy on first page. When he select (or submit without selecting anything) product than the servlet RequestDispatcher (controller) will choose to which JSP page (view) will send request and put product transfer object - DTO (model) to request scope attribute.

Here are couple of images:
First image show list of products, second image show JSP page that is displayed after controller decide which view to show (you can see here that we do not have enough amount of that product on stock, so we suggest customer to buy another product).




Here is controller servlet code:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //get parameter
        String param = request.getParameter("productId");
        //check if null
        int productId = param != null ? Integer.parseInt(param) : 0;

        Product product = Product.findProduct(productId);

        String forwardAddress = "/NoProduct.jsp";

        if (product != null) {
            request.setAttribute("currentProduct", product);

            if (product.getAmount() < 10) {
                forwardAddress = "/LowAmount.jsp";
            } else if (product.getAmount() > 10) {
                forwardAddress = "/SufficientAmount.jsp";
            }
        }        
        RequestDispatcher dispatcher =
                request.getRequestDispatcher(forwardAddress);
        dispatcher.forward(request, response);
    }

As you can see, first we get selected product id (if any) and then we choose appropriate JSP page for that product based on it's amount. If user do not choose any product page "NoProduct.jsp" will be displayed.

Product class is quite simple (it's DTO with static initializing block):

package org.codingwithpassion.model;

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author jan.krizan
 */
public class Product {

    private static Map products;

    /*
     * Execute on object create (only once).
     */
    static {
        products = new HashMap();

        products.put(1, new Product(1, "Square ball", 12, 122));
        products.put(2, new Product(2, "Invisible cup", 1223, 12234));
        products.put(3, new Product(2, "Vitamins", 1, 2));

    }
    private int id;
    private String name;
    private int price;
    private int amount;

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public Product(int id, String name, int age, int amount) {
        this.id = id;
        this.name = name;
        this.price = age;
        this.amount = amount;
    }

    /*
     * Required no-argument constructor.
     */
    public Product() {
    }

    public int getAge() {
        return price;
    }

    public void setAge(int age) {
        this.price = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public static Product findProduct(int id) {
        return (Product) products.get(id);
    }
}

Final remarks

It is not necessary to use MVC in whole web application (GOD servlet is not a good idea). You can use MVC on places you think you will get most from this pattern and on other places use simple JSP.

Controller servlet in MVC do not create any output, the output should be handled only by JSP pages (or any other view technology). So remember, servlet do not call response.setContentType, response.getWriter, etc.

You can forward (using dispatcher) or you can redirect (using request.sendRedirect) to transfer control from controller servlet to view (JSP page).
When you use forward then control is transfered entirely on the server (no network traffic) and user do not see that address of destination JSP page. You should put JSP pages into WEB-INF if those JSP pages make sense only in the context controller servlet.
When you use redirect then control is transfered by sending client a 302 status code together with Location response header. This require an additional network traffic and user sees the address of destination JSP page.

Final remark (of final remarks) is about pointing out that you are not limited for usingrequest scope, but also you can use session or application scope, but remember to synchronize scope declaration in servlet and JSP page.

Out of the box MVC frameworks

I must admit that I'm not a big fan on Java web frameworks. I understand that they help in organization and work load distribution in complex development undertaking, but for small project they are obviously overkill. They bring complexity but on other hand they bring good patterns and common sense guidelines.

This Model-2 MVC architecture is quite powerful and good as core pattern for most simple to mid size project. If you are developing reasonably complex Java web application please see Struts 2 or Spring MVC (the most popular out of action-based frameworks).

5 comments:

  1. Hi,
    Thanks for htis Nice artilce just to add while discussing about HashMap its worth mentioning following questions which frequently asked in Java interviews now days like How HashMap works in Java or How get() method of HashMap works in JAVA very often. on concept point of view these questions are great and expose the candidate if doesn't know deep details.

    Javin
    FIX Protocol tutorial

    ReplyDelete
  2. Wow, what an awesome spot to spend hours and hours! It's beautiful and I'm also surprised that you had it all to yourselves! Kindly visit us @ Best HIV Treatment in India | Top HIV Hospital in India | HIV AIDS Treatment in Mumbai
    HIV Specialist in Bangalore | HIV Positive Treatment in India | Medicine for AIDS in India

    ReplyDelete