Friday, July 25, 2014

JPA + Spring + hibernate Integration with JPA DAO Pattern

The target is to use JPQL in the code, use hibernate as underlying jpa provider, and use spring to manage transaction.


  • This is the project structure:





















  • 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>wx</groupId>
<artifactId>jpa1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>jpa1</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.2.14.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0.1</version>
</dependency>

</dependencies>
</project>

  • spring configuration 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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>

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

<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/testdb1" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>

<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value="wx.jpa1.entity" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>

<context:component-scan base-package="wx.jpa1" />

</beans>

----- persistence.xml is not required since spring v3.1
----- use spring container to manage transaction propagation
----- use org.springframework.orm.jpa.JpaTransactionManager
  • create database and table in mysql
create database testdb1;

use testdb1;

create table student(
stud_id int not null auto_increment,
name varchar(50) not null,
age int,
depart varchar(20),
primary key (stud_id)
)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

  • entity class with jpa annotation
package wx.jpa1.entity;

import java.io.Serializable;

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 org.apache.commons.lang3.builder.ToStringBuilder;

/**
 * student entity object
 * 
 */
@Entity
@Table(name = "student")
public class StudentEO implements Serializable {

private static final long serialVersionUID = 1492053620157953609L;
private Long studId;
private String name;
private int age;
private String depart;

/*
* As an entity object, the default constructor is a must.
*/
public StudentEO() {

}

@Id
@Column(name = "stud_id")
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getStudId() {
return studId;
}

public void setStudId(Long studId) {
this.studId = studId;
}

@Column(name = "name")
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Column(name = "age")
public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Column(name = "depart")
public String getDepart() {
return depart;
}

public void setDepart(String depart) {
this.depart = depart;
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}

}

  • DAO tier

------------interface IGenericDao ------------

package wx.jpa1.dao;

import java.io.Serializable;
import java.util.List;

public interface IGenericDao<T, PK extends Serializable> {

public T find(PK id);

public void save(T entity);

public T update(T entity);

public void delete(PK id);

public List<T> findAll();

public List<T> findByNamedQuery(String queryName, Object... objects);

}

---------------- implement above interface with jpa ----------

