Monday, December 31, 2012

Lightweight Web Application Framework : PrimeFaces (JSF) + Guice + MyBatis (PART1)

Recently, my friend asks me how to build a lightweight java web application. Many Java web developer would choose Spring and hibernate to build a traditional web application. However, it may not be lightweight enough. I suggested him try to use Guice and MyBatis to build the application framework. Although Spring is more feature-riched than Guice, I admitted that Guice is more lightweight and easier to use. MyBatis is also a lightweight SQL map framework. It can integrate with Guice framework very well.

Here, I will try to set up a simple web application with PrimeFaces, Guice and MyBatis. I hope that my friend could learn how to do it. :)

Using MyFaces and PrimeFaces in presentation layer.
Integrate MyFaces and PrimeFaces is simple. Just simply get the JARS file from MyFaces website and PrimeFaces website.

For MyFaces, just add the following sample configuration into your web.xml.
<display-name>TestGuice</display-name>
<context-param>
    <param-name>facelets.DEVELOPMENT</param-name>
    <param-value>false</param-value>
  </context-param>
  <context-param>
    <param-name>facelets.REFRESH_PERIOD</param-name>
    <param-value>2</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name>
    <param-value>/WEB-INF/faces-config.xml</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>
  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
    <param-value>true</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.AUTO_SCROLL</param-name>
    <param-value>false</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name>
    <param-value>false</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.ERROR_HANDLING</param-name>
    <param-value>false</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
    <param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.PRETTY_HTML</param-name>
    <param-value>false</param-value>
  </context-param>
  <welcome-file-list>
    <welcome-file>index.do</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>org.apache.myfaces.webapp.MyFacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

For PrimeFaces, there should be no configuration. If you want to use the PrimeFaces theme, you could add the following context parameter in the web.xml.
<context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>glass-x</param-value>
  </context-param>


Integrate Google Guice with JSF
Google Guice will be used as IOC container. Dependency Injection for service class and SQL mapper class is done though Guice. To integrate with JSF, I suggest to simply add a
ServletContextListener to do it.

Add the following configration in your web.xml:
<listener>
    <listener-class>org.borislam.GuiceContextListener</listener-class>
  </listener>

Inside the ServletContextListener, just create a Guice Injector and put it in ServletContext:
public class GuiceContextListener implements ServletContextListener {

   public void contextDestroyed(ServletContextEvent servletContextEvent) {
     ServletContext servletContext = servletContextEvent.getServletContext();
     servletContext.removeAttribute(Injector.class.getName());
   }

   public void contextInitialized(ServletContextEvent servletContextEvent) {
     Injector injector = Guice.createInjector(
       new MyBatisModule() {
        @Override
        protected void initialize() {         
         //add singleton service class
         bind(SimpleService.class).to(SimpleServiceImpl.class).in(Singleton.class); 
        }
       );
     
     ServletContext servletContext = servletContextEvent.getServletContext();
     servletContext.setAttribute(Injector.class.getName(), injector);
  }
}  

Create a JSF base backing bean.
In the base backing bean, get the Guice injector in the PostConstruct method. Then, every backing beans in your web application need to extends this base backing bean.

package org.borislam.view;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import com.google.inject.Injector;

public abstract class BasePageBean implements Serializable{

   private Injector injector;
   
   public BasePageBean() {}
   
   public Injector getInjector() {
     if(injector == null) {
       ServletContext servletContext = (ServletContext)FacesContext.getCurrentInstance().
                                        getExternalContext().getContext();
       injector = (Injector)servletContext.getAttribute(Injector.class.getName());  
     }
     return injector;
   }
   public void setInjector(Injector injector) {
     this.injector = injector;
   }
   
   @PostConstruct
   public void init() {
     getInjector().injectMembers(this);
   }
}      

In the second part, I will continue to demonstrate how to integrate MyBatis and Guice.

No comments: