Summary

This article explains a real world implementation of Strategy design pattern used with technology stack as JSF, Hibernate, IBM Websphere Application Server.

Motivation

There are common situations when classes differ only in their behavior. For this cases is a good idea to isolate the algorithms in separate classes in order to have the ability to select different algorithms at runtime.

Story

In one of the previous projects during audit it came out the we have to build the Junit and coverage report. Since we were not using Spring for this project (I would not like to go into details that why we were not using Spring except one liner “We were not using Spring Framework due to our crazy technical managers.”), Transaction Management was not easy to handle. We used Hibernate implementation of JDBC Transaction management to manage transactions. This was not the reason to use Hibernate.

Our Business Classes were made of simple POJO classes. We made a practice that all transactions begin and commit or rollback will be handled in the business methods so that DAO methods of all modules are free from transaction management and DAO methods can be re-used in business methods without any restriction and fear of data corruption and inconsistency. So transaction management was intertwined with the business logic.

Example

 Java |  copy code |? 
01
public Boolean addNewOrder(Order order) {
02
 
03
    HibernateUtilProxy.startSession();
04
 
05
    HibernateUtilProxy.beginTransaction();
06
 
07
     try {
08
 
09
       // Add new order
10
 
11
     } catch(OrderAlreadyExistException e) {
12
 
13
        HibernateUtilProxy.rollbackTransaction();
14
 
15
     } finally {
16
 
17
         HibernateUtilProxy.commitTransaction();
18
 
19
         HibernateUtilProxy.closeSession();
20
 
21
     }
22
 
23
}

In managed environment testing is always a tricky task. Since we were getting DB connection using DataSource in a managed environment, it was difficult to test the same code using Junit outside the web container. If we had been using Spring, transaction management would have been managed easily using AOP. In that case we could have used EasyMock or similar framework to mock dependent objects like DAO objects (I am not considering here other advanced dependencies as other people might have faced; I just want to keep it simple). In such scenario testing outside the container is very trivial and easy to maintain.

Since we have a different scenario here, now to execute our business methods using JUnit test cases outside the container we need to cut the dependency on DataSource that is looked up by the Hibernate framework using JNDI during its initialization. But the big question arises how to cut that dependency with minimal changes in config files and without changing the java classes? It is not feasible to change dependent code in java classes every time and compile them to take effect of the change. We want to use to mechanism that should be able to change the implementation class dynamically just by changing a single parameter in the config file.

This case was a prefect candidate where Strategy Pattern can be used to solve the problem. The Design Patterns authors define the Strategy pattern as:

"Define a family of algorithms, encapsulate each one, and make them interchangeable. The Strategy pattern lets the algorithm vary independently from clients that use it".

The Strategy pattern embodies two such principles—encapsulate the concept that varies and program to an interface, not an implementation.

So to stick with this we defined an interface IHibernateUtil and defined to classes that implements IHibernateUtil are HibernateUtilWithDatasourceSupport (for managed environment) and HibernateUtilWithJDBCSupport (for non-managed environment). That means we followed both the principles –

1) By encapsulating the concept of connecting to database using DataSource and JDBC in two different implemenation.

2) By implementing the IHibernateUtil interface.

The below example code is not very detailed. The purpose is to give you the idea about how strategy pattern was implemented.

HibernateUtilProxy

 Java |  copy code |? 
01
package com.test.hibernate;
02
 
03
import java.io.IOException;
04
 
05
import java.util.Properties;
06
 
07
public class HibernateUtilProxy {
08
 
09
private static IHibernateUtil iHibernateUtil = null;
10
 
11
static {
12
 
13
try {
14
 
15
Properties prop = new Properties();
16
 
17
prop.load(HibernateUtilProxy.class.getClassLoader()
18
 
19
.getResourceAsStream("config.properties"));
20
 
21
String clazz = prop.getProperty("class");
22
 
23
Class cz = Class.forName(clazz);
24
 
25
iHibernateUtil = (IHibernateUtil) cz.newInstance();
26
 
27
} catch (IOException e) {
28
 
29
throw new Error("Unable to load HibernateUtil");
30
 
31
} catch (ClassNotFoundException e) {
32
 
33
throw new Error(
34
 
35
"Unable to load HibernateUtil. ClassNotFoundException occured.");
36
 
37
} catch (IllegalAccessException e) {
38
 
39
throw new Error("Unable to load HibernateUtil.");
40
 
41
} catch (InstantiationException e) {
42
 
43
throw new Error("Unable to load HibernateUtil.");
44
 
45
}
46
 
47
}
48
 
49
public static void beginTransaction() {
50
 
51
iHibernateUtil.beginTransaction();
52
 
53
}
54
 
55
public void closeSession() {
56
 
57
iHibernateUtil.closeSession();
58
 
59
}
60
 
61
public void commitTransaction() {
62
 
63
iHibernateUtil.commitTransaction();
64
 
65
}
66
 
67
public void rollbackTransaction() {
68
 
69
iHibernateUtil.rollbackTransaction();
70
 
71
}
72
 
73
public void startSession() {
74
 
75
iHibernateUtil.startSession();
76
 
77
}
78
 
79
}

IHibernateUtil

 Java |  copy code |? 
01
package com.test.hibernate;
02
 
03
public interface IHibernateUtil {
04
 
05
public void startSession();
06
 
07
public void beginTransaction();
08
 
09
public void commitTransaction();
10
 
11
public void rollbackTransaction();
12
 
13
public void closeSession();
14
 
15
}

HibernateUtilWithJDBCSupport (For Non Managed Environment) - Used with JUnit test cases

 Java |  copy code |? 
01
package com.test.hibernate;
02
 
03
import org.hibernate.Session;
04
 
05
import org.hibernate.SessionFactory;
06
 
07
import org.hibernate.Transaction;
08
 
09
import org.hibernate.cfg.Configuration;
10
 
11
public class HibernateUtilWithJDBCSupport implements IHibernateUtil {
12
 
13
private static final SessionFactory sessionFactory;
14
 
15
private static final ThreadLocal threadSession = new ThreadLocal();
16
 
17
private static final ThreadLocal threadTransaction = new ThreadLocal();
18
 
19
static {
20
 
21
// Initialize the Hibernate Session Factory using JDBC Settings
22
 
23
// in hibernate-config-jdbc.cfg.xml
24
 
25
sessionFactory = new Configuration().configure(
26
 
27
"hibernate-config-jdbc.cfg.xml").buildSessionFactory();
28
 
29
}
30
 
31
@Override
32
 
33
public void beginTransaction() {
34
 
35
// TODO Auto-generated method stub
36
 
37
}
38
 
39
@Override
40
 
41
public void closeSession() {
42
 
43
// TODO Auto-generated method stub
44
 
45
}
46
 
47
@Override
48
 
49
public void commitTransaction() {
50
 
51
// TODO Auto-generated method stub
52
 
53
}
54
 
55
@Override
56
 
57
public void rollbackTransaction() {
58
 
59
// TODO Auto-generated method stub
60
 
61
}
62
 
63
@Override
64
 
65
public void startSession() {
66
 
67
// TODO Auto-generated method stub
68
 
69
}
70
 
71
}

HibernateUtilWithDataSourceSupport (For Managed Environment) - Actual implementation that will be used in production.

 Java |  copy code |? 
01
package com.test.hibernate;
02
 
03
import org.hibernate.Session;
04
 
05
import org.hibernate.SessionFactory;
06
 
07
import org.hibernate.Transaction;
08
 
09
import org.hibernate.cfg.Configuration;
10
 
11
public class HibernateUtilWithDataSourceSupport implements IHibernateUtil{
12
 
13
private static final SessionFactory sessionFactory;
14
 
15
private static final ThreadLocal threadSession = new ThreadLocal();
16
 
17
private static final ThreadLocal threadTransaction = new ThreadLocal();
18
 
19
static {
20
 
21
// Initialize the Hibernate Session Factory using JDBC Settings
22
 
23
// in hibernate-config-datasource.cfg.xml
24
 
25
sessionFactory = new Configuration().configure(
26
 
27
"hibernate-config-datasource.cfg.xml").buildSessionFactory();
28
 
29
}
30
 
31
@Override
32
 
33
public void beginTransaction() {
34
 
35
// TODO Auto-generated method stub
36
 
37
}
38
 
39
@Override
40
 
41
public void closeSession() {
42
 
43
// TODO Auto-generated method stub 
44
 
45
}
46
 
47
@Override
48
 
49
public void commitTransaction() {
50
 
51
// TODO Auto-generated method stub
52
 
53
}
54
 
55
@Override
56
 
57
public void rollbackTransaction() {
58
 
59
// TODO Auto-generated method stub
60
 
61
}
62
 
63
@Override
64
 
65
public void startSession() {
66
 
67
// TODO Auto-generated method stub
68
 
69
}
70
 
71
}

config.properties

 Text |  copy code |? 
1
class=com.test.hibernate.HibernateUtilWithDataSourceSupport
Motivation
Sharable with
  • Digg
  • Facebook
  • Google Bookmarks
  • Diigo
  • MySpace
  • StumbleUpon
  • Technorati
  • del.icio.us
  • Reddit
  • Twitter
  • DZone
  • email
  • Yahoo! Bookmarks
  • Yahoo! Buzz
  • blogmarks
  • MSN Reporter
  • PDF