Wednesday, 5 November 2014

Caching in Hibernate

Why caching is required?
To improve the performance the enterprise applications often it’s required to cache the data from database somewhere in the RAM or hard drive. This will boost the response time of application as most of the data accessed from the cached location instead of hitting the database for each and every request. For example suppose application displays configuration related data which most of the time will not changes often. This data can be cached for the very first request and displayed later.Now we can think of Hibernate how it manages caching in application.
Hibernate supports two types of caching:

1.       First level caching and

2.       Second level caching

First level caching:
By default hibernate API supports First level caching by session. But scope of cached data limited for that session only.
Second Level Cache:
Session Factory holds the second level cache data. Cached data will be available for entire application. Configurations required to enable the second level cache. There are different vendors available in the market to provide caching implementation.
1.       EH cache (Easy Hibernate Cache)

2.       Swaram Cache

3.       JBoss Cache

4.       OS Cache




How does Second Level Cache Works?
Entity objects never cached instead entity data will be cached in the system.  The data is stored in dehydrated format and it looks like hash map where key will be entity id and values will be list of primitive values.
*-----------------------------------------*
|          Person Data Cache              |
|-----------------------------------------|
| 1 -> [ "Suresh" , "Q" , "Public" , null ] |
| 2 -> [ "Mahesh" , "D" , "Public" ,  1   ] |
| 3 -> [ "Ramesh" , "N" , "Public" ,  1   ] |
*-----------------------------------------*

Sample EHcache xml file:
 <?xml version="1.0" encoding="UTF-8"?>

xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"

monitoring="autodetect" dynamicConfig="true">

<diskStore path="java.io.tmpdir/ehcache" />

<defaultCache maxEntriesLocalHeap="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"

maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"

memoryStoreEvictionPolicy="LRU" statistics="true">

<persistence strategy="localTempSwap" /></defaultCache>

<cache name="com.gps.model.FoodItems" maxEntriesLocalHeap="10000" eternal="false"

timeToIdleSeconds="5" timeToLiveSeconds="10">

<persistence strategy="localTempSwap" />

</cache>

<cache name="org.hibernate.cache.internal.StandardQueryCache"

maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="10">

<persistence strategy="localTempSwap" />

</cache>

<cache name="org.hibernate.cache.spi.UpdateTimestampsCache"maxEntriesLocalHeap="5000" eternal="true">
<persistence strategy="localTempSwap" />

</cache>
</ehcache>

configuration can be reffered by below settings.
<property name="net.sf.ehcache.configurationResourceName">/Ehcache.xml</property>
How does Query Cache Works?
Conceptually query cache works like hash map where key will be query text along with parameter values and value will be list of entity IDs that match the query.
*----------------------------------------------------------*
|                       Query Cache 
                                              | Value
           KEY                                |
|----------------------------------------------------------|
| ["from dept1 where id=?", ["1"] ] -> [1, 2] ] |
*----------------------------------------------------------*
Some queries don't return entities instead of they return only primitive values. In those cases the values themselves will be stored in the query cache. The query cache gets populated when a cacheable JPQL/HQL query gets executed.

Note:If EHCache settings are not provided default settings will considered.


Database for Demo purpose:
Download H2 database and install. Open link http://localhost:8082 and login to test schema.

 
Steps for Query Level Cache
Step 1: Create an entity DepartmentEntity and annotate as highlighted in blue.
package hibernate.test.dto;
import java.io.Serializable;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;


@Entity (name = "dept1")
@Cacheable
@Table(name = "DEPARTMENT", uniqueConstraints = {
@UniqueConstraint(columnNames = "ID"),
@UniqueConstraint(columnNames = "NAME") })

