Monday, January 27, 2014

Maven + Struts2 + Spring + Hibernate + Struts2-Convention-Plugin + Hibernate Search

This blog is in continuation with one of my previous blog maven+struts2+spring+hibernate+struts2 connvention plugin. So, you must need to open this post in order to get better understanding by sample code.

First question raises up in mind that why do we need 'hibernate search' when we have 'hibernate' already in our application. But HibernateSearch is completley different from hibernate. As hibernateSearch is giving a capability of indexing in your application by using Lucene. And instead of adding too many line of code in order to integrate lucene with your application. You can simply integrate hibernatesearch with your application and rest will be taken care by this.

In lucene the major problem we face is to merge indexes. But, in HibernateSearch after each transaction indexes get updated automatically. Few things must need to consider before jumping into code. 

  • HibernateSearch never replace the existing index, once it created then it will be keep on updating it with transactions not every time it loads the application.
  • HibernateSearch is a support of Lucene which may have few limitations
  • Must take care of adding an index because it may add extra burden to add and update process.

Directory structure of this application will remain same. But, you must need to update few libraries from the older version to newer one. As in order to get HibernateSearch you must need newer version of hibernate and spring. 


pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <groupId>LmsWar</groupId>
       <artifactId>LmsWar</artifactId>
       <version>0.0.1-SNAPSHOT</version>
       <packaging>war</packaging>
       <name />
       <description />
       <properties>
              <spring.framework.version>3.2.0.RELEASE</spring.framework.version>
              <hibernate.version>4.1.9.Final</hibernate.version>
              <sl4j.version>1.7.2</sl4j.version>

       </properties>
       <dependencies>
              <dependency>
                     <groupId>org.apache.struts</groupId>
                     <artifactId>struts2-core</artifactId>
                     <version>2.3.16</version>
              </dependency>

              <!-- Struts 2 + Spring plugins -->
              <dependency>
                     <groupId>org.apache.struts</groupId>
                     <artifactId>struts2-spring-plugin</artifactId>
                     <version>2.3.16</version>
              </dependency>
       <!-- MySQL database driver -->
              <dependency>
                     <groupId>mysql</groupId>
                     <artifactId>mysql-connector-java</artifactId>
                     <version>5.1.9</version>
              </dependency>
              <!-- Spring framework -->

              <dependency>
                     <groupId>org.springframework</groupId>
                     <artifactId>spring-orm</artifactId>
                     <version>3.2.0.RELEASE</version>
              </dependency>
              <dependency>
                     <groupId>org.springframework</groupId>
                     <artifactId>spring-context</artifactId>
                     <version>3.2.0.RELEASE</version>
              </dependency>
              <dependency>
                     <groupId>org.springframework</groupId>
                     <artifactId>spring-core</artifactId>
                     <version>3.2.0.RELEASE</version>
              </dependency>

              <dependency>
                     <groupId>org.springframework</groupId>
                     <artifactId>spring-tx</artifactId>
                     <version>${spring.framework.version}</version>
              </dependency>
              <dependency>
                     <groupId>org.springframework</groupId>
                     <artifactId>spring-web</artifactId>
                     <version>${spring.framework.version}</version>
              </dependency>
              <dependency>
                     <groupId>org.springframework</groupId>
                     <artifactId>spring-beans</artifactId>
                     <version>${spring.framework.version}</version>
              </dependency>
              <!-- Hibernate core -->
              <dependency>
                     <groupId>asm</groupId>
                     <artifactId>asm-all</artifactId>
                     <version>3.3</version>
              </dependency>
              <dependency>
                     <groupId>asm</groupId>
                     <artifactId>asm</artifactId>
                     <version>3.3</version>
              </dependency>
              <dependency>
                     <groupId>org.hibernate</groupId>
                     <artifactId>hibernate-core</artifactId>
                     <version>4.1.9.Final</version>
              </dependency>
              <dependency>
                     <groupId>org.hibernate</groupId>
                     <artifactId>hibernate-search</artifactId>
                     <version>4.1.0.Final</version>
              </dependency>







              <dependency>
                     <groupId>org.apache.struts</groupId>
                     <artifactId>struts2-convention-plugin</artifactId>
                     <version>2.3.16</version>
              </dependency>
              <dependency>
                     <groupId>org.apache.struts</groupId>
                     <artifactId>struts2-tiles-plugin</artifactId>
                     <version>2.3.16</version>
                     <scope>compile</scope>
              </dependency>
              <dependency>
                     <groupId>javax.servlet</groupId>
                     <artifactId>javax.servlet-api</artifactId>
                     <version>3.0.1</version>
                     <scope>provided</scope>
              </dependency>
              <dependency>
                     <groupId>log4j</groupId>
                     <artifactId>log4j</artifactId>
                     <version>1.2.15</version>
                     <exclusions>
                           <exclusion>
                                  <groupId>com.sun.jmx</groupId>
                                  <artifactId>jmxri</artifactId>
                           </exclusion>
                           <exclusion>
                                  <groupId>com.sun.jdmk</groupId>
                                  <artifactId>jmxtools</artifactId>
                           </exclusion>
                           <exclusion>
                                  <groupId>javax.jms</groupId>
                                  <artifactId>jms</artifactId>
                           </exclusion>
                     </exclusions>
              </dependency>
              <dependency>
                     <groupId>joda-time</groupId>
                     <artifactId>joda-time</artifactId>
                     <version>2.0</version>
              </dependency>
              <dependency>
                     <groupId>commons-configuration</groupId>
                     <artifactId>commons-configuration</artifactId>
                     <version>1.6</version>
              </dependency>

              <dependency>
                     <groupId>com.jgeppert.struts2.jquery</groupId>
                     <artifactId>struts2-jquery-plugin</artifactId>
                     <version>3.7.0</version>
              </dependency>
              <dependency>
                     <groupId>com.jgeppert.struts2.jquery</groupId>
                     <artifactId>struts2-jquery-grid-plugin</artifactId>
                     <version>3.7.0</version>
              </dependency>
              <dependency>
                     <groupId>com.jgeppert.struts2.jquery</groupId>
                     <artifactId>struts2-jquery-richtext-plugin</artifactId>
                     <version>3.7.0</version>
              </dependency>
              <dependency>
                     <groupId>com.jgeppert.struts2.jquery</groupId>
                     <artifactId>struts2-jquery-tree-plugin</artifactId>
                     <version>3.7.0</version>
              </dependency>
              <dependency>
                     <groupId>com.jgeppert.struts2.jquery</groupId>
                     <artifactId>struts2-jquery-mobile-plugin</artifactId>
                     <version>3.7.0</version>
              </dependency>

              <!-- Hibernate query library dependency end -->
       </dependencies>
       <build>
              <sourceDirectory>${basedir}/src</sourceDirectory>
              <outputDirectory>${basedir}/WebRoot/WEB-INF/classes</outputDirectory>
              <resources>
                     <resource>
                           <directory>${basedir}/src</directory>
                           <excludes>
                                  <exclude>**/*.java</exclude>
                           </excludes>
                     </resource>
              </resources>
              <plugins>
                     <plugin>
                           <artifactId>maven-war-plugin</artifactId>
                           <configuration>
                                  <webappDirectory>${basedir}/WebRoot</webappDirectory>
                                  <warSourceDirectory>${basedir}/WebRoot</warSourceDirectory>
                           </configuration>
                     </plugin>
                     <plugin>
                           <artifactId>maven-compiler-plugin</artifactId>
                           <configuration>
                                  <source>1.5</source>
                                  <target>1.5</target>
                           </configuration>
                     </plugin>
              </plugins>
       </build>
</project>


As we have updated to Hibernate 4 from Hibernate 3, so few changes will come in our code too:
UserDAOImpl.java


package com.test.lab.dao.impl;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;

import com.test.lab.dao.UserDAO;
import com.test.lab.model.UpUser;
import com.test.lab.model.UpUserProfile;

public class UserDAOImpl extends HibernateDaoSupport
implements UserDAO{
       SessionFactory sessionFactory;
       public void setSessionFactory(SessionFactory sessionFactory) {
              this.sessionFactory = sessionFactory;
       }
       public SessionFactory getSessionFactory() {
              return sessionFactory;
       }
     
      public Boolean verifyUser(UpUser user) {
            // TODO Auto-generated method stub
          Boolean result = false;
          final Session session = sessionFactory.openSession();
          Criteria criteria = session.createCriteria(
                            UpUser.class);        
          criteria.add(Restrictions.eq("userScreenName", user.getUserScreenName()));
          criteria.add(Restrictions.eq("userPassword", user.getUserPassword()));
         
             List<UpUser> list = getHibernateTemplate().findByCriteria(criteria);
             if(list.size()>0)
                   result = true;
             return result;
      }
}

Now, it's time to index your application by simply adding few annotations in your code.

Entity of UpUser:
package com.test.lab.model;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;

import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;

/**
 * UpUser entity. @author MyEclipse Persistence Tools
 */
