Thursday, October 1, 2009

Quartz Scheduler with Spring

Spring and Quartz Scheduler:

We will take an example of sending the reminder of timesheet submission every Friday at 1:00 PM to all the employees using Quartz Scheduler:
Quartz Scheduler mainly uses the following 3 for implementing the job scheduling using spring:

1. JobDetailBean
2. CronTriggerBean
3. SchedulerFactoryBean
Let us see the role of each of them in detail:

JobDetailBean: JobDetailBean is simply a JavaBean representation of a JobDetail. JobDetail can be considered something whose objects contain all the information needed to run a Job. i.e. JobDetailsBean is a subclass of Quartz’s org.quartz.JobDetail, which requires the Job implementation be set through ‘jobClass' property. Let’s see how we configure a JobDetailBean in our context file:

<bean name="timsheetReminderJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.prokarma.TimeSheetReminderJob"/>
<property name="jobDataAsMap">
<map>
<entry key="timesheetServive" value-ref="timesheetService"/>
</map>
</property>
</bean>

And here is the TimeSheetReminderJob class which is declared above:

public class TimeSheetReminderJob extends QuartzJobBean {

private TimesheetService timesheetService;

/**
* Setter called after the TimesheetReminderJob is instantiated
* with the value from the JobDetailBean
*/
public void setTimesheetService(TimesheetService timesheetService) {
this.timesheetService = timesheetService;
}

protected void executeInternal(JobExecutionContext ctx)
throws JobExecutionException {
// do the actual work i.e. send timesheetRemiders
timesheetService.sendTimesheetRemiders();
}
}


