<body><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script> <script type="text/javascript"> gapi.load("iframes-styles-bubble", function() { if (window.iframes && iframes.open) { iframes.open( '//www.blogger.com/navbar.g?targetBlogID\758334277\46blogName\75Sriram\47s+Blog\46publishMode\75PUBLISH_MODE_BLOGSPOT\46navbarType\75BLUE\46layoutType\75CLASSIC\46searchRoot\75http://metallicatony.blogspot.com/search\46blogLocale\75en_US\46v\0752\46homepageUrl\75http://metallicatony.blogspot.com/\46vt\75-8718433808682107797', { container: "navbar-iframe-container", id: "navbar-iframe" }, { }); } }); </script>

Wednesday, April 03, 2013

CRUD using Java, Spring, Hibernate, Maven and Log4J

This post illustrates how to integrate Spring into a simple java project and how that in turn simplifies and paves way for an effective coding approach. This project is similar to the previous one CRUD with Java, Hibernate and Maven for the most part. The one big difference is that this project uses Spring in addition to the first one to demonstrate how the application code can be further simplified, modularized and can be more organized and structured. This was possible because Spring framework takes the responsibility of instantiating the required beans, autowiring and injecting the needed dependencies, managing the lifecycle of instantiated beans and it takes care of database sessions and transactions too. By using Spring, much of the boiler plate redundant code is removed and thus simplified. I tried to follow the same design patterns that were used in previous project.
Software Used
1) Java 1.6
2) Spring Tool suite (STS) 3.1.0
3) Spring framework 3.2.2
4) Oracle 11g Express Edition
5) Apache maven 3.0.4
6) Hibernate 4.1.8 Final
7) Log4j 1.2.16 and Slf4j 1.6.1

What's new in this project from the previous one?
a) Configuration and integration of Spring
b) Spring annotations - @Repository, @Component, @Service, @Transactional, @Autowired and component scanning
c) Hibernate annotations - One to many and Many to one, Fetch Types, Fetch modes
d) New tables EMPLOYEE_EXPENSE (which has the list of expenses for every employee) and DEPARTMENT (list of departments) are introduced

Pre-installation and validation steps
Installation and setup is exactly same like the previous project. An additional thing to do is – to create the new tables EMPLOYEE_EXPENSE and DEPARTMENTS and insert data. The below script was used for it

CREATE TABLE EMPLOYEE_EXPENSE
  (
    "EMP_EXP_ID"    NUMBER,
    "EMP_ID"        NUMBER(5,0),
    "YEAR"          NUMBER(4,0),
    "MONTH"         NUMBER(2,0),
    "EXPENSE_CLAIM" NUMBER(7,2),
    "APPROVED_AMT"  NUMBER(7,2),
    "PAID_DATE" DATE,
    CONSTRAINT "EMP_EXP_PK" PRIMARY KEY ("EMP_EXP_ID"), 
    CONSTRAINT "FK_EMPLOYEE" FOREIGN KEY ("EMP_ID") REFERENCES "EMPLOYEE" ("EMP_ID") ENABLE
  );

REM INSERTING INTO EMPLOYEE_EXPENSE
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (1,7369,2002,2,3072.43,3072.43,to_timestamp('03-MAR-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (2,7369,2002,4,30,30,to_timestamp('01-JUN-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (3,7369,2002,5,235.03,35.03,to_timestamp('01-JUN-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (4,7369,2002,9,5095.98,5095.08,to_timestamp('31-OCT-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (5,7369,2002,12,1001.01,1001.01,to_timestamp('01-FEB-03','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (6,7782,2002,1,111.09,111.09,to_timestamp('01-FEB-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (7,7782,2002,3,9.85,9.85,to_timestamp('01-APR-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (8,7782,2002,7,3987.32,3987.32,to_timestamp('01-AUG-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (9,7782,2002,9,1200,1200,to_timestamp('01-OCT-02','DD-MON-RR HH.MI.SSXFF AM'));


CREATE TABLE DEPARTMENT
  (
    "DEPT_ID"     NUMBER(5,0) NOT NULL ENABLE,
    "NAME"        VARCHAR2(20 BYTE),
    "LOCATION_ID" NUMBER(3,0),
    CONSTRAINT "DEPARTMENT_PK" PRIMARY KEY ("DEPT_ID")
  );

REM INSERTING into DEPARTMENT
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (10,'ACCOUNTING',122);
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (20,'RESEARCH',124);
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (30,'SALES',null);
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (40,'OPERATIONS',167);


Create maven project(pom.xml)
The one additional step that was done here is to add spring related configuration in pom.xml. This involves adding spring artifacts spring-orm and spring-context. Here is the complete 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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.samples</groupId>
  <artifactId>associationMapper</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>associationMapper</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>3.2.2.RELEASE</spring.version>
    <hibernate.version>4.1.9.Final</hibernate.version>
    <oracle.version>11.2.0</oracle.version>
    <junit.version>4.11</junit.version>
    <commons-logging.version>1.1.1</commons-logging.version>
    <log4j.version>1.2.16</log4j.version>
    <slf4j.version>1.6.1</slf4j.version>
  </properties>

  <dependencies>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>${spring.version}</version>
 </dependency>
   <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>${spring.version}</version>
 </dependency>
 <dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>${hibernate.version}</version>
 </dependency>
 <dependency>
  <groupId>com.oracle</groupId>
  <artifactId>ojdbc6</artifactId>
  <version>${oracle.version}</version>
 </dependency>
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>${slf4j.version}</version>
 </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

applicationContext.xml (src/main/resources)
This is the master configuration file that Spring reads to instantiate all needed beans. The filename can be anything.xml. It doesn’t matter. I have provided the entire contents of this spring bean config below. All it contains is the configuration for the beans that would be instantiated by Spring framework. The needed properties for every bean is provided so that it gets instantiated successfully. For example, to create a datasource bean, we need all the database related properties and so it is provided. But instead of providing all database connection properties inline, we are reading them using spring’s PropertyPlaceholderConfigurer class. By doing so, these property values can be used elsewhere in the config file using ${variable} notation. And doing this way could help us having the environment specific database properties easily swapped based on which environment (dev/qa/prod) the code is deployed. In our case, the property place holder uses the configurations from the file database.properties which is present in the class path (src/main/resources)

jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:XE
jdbc.username=metallicatony
jdbc.password=xxx

Following the datasource configuration, comes the SessionFactory bean. To instantiate SessionFactory, we use the new LocalSessionFactoryBean class instead of the old AnnotationSessionFactoryBean class. SessionFactory bean needs datasource, hibernate properties and the list of annotated classes as properties. Using all these properties, Spring will be able to instantiate the hibernate sessionFactory bean which in turn will be used by the application code. In addition to that, we have the configuration for hibernate transaction manager and the definition which ensures that the application supports annotation based transactions.
 <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory"/>
 </bean>
 <tx:annotation-driven transaction-manager="transactionManager" />
And the last and most important configuration that saves all our programmers lives is “component scan”!

Just imagine, if we were to define all the hundreds and thousands of (application) beans that we are using in an enterprise application to be defined for Spring!! Argh!! So, instead of defining every single bean in this config file, we ask Spring to scan and autodetect implementation classes using the annotations and instantiate beans through that. The classes that were declared with @Service (service layer beans), @Component(generic beans), @Repository (DAO layer beans) will be created as beans.

ApplicationMain.java 

In ApplicationMain class, the previously discussed applicationContext.xml is used by Spring's ClassPathXmlApplicationContext class to create the application context. This context will hold all the instantiated beans - beans from both applicationContext.xml and the beans that were instantiated through annotations.

Service Layer

From application coding perspective, I have added one more layer – yes, it’s the service layer. The ApplicationMain class calls this service layer from which the control passes down to BO layer, DAO layer and then to the domain layer. 

Here is the complete 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"
    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.1.xsd">
              
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
 <property name="location">
  <value>database.properties</value>
 </property>
</bean>
 
<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="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.Oracle10gDialect</prop>
         <prop key="default_schema">METALLICATONY</prop>
         <prop key="hibernate.show_sql">true</prop>
       </props>
    </property>
 
    <property name="annotatedClasses">
 <list>
  <value>com.samples.domain.Employee</value>
  <value>com.samples.domain.Department</value>
  <value>com.samples.domain.EmployeeExpense</value>
 </list>
    </property>
 </bean>
 
 <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory"/>
 </bean>
 <tx:annotation-driven transaction-manager="transactionManager" />

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

SessionFactory and Transactions
Please remember that as of Hibernate 3.0, there is no need of using HibernateTemplate. In the past, this was used to get a session factory object which in turn was used to get a session before every database transaction. This route is not taken these days and SessionFactory can be directly used to get a session object (sessionFactory.getCurrentSession())

Every DAO class will now have SessionFactory bean auto-injected like this

@Autowired 
SessionFactory sessionFactory;
using which we can get the current session to perform every database operation. Added to that, we now have @Transactional declaration
@Transactional(propagation=Propagation.REQUIRED)
on every method in the service layer (com.samples.service.impl) that does atleast one database operation. By doing that, we are trying to say that all db operations that happen in that method will be within a single transaction (a basic unit of work on a database). This annotation takes care of creating a new transaction and ending the transaction after the unit of work is complete. What really happened underneath was that the DAO method was intercepted and proxied inside a transaction before proceeding with the actual code that we have written!! Wheeee!! This kind of programming technique is called Aspect Oriented Programming (AOP). The transaction propagation (a parameter to the transactional annotation) is used to tell the behavior of a transaction. Propagation.REQUIRED says to continue the transaction if there was any before and to create a new transaction if there wasn’t any. 

One last thing that is new in this project is – Hibernate annotations for One to Many and Many to One. There are lot of confusions in internet about this. So let me clear this. Lets say if there is an EMPLOYEE table and for every employee there are many expenses in EMPLOYEE_EXPENSES table, then we say EMPLOYEE has ONE TO MANY relation to EMPLOYEE_EXPENSES. If the EMPLOYEE table has a department_id column and every employee will belong to one of the available departments in the DEPARTMENT table, then we say it’s a MANY (employees) TO ONE (department) relation using the foreign key column department_id in the EMPLOYEE table. 


It’s important to have @Join annotation on the property of the entity that holds the foreign key column. The entity on the other side of the relationship (parent table) will hold a Set property that can hold the list of the records from the foreign key (child) table. And that’s the reason, we have the below in EmployeeExpense.java
@ManyToOne
@JoinColumn(name="EMP_ID")
private Employee employee;
and the below in Employee.java
@OneToMany(mappedBy="employee", fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<EmployeeExpense> employeeExpenses;
In the same way, the Many to one relation between Employee and department is configured as follows. In Employee.java
@ManyToOne(fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
@JoinColumn(name="DEPT_ID")
private Department department;
and in Department.java
@OneToMany(mappedBy="department")
private Set<Employee> employees;

Huh, did you notice the fetching strategy that was mentioned above? In hibernate, there are 2 FetchTypes – LAZY, EAGER and 3 FetchModes – SELECT, JOIN, SUBSELECT.LAZY and SELECT go together i.e when we get Employee record, it won't get the in-relation records - EmployeeExpense but would wait for its access to fetch. EAGER and JOIN or SUBSELECT go together i.e when we get Employee record, it would get the in-relation records using a JOIN or SUBSELECT SQL query. Here the associated data is EAGER fetched.


I hope this project gives anyone an overall idea about Spring, Hibernate, their integration and the various coding and configuration details that needs to be adapted for creating a better coding world!! Feel free to browse through or download the source from my git repository GitHub - CRUD with Spring and Hibernate

Labels: ,

Sunday, February 10, 2013

CRUD using Java, Hibernate, maven and Log4j

This post briefs about the very basics of Hibernate and how I integrated it with a simple java project to perform CRUD operations. CRUD stands for Create, Read, Update and Delete operations – which we end up doing in most of our day to day programming. I forced myself to follow business object (BO) and Data Access Object (DAO) patterns in this project so that I become habituated with both of them. I agree that business object pattern does not make any sense at all for this sample project but DAO pattern does make a lot of sense. As a matter of fact, DAO makes a lot of sense in any project that deals with data.

Software Used
1)      Java 1.6
2)      Spring Tool suite (STS) 3.1.0
3)      Oracle 11g Express Edition
4)      Apache maven 3.0.4
5)      Hibernate 4.1.8 Final
6)      Log4j 1.2.16 and Slf4j 1.6.1

Pre-installation and validation steps
The below steps were done before the actual java project was created
1)      Installed Java 1.6 and added JAVA_HOME in System Path and System environment variables
2)      Installed Spring Tool Suite
3)      Installed Maven 3.0.4 and added M2_HOME in System Path and System environment variables. Configured STS to use this installed maven instead of its native one. This can be done in STS Window menu -> Preferences -> Maven -> Installations.
4)      Installed Oracle 11g Express Edition, created a new database user and ran the below script (as the new user) to create a table in his schema. This script will also insert data into the table

CREATE TABLE EMPLOYEE(
    EMP_ID            NUMBER(5)    NOT NULL,
    FNAME             VARCHAR2(20),
    LNAME             VARCHAR2(20),
    DEPT_ID           NUMBER(5)    NOT NULL,
    MANAGER_EMP_ID    NUMBER(5),
    SALARY            NUMBER(5),
    HIRE_DATE         DATE,
    JOB_ID            NUMBER(3),
    ACTIVE            CHAR(1)  DEFAULT 'Y' NOT NULL,
    CONSTRAINT employee_pk PRIMARY KEY (EMP_ID)
);

-- Insert Data into the tables.

insert into employee
(EMP_ID,FNAME,LNAME,DEPT_ID,MANAGER_EMP_ID,SALARY,HIRE_DATE,JOB_ID)
select e.emp_id, e.fname, e.lname, e.dept_id, e.manager_emp_id, e.salary, e.hire_date, e.job_id
from
(
select 7369 emp_id, 'JOHN' fname, 'SMITH' lname, 20 dept_id, 7902 manager_emp_id, 800 salary, '17-DEC-80' hire_date, 667 job_id from dual union all
select 7499 emp_id, 'KEVIN' fname, 'ALLEN' lname, 30 dept_id, 7698 manager_emp_id, 1600 salary, '20-FEB-81' hire_date, 670 job_id from dual union all
select 7521 emp_id, 'CYNTHIA' fname, 'WARD' lname, 30 dept_id, 7698 manager_emp_id, 1250 salary, '22-FEB-81' hire_date, null job_id from dual union all
select 7566 emp_id, 'TERRY' fname, 'JONES' lname, 20 dept_id, 7839 manager_emp_id, 2000 salary, '02-APR-81' hire_date, 671 job_id from dual union all
select 7654 emp_id, 'KENNETH' fname, 'MARTIN' lname, 30 dept_id, 7698 manager_emp_id, 1250 salary, '28-SEP-81' hire_date, 670 job_id from dual union all
select 7698 emp_id, 'MARION' fname, 'BLAKE' lname, 30 dept_id, 7839 manager_emp_id, 2850 salary, '01-MAY-80' hire_date, 671 job_id from dual union all
select 7782 emp_id, 'CAROL' fname, 'CLARK' lname, 10 dept_id, 7839 manager_emp_id, 2450 salary, '09-JUN-81' hire_date, 671 job_id from dual union all
select 7788 emp_id, 'DONALD' fname, 'SCOTT' lname, 20 dept_id, 7566 manager_emp_id, 3000 salary, '19-APR-87' hire_date, 669 job_id from dual union all
select 7839 emp_id, 'FRANCIS' fname, 'KING' lname, 10 dept_id, null manager_emp_id, 5000 salary, '17-NOV-81' hire_date, 672 job_id from dual union all
select 7844 emp_id, 'MARY' fname, 'TURNER' lname, 30 dept_id, 7698 manager_emp_id, 1500 salary, '08-SEP-81' hire_date, 670 job_id from dual union all
select 7876 emp_id, 'DIANE' fname, 'ADAMS' lname, 20 dept_id, 7788 manager_emp_id, 1100 salary, '23-MAY-87' hire_date, null job_id from dual union all
select 7900 emp_id, 'FRED' fname, 'JAMES' lname, 30 dept_id, 7698 manager_emp_id, 950 salary, '03-DEC-81' hire_date, 667 job_id from dual union all
select 7902 emp_id, 'JENNIFER' fname, 'FORD' lname, 20 dept_id, 7566 manager_emp_id, 3000 salary, '03-DEC-81' hire_date, 669 job_id from dual union all
select 7934 emp_id, 'BARBARA' fname, 'MILLER' lname, 10 dept_id, 7782 manager_emp_id, 1300 salary, '23-JAN-82' hire_date, 667 job_id from dual
) e;
commit;

Create maven project
The first and foremost task is to create a maven project in STS which generates a default maven project structure that includes the pom.xml file. Use the below pom.xml file instead of the default one that STS provides.

<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>com.samples</groupId>
  <artifactId>hibernateCrud</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>hibernateCrud</name>
  <url>http://maven.apache.org</url>
  
  <repositories>
  <repository>
   <id>JBoss repository</id>
   <url>http://repository.jboss.org/nexus/content/groups/public/</url>
  </repository>
 </repositories>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <hibernate.version>4.1.8.Final</hibernate.version>
    <oracle.version>11.2.0</oracle.version>
    <junit.version>4.11</junit.version>
    <commons-logging.version>1.1.1</commons-logging.version>
    <log4j.version>1.2.16</log4j.version>
    <slf4j.version>1.6.1</slf4j.version>
  </properties>

  <dependencies>
 <dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>${hibernate.version}</version>
 </dependency>
 <dependency>
  <groupId>com.oracle</groupId>
  <artifactId>ojdbc6</artifactId>
  <version>${oracle.version}</version>
 </dependency>
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>${slf4j.version}</version>
 </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
In this pom.xml file –<groupid>, <artifactid>, <version>, <packaging> and <name> elements describe about the type and name of the artifact that this project would generate after building with maven. Usually it’s a good practice to match the groupId value with the base package name of java class. <repositories> tells about the nexus repository where the dependent artifact jars (like hibernate, log4J etc) can be found. <properties> is a place where you can centralize the configuration of version numbers of all the artifacts and then can be referred elsewhere int the pom.xml file with ${property-name} representation. <dependencies> lists the various artifacts that this project is dependent on. Once pom.xml is configured, navigate to the project location in command line and type mvn clean install to clean and build the project. This automatically downloads the needed artifacts that were configured in pom.xml too. The downloaded artifacts as well as the jar or war artifact that you build out of this project are placed in /.m2 folder.

Log4j configuration
SLF4J (Simple Logging Facade for Java) is a simple façade or abstraction framework over other logging frameworks like java.util.Logging and Log4J. The desired logging framework is decided during the deployment time.
<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-log4j12</artifactId>
 <version>${slf4j.version}</version>
</dependency>
This downloads slf4j-log4j12-<version>.jar, slf4j-api-<version>.jar and log4j-<log4j-version>.jar to your local .m2 repository folder. Between, <version> and <logj-version> are the versions that you have mentioned under the properties tag of pom.xml

Log4j Properties
This property file is used to configure the root Logger and how the output is formatted when you use a log statement. Below is the configuration I have used to send the logs to console using the specified pattern
log4j.rootLogger=INFO,out
log4j.appender.out=org.apache.log4j.ConsoleAppender
log4j.appender.out.layout=org.apache.log4j.PatternLayout
log4j.appender.out.layout.ConversionPattern=[%t] [class: %-c{1}] %-5p - %m%n

Database and Hibernate configuration in pom.xml
To configure database (oracle), the pom needs an oracle driver (ojdbc) and to configure Hibernate ORM, the pom needs hibernate-core jar file and so the below configuration
<dependency>
 <groupId>com.oracle</groupId>
 <artifactId>ojdbc6</artifactId>
 <version>${oracle.version}</version>
</dependency>
<dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-core</artifactId>
 <version>${hibernate.version}</version>
</dependency>
HibernateUtil.java contains code to instantiate a session. Create a new configuration object which will hold all properties from the hibernate xml config file. If a different file name is used then you have to mention the filename to the configuration object so that it can read all the properties. These properties are used to create a service registry using service registry builder. Using the resulting service registry, the immutable session factory object is created. The way we create session factory object has changed from Hibernate version 4. A snippet from HibernateUtil’s buildSessionFactory() method
Configuration configuration = new Configuration();
//If you ignore the below configure filename, then it searches hibernate.cfg.xml by default
configuration.configure("hib.cfg.xml");
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
return configuration.buildSessionFactory(serviceRegistry);