@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="CRDEPT") public class DepartmentEntity implements Serializable {

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID", unique = true, nullable = false)
private Integer id;
@Column(name = "NAME", unique = true, nullable = false, length = 100)
private String name;
public Integer getId() {
return id;

}
public void setId(Integer id) {

this.id = id;

}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Step 2: Create hibernate configuration file.
Below are the properties needs to be explicitly declared in the configuration file.
hibernate.cache.provider_class----->which cache provider needs to be allowed
hibernate.cache.use_query_cache------>explicitly allow query cache
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property><property name="hibernate.cache.use_query_cache">true</property>
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
                <session-factory>
                                <property name="hibernate.connection.driver_class">org.h2.Driver</property>
                                <property name="hibernate.connection.url">jdbc:h2:tcp://localhost/server~/test</property>
                                <property name="hibernate.connection.password">password</property>
                                <property name="hibernate.connection.username">sa</property>
                                <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
                                <property name="show_sql">true</property>
                                <property name="hbm2ddl.auto">update</property>
                                <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
                                <property name="hibernate.cache.use_query_cache">true</property>
                                <mapping class="hibernate.test.dto.DepartmentEntity"></mapping>
                </session-factory>
</hibernate-configuration>
Step 3: executing queries.
Set the query as catchable.  Here HQL is ---->from dept1. Once the query is executed result will be cached and if same query is executed in second session no SQL sent to DB.
 
                                           // Open the hibernate session
                                                                        Session session = HibernateUtil.getSessionFactory().openSession();
                                                                        session.beginTransaction();
                                                                        //Query q = session.createQuery("from dept1 where ID=:dpt_id ").setParameter("dpt_id", 1);
                                                                        Query q = session.createQuery("from dept1");
                                                                        //Query q = session.createQuery("select count(*)from dept1");
                                                                        q.setCacheable(true);
                                                                        //q.setCacheRegion("dept1");
                                                                        List<DepartmentEntity> listobjects1 = null; 
                                                                        listobjects1 = q.list();
                                                                        Iterator<DepartmentEntity> it1 = listobjects1.iterator();
                                                                        System.out.println("First Session Data:");
                                                                        while (it1.hasNext())
                                                                        {
                                                                                                DepartmentEntity departmentEntity = (DepartmentEntity) it1.next();
                                                                                                System.out.println("Department Names-->"+ departmentEntity.getName());
                                                                        }
                                                                        session.getTransaction().commit();
                                                                        session.close();
                                                                        Session session1 = HibernateUtil.getSessionFactory().openSession();
                                                                        session1.beginTransaction();
                                                                        //Query q1 = session1.createQuery("from dept1 where ID=:dpt_id").setParameter("dpt_id", 50);
                                                                        Query q1 = session1.createQuery("from dept1");
                                                                        //Query q1 = session1.createQuery("select count(*)from dept1");
                                                                        q1.setCacheable(true);
                                                                        //q1.setCacheRegion("dept1");
                                                                        List<DepartmentEntity> listobjects11 = null;
                                                                        listobjects11 = q1.list();
                                                                        Iterator<DepartmentEntity> it11 = listobjects11.iterator();     
                                                                        System.out.println("Second Session Data:");
                                                                        while (it11.hasNext())
                                                                        {
                                                                                DepartmentEntity departmentEntity = (DepartmentEntity) it11.next();
                                                                                System.out.println("Department Names-->"+ departmentEntity.getName());
                                                                        }
                                                                        session1.getTransaction().commit();
                                                                        session1.close();
Result:
As we can see only one time SQL sent to DB.
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).

log4j:WARN Please initialize the log4j system properly.

Hibernate: select department0_.ID as ID0_, department0_.NAME as NAME0_ from DEPARTMENT department0_

First Session Data:

Department Names-->        Human Resource

Department Names-->        Dev

Department Names-->        QA

Department Names-->        QA_1

Second Session Data:

Department Names-->        Human Resource

Department Names-->        Dev

Department Names-->        QA

Department Names-->        QA_1


 

 

Tuesday, 28 October 2014

Log4j Configuration


Tools/Software’s required

1. Eclipse

2. log4j-1.2.15.jar

3. Tomcat Server 6.0

We need to fallow simple below steps.

STEP 1: Keep below log4.properties file in WEB-INF/classes.


# Root logger option

log4j.rootLogger=DEBUG, stdout, file

# Redirect log messages to console

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target=System.out

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Redirect log messages to a log file, support file rolling.

log4j.appender.file=org.apache.log4j.RollingFileAppender

log4j.appender.file.File=D:\\log4j-application.log

log4j.appender.file.MaxFileSize=5MB

log4j.appender.file.MaxBackupIndex=10

log4j.appender.file.layout=org.apache.log4j.PatternLayout

log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# STOP NON-APPLICATION LOGS

log4j.logger.org.hibernate=OFF

log4j.logger.org.springframework=OFF
log4j.logger.org.apache.commons=OFF

STEP 2: Keep below entry in required class. This will be a class level declaration.

Example:

final static Logger logger = Logger.getLogger(LoginController.class);

 

Thursday, 23 October 2014

Datasource@Tomcat using spring mvc


 

Software’s/Tools Required:

JDK 1.7

Tomcat 6.0

Eclipse

Spring 3.0 jars

Hibernate 4.0 jars

H2 Database

h2-1.3.176.jar driver



# Simple application to validate username/password from database

# Required Configurations


1. Spring context configuration

a. InternalResourceViewResolver

Configure to locate views created in application.

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

 

b. Package configuration

 

Allow spring to access available packages in application

< context:component-scan base-package="com.gps"></context: component-scan>


c. Session factory

Allow annotation based session configuration in spring.

Set property "dataSource" as per configuration provided in application.

Set property "configlocation" where exactly hibernate property file available in application.

Set property "annotatedClasses" as a list of model classes used in application.

< bean id="sessionfactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="annotatedClasses">
<list>
<value>com.gps.model.User</value>
<value>com.gps.model.FoodItems</value>
</list>
</property>
</bean>

d. Transaction Manager

Configure transaction manager. Here transaction manager will hibernate and set its property "sessionFactory" with configured sessionfactory.

< bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionfactory" />
</bean>

< tx:annotation-driven transaction-manager="hibernateTransactionManager" />

e. Datasource configuration.

Here we can configured datasource in Tomcat server and tagged as JNDI Name. Below class will access the datasource by JNDI name configured in Tomcat.

< bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/MyLocalDB"/>


f. Datasource configuration in Tomcat.

 

Keep below entry under GlobalNamingResources of server.xml file.

 

<Resource auth="Container"

 driverClassName="org.h2.Driver"
 global="jdbc/TestDB"

 maxActive="100"

 maxIdle="20"

 maxWait="10000"
 minIdle="5"

 name="jdbc/TestDB"

 password="password"

 type="javax.sql.DataSource"
url="jdbc:h2:tcp://localhost/server~/test" username="sa" />

 

Keep below entry in context.xml. This will link the resource configured above to with name "jdbc/MyLocalDB".

Now application can access the datasource by name"jdbc/MyLocalDB".


<ResourceLink name="jdbc/MyLocalDB" global="jdbc/TestDB"
auth="Container" type="javax.sql.DataSource" />

 

2. Hibernate.cfg.properties file.

 

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

<hibernate-configuration>

                <session-factory>

                                <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>

                                <property name="show_sql">true</property>

                                <property name="hbm2ddl.auto">update</property>

                                <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

                                <property name="hibernate.cache.use_query_cache">true</property>

                                <property name="net.sf.ehcache.configurationResourceName">/Ehcache.xml</property>       

                </session-factory>

</hibernate-configuration>

 

3. applicationContext.xml file.

 

<?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:context="http://www.springframework.org/schema/context" 

    xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:mvc="http://www.springframework.org/schema/mvc"

    xsi:schemaLocation=" 

http://www.springframework.org/schema/beans 

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 

http://www.springframework.org/schema/context 

http://www.springframework.org/schema/context/spring-context-3.0.xsd 

http://www.springframework.org/schema/tx 

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

 

                <context:component-scan base-package="com.gps"></context:component-scan>

                <mvc:annotation-driven />

                <bean

                                class="org.springframework.web.servlet.view.InternalResourceViewResolver">

                                <property name="prefix" value="/pages/" />

                                <property name="suffix" value=".jsp" />

                </bean>

                <bean id="sessionfactory"

                                class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

                                <property name="dataSource" ref="dataSource" />

                                <property name="configLocation" value="classpath:hibernate.cfg.xml" />

                                <property name="annotatedClasses">

                                                <list>

                                                                <value>com.gps.model.User</value>

                                                                <value>com.gps.model.FoodItems</value>

                                                </list>

                                </property>

                </bean>

                <bean id="hibernateTransactionManager" 

        class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 

        <property name="sessionFactory" ref="sessionfactory" /> 

    </bean>

    <tx:annotation-driven transaction-manager="hibernateTransactionManager" /> 

               

                <!-- <bean id="dataSource"

                                class="org.springframework.jdbc.datasource.DriverManagerDataSource">

                                <property name="driverClassName" value="${jdbc.driverClassName}" />

                                <property name="url" value="${jdbc.url}" />

                                <property name="username" value="${jdbc.username}" />

                                <property name="password" value="${jdbc.password}" />

                </bean> -->

                 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

        <property name="jndiName" value="java:comp/env/jdbc/MyLocalDB"/>

    </bean>

 

                <context:property-placeholder location="classpath:properites/database.properties"/>

 

</beans>




3. Web.xml

 

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" id="WebApp_ID"

       version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

       <display-name>Springmvc1</display-name>

       <welcome-file-list>

                     <welcome-file>/pages/loginnew.jsp</welcome-file>

       </welcome-file-list>

 

       <servlet>

              <display-name>DispatchServlet</display-name>

              <servlet-name>AppFrontController</servlet-name>

              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

              <init-param>

                           <param-name>contextConfigLocation</param-name>

                           <param-value>        </param-value>

                     </init-param>

              <load-on-startup>1</load-on-startup>    

       </servlet>

       <context-param>

              <description>ServletInitialization Parameters</description>

              <param-name>contestLocation</param-name>

              <param-value>WEB-INF/applicationContext.xml</param-value>

       </context-param>

       <servlet-mapping>

              <servlet-name>AppFrontController</servlet-name>

              <url-pattern>*.htm</url-pattern>

       </servlet-mapping>

       <listener>

                     <listener-class>

                             org.springframework.web.context.ContextLoaderListener

               </listener-class>

              </listener>