As can be seen from the bean declaration and the TimeSheetRemiderClass, We have configured a bean named as ‘timeSheetReminder’ as a JobDetailBean. The properties of this bean are very important to understand. 'jobClass' property specifies which class will act as a job (In this case, TimeSheetReminderJob) and hence run. This class should extend QuartzJobBean and implement the method executeExternal which contains the business logic that should be implemented for the job (in this case, sending timesheet reminders by calling sendTimeSheetRemider() method form it). The jobDataAsMap’ property takes a java.util.Map that contains properties that are to be set on the object specified by the jobClass (Since, we have just 1 property ‘timeSheetService’, we set it and give it a ref to another bean somewhere defined in the context file.

CronTriggerBean: Now, since the job is created, we need to specify when this job should run (In our case, as we said earlier, we need it to run every Friday at 1:00 PM). This is specified through org.quartz.Trigger class. There are 2 implementation of Trigger class. They are SimpleTriggerBean and CronTriggerBean. Using SimpleTriggerBean, we can just specify how often a job should run and (optionally) how long to wait for the job to run for the first time (i.e. after the context startup). Here we cannot specify inner details like the exact day/date/month/year etc and exact time on which it should run. Hence, we opted for CronTriggerBean as our Trigger for our TimeSheetReminderJob and specify the exact date and time for the job.
Here is how we configure the CronTiggerBean as a bean in our context file:

<bean id="cronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="timesheetReminderJob"/>
<!-- run every Friday at 1 PM -->
<property name="cronExpression" value="0 0 13 ? * FRI"/>
</bean>


As can be seen, we just need to set 2 properties for the CronTriggerBean. They are: jobDetail (which specifies the JobDetailBean we declared earlier i.e. which specifies the class which acts as a job) and ‘cronExpressionProperty’ which specifies a expression that identifies the runtime of a job. It can be broken upto six (or possibly seven) time elements, separated by spaces. In order from left to right, these elements are defined as follows:

1. Seconds (0-59)
2. Minutes (0-59)
3. Hours (0-23)
4. Day of month (1-31)
5. Month (1-12 or JAN-DEC)
6. Day of Week (1-7 or SUN-SAT)
7. Year (1970-2099)


Each of these elements can be specified with an explicit value (eg. 6), a range (ex: 9-12), a list (eg. 9,10,11) or a wildcard (eg. *). The day of the month and day of the week are mutually exclusive, so you should specify just one of those fields by specifying the other field as a blank (i.e. a ‘?’)
In the case of our cronTriggerBean, we’ve set the cronExpression as “0 0 13 ? * FRI”. You can read this as “Zeroth second of 0th minute of 1 PM (13:00 in 24hrs format is 1:00 PM ) on any day of the month of any month and every Friday of the week”. Some examples of cron expressions and their meanings are specified below:

0 0 10,14,16 * * ? Every day at 10AM, 2PM and 4PM
0 0,15,30,45 * 1-30 ? Every 15 minutes on the first 30 days of the month
30 0 0 1 1 ? 2012 30 seconds after midnight on Jan 1, 2012
0 0 8-17 ? * MON-FRI Every Monday to Friday from 8AM to 5PM

SchedulerFactoryBean: To start a Quartz’s job, we will use Spring’s SchedulerFactoryBean. It is declared as:

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTriggerBean"/>
</list>
</property>
</bean>

The triggers’ property takes an array of references to trigger beans. Since we only have a single trigger at the moment, we simply need to wire it with a list containing a single reference to the cronTriggerBean bean.
This was the final step in setting up the Quartz scheduler in Spring. At this time, our timesheet reminder service will be calling sendTimesheetRemiders() menthod on every Friday at 1 PM.

Wednesday, September 30, 2009

Sending email using Spring with JavaMail

Spring and JavaMail for sending emails:

Being a good java and spring developer, we might face a scenario sometime where we would be asked to construct and send an email from our application when something happens. This something may be like when our timesheet is pending or say when we have deposited or withdrawn some amount from our bank account. When we need to do that, there is nothing much simpler than using spring with javamail api for sending emails. Let us take the same example of the banking operation in our example and see how we configure spring with javamail to send emails.
As we all know, spring uses the concept of DI which is nothing but making our classes and interfaces as beans in the context files and wiring the properties directly or through references. Well, spring uses the same concept for emails. The 2 most important interfaces that we need to configure in spring is:
1. MailSender
2. MailMessage
MailSender: Spring comes with an email abstraction API that makes simple work of sending emails. This is MailSender interface. i.e. The purpose of MailSender interface is to send emails after configuring the mail properties from the MailMessage such as the from and to address, subject of the email, body of the email etc. Spring comes with 2 implementation of MailSender interface. They are CosMailSenderImpl and JavaMailSenderImpl. We will not talk about CosMailSenderImpl.
JavaMailSenderImpl is most versatile and widely used. It is a MailSender based on the JavaMail API. It allows us to send messages of MIME type and even to send non SMTP mail (such as Lotus Notes).
Here is how we configure the JavaMailSenderImpl as a bean in our context file, assuming that we would be sending the email to gmail ids, needing authentication

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="465" />
<property name="protocol" value="smtps" />
<property name="username" value="banking@gmail.com" />
<property name="password" value="banking" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtps.auth">true</prop>
<prop key="mail.smtps.starttls.enable">true</prop>
<prop key="mail.smtps.debug">true</prop>
</props>
</property>
</bean>

The properties explained in the mailSender are self explainatory. For ex: host specifies the hostname of the mail server that we will use for sending emails. port specifies that the mail server is listening to this port no. (This is by default 25. But smtp gmail listens on port no. 465). Since our mails server need authentication, we have specified the username and password property. We have also specified that authentication is required by specifying the mail.smtps.auth javaMailProperty to true. When we specify mail.smtps.starttls.enable as true, it means that the email is delivered in an encrypted way to the user, hence preventing from any unauthorized access.

MailMessage: MailMessage is nothing but the actual message that will be constructed while sending the email. We have lot of implementations of MailMessage but we will just look at its simplest implementation that sends emails as normal text and without any attachments etc. The simplest implementation of the MailMessage is SimpleMailMessage and as said earlier, we configure details like: from and to address, subject and body of the email using the mail message.
It is necessary to configure the MailMessage in the context file, but we have the option of setting its properties in the class level itself. However, it is a generic thing and we can thus create a template of a MailMessage in the context file by specifying the place holders in the template and replace those place holders in the actual class file. Let us see how we can do this:



<bean id="mailMessage" class="org.springframework.mail.SimpleMailMessage">
<property name="from">
<value>
<![CDATA[JDBCBanking <banking@gmail.com>]]>
</value>
</property>
<property name="subject">
<value><![CDATA[Amount deposited in your account></value>
</property>
<property name="text">
<value>
<![CDATA[Hello %NAME%!
This is to inform you that %AMOUNT% Rupees has been deposited to your account on %DAT%
Your balance is now Rupees %BAL%

Thanks
Admin-JDBCBanking
]]>
</value>
</property>
</bean>

Now, we need to wire the 2 beans that we created above (i.e. mailSender and mailMessage) into our service bean like:



<bean id="memberService" class="com.prokarma.service.MemberServiceImpl">
<property name=”mailSender” ref=”mailSender” />
<property name=”mailMessage” ref=”mailMessage” />
</bean>

Finally, lets see how we consider these properties in our class and replace the place holders for them with specific values and send email.

In MemberServiceImpl class, provide setter methods for MailSender and MailMessage as:


private MailSender mailSender;
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}

private SimpleMailMessage mailMessage;
public void setMailMessage(SimpleMailMessage mailMessage) {
this.mailMessage = mailMessage;
}

Here is how you can construct the mail message by obtaining from the context file and replacing the place holders and finally send it:



SimpleMailMessage message = new SimpleMailMessage(mailMessage);
message.setTo(member.getEmail().trim());

String text = message.getText(); //Obtains the text form the template
//replaces the %NAME% placeholder from template with actual member's name
text = StringUtils.replace(text,"%NAME%",member.getName());
text = StringUtils.replace(text,"%AMOUNT%",member.getDepositAmount().toString());
text = StringUtils.replace(text,"%DAT%",member.getDepositDate());
text = StringUtils.replace(text,"%BAL%",member.getBalance());

message.setText(text); // Finally, sets the message text with specific member details

mailSender.send(message);


We have first obtained the template text from the context file, then we edit it for a specific member by replacing the place holders with the specific member details and using StringUtils to replace them. Finally, we set the text of the message again and last step is to send the mail by calling mailSender.send(message);

Saturday, September 5, 2009

Singleton Objects

Singleton objects:

The normal way in which we create an object in java is using the ‘new’ keyword along with the proper constructor. In that way, each time an object is created, we get a new one. However, we may come under scenarios sometimes where we need the same object whenever we access it. That is the time we actually go for creating a singleton object. One very common example is when we have license for only one connection for our database or our JDBC driver has trouble with multi threading. In that case, Singleton ensures that only one connection is made or that only one thread can access to the connection object at any time.

In definitive terms, we can say that a Singleton is an object that can be created but cannot be instantiated by the developers. It does mean that a singleton object has control over how it is created. The restriction on a singleton is that there can be only one instance of a singleton created by the Java Virtual Machine (JVM) and by preventing direct instantiating; we ensure that developers cannot create a second copy.

Let’s take a look at the following example for better understanding of the singleton objects:

public class SingletonExample {

private static SingletonExample ref;
private String name;

private SingletonExample() {

}


public static synchronized SingletonExample getSingletonExample() {
if(ref == null)
ref = new SingletonExample();
return ref;
}


public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}


public static void main(String[] args) {
SingletonExample singletonExample =
SingletonExample.getSingletonExample();
singletonExample.name = "Varun";
SingletonExample singletonExample2 =
SingletonExample.getSingletonExample();
System.out.println(singletonExample2.name);
}
}


If we look at the above example, we find that following are the different rules that need to be applied to make an object singleton.

Rule #1: We should create a default ‘private constructor’. Private constructors ensure that there is no way that an object can be created (instantiated) form outside of the same class.
private SingletonExample() {

}

Rule #2: Create a private static member variable of the class and a public accessor method that returns the singleton objects and does not create a new one every time it is called:
private static SingletonExample ref;
public static SingletonExample getSingletonExample() {
if(ref == null)
ref = new SingletonExample();
return ref;
}

If you look at the method, you will see that when it is called, we first check if the reference is null (which will be the case, when it is called first time) and if it is null, we create the object i.e. instantiate it using the constructor. Note that we can create the object by calling the private constructor here since we have this method in the same class itself and hence have access to private methods/variables/constructors too. If it is however, not null, it means it is already created and hence we return the same instance.
Also, since the member variable ‘ref’ is static, a same copy of it is returned every time allowing the method to return singleton instance.

Rule #3: Mark the accessor method that returns the singleton object as ‘synchronized’: Rule 1 and 2 ensures that the object returned is singleton. Well, not exactly. Imagine what if you have two separate threads say, Thread A and Thread B running and both the threads gets access to the accessor method we created above at the same time. In that case, we still end up in creating two different objects (one by Thread A and other by Thread B). To prevent this, we mark the accessor method as ‘synchronized’ so that only one thread is allowed to access it at any given point of time and hence multithreading also does not ends up in creating 2 different references of a singleton object.
public static synchronized SingletonExample getSingletonExample() {
if(ref == null)
ref = new SingletonExample();
return ref;
}

Rule #4: If we think, there is one more problem that can make our object deviate from its singleton rule. Well, consider what if I clone the already created the singleton object as:
SingletonExample obj = SingletonExample.getSingletonExample();
SingletonExample clone = (SingletonExample) obj.clone();

In the above way, we cloned the already created singleton object and hence ended up in having 2 different copies of the object to play with (1 is the singleton and other one is the cloned one). This violates our singleton principle. So, to prevent this, we need to add the clone() method and make sure that we cannot clone any object of this class by throwing the CloneNotSupportedException.

public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}