package wx.jpa1.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class GenericDaoJpaImpl<T, PK extends Serializable> implements
IGenericDao<T, PK> {

protected Class<T> entityClass;

@PersistenceContext
protected EntityManager entityManager;

@SuppressWarnings("unchecked")
public GenericDaoJpaImpl() {
if (entityClass == null) {
this.entityClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
}

public T find(PK id) {
return this.entityManager.find(entityClass, id);
}

public void save(T entity) {
this.entityManager.persist(entity);
}

public T update(T entity) {
return this.entityManager.merge(entity);
}

public void delete(PK id) {
this.entityManager.remove(this.entityManager.getReference(entityClass,
id));
}

@SuppressWarnings("unchecked")
public List<T> findAll() {
return this.entityManager.createQuery(
"select h from " + this.entityClass.getName() + " h")
.getResultList();
}

public List<T> findByNamedQuery(String queryName, Object... objects) {
// TODO Auto-generated method stub
return null;
}
}

---------------- for particular DAO interface----
package wx.jpa1.dao;

import java.util.List;

import wx.jpa1.entity.StudentEO;

public interface IStudentDao extends IGenericDao<StudentEO, Long> {

public List<StudentEO> findByDepart(String depart);
}

---------------- implement above dao interface -------

package wx.jpa1.dao;

import java.util.List;

import org.springframework.stereotype.Repository;

import wx.jpa1.entity.StudentEO;

@Repository("studentDao")
public class StudentDaoImpl extends GenericDaoJpaImpl<StudentEO, Long>
implements IStudentDao {

public List<StudentEO> findByDepart(String depart) {
// TODO
return null;
}

}

  • Service tier
------------- service interface -----------------
package wx.jpa1.service;

import java.util.List;

import wx.jpa1.entity.StudentEO;

public interface IStudentService {
public void registerStudent(StudentEO student);
public List<StudentEO> findAll();
}

------------- implement above interface -------------

package wx.jpa1.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import wx.jpa1.dao.IStudentDao;
import wx.jpa1.entity.StudentEO;

@Service("studentService")
@Transactional
public class StudentServiceImpl implements IStudentService {

@Autowired
@Qualifier("studentDao")
private IStudentDao studentDao;

public IStudentDao getStudentDao() {
return studentDao;
}

public void setStudentDao(IStudentDao studentDao) {
this.studentDao = studentDao;
}

public void registerStudent(StudentEO student) {
studentDao.save(student);
}

public List<StudentEO> findAll() {
return studentDao.findAll();
}

}


-------------------- junit test -----------------

package wx.jpa1;

import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import wx.jpa1.entity.StudentEO;
import wx.jpa1.service.IStudentService;

@RunWith(org.springframework.test.context.junit4.SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:app-context.xml")
@Transactional
@TransactionConfiguration(defaultRollback=false)
public class IStudentServiceTest {

@Autowired
IStudentService studentService;

@Before
public void setUp() throws Exception {

}

@After
public void tearDown() throws Exception {
studentService = null;
}

@Test
public void testRegisterStudent() {
StudentEO student = new StudentEO();
student.setAge(20);
student.setDepart("Computer");
student.setName("Adam");
studentService.registerStudent(student);
}
@Test
public void testQueryStudent() {
List<StudentEO> result = studentService.findAll();
System.out.println(result);
}
}

-------------- test result ------

mysql> select * from student;
+-------------+----------------------------------------------------+-------------+----------------------+
| stud_id     | name                                               | age         | depart               |
+-------------+----------------------------------------------------+-------------+----------------------+
|           5 | Adam                                               |          20 | Computer             |
|           6 | Adam                                               |          20 | Computer             |
|           7 | Adam                                               |          20 | Computer             |
|           8 | Adam                                               |          20 | Computer             |
|          11 | John                                               |          20 | Computer             |
+-------------+----------------------------------------------------+-------------+----------------------+
5 rows in set (0.00 sec)

Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@1b6aa42e]; rollback [false]
Hibernate: 
    select
        studenteo0_.stud_id as stud_id1_0_,
        studenteo0_.age as age2_0_,
        studenteo0_.depart as depart3_0_,
        studenteo0_.name as name4_0_ 
    from
        student studenteo0_
[wx.jpa1.entity.StudentEO@13ef45e0[studId=5,name=Adam,age=20,depart=Computer], wx.jpa1.entity.StudentEO@2d0c94a7[studId=6,name=Adam,age=20,depart=Computer], wx.jpa1.entity.StudentEO@14f3770c[studId=7,name=Adam,age=20,depart=Computer], wx.jpa1.entity.StudentEO@7c0cbf92[studId=8,name=Adam,age=20,depart=Computer]]
Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [TestContext@22dca7d0 testClass = IStudentServiceTest, testInstance = wx.jpa1.IStudentServiceTest@448d5a91, testMethod = testQueryStudent@IStudentServiceTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1c3508c0 testClass = IStudentServiceTest, locations = '{classpath:app-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (2): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@1b6aa42e]; rollback [false]
Hibernate: 
    insert 
    into
        student
        (age, depart, name) 
    values
        (?, ?, ?)
Jul 25, 2014 12:08:16 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [TestContext@22dca7d0 testClass = IStudentServiceTest, testInstance = wx.jpa1.IStudentServiceTest@f292738, testMethod = testRegisterStudent@IStudentServiceTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1c3508c0 testClass = IStudentServiceTest, locations = '{classpath:app-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]

Thursday, July 24, 2014

JPA - JTA or Resouce_Local

Before using JPA, we have to consider to use transaction type as JTA or Resource_Local because it will cause different coding and transaction management.


  • JTA - container-managered entity manager
  1. injected to app automatically by j2ee container
  2. close/rollback transaction automatically without extra coding
  3. transaction propagation supported by j2ee container
  4. multiple data resources are required, such as more than 1 DB, DB and JMS,etc  
  • Resource_Local - application-managed entity manager
  1. can be used in j2ee container, J2SE and web container
  2. need to create entity manager explicitly
  3. need to close entity manager explicitly
  4. NO transaction propagation
But I think we can rely on Spring framework to inject entity manager and support transaction propagation.


  • eliminate DAO or JPA DAO Pattern
There are some discussion on DAO tier since JPA is introduced. I prefer to adopt jpa dao pattern personally.

1. A generic DAO interface

public interface GenericDao <T, PK extends Serializable> {

    PK create(T newInstance);
    T read(PK id);
    void update(T transientObject);
}

2. implement the genericDAO
3. For particular entity, if any new behavior is required
public interface UserDAO extends GenericDao<Person,ID> {
// define new method
List<User> findByName(String name);
}


Reference URL:
http://employees.oneonta.edu/higgindm/sweng/Generic_DAO.htm
http://www.ibm.com/developerworks/java/library/j-genericdao/index.html

Tuesday, December 10, 2013

AngularJS Learning Notes 1 - Views and Routing

For normal html page, if open a URL, server will find out the individual html page to show. But for angularjs, it will dynamically render individual html page as a div for the tag "ng-view".


  • This is a sample folder structure:

/rest
     | - css
     |- img
     |- js
          | - app.js
          |- controllers.js
          |- directives.js
          |- filters.js
          |- services.js
     |- lib
          |- angular
                |- angular.js
     |- partials
          |- home.html
          |- page1.html
          |- page2.html


  • home.html to define ng-view
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
  <meta charset="utf-8">
  <title>My App</title>
</head>
<body>
 
  <div id="container-main" ng-view> </div>

  <script src="lib/angular/angular.js"></script>
  <script src="js/app.js"></script>
  <script src="js/services.js"></script>
  <script src="js/controllers.js"></script>
  <script src="js/filters.js"></script>
  <script src="js/directives.js"></script>
</body>
</html>
  • app.js to define router
'use strict';
//define a module which will be used throughout the article.
var mymodule = angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives']);
// configure the router
mymodule.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/home', {templateUrl: 'partials/home.html'});
    $routeProvider.when('/page1', {templateUrl: 'partials/page1.html', controller: 'MyCtrl1'});
    $routeProvider.when('/page2', {templateUrl: 'partials/page2.html'});
    $routeProvider.otherwise({redirectTo: '/home'});
  }]);

  • controllers.js
