Monday, August 17, 2009

Bean Factory and Application Context

Spring IOC Container:

In Spring, the application objects will live within the Spring container. The Spring IOC container is mainly responsible for creating the objects, wiring them together, configuring them and managing their complete lifecycle i.e. from initializing to destruction. There are various implementation of Spring Containers. The 2 most common of them are:

1. BeanFactory (org.springframework.beans package) and

2. ApplicationContext (org.springframework.context package)

BeanFactory (org.springframework.beans.factory.BeanFactory interface) is the simplest of containers, providing the basic functionality of Dependency Injection. ApplicationContext (org.springframework.context.ApplicationContext interface) builds on the top of BeanFactory and provides application framework services such as the ability to resolve textual messages from a properties file (for i18N), ability to publish application events to interested event listeners etc

BeanFactory:

BeanFactory is an implementation of Factory design Pattern. BeanFactory knows about many objects in the application, it is able to create association between collaborating objects as they are instantiated. As a result, when the bean factory hands out the objects, those objects are fully configured, are aware of their collaborating objects and are ready to use. A BeanFactory also takes part in the lifecycle of the bean, making calls to custom initialization and destruction methods, if they are defined.
There are several implementations of BeanFactory but the one that is most commonly used is org.springframework.beans.factory.xml.XmlBeanFactory, which loads its beans based on the definitions contained in an XML file.To create an XmlBeanFactory, you must pass an instance of org.springframework.core.io.Resource to the constructor. The Resource object will provide the Xml to the factory. There are several implementations of the Resource, but the 2 most commonly used Resource are: FileSystemResource (which reads the bean definitions from an XML file in the file system) and ClassPathResource (which reads the bean definitions from and XML file placed in the classpath)
Let us consider an example which retreives its bean from a file called as applicationContext.xml and is in the classpath of our application

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

This line tells the bean factory to read the bean definitions from the XML file. But the bean factory doesn't instantiate the beans yet. Beans are "lazily" loaded into bean factories, which means, while the bean factory immediately load the bean definitions (the description of beans and their properties), the beans are not instantiated until they are needed.
To retreive a bean from a BeanFactory, simply call the getBean() method, passing the ID of the bean you want to retreive:

MyBean myBean = (MyBean) factory.getBean("myBean");

When getBean() is called, the factory will instantiate the bean and sets its properties using DI, thus begins the lifecycle of a bean within the Spring Container.

ApplicationContext:


A bean factory is fine for simple applications, but to take advantage of the full power of Spring framework, you'll probably want to load your beans using Spring's more advanced container: the ApplicationContext
ApplicationContext is pretty much similar to the BeanFactory as both load bean definitions, wire beans together, and dispense beans upon request. But ApplicationContext offers much more:

1. It provides means for resolving text messages, including support for internationalization (I18N) of those messages

2. Provides generic way to load file resources, such as images

3. Can publish events to beans that are registered as listeners.


Three most commonly used implementations of ApplicationContext are: FileSystemXmlApplicationContext, ClassPathXmlApplicationContext and XmlWebApplicationContext
Loading an application context from file system or class path is pretty similar to how we load using bean factory. For example, here is how you would load beans from a FileSystemXmlApplicationContext and

ClassPathXmlApplicationContext:ApplicationContext context = new FileSystemXmlApplicationContext("c://applicationContext.xml"); (OR)
ApplicationContext context = new ClasspathXmlApplicationContext("applicationContext.xml");

One major difference between application context and bean factory is how the singleton beans are loaded:A bean factory lazily loads all the singleton beans , deffering the bean creation until getBean() is called. An applicatio context is a bit smarter and pre loads all the singleton beans upon context startup. By preloading singleton beans you ensure that beans will be ready to use when needed- your application won't have to wait for them to be created.

Sunday, August 2, 2009

Composite Key(s)

Using composite-key for a table with not 1 but more than 1 primary keys:

One of the major rule hibernate enforces is that there should be a primary key in any given table and thus its respective hbm file. This is important not only for the unique identification of each row from other but also for mapping the different tables by foreign keys.

However, we may come under situations where we might either not have any primary key at all or may have more than one. When we said more than one, it means either we created a composite primary key (primary key with more than 1 column) while creating the table itself or we may have unique constraints on one or more columns of the table which does not have any primary key. In both the situations, hibernate allow us to deal with the concept of something called as composite-key(s).

Let us consider a small example that will give a clear idea on use of composite-key in hibernate:
Create the following two tables in oracle database:

Create table addr(id integer primary key, street varchar2(20), city varchar2(20));
Create table compo_person(name varchar2(30), addr_id integer references addr(id), age integer, primary key(name,addr_id));


As you can see, we have created a composite primary key on compo_person table i.e. a table with not 1 but 2 columns acting as primary keys. We will consider these tables for looking at how hibernate composite keys work:

Create 3 different pojos namely Address, Person and CompositePerson as follows:

Address: int id, String street, String city
Person implements Serializable: String name, Address address;
CompositePerson: Person person, int age;

Now, create a file called CompositeExample.hbm.xml as follows:


<hibernate-mapping>
<class name="CompositePerson" table="compo_person">
<composite-id name="person" class="Person">
<key-property name="name" type="string" column="name"/>
<key-many-to-one name="address" class="Address" column="addr_id"/>
</composite-id>
<property name="age" column="age" type="java.lang.Integer"/>
</class>

<class name="Address" table="addr">
<id name="addressId" column="id" type="java.lang.Integer">
<generator class="assigned"/>
</id>
<property name="street" column="street" type="string"/>
<property name="city" column="city" type="string"/>
</class>
</hibernate-mapping>

From the above file, if you see, Address is a simple mapping mapped normally to the addr table. However, since we have compo_person table with a composite primary key, i.e. 2 primary keys, we need to tell hibernate about it and map it accordingly in this file. This is done through the tag <composite-id>. The difference between normal <id;> and <composite-id> is that while <id> allows us to just specify one property of the class as a primary key, <composite-id> allows us to add a set of columns.
It is always a good idea to create a seperate class which contains of just those columns that are added as composite primary keys in the table. For this purpose, we have created a seperate class called Person and added address and name fields in it which as we can see from the hbm file, are mapping to addr_id and name columns from the table. Thus, Person class will act as a class for holding our Composite keys.

Apart from this composite primary key, we also attached the other normal property “age” inside CompositePerson class.
Now, let us see, how do we use this composite key to save and load the values to/from the database:


Save composite key values:

Address address = new Address(3,"street2","city2");
session.save(address);
Person person = new Person("name3",address);
CompositePerson compositePerson = new CompositePerson(person,23);

System.out.println("Saving composite person now");
session.save(compositePerson);
session.flush();

As we see from the above example, save is no different than saving from our normal classes. We first save the address, then set that address to the person as it is one of the parameter for Person class.

Load composite key values:

CompositePerson compositePerson2 = (CompositePerson) session.load(CompositePerson.class, person);


The only difference here is, instead of passing a single id parameter which we pass in case of normal primary key, we pass a composite key reference i.e. we pass a person instance since person instance holds the reference to different name(&)address columns. As we know, load method will search the database with a given id that we specify but since we have a composite id in this case, we pass that to load a particular compositeperson. Remember that since Each person is different (separate name & address combination), we always get only one CompositePerson object just as we would have got if we had used a normal primary key and passed that to the load method.

The above statement will generate an sql query like:

"select p.name, a.addr_id, a.street, a.city, c.age from person p, addr a, compo_person c where c.name = p.name and c.addr_id = a.id"

Saturday, August 1, 2009

Hibernate get() Vs load()

Hibernate get() Vs load()
1. Load method will not hit the database until any field/property of the instance that we load is accessed i.e
a) User u = (User) session.load(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());

In the above case, the database hit is performed at step (b) where we are actually accessing a property of the user by calling its getName() method

Get method will perform the database hit immediately when it is called. i.e.
a) User u = (User) session.get(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());

In above case, the database hit is performed at step (a) itself.

2. With load, We cannot access the properties of a JavaBean instance after the session is closed. i.e. the scope of the instance obtained from the load is limited to a session context in which it is called. i.e.
a) User u = (User) session.load(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());
c) session.close();
d) System.out.println("User is: "+u.getName());

In above case, the step 'b' would work fine since we are accessing the user instance in the scope of the session. However, the step 'd' would raise 'LazyInitializationException' because the session is closed
Get method Instances will be active even when the session is closed. i.e.
a) User u = (User) session.get(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());
c) session.close();
d) System.out.println("User is: "+u.getName());

In above case, both steps 'b' and 'd' would work fine

3. Load method will throw an ObjectNotFoundException if the instance that we are trying to load does not exist in the database with the primary key value that we supply.i.e.
a) User u = (User) session.load(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());

In above case, when the load is called and when the database hit is performed at step 'b', if the user with id 1 is not existing in the database, we get 'ObjectNotFoundException' at step 'b' since it hits the database at step 'b'
Get method will return null if the instance with the id we specify is not found, so we can check for null values

Small gottcha with session.load():
One Very important we must note is that when we give the following kind of statement:
User u = (User) session.load(User.class, new Long(15));
Then if we just pass that instance variable 'u' as it is to some other Class (like address.setUser(u)) without accessing any of u's property (like u.getName(), but NOT u.getId()), or if we just call u.getId() there itself, we wont get any exception and u.getId() will print whatever id we have passed for loading the user (15 in this case) even if that row doesnot exist in the database.
The reason is, in the load method, the second parameter passed will be considered and set as the id parameter by default for whatever is being loaded and after some other property is accessed like getName() etc, it will be overriden (which again would be same value if the user with that id exist in the database otherwise an exception will be thrown at that point).
To clarify the above point, consider the following example:
class User {
private int id;
private String name;
public User(int id,String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String Name() {
return name;
}

public String toString() {
return "User id = "+this.getId();
}
}


Now, Consider another class like Address as:

class Address {
private int id;
private User user;

public Address(int id, User user) {
this.id = id;
this.user = user;
}
}


Now, let us say that currently there is no user in the database.
Then,
User user = (User) session.load(User.class, new Integer(1));
System.out.println("User id = "+user.getId());
Address address = new Address(1,user);
session.save(address);

The first 3 lines from above code works just fine and we wont get any exception (even though no users are there in database). Here,
second line will give the output as: User id = 1
third line will consider the dummy user itself.
However, when we try to save the address which has a user associated with it through a foreign key relation and since we did not find any user, the batch update that is being performed for saving address along with its user fails and we get Could not execute JDBC Batch update exception.

However, if change the above example as follows:

User user = (User) session.load(User.class, new Integer(1));
System.out.println(user); (or) System.out.println(user.getName());

Then, the actual database hit is performed and we get the exception we wanted. This is because, we are performing the toString method on user in first case (Which is overriden and now returning the actual id of the user through its this.getId). Even if we dont override the toString() method, and try to log the user on console as System.out.println(user), ObjectNotFoundException would be thrown . And in second case, we are accessing a property other than id i.e. getName() is called on u, so the database is hit and it will NOW try to get the user details with that id which could not be found.

This can be a considered as a bit of a gottcha in load method of session since it is mentioned that load() will perform the hit as soon as any of the property of that particular instance which is being loaded is accessed and if it is not found, we get ObjectNotFoundException immediately. However, the 2 cases in which we consider we do not get the ObjectNotFoundException is:
1. We access the id property
2. We pass the loaded instance to another instance without accessing any of loaded instance's properties.