Now run the above example. You will find that the name variable is assigned the value of ‘Varun’ even for the second object that is created. This is because we have created a singleton object i.e. a single object is returned every time and hence all the instance variables values are shared.

Friday, September 4, 2009

Serialization in Java

We all know the Java platform allows us to create reusable objects in memory. However, all of those objects exist only as long as the Java virtual machine1 remains running. It would be nice if the objects we create could exist beyond the lifetime of the virtual machine, wouldn't it? Well, with object serialization, you can flatten your objects and reuse them in powerful ways.

Serialization: Object serialization is the process of saving an object's state to a sequence of
bytes, as well as the process of rebuilding those bytes into a live object at some future time.

Following are the set of rules to be implemented when we make an object as Serializable:
Rule #1: The object to be persisted must implement the Serializable interface or inherit that implementation from its object hierarchy

Rule #2: The object to be persisted must mark all nonserializable fields (fields that don't get saved) as transient

Rule #3: The class that is being serialized should declare a serialVersionUID; as private static final long serialVersionUID. This is used to identify the differences between a class's object between a write and read and hence take appropriate actions. If you dont create it, it will be provided by compiler but it has its limitations.

Rule #4: By default, the serialized object would be written to the default stream and that would be taken care by compiler and JVM. However, if you wish to save to some other place like a file or a database, you need to create an OutputStream for it and call the ObjectOutputStream's writeObject method (this is the method that marshalls the actual object fields into sequence of bytes), passing the output stream created. Similarly, at the time of unmarshalling the bytes back to the actual object, we should call the readObject method and cast the received object to its actual type.

Rule #5: If we want to perform some logic (like encrypting a password before saving it and decrypting it upon restoring it), we can override the writeObject and readObject methods with their exact signatures and perform the logic inside those methods and finally call the defaultWriteObject and defaultReadObject from those 2 methods.

Let us consider the above rules with an example:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Employee implements Serializable {

private static final long serialVersionUID = 1L;

private String name;
private int empNo;
private String designation;
private transient String department;

public Employee() {

}

public Employee(String name,int empNo,String designation,String department) {
this.name = name;
this.empNo = empNo;
this.designation = designation;
this.department = department;
}
/*private void writeObject(ObjectOutputStream oos) throws IOException {
if(designation.equalsIgnoreCase("SE"))
this.designation = "Software Engineer";

else if(designation.equalsIgnoreCase("SSE"))
this.designation = "Senior Software Engineer";

oos.defaultWriteObject();
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
}*/


public String toString() {
return "Employee name is: "+this.name+" and his designation is: "+this.designation+" his id is: "+this.empNo+" " +
"and his department is: "+this.department;
}
}
public class SerializedEmployee {

public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("emp.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
Employee employee = new Employee("Varun",123,"SE","Java");
oos.writeObject(employee);
System.out.println("Object saved to the file");
FileInputStream fis = new FileInputStream("emp.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Employee emp = (Employee) ois.readObject();
System.out.println("Object read is: ");
System.out.println(emp);
} catch (FileNotFoundException e) {
System.out.println("FileNotFoundException");
} catch (IOException e) {
System.out.println("IOException");
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFoundException");
}
}
}


From the above example, we see each rule is marked in the same color in the code as the one it is explained under. i.e.
Rule# 1: Employee class is a persistent class as it is implementing Serializable
Rule #2: the 'department' field is marked as transient. So, this field wont be persistent. This can be seen when we called the writeObject and then subsequent call to readObject prints null value for the department field. Try to run the above example and you will see that 'though, we have passed 'Java' as the employee's department field, department' will be shown as 'null' when we print that employee object.
Rule #3: We have declared a 'serialVersionUID' for the class. This helps us in Versioning control which is explained below:
Versioning:
Imagine you create a class, instantiate it, and write it out to an object stream. That flattened object sits in the file system for some time. Meanwhile, you update the class file, perhaps adding a new field. What happens when you try to read in the flattened object?
Well, the bad news is that an exception will be thrown -- specifically, the java.io.InvalidClassException -- because all persistent-capable classes are automatically given a unique identifier. If the identifier of the class does not equal the identifier of the flattened object, the exception will be thrown. However, if you really think about it, why should it be thrown just because I added a field? Couldn't the field just be set to its default value and then written out next time?

Yes, but it takes a little code manipulation. The identifier that is part of all classes is maintained in a field called serialVersionUID. If you wish to control versioning, you simply have to provide the serialVersionUID field manually and ensure it is always the same, no matter what changes you make to the classfile.

For trying to know it better, just run the above example once. Then, comment the part that saves or writes the employee object, change the serialVersionUID to 2L or anything other than 1L (or) perform any change from the bleow list that can adversely affect the saved object.

The Sun documentation lists the various class format changes that can adversely affect the restoration of an object (if the serialVersionUID is changed or not provided). A few of these include:

1 Deleting a field, or changing it from non-static or non-transient to static or transient, respectively.
2 Changing the position of classes in a hierarchy.
3 Changing the data type of a primitive field.



You will notice that you get an exception that states:
"IOException--->java.io.InvalidClassException: Employee; local class incompatible: stream classdesc serialVersionUID = 1L, local class serialVersionUID = 2L".

On the other hand, not every change will have a negative effect. Here are some changes to class versions that do not have a detrimental effect on object behavior:

1 Adding fields, which will result in default values (based on data type) being assigned to the new fields upon restoration.
2 Adding classes will still allow an object of the added class to be created, since the class structure information is included in the stream. However, its fields will be set to the default values.
3 Changing the access modifier (public, private, etc.) for a field, since it is still possible to assign a value to the field.
4 Changing a field from static or transient to to non-static or non-transient, respectively.



Rule #4: We have created the employee object. We want to store the object into a File. So, we created the File using FileOutputStream and then created an ObjectOutputStream with the reference of fileoutput stream. Finally called the writeObject method of the stream by passing the employee object. Here, it saves all the fields of the employee object except those which are marked transient (as explained in rule#2) and those will be saved or marshalled as sequence of bytes.
Similarly, We retreive the marshalled sequence of bytes of the employee object by calling the readObject method and casting it back to employee object.

Rule #5: Say, we have a scenario where we want to process some values just before it is been saved. In this case, we can override the writeObject method. So, from our example, remove the comments for the writeObject and readObject method of the exmployee class. In the writeObject, we have performed a logic which cheks for the designation code and updates the proper designation value. After this is done, we call the defaultWriteObject() that is the method which will be called by writeObject if we dont override it. Similarly, we can even perform some logic while unmarshalling (reading) the object in the readObject method. We did nothing here but just called the defaultReadObject method.

NOTE: If we have a class in a inheritance hierarchy such that the superclass implements serializable, but we dont want the subclass to be serialized, then the only way we can acheive it is by overriding the writeObject and readObject methods in subclass with their exact signatures and throwing "NotSerializableException" from those two methods.

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.

Friday, July 31, 2009

Object states in hibernate

Object states in hibernate:
An object in a hibernate can be in one of the following states:

1. Transient
2. Persistent
3. Detached

1. Transient: An object which is just instantiated using the "new" operator but not associated with any session in hibernate is said to be in Transient state. In other words, a transient object doesnot have any existing representation in the database .
Ex: User user = new User(); //Here, we just instantiated but did not associated it with the session. So, it user is said to be in transient state.


2. Persistent: An object is said to be in persistent state under the following scenarios:
a) It is associated with a hibernate session in some way like get, load, save, saveOrUpdate etc and is in the scope of an active transaction within that session.
ib) It has not been manually detached or evicted from the session either by calling evict on session (or) by closing the session (or) by ending the transaction through commit() or rollback()
Ex:
i) User user = new User();
ii) Session session = getSessionFactory().openSession();
iii) Transaction tx = session.beginTransaction();
iv) user = (User) session.get(User.class, new Long(1));
v) user.setName("Varun");
vi) session.saveOrUpdate(user);
vii) user.setEmail("varun@gmail.com");
viii) user.setJob("Software Engineer");
ix) tx.commit();


In the above example, the user object will be in transient state in step (i) and will continue to be in that state till step (iii). However, at step (iv), the user object is associated with a hibernate session through session.get(...) method. It is at this point of time, that the object of user instance is said move from 'transient' to 'persistent' state and it will continue to remain in that state till the last step i.e. step (ix) where the transaction is committed. One important thing to remember for hibernate's persistent state is that once an object is in persistent state (i.e. associated with the session), all the changes made to that instance are commited in the database when we commit the transaction. There is no need to call save or saveOrUpdate whenever we change few properties of that instance if it is still associated within a transaction. So, even though we called saveOrUpdate at step (v), but when the tx is committed at step (ix), we would find the user's email and job also saved with the values we supplied at steps (vii) and (viii)

3. Detached: An object or instance is said to be in 'detached' when it is no longer associated with a hibernate session or no mechanism exist to tie the instance to the database. This happens in either of the following conditions:
a) transaction is commited
b) session is closed
c) we programatically detach the instance by calling session.evict and passing the instance to it.
Furthermore, if you have any instances in scope while the transaction failed, those instances will become detached instances, because the transaction and the Hibernate Session with which they were associated are junked, and no longer capable of persisting the state of your data.
Points a and b from above are self explainatory. For example on programatically detaching the instance from the session, consider the following scenario:
User u = new User();
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
user = (User) session.load(User.class, new Long(1));
user.setEmail("varun@gmail.com");
session.save(user);
user.setEmail("abc@gmail.com");
session.save(user);
session.evict(user);
user.setEmail("def@gmail.com");
tx.commit();

In the above example, the value of the user email would be set in database as "abc@gmail.com". Since after this, we have detached the user from the session, the session will no longer have a user associated with it. It has moved to detached instance. And once a user is detached, then, even if we change some of its values and commit the transaction under which it is runnning, those values wont be persisted to the database since the transaction just checks for the instances which are associated with the session under which it began.

If the above example is changed to:

user.setEmail("varun@gmail.com");
session.save(user);
user.setEmail("abc@gmail.com");
session.save(user);
user.setEmail("def@gmail.com");
tx.commit();
user.setEmail("ghi@gmail.com");
session.save(user);


Then, the value of the user's email property would be "def@gmail.com". This is because the instance gets detached automatically when the transaction which is opened under a session is committed.
One important rule Hibernate strictly enforces: only one instance of a class with a given unique primary key can be associated with the Session at a time. In the below shown example, if we try to re-associate the evicted user1 with the Hibernate Session, Hibernate will kick out to us a NonUniqueObjectException, indicating that it is already managing an instance that represents that particular database record.
User user1 = new User();
user1.setPassword("aaaaaa");
Long id = (Long)session.save(user1);
session.evict(user1);
User user2 = (User)session.get(User.class, id);
user1.setVerified(true);
session.saveOrUpdate(user1);
HibernateUtil.commitTransaction();