'use strict';
function MyCtrl1(){}
  • Testing
After deploy to tomcat, open the following URLs to test

http://localhost:8080/rest/#/home
http://localhost:8080/rest/#/page1
http://localhost:8080/rest/#/page2


Reference website:
http://docs.angularjs.org/tutorial/step_07

Monday, July 1, 2013

Portable Git reuses existing ssh key

1) put existing key to c:\Users\<win account>\.ssh
2) run git-bash.bat from portable git folder
3) run command 'exec ssh-agent bash'
4) run command 'ssh-add'

then ssh-add will load the key file from c:\Users\<win account>\.ssh\id_rsa

Wednesday, April 3, 2013

spring eclipse jetty maven setup

1) setup jetty in your web app project


                       <plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.10.v20130312</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
<contextPath>${project.artifactId}</contextPath>
<descriptor>${basedir}/src/main/webapp/WEB-INF/web.xml</descriptor>
<jettyEnvXml>${basedir}/src/test/resources/jetty-env.xml</jettyEnvXml>
</webApp>
<scanTargets>
<scanTarget>src/main/java</scanTarget>
<scanTarget>src/main/resources</scanTarget>
<scanTarget>src/main/webapp</scanTarget>
</scanTargets>
<scanTargetPatterns>
<scanTargetPattern>
<directory>src/test/resources</directory>
<includes>
<include>jetty*.xml</include>
</includes>
<excludes>
<exclude></exclude>
</excludes>
</scanTargetPattern>
</scanTargetPatterns>
</configuration>
</plugin>

2) setup jndi in jetty-env.xml


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<Configure id='wac' class="org.mortbay.jetty.plugin.JettyWebAppContext">

<New id="mysql" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref id="wac"/></Arg>
      <Arg>jdbc/abcd</Arg>
      <Arg>
        <New class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<Set name="driverClassName">com.mysql.jdbc.Driver</Set>
<Set name="url">jdbc:mysql://localhost:3306/abcddb</Set>
<Set name="username">user1</Set>
<Set name="password">pwd123</Set>
</New>
      </Arg>
    </New>
 
</Configure>

and, in web.xml


<resource-ref>
<description>JNDI config to access MySQL Database</description>
<res-ref-name>jdbc/abcd</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

3) db config in spring


<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/cache
         http://www.springframework.org/schema/cache/spring-cache.xsd">

<aop:aspectj-autoproxy />

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/abcd</value>
</property>
</bean>
<context:component-scan base-package="com.yourproject.dao" />
<!-- We tell Spring that we are using annotations -->
<context:annotation-config />

<!-- switches on the @transactional behavior -->
<tx:annotation-driven transaction-manager="transactionManager" />

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

<!-- Hibernate SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="packagesToScan" value="com.yourproject.dao" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>

</beans>



Reference:
http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin



 

Thursday, March 21, 2013

jQuery Masonry Tips

jQuery Masonry : http://masonry.desandro.com/index.html

If call ajax and render each elements dynamically by javascrit, need to call 'appended' method. but sometimes the elements only to be shown on single column.
if need to show elements with multiple columns,
set width first
$("#div").masonry({columnWidth: 310});


 var box = renderSingleElement(item);
 var $singlebox = $(box);
 $("#div_single_element").append($singlebox).masonry( 'appended', $singlebox);

take note if set column width as 310, the width of single element should not be greater than 285, otherwise the elements still be in one column, not multiple columns, so take care to set the element width and column width.


expose URL to access local files on server


Sometimes, we need to access local files on server via HTTP URL. If the files are under /webapp/<project>, take tomcat as an example, it is very east to access them via relative path. If the files are outside of tomcat or other web app servers, how to resolve it?

1) create soft link at /var/www/html/<your root context>


ln -s <file location on server> imgupload


2) modify apache setting

<Directory />
Options FollowSymlinks
Allow from all
</Directory>

refer to http://httpd.apache.org/docs/2.2/mod/core.html

3) then on web page
<img src="/imgupload/<subfolder if have>/abc.jpg" />