<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("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d8334277\x26blogName\x3dSriram\x27s+Blog\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dBLUE\x26layoutType\x3dCLASSIC\x26searchRoot\x3dhttp://metallicatony.blogspot.com/search\x26blogLocale\x3den\x26v\x3d2\x26homepageUrl\x3dhttp://metallicatony.blogspot.com/\x26vt\x3d-8718433808682107797', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script>

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  CRUD with Hibernate @ GitHub  and import it as a maven project into your favorite IDE. 

Labels: ,

0 Comments:

Post a Comment

<< Home