@Indexed
public class UpUser implements java.io.Serializable {

      // Fields

      private Integer userId;
     
      private String userScreenName;
      private String userPassword;
            // Constructors

      /** default constructor */
      public UpUser() {
      }

      /** minimal constructor */
      public UpUser(String userScreenName,String userPassword) {
            this.userScreenName = userScreenName;
            this.userPassword = userPassword;
            }

     
      // Property accessors
@DocumentId
      public Integer getUserId() {
            return this.userId;
      }

      public void setUserId(Integer userId) {
            this.userId = userId;
      }
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
      public String getUserScreenName() {
            return this.userScreenName;
      }
      public void setUserScreenName(String userScreenName) {
            this.userScreenName = userScreenName;
      }
      public String getUserPassword() {
            return this.userPassword;
      }
      public void setUserPassword(String userPassword) {
            this.userPassword = userPassword;
      }
}

In the above code we have added @DocumentId to our unique identifier field as it's mandatory, second change which we have done is in our getUserScreenName() which is actually an index to our application.
As hibernate search documentation is not the party of my post, so want to stick with the topic but, you can get more stuff from "Hibernate Search" reference page.

Now as we have updated the libraries so, few more things we need to change in our previous code:

Update the namespace in resources/com/test/lab/spring/UpUserBean.xml, resource/config/spring/DataSource.xml &  resources/config/spring/HibernateSessionFactory.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

Now, final change to setup the properties for lucene index.
update the sessionFactory Bean in resources/config/spring/HibernateSessionFactory.xml:
 <bean id="sessionFactory"
      class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
....
....
....
<property name="hibernateProperties">
    <props>
     <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
     <prop key="hibernate.show_sql">true</prop>
     <prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
  <prop key="hibernate.search.default.directory_provider">filesystem</prop>
 <prop  key="hibernate.search.default.indexBase">c:/lucene/indexes/first</prop>
   <prop key="hibernate.current_session_context_class">thread</prop>                </props>
</property>
     
This is it, we have integrated the HibernateSearch successfully with Sprirng+Hibernate