25 May 2015

Introduction

Required Software

  • JDK 1.7
  • Maven 2.2.x
  • Eclipse for J2EE

Steps to write code

  • Create a simple java project with src/main/java, src/main/resources as the source directory. Once project is created, you can add source directory from the below screen (Right click on project -> properties)
  • Convert the project into maven project (Right click on the project -> Configure -> Convert to Maven project)
  • Add the following dependancies in your pom.xml for Hibernate One to Many example

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>SpringAOP-TransactionManagement</groupId>
	<artifactId>SpringAOP-TransactionManagement</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<spring.version>4.0.1.RELEASE</spring.version>
		<aspectj.version>1.7.4</aspectj.version>
		<hibernate.version>4.0.1.Final</hibernate.version>
	</properties>

	<repositories>
		<repository>
			<id>jboss</id>
			<url>http://repository.jboss.org/maven2</url>
		</repository>
	</repositories>

	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- This dependancy is required for spring ApplicationContext container -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring AOP dependency -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- AspectJ dependencies -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${aspectj.version}</version>
		</dependency>

		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${aspectj.version}</version>
		</dependency>

		<!-- Spring datasource -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Hibernate Dependencies -->
		<!-- Hibernate core -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<!-- Hibernate annotation -->
		<dependency>
			<groupId>hibernate-annotations</groupId>
			<artifactId>hibernate-annotations</artifactId>
			<version>3.3.0.GA</version>
		</dependency>

		<dependency>
			<groupId>hibernate-commons-annotations</groupId>
			<artifactId>hibernate-commons-annotations</artifactId>
			<version>3.0.0.GA</version>
		</dependency>
		
		<!-- Hibernate library dependecy start -->
		<dependency>
			<groupId>dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>1.6.1</version>
		</dependency>

		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>

		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2.1</version>
		</dependency>

		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2</version>
		</dependency>
		<!-- Hibernate library dependecy end -->

		<!-- HSQL database -->
		<dependency>
			<groupId>hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<version>1.8.0.10</version>
		</dependency>
	</dependencies>
</project>
  • Create other files as shown below

The purpose of each files are described in the below table

SL NO Class Name Description
1 spring-config.xml Data source, session factory and transaction management is configured in this file. In this file we can configure the methods for which the transaction management will be applied. Spring AOP and Dependency Injection configuration is done in this file
2 com.ashish.entity.EmployeeEntity and com.ashish.entity.EmployeeAllocationEntity These two hibernate entity classes are having one to many relationsship. In EmployeeEntity class @OneToMany and in EmployeeAllocationEntity class @ManyToOne annotations are used to established the relationship in hibernate
3 com.ashish.dao.EmployeeDAO and com.ashish.dao.EmployeeDAOImpl EmployeeDAOImpl implements insertRecords() and listRecords() methods of EmployeeDAO interface.
4 com.ashish.service.EmployeeService and com.ashish.service.EmployeeServiceImpl EmployeeServiceImpl implements insertRecords() and listRecords() methods of EmployeeService interface. The Spring framework controlled transaction management is configured for insertRecords() method. If database the transaction fails it will get rolled back automatically.
5 com.ashish.aop.LoggingAspect Audit Logging is done in this file. @Before and @AfterThrowing advises are implemented in this file.
6 com.ashish.main.MainApp This class contains the main method and calls Employee services to insert records.
  • spring-config.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:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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/aop
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<context:component-scan base-package="com.ashish" />
	
	<!-- AspectJ: Audit Logging Aspect -->
	<aop:aspectj-autoproxy />
    <bean id="loggingAspect" class="com.ashish.aop.LoggingAspect"></bean>
  	
	<!-- Data source: DB connection properties -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
		<property name="url" value="jdbc:hsqldb:mem:ashish" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>

	<!-- Session Factory for the integration with Hibernate ORM -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.archive.autodetection">class</prop>
				<prop key="hibernate.hbm2ddl.auto">create</prop>
			</props>
		</property>
		<property name="annotatedClasses">
			<list>
				<value>com.ashish.entity.EmployeeEntity</value>
				<value>com.ashish.entity.EmployeeAllocationEntity</value>
			</list>
		</property>
	</bean>

	<!-- TransactionManager and TransactionInterceptor is used for the Spring 
		AOP Transaction Management -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="dataSource" ref="dataSource" />
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>


	<!-- We can manage transaction in two ways
		1. By adding @Transactional(readOnly = false) on top of a method OR
		2. By regex matching method name in the tx:advice as shown below
	 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" propagation="REQUIRED" read-only="true" />
			<tx:method name="insert*" propagation="REQUIRED" read-only="false" />
		</tx:attributes>
	</tx:advice>

	<!-- Below configuration says where we want to apply apply the transaction. In the below example we want to apply the transaction in 
		<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation" />
	 -->
	<aop:config>
		<aop:pointcut id="createOperation" expression="execution(* com.ashish.service.EmployeeService.insert*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation" />
	</aop:config>

	<bean id="employeeDao" class="com.ashish.dao.EmployeeDAOImpl">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>

	<bean id="employeeService" class="com.ashish.service.EmployeeServiceImpl">
		<property name="employeeDao" ref="employeeDao"></property>
	</bean>