The only hibernate entity that we have used is the “Employee” class that is mapped to EMPLOYEE table which we already created using the above script. An important point to note is that this entity is referred as value for the element in hibernate xml config file.
  <mapping class="com.samples.domain.Employee"></mapping>

BO, DAO and other layers
As I said, this project is all about doing CRUD operations using hibernate. Totally there are four different packages or layers in this project.
Application Layer (com.samples)
Contains application code in HibernateCRUD.java and code for creating session factory object in HibernateUtil.java
Business object layer (com.samples.BO)
This layer contains code for business validations to check whether the in or out data conforms to the business rules.  As we know, it interfaces with DAO layer and so it converts every business object or the individual java properties to its equivalent domain object.
Data access object layer (com.samples.DAO)
This layer encapsulates the code for all the database operations, session and transaction management. This layer interacts with the underlying Hibernate ORM or Database. Any data related operation cannot by pass this layer.
Domain layer (com.samples.domain)
This holds all the domain or entity objects of the application. These are simple POJOs that map to the underlying database database tables.

Following a layered approach makes us to write uncluttered code and making us to think - to which layer does a new piece of code will fit in. The above approach helps us to use business object pattern and data access object pattern. Every read/write operation from the application code passes through the BO layer then to the DAO layer and then finally transforms as an action on the database. Similarly when the action is complete, the data passes through the DAO layer and to BO layer and then finally to the application layer. Having this in mind, if you navigate the code, it could be easily understood. But as a whole, this project depicts how to perform – add, get, list (get all), update and delete operations using hibernate.

Before bringing this post to an end, let me talk about the domain or hibernate entity mapping of the “Employee” POJO. The mapping is pretty straight forward but the one thing to note is the ID property mapped to EMP_ID column of table.
@Column(name="EMP_ID")
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_id_seq")
@SequenceGenerator(name="emp_id_seq", sequenceName="emp_id_sequence", allocationSize=1)
private Integer empId;
Here we are asking to use an Oracle sequence generated value for the column “EMP_ID”. By default hibernate uses HILO algorithm to generate the sequence numbers and bumps the numbers by 50 for every fetch. To override this we have used an allocation size of 1. By doing this way there won’t be big gap in two successive rows of this table.

All this is possible by having a database sequence called “emp_id_sequence” which can be created with the below BEFORE trigger
CREATE OR REPLACE TRIGGER "METALLICATONY"."EMP_ID_TRIGGER"
BEFORE INSERT ON EMPLOYEE REFERENCING NEW AS NEW
FOR EACH row
BEGIN IF :NEW.emp_id IS NULL THEN
  SELECT emp_id_sequence.nextval INTO :NEW.emp_id FROM dual;
END IF;
ALTER TRIGGER "METALLICATONY"."EMP_ID_TRIGGER" ENABLE;
Having a CHAR(1) column ACTIVE in database, we can map it to a Boolean type in Hibernate entity using the @Type annotation. The ACTIVE column can take Y or N which actually maps to true or false in the domain object
@Column(name="ACTIVE")
@org.hibernate.annotations.Type(type="yes_no")
private Boolean active;

This project is pretty straight forward and it helped me to get easy with maven, hibernate and Log4J. Hope it would help you too. Feel free to browse through or download the source from my git repository  GitHub - CRUD with Hibernate  and import it as a maven project into your favorite IDE. 

Labels: ,

Thursday, January 10, 2013

Books Read

These are some of the books that i have read in the past or currently reading. I wanted to voice out some opinions about them. I'm really not an insane reader. I read here and there when there is a need. But i always wanted to record what i read and so here it is. I classify myself more as a techie reader than a casual novel reader. When i take a book to read, mostly i try to read the entire book but in some cases if the book turns out to be dry, boring and if it does not trigger any of my neural senses then i drop reading it abruptly. In some cases (while reading a technical book), i try to skip some chapters that are irrelevant to me.

Spring Persistence with Hibernate (currently reading)


Head First Servlets and JSP, 2nd Edition



Java Trail Book, 5th Edition



The Secret by Rhonda Byrne



Beginning iPhone 3 Development



Learn Objective-C on the Mac



Oracle PL/SQL by Example



Oracle SQL by Example

Labels: