Saturday, January 17, 2009

Interceptors in Hibernate ORM Framework - An Introduction

1) Introduction

This article deals with Hibernate Interceptors. Hibernate is an open-source project that provides ORM solution. For more information about Hibernate, novice readers are encouraged to read the article An Introduction to Hibernate on javabeat before reading this article.

Situations may demand to perform some set of pre-requisite/post-requisite operations before/after the core functional logic. In such a case, an interceptor can be used to intercept the existing business functionality to provide extensible or add-on features. They provide pluggable architecture and are generally callback methods that will be called by the framework in response to a particular set of events/actions if properly registered and configured. They follow the standard Interceptor pattern and they have various advantages in an application design. They can be used to monitor the various parts of the input that are passed to an application to validate them. They even have the capability to overwrite the core functional logic of the module.

For example, consider an online shopping system that ships goods to the customer's shipping address upon placing a request. Suppose, there is an enhancement to this application telling that the request has to be validated because of the increasing number of spams and the customer should be notified through e-mail (or mobile) upon successful delivery of the goods. These two enhancements have to be projected into the application's core logic.

Having a general overview of the core logic will look something like the following,

Validate the User Request
Ship the Goods to the customer
Notify the customer about its successful delivery
As we can see above, the two enhancements have to be projected within the application's core logic which requires code changes. But, if the application has to be properly designed with the notion of Interceptors, then the code change can be eliminated to the maximum.

2) Interceptors in Hibernate

Hibernate provides an ORM solution for persisting and querying data in the database. A Hibernate application can be structured in a way such that certain methods can be make to be invoked when a particular life-cycle event occurs. Not always the API in a software/product will completely satisfy the application needs and requirements. Hibernate is no more away from this. Therefore, Hibernate API is designed in such a way to provide pluggable framework through the notion of Interceptors.

In a multi-tiered application, the situation for the inclusion of Interceptors can happen at any level. It can happen at the Client level, Server level and even at the persistence level. Imagine an application is saving employee records in a database and now the application mandates to display to the Database admin about the history of inserts and updates.

A simple general overview of the logic looks like the following,

Insert/Update the records in the Database
During Insert/Update, maintain the log information in a file
As we can see, the maintenance of this logging information should happen whenever when an insert/update goes to the Database. Such a logger interceptor can be easily plugged into the application with minimal code change because of the flexible design of Hibernate.

2.1) Types of Interceptors

Based on their scope, Interceptors in Hibernate can fall under two categories. They are,

Application-scoped Interceptors
Session-scoped Interceptors
2.1.1) Application-scoped Interceptor

An application can contain one or more database sessions represented by the Session interface. If an application is configured to use Global Interceptors, then it will affect the persistent objects in all the sessions. The following code configures a global interceptor,

Configuration configuration = new Configuration();
configuration.setInterceptor(new MyInterceptor());

SessionFactory sessionFactory = configuration.buildSessionFactory();

Session session1 = sessionFactory.openSession();
Employee e1, e2 = null;
// Assume e1 and e2 objects are associated with session1.

Session session2 = sessionFactory.openSession();
User u1, u2 = null
//Assume u1 and u2 objects are associated with session1.
A global-scoped interceptor can be set to an application by calling the Configuration.setInterceptor(Interceptor) method. In the above code, we have two different session objects 'session1' and 'session2'. Let us assume that e1 and e2 Employee objects are associated with session 'session1' and u1 and u2 User objects are associated with session 'session2'. The applied application-scoped interceptor would have affected all the objects (e1, e2, u1 and u2), even though they are in different sessions.

2.1.2) Session-scoped Interceptor

A session-scoped interceptor will affect all the persistent objects that are associated with that particular session only. The following code shows how to configure a session-scoped interceptor,

Configuration configuration = new Configuration();

SessionFactory sessionFactory = configuration.buildSessionFactory();

MyInterceptor myInterceptor = new MyInterceptor();
Session session1 = sessionFactory.openSession(myInterceptor);
Employee e1, e2 = null;
// Assume e1 and e2 objects are associated with session 'session1'.

MyAnotherInterceptor myAnotherInterceptor = new MyAnotherInterceptor ();
Session session2 = sessionFactory.openSession(myAnotherInterceptor);
User u1, u2 = null;
// Assume u1 and u2 objects are associated with session 'session2'.
From the above code, we can infer that a session-scoped interceptor can be set by calling the method SessionFactory.openSession(Interceptor). In the above code, we have two different session objects 'session1' and 'session2' being configured with interceptors MyInterceptor and MyAnotherInterceptor respectively. So, e1 and e2 objects will be affected by MyInterceptor, whereas u1 and u2 objects will be affected by MyAnotherInterceptor.

What is new in Java 6.0 Collections API?

Introduction

In this article I will write about the new Collections APIs introduced in Java 6.0. Mustang has few interesting changes in the Collections APIs, one amoung them is the Deque. Deque is used for the Bi-Directional traversal. It has different implementations including BlockingDeque,ArrayDeque,etc. I will talk about the Deque and its various implementation, also few more changes in the Collectiona API in Java 6.0.

Java 6.0 New Collection APIs an Overview

The following are the new collection APIs introduced in Java 6.0. I listes them as Interfaces and classes.
New Interfaces

Deque
BlockingDeque
NavigableSet
NavigableMap
New Classes

ArrayDeque
LinkedBlockingDeque
ConcurrentSkipListSet
ConcurrentSkipListMap
AbstractMap.SimpleEntry
AbstractMap.SimpleImmutableEntry
Updated Classes in Java 6.0

LinkedList
TreeSet
TreeMap
Collections
Deque and ArrayDeque

Deque is the abbreviation of “Double Ended Queue”. A Collection that allows us to add (or) remove elements at both ends. Deque supports total size of collection for both fixed and unspecified size limits.

Deque implementation can be used as Stack(Last in first out ) or Queue(First in First Out).For each insertion, retrieval and removal of elements from deque there exists methods in 2 flavours. One will throw exception if it fails in an operation and another one returns status or special value for each operation.

Operation Special value method Exception throwing method
Insertion at head offerFirst(e) addFirst(e)
Removal at head pollFirst() removeFirst()
Retrieval at Head
peekFirst() getFirst()
Insertion at Tail offerLast(e) addLast(e)
Removal at Tail pollLast() removeLast()
Retrieval at Tail
peekLast() getLast()
Implementation of Deque doesn’t require preventing the insertion of null, but when we are using special value method null is return to indicate that collection is empty. So it is recommendable not to allow insertion of null.

ArrayDeque is a class that implements Deque. It has no capacity restrictions. It will perform faster than stack when used as stack and faster than linked list when used as queue. ArrayDeque is not thread Safe. The following example explains how to write program using ArrayDeque.

Example
import java.util.ArrayDeque;
import java.util.Iterator;

public class DequeExample
{
public static void main(String as[])
{
ArrayDeque adObj = new ArrayDeque(); 

//Insertion by using various methods
adObj.add("Oracle"); 
adObj.addFirst("DB2");
adObj.offerFirst("MySQL");   //returns boolean - true R false 
adObj.offerLast("Postgres");   //returns boolean - true R false

//Retrievals 
System.out.println("Retrieving First Element :" + adObj.peekFirst());
System.out.println("Retrieving Last Element  :"+ adObj.peekLast());

//Removals
System.out.println("Removing First  Element  :"+ adObj.pollFirst());
System.out.println("Removing Last  Element   :"+ adObj.pollLast());

//Reverse traversal
System.out.println("Remaining Elements :");
Iterator it = adObj.descendingIterator();
while(it.hasNext())
{
System.out.println(it.next());
}  
}
}
Output:
Retrieving First Element :MySQL
Retrieving Last Element  :Postgres
Removing First  Element  :MySQL
Removing Last  Element   :Postgres
Remaining Elements :
Oracle
DB2
BlockingDeque and LinkedBlockingDeque

A BlockingDeque is similar to Deque and provides additionally functionality. When we tries to insert an element in a BlockingDeque, which is already full, it can wait till the space becomes available to insert an element. We can also specify the time limit for waiting.

BlockingDeque methods available in four flavours

Methods throws exception
Methods returns special value
Methods that blocks(Waits indefinitely for space to available)
Methods that times out(Waits for a given time for space to available)
Operation Special Value Throws Exception Blocks Times out
Insertion at head addFirst(e) offerFirst(e) putFirst(e) offerFirst(e,time,unit)
Removal from head removefirst() pollFirst() takeFirst() takeFirst(time,unit)
Retrieval from head getFirst() peekfirst() NA NA
Insertion at tail addLast(e) offerLast(e) putLast(e) offerLast(e,time,unit)
Removal from tail removeLast() pollLast() takeLast() takeLast(time,unit)
Retrieval from tail getLast() peekLast() NA NA
A LinkedBlockingDeque is a Collection class, which implements BlockingDeque interface in which we can specify maximum capacity if we want.If we did not specify the capacity then maximum capacity will be Integer.MAX_VALUE.
import java.util.concurrent.*;
class BlockingDequeExample implements Runnable
{
LinkedBlockingDeque lbd = new LinkedBlockingDeque(1);
volatile boolean b = true;
public void run()
{
try
{
/*First thread once enters into the block it modifies 
instance variable b to false and prevents second 
thread to enter into the block */
if(b)
{
b = false;
Thread.sleep(5000);//Makes the Thread to sleep for 5 seconds
System.out.println("Removing "+lbd.peek());
lbd.poll();//Removing an element from collection
}
else
{
System.out.println("Waiting "); 
/*This method makes to wait till the first thread removes an elements*/
lbd.put("B"); 
System.out.println("Inserted "+lbd.peek()); 
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception
{
BlockingDequeExample bdeObj = new BlockingDequeExample();
bdeObj.lbd.offer("A");
System.out.println("Inserted "+bdeObj.lbd.peek()); 
Thread tMainObj = new Thread(bdeObj);
tMainObj.start();
Thread tSubObj = new Thread(bdeObj);
tSubObj.start();  
}
}
Output:
Inserted A
Waiting
Removing A
Inserted B
NavigableSet and ConcurrentSkipListSet

Suppose we have a requirement, from sorted set elements [5,10,15,20] we want few things like this

Retrieve the element which is immediately greater than or lower than element 15
Retrieve all elements greater than or lower than 10
With the help of existing methods we need to take few risks to achieve them. But with NavigableSet methods it becomes just a method call.NavigableSet methods used to return the closest matches of elements for the given elements in the collection. ConcurrentSkipListSet is one of the class that implements NavigableSet.

Example
import java.util.concurrent.*;
import java.util.*;
class SkipListSetTest 
{
public static void main(String[] args) 
{
ConcurrentSkipListSet csls = new ConcurrentSkipListSet();
csls.add(15);
csls.add(20);
csls.add(5);
csls.add(10);
System.out.println("Elements in the collections are");
for(Integer i: csls)
{
System.out.println(i);
}
/* Retrieve immediate element less than or equal to  the given element */
System.out.println("Floor    "+csls.floor(12));
/* Retrieve immediate  element greater than or equal to the given element */
System.out.println("Ceiling  "+csls.ceiling(12));
/* Retrieve immediate element less than the given element */
System.out.println("Lower    "+csls.lower(10));
/* Retrieve immediate element greater than the given element */
System.out.println("heigher  "+csls.higher(10));
System.out.println("Head Elements ");
Set cslsHeadView =  csls.headSet(10);
//HeadSet excludes the given element
for(Integer i: cslsHeadView)
{
System.out.println(i);
}
Set cslsTailView =  csls.tailSet(10);
//TailSet includes the given element
System.out.println("Tail Elements");
for(Integer i: cslsTailView)
{
System.out.println(i);
}
}
}
Output:
Elements in the collections are
5
10
15
20
Floor    10
Ceiling  15
Lower    5
heigher  15
Head Elements
5
Tail Elements
10
15
20
NavigableMap and ConcurrentSkipListMap

NaviagableMap is similar to NaviagableSet. In NavigableSet, methods use to return values, but in NaviagableMap methods used to return the key,value pair.ConcurrentSkipListMap is the one of the class which implements NaviagableMap.

import java.util.*;
import java.util.concurrent.*;

class NavigableMapExample 
{
public static void main(String[] args) 
{
NavigableMap nm = new ConcurrentSkipListMap();
nm.put(1,"One");
nm.put(2,"Two");
nm.put(3,"Three");
nm.put(4,"Four");
nm.put(5,"Five");
/* Retrieves the key,value pair immediately lesser than the given key */
Map.Entry ae = nm.lowerEntry(5);
/* Map.Entry is a Static interface nested inside Map 
interface,just use to hold key and value */
System.out.println("Key" + ae.getKey());
System.out.println("Value"+ ae.getValue());
/* Retrieves key,value pairs equal to and greater then the given key */
SortedMap mm = nm.tailMap(3);
Set s = mm.keySet(); 
System.out.println("Tail elements are");
for(Integer i:s)
{
System.out.println("Key "+ i + "Value "+ mm.get(i));
}
}
}
output
Key 4
Value Four
Tail elements are
Key 3  Value Three
Key 4  Value Four
Key 5  Value Five
Notes :
floorEntry method retrieves less than or equal to the givenkey (or) null
lowerEntry method retrieves always less than the givenkey (or) null
headMap method retrieves all elements less than the givenkey
tailMap method retrieves all elements greater than or equal to the givenkey
AbstractMap.SimpleEntry and AbstractMap.SimpleImmutableEntry

AbstractMap.SimpleEntry and AbstractMap.SimpleImmutableEntry are a static classes nested inside abstractMap class.The instance of this classes use to hold the key,value pair of one single entry in a Map.The difference between these two classes is that former one allow us to set the value and later one if we try to set the value, it throws UnsupportedOperationException

Modified classes

Classes are modified to implement the new interfaces in the existing classes.LinkedList is modified to implement Deque. TreeSet is modified to implement NavigableSet.TreeMap is modified to implement NavigableMap.In Collections 2 new methods newSetFromMap and asLifoQueue are added.

Conclusion

With java6.0 collections bi- directional traversal becomes easier and retrieval of elements in our desired way also possible. Some attention is also given towards Concurrent operations in Collection.