</beans>
  • EmployeeEntity.java: This class has a set to hold the one to many relationship.
@Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "EMPLOYEE", uniqueConstraints = {
		@UniqueConstraint(columnNames = "ID"),
		@UniqueConstraint(columnNames = "EMAIL") })

public class EmployeeEntity implements Serializable {
	private static final long serialVersionUID = -1798070786993154676L;
	@Id
	@Column(name = "ID", unique = true, nullable = false)
	private Integer employeeId;
	@Column(name = "EMAIL", unique = true, nullable = false, length = 100)
	private String email;
	@Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
	private String firstName;
	@Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
	private String lastName;
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "allocationId")
	private Set<EmployeeAllocationEntity> empAllocations = new HashSet<EmployeeAllocationEntity>();

	public EmployeeEntity(int empId, String firstName, String lastName, String emailId) {
		this.employeeId = empId;
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = emailId;
	}
	
	// All getter and setter methods
}
  • EmployeeAllocationEntity.java: @ManyToOne annotation is used to to establish the relationship.

@Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "EMPLOYEE_ALLOCATION", uniqueConstraints = {
		@UniqueConstraint(columnNames = "ID") })
		
public class EmployeeAllocationEntity implements Serializable {
	private static final long serialVersionUID = -1798070786993154676L;
	@Id
	@Column(name = "ID", unique = true, nullable = false)
	private Integer allocationId;
	@Column(name = "ALLOCATION_NAME", unique = true, nullable = false, length = 100)
	private String allocationName;
	@ManyToOne
	@JoinColumn(name="employeeId")
	private EmployeeEntity empEntity;
	
	public EmployeeAllocationEntity(int allocationId, String allocationName, EmployeeEntity emp) {
		this.allocationId = allocationId;
		this.allocationName = allocationName;
		this.empEntity = emp;
	}
	
	// All getter and setter methods
}
  • EmployeeDAOImpl.java: EmployeeDAOImpl implements insertRecords() and listRecords() methods of EmployeeDAO interface
package com.ashish.dao;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.sql.DataSource;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;

import com.ashish.entity.EmployeeAllocationEntity;
import com.ashish.entity.EmployeeEntity;

public class EmployeeDAOImpl extends HibernateDaoSupport implements EmployeeDAO {
	
	@Override
	public void insertEmpRecords() {
			
		// Add new Employee object
	      EmployeeEntity emp = new EmployeeEntity(1, "Ashish", "Mondal", "ashismo@gmail.com");
	      
	      // Ashish Mondal has two allocations called Project1 and Project2
	      EmployeeAllocationEntity empAllocation = new EmployeeAllocationEntity(1, "Project1", emp);
	      emp.setEmpAllocations(empAllocation);
	      empAllocation = new EmployeeAllocationEntity(2, "Project2", emp);
	      emp.setEmpAllocations(empAllocation);
	      
	      getHibernateTemplate().save(emp);
	      
	   // Add another Employee object
	      emp = new EmployeeEntity(2, "Ujan", "Mondal", "ujanmo@gmail.com");
	      
	      // Ujan Mondal has two allocations called Project2 and Project3. 
	      // Also note that: In project 2, Ashish and Ujan both are allocated
	      emp.setEmpAllocations(empAllocation);
	      
	      empAllocation = new EmployeeAllocationEntity(3, "Project3", emp);
	      emp.setEmpAllocations(empAllocation);
	      
	      getHibernateTemplate().save(emp);
	      
	      // If we uncomment the below line then the transaction will get automatically rolled back
//	      throw new RuntimeException();
	}

	@Override
	public void listEmployees() {
		// Select Employee
			Session session = getSessionFactory().openSession();
	     List<EmployeeEntity> empList = session.createQuery("from EmployeeEntity").list();
	     for(EmployeeEntity emp : empList) {
	    	 System.out.println("==================Employee Details======================");
	    	 System.out.println("Employee Name: " + emp.getFirstName() + " " + emp.getLastName());
	    	 System.out.println("Email : " + emp.getEmail());
	    	 
	    	 System.out.println("+++++++++++++Employee Allocation Details+++++++++++++");
	    	 Set<EmployeeAllocationEntity> empAllocationSet = emp.getEmpAllocations();
	    	 Iterator<EmployeeAllocationEntity> it = empAllocationSet.iterator();
	    	 while(it.hasNext()) {
	    		 System.out.println("Allocation: " + it.next().getAllocationName());
	    	 }
	     }
	     session.close();
	}

	@Override
	public void releaseResources() {
		getSessionFactory().close();
	}
	
}
  • EmployeeServiceImpl.java: Transaction management is done in the insertRecords() method. Transaction management can be done by @Transactional(readOnly = false) annotation or can be configured in the spring-config.xml file. In our example, we have done the configuration in the spring-config.xml file.
package com.ashish.service;

import org.springframework.transaction.annotation.Transactional;

import com.ashish.dao.EmployeeDAO;

public class EmployeeServiceImpl implements EmployeeService {
	
	private EmployeeDAO employeeDao = null;
	/**
	 * Declarative Transaction Management using Spring AOP is applied 
	 * on this method by marking the method with @Transactional 
	 */
//	@Transactional(readOnly = false)
	@Override
	public void insertEmpRecords() {
		employeeDao.insertEmpRecords();
		
	}

	@Override
	public void listEmployees() {
		employeeDao.listEmployees();
	}

	@Override
	public void releaseResources() {
		employeeDao.releaseResources();
		
	}
	
	/**
	 * @return the employeeDao
	 */
	public EmployeeDAO getEmployeeDao() {
		return employeeDao;
	}

	/**
	 * @param employeeDao the employeeDao to set
	 */
	public void setEmployeeDao(EmployeeDAO employeeDao) {
		this.employeeDao = employeeDao;
	}

}
  • LoggingAspect.java: Audit Logging is done in this file. @Before and @AfterThrowing advises are implemented in this file

package com.ashish.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LoggingAspect {

	@Before("execution(* com.ashish.service.EmployeeService.insert*(..))")
	public void beforeExecution(JoinPoint jp) {
		System.out.println("Before method: " + jp.getSignature().getName()
				+ ". Class: " + jp.getTarget().getClass().getSimpleName());
	}

	@AfterThrowing(pointcut = "execution(* com.ashish.service.EmployeeService.insert*(..))", throwing = "ex")
	public void afterThrowingExecution(JoinPoint jp, Exception ex) {
		System.out.println("After throwing advice: "
				+ jp.getSignature().getName() + ". Class: "
				+ jp.getTarget().getClass().getSimpleName());
		System.out.println("Exception: " + ex.getMessage());
	}
}

  • MainApp.java: This class contains the main method and calls DAO services.
package com.ashish.main;


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ashish.service.EmployeeService;
import com.ashish.service.EmployeeServiceImpl;
 
 
public class MainApp
{
   public static void main(String[] args)
   {
	   ApplicationContext appContext = new ClassPathXmlApplicationContext("spring-config.xml");
		
	   EmployeeService employeeService = (EmployeeService) appContext.getBean("employeeService");
	   try {
		   employeeService.insertEmpRecords();
	   } catch (Exception e) {
		   e.printStackTrace();
	   }
	   employeeService.listEmployees();
	   employeeService.releaseResources();
   }

	
}

Output



blog comments powered by Disqus
J2EE,SOAP,RESTful,SVN,PMD,SONAR,JaCoCo,HTTP,API,MAVEN,AngularJS,GitHub,LDAP,AOP,ORM,JMS,MVC,AWS,SQL,PHP,H2DB,JDBC