</web-app>

 

4. Ehcache.xml

 

 

<?xml version="1.0" encoding="UTF-8"?>

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"

       monitoring="autodetect" dynamicConfig="true">

 

       <diskStore path="java.io.tmpdir/ehcache" />

 

       <defaultCache maxEntriesLocalHeap="10000" eternal="false"

              timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"

              maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"

              memoryStoreEvictionPolicy="LRU" statistics="true">

              <persistence strategy="localTempSwap" />

       </defaultCache>

 

       <cache name="com.gps.model.FoodItems" maxEntriesLocalHeap="10000" eternal="false"

              timeToIdleSeconds="5" timeToLiveSeconds="10">

              <persistence strategy="localTempSwap" />

       </cache>

 

       <cache name="org.hibernate.cache.internal.StandardQueryCache"

              maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="10">

              <persistence strategy="localTempSwap" />

       </cache>

 

       <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"

              maxEntriesLocalHeap="5000" eternal="true">

              <persistence strategy="localTempSwap" />

       </cache>

</ehcache>

 

Controller: LoginController.java

 

 

 

 

package com.gps.controller;

 

import java.util.List;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.ModelMap;

import org.springframework.web.bind.annotation.ModelAttribute;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.portlet.ModelAndView;

 

import com.gps.model.User;

import com.gps.service.FoodService;

import com.gps.service.UserService;

 

@Controller

public class LoginController {

       @Autowired

       UserService userService;

       @Autowired

       FoodService foodService;

 

       @RequestMapping(method = RequestMethod.POST, value = "home.htm")

       public String loginValidate(@ModelAttribute("HelloWeb") User user,

                     ModelMap  model) {

 

              String password = user.getPassword();

              String username = user.getUsername();

              System.out.println("user--->" + username);

              System.out.println("password -->" + password);

              // UserDao dao = new UserDaoImpl();

              // FoodItemDao foodDao = new FoodItemDaoIml();

              List<String> list = foodService.getFoodItems();

 

              System.out.println(list.size());

 

              User userdetails = userService.getUser(user);

              if (userdetails != null && userdetails.getPassword() != null

                           && userdetails.getPassword().equals(password)) {

 

                     System.out.println("User is valid");

                     ModelAndView view = new ModelAndView("home");

                     return "home";

 

              } else {

 

                     System.out.println("User is Invalid");

 

                     ModelAndView view1 = new ModelAndView("loginnew.htm");

                     model.addAttribute("error",

                                  "Bad Credentials Login Failed. Kindly relogin");

                     return "loginnew";

              }

 

       }

 

}

Model: User

 
package com.gps.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity(name="user")
@Table(name = "USER")
public class User {
                @Id
                @GeneratedValue(strategy = GenerationType.SEQUENCE)
                @Column(name = "ID", unique = true, nullable = false)
                private String username;
                @Column(name = "password", unique = true, nullable = false)
                private String password;
                public String getUsername() {
                                return username;
                }
                public void setUsername(String username) {
                                this.username = username;
                }
                public String getPassword() {
                                return password;

                }
                public void setPassword(String password) {

                                this.password = password;

                }

}
DAO Layer:

 
package com.gps.dao;

import com.gps.model.User; 

public interface  UserDao {       

       public User getUser(User user); 

}

package com.gps.daoiml;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.gps.dao.UserDao;
import com.gps.model.User;
@Repository
public class UserDaoImpl implements UserDao {
                @Autowired
                  private SessionFactory sessionfactory; 
                @Override
                @Transactional
                public User getUser(User user) {
                                /*Session session = HibernateUtil.getSessionFactory().openSession();                                session.beginTransaction();
                                User userdetails = (User) session.get(User.class, user.getUsername());
                                session.getTransaction().commit();

                                // session.close();

                                return userdetails;*/                    

                                Session session= sessionfactory.openSession();
                                User userdetails = (User) session.get(User.class, user.getUsername());
                                return userdetails;                               

                }

}

Service Layer

 
package com.gps.service;

import com.gps.model.User; 

public interface UserService {      

       public User getUser(User user); 

}

package com.gps.serviceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.gps.dao.UserDao;
import com.gps.model.User;
import com.gps.service.UserService;
@Service
public class UserServiceImpl implements UserService {
                @Autowired
                UserDao userDao;
                @Override
                public User getUser(User user) {
                                return userDao.getUser(user);
                }

}
UI Screenshots
User credentials:

 

 

 


With valid login credentials:
 
 

Login Successful:
 

Invalid Login: