Friday, July 27, 2007

HIBERNATE - Relational Persistence for Idiomatic Java

Introduction to Hibernate

1.1. Preface


This chapter is an introductory tutorial for new users of Hibernate. We start
with a simple command line application using an in-memory database and develop
it in easy to understand steps.


This tutorial is intended for new users of Hibernate but requires Java and
SQL knowledge. It is based on a tutorial by Michael Gloegl, the third-party
libraries we name are for JDK 1.4 and 5.0. You might need others for JDK 1.3.


The source code for the tutorial is included in the distribution in the
doc/reference/tutorial/ directory.

1.2. Part 1 - The first Hibernate Application


First, we'll create a simple console-based Hibernate application. We use an
Java database (HSQL DB), so we do not have to install any database server.


Let's assume we need a small database application that can store events we want to
attend, and information about the hosts of these events.


The first thing we do, is set up our development directory and put all the
Java libraries we need into it. Download the Hibernate distribution from the
Hibernate website. Extract the package and place all required libraries
found in /lib into into the /lib directory
of your new development working directory. It should look like this:

.
+lib
antlr.jar
cglib.jar
asm.jar
asm-attrs.jars
commons-collections.jar
commons-logging.jar
hibernate3.jar
jta.jar
dom4j.jar
log4j.jar


This is the minimum set of required libraries (note that we also copied
hibernate3.jar, the main archive) for Hibernate at the time of writing.
The Hibernate release you are using might require more or less libraries. See the
README.txt file in the lib/ directory of the
Hibernate distribution for more information about required and optional third-party
libraries. (Actually, Log4j is not required but preferred by many developers.)


Next we create a class that represents the event we want to store in database.

1.2.1. The first class


Our first persistent class is a simple JavaBean class with some properties:

package events;

import java.util.Date;

public class Event {
private Long id;

private String title;
private Date date;

public Event() {}

public Long getId() {
return id;
}

private void setId(Long id) {
this.id = id;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}


You can see that this class uses standard JavaBean naming conventions for property
getter and setter methods, as well as private visibility for the fields. This is
a recommended design - but not required. Hibernate can also access fields directly,
the benefit of accessor methods is robustness for refactoring. The no-argument
constructor is required to instantiate an object of this class through reflection.


The id property holds a unique identifier value for a particular event.
All persistent entity classes (there are less important dependent classes as well) will need
such an identifier property if we want to use the full feature set of Hibernate. In fact,
most applications (esp. web applications) need to distinguish objects by identifier, so you
should consider this a feature rather than a limitation. However, we usually don't manipulate
the identity of an object, hence the setter method should be private. Only Hibernate will assign
identifiers when an object is saved. You can see that Hibernate can access public, private,
and protected accessor methods, as well as (public, private, protected) fields directly. The
choice is up to you and you can match it to fit your application design.


The no-argument constructor is a requirement for all persistent classes; Hibernate
has to create objects for you, using Java Reflection. The constructor can be
private, however, package visibility is required for runtime proxy generation and
efficient data retrieval without bytecode instrumentation.


Place this Java source file in a directory called src in the
development folder, and in its correct package. The directory should now look like this:

.
+lib
<Hibernate and third-party libraries>
+src
+events
Event.java


In the next step, we tell Hibernate about this persistent class.

1.2.2. The mapping file


Hibernate needs to know how to load and store objects of the persistent class.
This is where the Hibernate mapping file comes into play. The mapping file
tells Hibernate what table in the database it has to access, and what columns
in that table it should use.


The basic structure of a mapping file looks like this:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
[...]
</hibernate-mapping>


Note that the Hibernate DTD is very sophisticated. You can use it for
auto-completion of XML mapping elements and attributes in your editor or
IDE. You also should open up the DTD file in your text editor - it's the
easiest way to get an overview of all elements and attributes and to see
the defaults, as well as some comments. Note that Hibernate will not
load the DTD file from the web, but first look it up from the classpath
of the application. The DTD file is included in hibernate3.jar
as well as in the src/ directory of the Hibernate distribution.


We will omit the DTD declaration in future examples to shorten the code. It is
of course not optional.


Between the two hibernate-mapping tags, include a
class element. All persistent entity classes (again, there
might be dependent classes later on, which are not first-class entities) need
such a mapping, to a table in the SQL database:

<hibernate-mapping>

<class name="events.Event" table="EVENTS">

</class>

</hibernate-mapping>


So far we told Hibernate how to persist and load object of class Event
to the table EVENTS, each instance represented by a row in that table.
Now we continue with a mapping of the unique identifier property to the tables primary key.
In addition, as we don't want to care about handling this identifier, we configure Hibernate's
identifier generation strategy for a surrogate primary key column:

<hibernate-mapping>

<class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
</class>

</hibernate-mapping>


The id element is the declaration of the identifer property,
name="id" declares the name of the Java property -
Hibernate will use the getter and setter methods to access the property.
The column attribute tells Hibernate which column of the
EVENTS table we use for this primary key. The nested
generator element specifies the identifier generation strategy,
in this case we used native, which picks the best strategy depending
on the configured database (dialect). Hibernate supports database generated, globally
unique, as well as application assigned identifiers (or any strategy you have written
an extension for).


Finally we include declarations for the persistent properties of the class in
the mapping file. By default, no properties of the class are considered
persistent:


<hibernate-mapping>

<class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
</class>

</hibernate-mapping>


Just as with the id element, the name
attribute of the property element tells Hibernate which getter
and setter methods to use. So, in this case, Hibernate will look for
getDate()/setDate(), as well as getTitle()/setTitle().


Why does the date property mapping include the
column attribute, but the title
doesn't? Without the column attribute Hibernate
by default uses the property name as the column name. This works fine for
title. However, date is a reserved
keyword in most database, so we better map it to a different name.


The next interesting thing is that the title mapping also lacks
a type attribute. The types we declare and use in the mapping
files are not, as you might expect, Java data types. They are also not SQL
database types. These types are so called Hibernate mapping types,
converters which can translate from Java to SQL data types and vice versa. Again,
Hibernate will try to determine the correct conversion and mapping type itself if
the type attribute is not present in the mapping. In some cases this
automatic detection (using Reflection on the Java class) might not have the default you
expect or need. This is the case with the date property. Hibernate can't
know if the property (which is of java.util.Date) should map to a
SQL date, timestamp, or time column.
We preserve full date and time information by mapping the property with a
timestamp converter.


This mapping file should be saved as Event.hbm.xml, right in
the directory next to the Event Java class source file.
The naming of mapping files can be arbitrary, however the hbm.xml
suffix is a convention in the Hibernate developer community. The directory structure
should now look like this:

.
+lib
<Hibernate and third-party libraries>
+src
+events
Event.java
Event.hbm.xml


We continue with the main configuration of Hibernate.

1.2.3. Hibernate configuration


We now have a persistent class and its mapping file in place. It is time to configure
Hibernate. Before we do this, we will need a database. HSQL DB, a java-based SQL DBMS,
can be downloaded from the HSQL DB website. Actually, you only need the hsqldb.jar
from this download. Place this file in the lib/ directory of the
development folder.


Create a directory called data in the root of the development directory -
this is where HSQL DB will store its data files. Now start the database by running
java -classpath ../lib/hsqldb.jar org.hsqldb.Server in this data directory.
You can see it start up and bind to a TCP/IP socket, this is where our application
will connect later. If you want to start with a fresh database during this tutorial,
shutdown HSQL DB (press CTRL + C in the window), delete all files in the
data/ directory, and start HSQL DB again.


Hibernate is the layer in your application which connects to this database, so it needs
connection information. The connections are made through a JDBC connection pool, which we
also have to configure. The Hibernate distribution contains several open source JDBC connection
pooling tools, but will use the Hibernate built-in connection pool for this tutorial. Note that
you have to copy the required library into your classpath and use different
connection pooling settings if you want to use a production-quality third party
JDBC pooling software.


For Hibernate's configuration, we can use a simple hibernate.properties file, a
slightly more sophisticated hibernate.cfg.xml file, or even complete
programmatic setup. Most users prefer the XML configuration file:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<mapping resource="events/Event.hbm.xml"/>

</session-factory>

</hibernate-configuration>


Note that this XML configuration uses a different DTD. We configure
Hibernate's SessionFactory - a global factory responsible
for a particular database. If you have several databases, use several
<session-factory> configurations, usually in
several configuration files (for easier startup).


The first four property elements contain the necessary
configuration for the JDBC connection. The dialect property
element specifies the particular SQL variant Hibernate generates.
Hibernate's automatic session management for persistence contexts will
come in handy as you will soon see.
The hbm2ddl.auto option turns on automatic generation of
database schemas - directly into the database. This can of course also be turned
off (by removing the config option) or redirected to a file with the help of
the SchemaExport Ant task. Finally, we add the mapping file(s)
for persistent classes to the configuration.


Copy this file into the source directory, so it will end up in the
root of the classpath. Hibernate automatically looks for a file called
hibernate.cfg.xml in the root of the classpath, on startup.

1.2.4. Building with Ant


We'll now build the tutorial with Ant. You will need to have Ant installed - get
it from the Ant download page.
How to install Ant will not be covered here. Please refer to the
Ant manual. After you
have installed Ant, we can start to create the buildfile. It will be called
build.xml and placed directly in the development directory.


A basic build file looks like this:

<project name="hibernate-tutorial" default="compile">

<property name="sourcedir" value="${basedir}/src"/>
<property name="targetdir" value="${basedir}/bin"/>
<property name="librarydir" value="${basedir}/lib"/>

<path id="libraries">
<fileset dir="${librarydir}">
<include name="*.jar"/>
</fileset>
</path>

<target name="clean">
<delete dir="${targetdir}"/>
<mkdir dir="${targetdir}"/>
</target>

<target name="compile" depends="clean, copy-resources">
<javac srcdir="${sourcedir}"
destdir="${targetdir}"
classpathref="libraries"/>
</target>

<target name="copy-resources">
<copy todir="${targetdir}">
<fileset dir="${sourcedir}">
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>

</project>


This will tell Ant to add all files in the lib directory ending with .jar
to the classpath used for compilation. It will also copy all non-Java source files to the
target directory, e.g. configuration and Hibernate mapping files. If you now run Ant, you
should get this output:

C:\hibernateTutorial\>ant
Buildfile: build.xml

copy-resources:
[copy] Copying 2 files to C:\hibernateTutorial\bin

compile:
[javac] Compiling 1 source file to C:\hibernateTutorial\bin

BUILD SUCCESSFUL
Total time: 1 second

1.2.5. Startup and helpers


It's time to load and store some Event objects, but first
we have to complete the setup with some infrastructure code. We have to startup
Hibernate. This startup includes building a global SessionFactory
object and to store it somewhere for easy access in application code.
A SessionFactory can open up new Session's.
A Session represents a single-threaded unit of work, the
SessionFactory is a thread-safe global object, instantiated once.


We'll create a HibernateUtil helper class which takes care
of startup and makes accessing a SessionFactory convenient.
Let's have a look at the implementation:

package util;

import org.hibernate.*;
import org.hibernate.cfg.*;

public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}

}


This class does not only produce the global SessionFactory in
its static initializer (called once by the JVM when the class is loaded), but also
hides the fact that it uses a static singleton. It might as well lookup the
SessionFactory from JNDI in an application server.


If you give the SessionFactory a name in your configuration
file, Hibernate will in fact try to bind it to JNDI after it has been built.
To avoid this code completely you could also use JMX deployment and let the
JMX-capable container instantiate and bind a HibernateService
to JNDI. These advanced options are discussed in the Hibernate reference
documentation.


Place HibernateUtil.java in the development source directory, in
a package next to events:

.
+lib
<Hibernate and third-party libraries>
+src
+events
Event.java
Event.hbm.xml
+util
HibernateUtil.java
hibernate.cfg.xml
+data
build.xml


This should again compile without problems. We finally need to configure a logging
system - Hibernate uses commons logging and leaves you the choice between Log4j and
JDK 1.4 logging. Most developers prefer Log4j: copy log4j.properties
from the Hibernate distribution (it's in the etc/ directory) to
your src directory, next to hibernate.cfg.xml.
Have a look at the example configuration and change the settings if you like to have
more verbose output. By default, only Hibernate startup message are shown on stdout.


The tutorial infrastructure is complete - and we are ready to do some real work with
Hibernate.

1.2.6. Loading and storing objects


Finally, we can use Hibernate to load and store objects. We write an
EventManager class with a main() method:

package events;
import org.hibernate.Session;

import java.util.Date;

import util.HibernateUtil;

public class EventManager {

public static void main(String[] args) {
EventManager mgr = new EventManager();

if (args[0].equals("store")) {
mgr.createAndStoreEvent("My Event", new Date());
}

HibernateUtil.getSessionFactory().close();
}

private void createAndStoreEvent(String title, Date theDate) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.beginTransaction();

Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);

session.save(theEvent);

session.getTransaction().commit();
}

}


We create a new Event object, and hand it over to Hibernate.
Hibernate now takes care of the SQL and executes INSERTs
on the database. Let's have a look at the Session and
Transaction-handling code before we run this.


A Session is a single unit of work. For now we'll keep things
simple and assume a one-to-one granularity between a Hibernate Session
and a database transaction. To shield our code from the actual underlying transaction
system (in this case plain JDBC, but it could also run with JTA) we use the
Transaction API that is available on the Hibernate Session.


What does sessionFactory.getCurrentSession() do? First, you can call it
as many times and anywhere you like, once you get hold of your SessionFactory
(easy thanks to HibernateUtil). The getCurrentSession()
method always returns the "current" unit of work. Remember that we switched the configuration
option for this mechanism to "thread" in hibernate.cfg.xml? Hence,
the current unit of work is bound to the current Java thread that executes our application.
However, this is not the full picture, you also have to consider scope, when a unit of work
begins and when it ends.


A Session begins when it is first needed, when the first call to
getCurrentSession() is made. It is then bound by Hibernate to the current
thread. When the transaction ends, either through commit or rollback, Hibernate automatically
unbinds the Session from the thread and closes it for you. If you call
getCurrentSession() again, you get a new Session and can
start a new unit of work. This thread-bound programming model is the most
popular way of using Hibernate, as it allows flexible layering of your code (transaction
demarcation code can be separated from data access code, we'll do this later in this tutorial).


Related to the unit of work scope, should the Hibernate Session be used to
execute one or several database operations? The above example uses one Session
for one operation. This is pure coincidence, the example is just not complex enough to show any
other approach. The scope of a Hibernate Session is flexible but you should
never design your application to use a new Hibernate Session for
every database operation. So even if you see it a few more times in
the following (very trivial) examples, consider session-per-operation
an anti-pattern. A real (web) application is shown later in this tutorial.


Have a look at Chapter 11, Transactions And Concurrency for more information
about transaction handling and demarcation. We also skipped any error handling and
rollback in the previous example.


To run this first routine we have to add a callable target to the Ant build file:

<target name="run" depends="compile">
<java fork="true" classname="events.EventManager" classpathref="libraries">
<classpath path="${targetdir}"/>
<arg value="${action}"/>
</java>
</target>


The value of the action argument is set on the command line when
calling the target:

C:\hibernateTutorial\>ant run -Daction=store


You should see, after compilation, Hibernate starting up and, depending on your
configuration, lots of log output. At the end you will find the following line:

[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)


This is the INSERT executed by Hibernate, the question marks
represent JDBC bind parameters. To see the values bound as arguments, or to reduce
the verbosity of the log, check your log4j.properties.


Now we'd like to list stored events as well, so we add an option to the main method:

if (args[0].equals("store")) {
mgr.createAndStoreEvent("My Event", new Date());
}
else if (args[0].equals("list")) {
List events = mgr.listEvents();
for (int i = 0; i < events.size(); i++) {
Event theEvent = (Event) events.get(i);
System.out.println("Event: " + theEvent.getTitle() +
" Time: " + theEvent.getDate());
}
}


We also add a new listEvents() method:

private List listEvents() {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.beginTransaction();

List result = session.createQuery("from Event").list();

session.getTransaction().commit();

return result;
}


What we do here is use an HQL (Hibernate Query Language) query to load all existing
Event objects from the database. Hibernate will generate the
appropriate SQL, send it to the database and populate Event objects
with the data. You can create more complex queries with HQL, of course.


Now, to execute and test all of this, follow these steps:


  • Run ant run -Daction=store to store something into the database
    and, of course, to generate the database schema before through hbm2ddl.


  • Now disable hbm2ddl by commenting out the property in your hibernate.cfg.xml
    file. Usually you only leave it turned on in continous unit testing, but another
    run of hbm2ddl would drop everything you have stored - the
    create configuration setting actually translates into "drop all
    tables from the schema, then re-create all tables, when the SessionFactory is build".


If you now call Ant with -Daction=list, you should see the events
you have stored so far. You can of course also call the store action a few
times more.


Note: Most new Hibernate users fail at this point and we see questions about
Table not found error messages regularly. However, if you follow the
steps outlined above you will not have this problem, as hbm2ddl creates the database
schema on the first run, and subsequent application restarts will use this schema. If
you change the mapping and/or database schema, you have to re-enable hbm2ddl once again.

1.3. Part 2 - Mapping associations


We mapped a persistent entity class to a table. Let's build on this and add some class associations.
First we'll add people to our application, and store a list of events they participate in.

1.3.1. Mapping the Person class


The first cut of the Person class is simple:

package events;

public class Person {

private Long id;
private int age;
private String firstname;
private String lastname;

public Person() {}

// Accessor methods for all properties, private setter for 'id'

}


Create a new mapping file called Person.hbm.xml (don't forget the
DTD reference at the top):

<hibernate-mapping>

<class name="events.Person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="native"/>
</id>
<property name="age"/>
<property name="firstname"/>
<property name="lastname"/>
</class>

</hibernate-mapping>


Finally, add the new mapping to Hibernate's configuration:

<mapping resource="events/Event.hbm.xml"/>
<mapping resource="events/Person.hbm.xml"/>


We'll now create an association between these two entities. Obviously, persons
can participate in events, and events have participants. The design questions
we have to deal with are: directionality, multiplicity, and collection
behavior.

1.3.2. A unidirectional Set-based association


We'll add a collection of events to the Person class. That way we can
easily navigate to the events for a particular person, without executing an explicit query -
by calling aPerson.getEvents(). We use a Java collection, a Set,
because the collection will not contain duplicate elements and the ordering is not relevant for us.


We need a unidirectional, many-valued associations, implemented with a Set.
Let's write the code for this in the Java classes and then map it:

public class Person {

private Set events = new HashSet();

public Set getEvents() {
return events;
}

public void setEvents(Set events) {
this.events = events;
}
}


Before we map this association, think about the other side. Clearly, we could just keep this
unidirectional. Or, we could create another collection on the Event, if we
want to be able to navigate it bi-directional, i.e. anEvent.getParticipants().
This is not necessary, from a functional perspective. You could always execute an explicit query
to retrieve the participants for a particular event. This is a design choice left to you, but what
is clear from this discussion is the multiplicity of the association: "many" valued on both sides,
we call this a many-to-many association. Hence, we use Hibernate's
many-to-many mapping:

<class name="events.Person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="native"/>
</id>
<property name="age"/>
<property name="firstname"/>
<property name="lastname"/>

<set name="events" table="PERSON_EVENT">
<key column="PERSON_ID"/>
<many-to-many column="EVENT_ID" class="events.Event"/>
</set>

</class>


Hibernate supports all kinds of collection mappings, a <set> being most
common. For a many-to-many association (or n:m entity relationship), an
association table is needed. Each row in this table represents a link between a person and an event.
The table name is configured with the table attribute of the set
element. The identifier column name in the association, for the person's side, is defined with the
<key> element, the column name for the event's side with the
column attribute of the <many-to-many>. You also
have to tell Hibernate the class of the objects in your collection (correct: the class on the
other side of the collection of references).


The database schema for this mapping is therefore:


_____________ __________________
| | | | _____________
| EVENTS | | PERSON_EVENT | | |
|_____________| |__________________| | PERSON |
| | | | |_____________|
| *EVENT_ID | <--> | *EVENT_ID | | |
| EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID |
| TITLE | |__________________| | AGE |
|_____________| | FIRSTNAME |
| LASTNAME |
|_____________|

1.3.3. Working the association


Let's bring some people and events together in a new method in EventManager:

private void addPersonToEvent(Long personId, Long eventId) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId);
Event anEvent = (Event) session.load(Event.class, eventId);

aPerson.getEvents().add(anEvent);

session.getTransaction().commit();
}


After loading a Person and an Event, simply
modify the collection using the normal collection methods. As you can see, there is no explicit call
to update() or save(), Hibernate automatically
detects that the collection has been modified and needs to be updated. This is called automatic
dirty checking
, and you can also try it by modifying the name or the date property of
any of your objects. As long as they are in persistent state, that is, bound
to a particular Hibernate Session (i.e. they have been just loaded or saved in
a unit of work), Hibernate monitors any changes and executes SQL in a write-behind fashion. The
process of synchronizing the memory state with the database, usually only at the end of a unit of
work, is called flushing. In our code, the unit of work ends with a commit
(or rollback) of the database transaction - as defined by the thread configuration
option for the CurrentSessionContext class.


You might of course load person and event in different units of work. Or you modify an object
outside of a Session, when it is not in persistent state (if it was persistent
before, we call this state detached). You can even modify a collection when
it is detached:

private void addPersonToEvent(Long personId, Long eventId) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Person aPerson = (Person) session
.createQuery("select p from Person p left join fetch p.events where p.id = :pid")
.setParameter("pid", personId)
.uniqueResult(); // Eager fetch the collection so we can use it detached

Event anEvent = (Event) session.load(Event.class, eventId);

session.getTransaction().commit();

// End of first unit of work

aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached

// Begin second unit of work

Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.beginTransaction();

session2.update(aPerson); // Reattachment of aPerson

session2.getTransaction().commit();
}


The call to update makes a detached object persistent again, you could
say it binds it to a new unit of work, so any modifications you made to it while detached
can be saved to the database. This includes any modifications (additions/deletions) you
made to a collection of that entity object.


Well, this is not much use in our current situation, but it's an important concept you can
design into your own application. For now, complete this exercise by adding a new action
to the EventManager's main method and call it from the command line. If
you need the identifiers of a person and an event - the save() method
returns it (you might have to modify some of the previous methods to return that identifier):

else if (args[0].equals("addpersontoevent")) {
Long eventId = mgr.createAndStoreEvent("My Event", new Date());
Long personId = mgr.createAndStorePerson("Foo", "Bar");
mgr.addPersonToEvent(personId, eventId);
System.out.println("Added person " + personId + " to event " + eventId);


This was an example of an association between two equally important classes, two entities.
As mentioned earlier, there are other classes and types in a typical model, usually "less
important". Some you have already seen, like an int or a String.
We call these classes value types, and their instances depend
on a particular entity. Instances of these types don't have their own identity, nor are they
shared between entities (two persons don't reference the same firstname
object, even if they have the same first name). Of course, value types can not only be found in
the JDK (in fact, in a Hibernate application all JDK classes are considered value types), but
you can also write dependent classes yourself, Address or MonetaryAmount,
for example.


You can also design a collection of value types. This is conceptually very different from a
collection of references to other entities, but looks almost the same in Java.

1.3.4. Collection of values


We add a collection of value typed objects to the Person entity. We want to
store email addresses, so the type we use is String, and the collection is
again a Set:

private Set emailAddresses = new HashSet();

public Set getEmailAddresses() {
return emailAddresses;
}

public void setEmailAddresses(Set emailAddresses) {
this.emailAddresses = emailAddresses;
}


The mapping of this Set:

<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
<key column="PERSON_ID"/>
<element type="string" column="EMAIL_ADDR"/>
</set>


The difference compared with the earlier mapping is the element part, which tells Hibernate that the collection
does not contain references to another entity, but a collection of elements of type
String (the lowercase name tells you it's a Hibernate mapping type/converter).
Once again, the table attribute of the set element determines
the table name for the collection. The key element defines the foreign-key column
name in the collection table. The column attribute in the element
element defines the column name where the String values will actually be stored.


Have a look at the updated schema:


_____________ __________________
| | | | _____________
| EVENTS | | PERSON_EVENT | | | ___________________
|_____________| |__________________| | PERSON | | |
| | | | |_____________| | PERSON_EMAIL_ADDR |
| *EVENT_ID | <--> | *EVENT_ID | | | |___________________|
| EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | <--> | *PERSON_ID |
| TITLE | |__________________| | AGE | | *EMAIL_ADDR |
|_____________| | FIRSTNAME | |___________________|
| LASTNAME |
|_____________|


You can see that the primary key of the collection table is in fact a composite key,
using both columns. This also implies that there can't be duplicate email addresses
per person, which is exactly the semantics we need for a set in Java.


You can now try and add elements to this collection, just like we did before by
linking persons and events. It's the same code in Java:

private void addEmailToPerson(Long personId, String emailAddress) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId);

// The getEmailAddresses() might trigger a lazy load of the collection
aPerson.getEmailAddresses().add(emailAddress);

session.getTransaction().commit();
}


This time we didnt' use a fetch query to initialize the collection.
Hence, the call to its getter method will trigger an additional select to initialize
it, so we can add an element to it. Monitor the SQL log and try to optimize this with
an eager fetch.

1.3.5. Bi-directional associations


Next we are going to map a bi-directional association - making the association between
person and event work from both sides in Java. Of course, the database schema doesn't
change, we still have many-to-many multiplicity. A relational database is more flexible
than a network programming language, so it doesn't need anything like a navigation
direction - data can be viewed and retrieved in any possible way.


First, add a collection of participants to the Event Event class:

private Set participants = new HashSet();

public Set getParticipants() {
return participants;
}

public void setParticipants(Set participants) {
this.participants = participants;
}


Now map this side of the association too, in Event.hbm.xml.

<set name="participants" table="PERSON_EVENT" inverse="true">
<key column="EVENT_ID"/>
<many-to-many column="PERSON_ID" class="events.Person"/>
</set>


As you see, these are normal set mappings in both mapping documents.
Notice that the column names in key and many-to-many are
swapped in both mapping documents. The most important addition here is the
inverse="true" attribute in the set element of the
Event's collection mapping.


What this means is that Hibernate should take the other side - the Person class -
when it needs to find out information about the link between the two. This will be a lot easier to
understand once you see how the bi-directional link between our two entities is created .

1.3.6. Working bi-directional links


First, keep in mind that Hibernate does not affect normal Java semantics. How did we create a
link between a Person and an Event in the unidirectional
example? We added an instance of Event to the collection of event references,
of an instance of Person. So, obviously, if we want to make this link working
bi-directional, we have to do the same on the other side - adding a Person
reference to the collection in an Event. This "setting the link on both sides"
is absolutely necessary and you should never forget doing it.


Many developers program defensive and create a link management methods to
correctly set both sides, e.g. in Person:

protected Set getEvents() {
return events;
}

protected void setEvents(Set events) {
this.events = events;
}

public void addToEvent(Event event) {
this.getEvents().add(event);
event.getParticipants().add(this);
}

public void removeFromEvent(Event event) {
this.getEvents().remove(event);
event.getParticipants().remove(this);
}


Notice that the get and set methods for the collection are now protected - this allows classes in the
same package and subclasses to still access the methods, but prevents everybody else from messing
with the collections directly (well, almost). You should probably do the same with the collection
on the other side.


What about the inverse mapping attribute? For you, and for Java, a bi-directional
link is simply a matter of setting the references on both sides correctly. Hibernate however doesn't
have enough information to correctly arrange SQL INSERT and UPDATE
statements (to avoid constraint violations), and needs some help to handle bi-directional associations
properly. Making one side of the association inverse tells Hibernate to basically
ignore it, to consider it a mirror of the other side. That's all that is necessary
for Hibernate to work out all of the issues when transformation a directional navigation model to
a SQL database schema. The rules you have to remember are straightforward: All bi-directional associations
need one side as inverse. In a one-to-many association it has to be the many-side,
in many-to-many association you can pick either side, there is no difference.


Let's turn this into a small web application.

1.4. Part 3 - The EventManager web application


A Hibernate web application uses Session and Transaction
almost like a standalone application. However, some common patterns are useful. We now write
an EventManagerServlet. This servlet can list all events stored in the
database, and it provides an HTML form to enter new events.

1.4.1. Writing the basic servlet


Create a new class in your source directory, in the events
package:

package events;

// Imports

public class EventManagerServlet extends HttpServlet {

// Servlet code
}


The servlet handles HTTP GET requests only, hence, the method
we implement is doGet():

protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");

try {
// Begin unit of work
HibernateUtil.getSessionFactory()
.getCurrentSession().beginTransaction();

// Process request and render page...

// End unit of work
HibernateUtil.getSessionFactory()
.getCurrentSession().getTransaction().commit();

} catch (Exception ex) {
HibernateUtil.getSessionFactory()
.getCurrentSession().getTransaction().rollback();
throw new ServletException(ex);
}

}


The pattern we are applying here is called session-per-request.
When a request hits the servlet, a new Hibernate Session is
opened through the first call to getCurrentSession() on the
SessionFactory. Then a database transaction is started—all
data access as to occur inside a transaction, no matter if data is read or written
(we don't use the auto-commit mode in applications).


Do not use a new Hibernate Session for
every database operation. Use one Hibernate Session that is
scoped to the whole request. Use getCurrentSession(), so that
it is automatically bound to the current Java thread.


Next, the possible actions of the request are processed and the response HTML
is rendered. We'll get to that part soon.


Finally, the unit of work ends when processing and rendering is complete. If any
problem occured during processing or rendering, an exception will be thrown
and the database transaction rolled back. This completes the
session-per-request pattern. Instead of the transaction
demarcation code in every servlet you could also write a servlet filter.
See the Hibernate website and Wiki for more information about this pattern,
called Open Session in View—you'll need it as soon
as you consider rendering your view in JSP, not in a servlet.

1.4.2. Processing and rendering


Let's implement the processing of the request and rendering of the page.

// Write HTML header
PrintWriter out = response.getWriter();
out.println("<html><head><title>Event Manager</title></head><body>");

// Handle actions
if ( "store".equals(request.getParameter("action")) ) {

String eventTitle = request.getParameter("eventTitle");
String eventDate = request.getParameter("eventDate");

if ( "".equals(eventTitle) || "".equals(eventDate) ) {
out.println("<b><i>Please enter event title and date.</i></b>");
} else {
createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
out.println("<b><i>Added event.</i></b>");
}
}

// Print page
printEventForm(out);
listEvents(out, dateFormatter);

// Write HTML footer
out.println("</body></html>");
out.flush();
out.close();


Granted, this coding style with a mix of Java and HTML would not scale
in a more complex application—keep in mind that we are only illustrating
basic Hibernate concepts in this tutorial. The code prints an HTML
header and a footer. Inside this page, an HTML form for event entry and
a list of all events in the database are printed. The first method is
trivial and only outputs HTML:

private void printEventForm(PrintWriter out) {
out.println("<h2>Add new event:</h2>");
out.println("<form>");
out.println("Title: <input name='eventTitle' length='50'/><br/>");
out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
out.println("<input type='submit' name='action' value='store'/>");
out.println("</form>");
}


The listEvents() method uses the Hibernate
Session bound to the current thread to execute
a query:

private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {

List result = HibernateUtil.getSessionFactory()
.getCurrentSession().createCriteria(Event.class).list();
if (result.size() > 0) {
out.println("<h2>Events in database:</h2>");
out.println("<table border='1'>");
out.println("<tr>");
out.println("<th>Event title</th>");
out.println("<th>Event date</th>");
out.println("</tr>");
for (Iterator it = result.iterator(); it.hasNext();) {
Event event = (Event) it.next();
out.println("<tr>");
out.println("<td>" + event.getTitle() + "</td>");
out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
out.println("</tr>");
}
out.println("</table>");
}
}


Finally, the store action is dispatched to the
createAndStoreEvent() method, which also uses
the Session of the current thread:

protected void createAndStoreEvent(String title, Date theDate) {
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);

HibernateUtil.getSessionFactory()
.getCurrentSession().save(theEvent);
}


That's it, the servlet is complete. A request to the servlet will be processed
in a single Session and Transaction. As
earlier in the standalone application, Hibernate can automatically bind these
ojects to the current thread of execution. This gives you the freedom to layer
your code and access the SessionFactory in any way you like.
Usually you'd use a more sophisticated design and move the data access code
into data access objects (the DAO pattern). See the Hibernate Wiki for more
examples.

1.4.3. Deploying and testing


To deploy this application you have to create a web archive, a WAR. Add the
following Ant target to your build.xml:

<target name="war" depends="compile">
<war destfile="hibernate-tutorial.war" webxml="web.xml">
<lib dir="${librarydir}">
<exclude name="jsdk*.jar"/>
</lib>

<classes dir="${targetdir}"/>
</war>
</target>


This target creates a file called hibernate-tutorial.war
in your project directory. It packages all libraries and the web.xml
descriptor, which is expected in the base directory of your project:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<servlet>
<servlet-name>Event Manager</servlet-name>
<servlet-class>events.EventManagerServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Event Manager</servlet-name>
<url-pattern>/eventmanager</url-pattern>
</servlet-mapping>
</web-app>


Before you compile and deploy the web application, note that an additional library
is required: jsdk.jar. This is the Java servlet development kit,
if you don't have this library already, get it from the Sun website and copy it to
your library directory. However, it will be only used for compliation and excluded
from the WAR package.


To build and deploy call ant war in your project directory
and copy the hibernate-tutorial.war file into your Tomcat
webapp directory. If you don't have Tomcat installed, download
it and follow the installation instructions. You don't have to change any Tomcat
configuration to deploy this application though.


Once deployed and Tomcat is running, access the application at
http://localhost:8080/hibernate-tutorial/eventmanager. Make
sure you watch the Tomcat log to see Hibernate initialize when the first
request hits your servlet (the static initializer in HibernateUtil
is called) and to get the detailed output if any exceptions occurs.

1.5. Summary


This tutorial covered the basics of writing a simple standalone Hibernate application
and a small web application.


If you already feel confident with Hibernate, continue browsing through the reference
documentation table of contents for topics you find interesting - most asked are
transactional processing (Chapter 11, Transactions And Concurrency), fetch
performance (Chapter 19, Improving performance), or the usage of the API (Chapter 10, Working with objects)
and the query features (Section 10.4, “Querying”).


Don't forget to check the Hibernate website for more (specialized) tutorials.

Tuesday, July 24, 2007

Saturday, July 21, 2007

Starting point for Sun's Java technology certification.

JCertify - http://www.enterprisedeveloper.com/jcertify/ Java Certification exam simulator with tutorials and integrated training content. [Commercial]

Whizlabs - http://www.whizlabs.com/jwhiz.html Provides exam simulators and online training for Sun Java Certification exams: SCJP, SCWCD, SCBCD and SCEA [Commercial].

Levteck.com - http://www.levteck.com/ Includes list of certification books, study aides, links for mock exams and salary surveys.

Java certification success, Part 1: SCJP - http://www-106.ibm.com/developerworks/edu/j-dw-java-scjp-i.html A tutorial designed to prepare programmers for SCJP 1.4 exam, providing a detailed overview of the exam's main objectives.

Marcus Green's Java Certification - http://www.jchq.net/ SCJP exam resource with tutorials, mock exam and community features.

Wah! Java - http://www.geocities.com/wahjava/ Contains topic-wise mock tests, tips from those who passed, recommended books and links to other testing/java resources.

JavaPrepare - http://www.javaprepare.com/ Tutorials, mock exams and other preparation material for SCJP and SCWCD.

Java Certification Study Group - http://groups.yahoo.com/group/javacertstudy/ Study community with forums, chat and resources.

SCWCD Certification Resources - http://resources.corejsp.com/scwcd.html Contains links to study guides, exam simulators and other resources for SCWCD examination.

SCWCD Exam Review - http://courses.coreservlets.com/Course-Materials/pdf/msajsp/15-Web-Component-Certification.pdf Review notes for the Sun Certified Web Component Developer exam.

Certified Java Programmer Mock Exam (310-025, 310-035) - http://www.danchisholm.net/ Contains mock exams and tutorials for SCJP exam.

Absolute Java - http://www.absolutejava.com/ Collection of tidbits to prepare for SCJP exam.

Jiris - http://www.jiris.com/ Contains mock exams, links, forum, code examples and other SCJP/SCWCD resources.

JavaCertificate - http://www.javacertificate.com/ A free online training centre that will help prepare for the Sun Certified Programmer for Java(tm) 2 Platform exam (SCJP 1.4).

Anilbachi Java Certification Resources - http://www.anilbachi.8m.com/ SCJP tutorial, mock exams, objectives, mock exam links and discussion forum.

Java certification success, Part 1: SCJP - http://www.whizlabs.com/tutorial/scjp/index.html A SCJP Tutorial to test the knowledge of Java fundamentals and requires in-depth knowledge of the syntax and semantics.

Certification: The Java Mock Test - http://www.aniyog.com/java/certification.htm Offers free applet based mock exam for SCJP2.

Java Certification (SCJP) - http://www.akgupta.com/Java/certification.htm Contains SCJP mock exam, tidbits, exam notes and links to other resources.

Java Certification Study Notes - http://www.geocities.com/velmurugan_p/ SCJP & SCWCD study notes, resources and tips.

Java Guru: Java Certification Forum Home Page - http://www.jguru.com/forums/JavaCertification Forum to pose and view the who, what, where, why and how questions on Java certification.

Sun Java 4 U - http://www.geocities.com/sunjava4u/ Links and resources useful for SCJP aspirants includes exam simulators, mock exams, study guides.

Java.CertifiedProgrammer.com - http://java.certifiedprogrammer.com/ Contains study aides, news and mock exams.

The Java Skinny - http://www.acmerocket.com/skinny/ Contains sample questions, SCJP exam objectives with code examples and other resources.

Sun Certified Java Programmer sample test paper! - http://www.geocities.com/skmajji/Main.html A practice test for SCJP comprising of 30 questions with answers.

Enthuware - http://www.enthuware.com/ Test simulators for Sun certification exams. [Commercial]

Java Quick Reference - http://www.janeg.ca/index.html Comprises of concise study notes for SCJP exam and other links.

JavaBeat - http://www.javabeat.net/ Java certification resources.

About.com - Java Certifications - http://certification.about.com/cs/freequestions/index.htm Explore information and links for Java and Sun certifications. Includes articles, practice tests, software reviews, book reviews, and forums.

CertGear Systems - Java - http://www.certgear.com/products/vendor/java.htm Java certification resources, including practice tests (SCJP SCWCD SCBCD ), free quizzes, and study aids.

Exams guide - http://www.examsguide.com Java certification resources.

SCJP Tiger Study Guide - http://java.boot.by/scjp-tiger/ Study Guide for exam CX-310-055 (Sun Certified Programmer for the Java 2 Platform, Standard Edition 5.0).

VoodooExam - http://www.geocities.com/gnashes30/java/mock.htm SCJP mock exam engine with facility to add new question/answers. Needs jdk1.2.1 or higher [download].

Inesystem's Java Certification - http://www.inesystems.com Provides exam simulators and online training for Sun Java Certification exams.

Prasks Resources - http://prasks.webahn.com/architect/scja.html Sun Certified Java Architect resources and experiences.

Java Certification Resources - http://www.javadeveloper.co.in Includes tutorials, mock exams, study notes and exam simulators for SCJP and SCWCD exams.

Tipsmart.com - http://www.tipsmart.com/ Contains interactive quizzes, pitfalls, FAQs by programmers, list of integrated development tools.

Mock Exam - http://www.valoxo.ch/jr/mocks/mock01a.html Javascript based SCJP Mock Exam.

Java Certification Exam Questions - http://home-1.tiscali.nl/~bmc88/java/javacert/ SCJP mock tests, exam notes and other resources.

SCJP2 MockExam - http://www.geocities.com/rraje_2000/MockExam.html 60 questions mock test [Download].

Radhika Palwai's Web Development Resources - http://www.geocities.com/r_palwai/scjp.htm Contains links to SCJP resources.

Free Java Certification Training - http://www.michael-thomas.com/ Contains mock tests, source code, resources for Sun Certifications, resources on Web-development and UML.

Everything you want to know about SCJP - http://dreamjava.blogspot.com A Blog to help SCJP aspirants with links and daily question.

Learn + play Java - http://www.jai.ch/ Interactive, downloadable course for SCJP with built-in Java source interpreter. Work and experiment with class libraries using the tests and JLS Summary.

Sun Java Certification Resource Center - http://www.certlobby.com/sun-java-certification.html Contains concise details on various Sun certification exams and links to resources.

Dallas SCJD Study Group - http://www.geocities.com/developergrp/ Developer exam resources including FAQs, guidelines, presentations, free books and discussion forum.

Sun Java Certification SCJP, Java Tutorials and ebooks - http://www.javaprogrammingworld.com The contents of this page are intended for SCJP 1.2 exam (310-025) and resources specific to SCJP 1.4 exam (310-035).

Java Mock Exams, Practice Questions, Tutorails, Articles - http://www.javacertificate.net Contains practice questions and mock exams for various Sun and IBM certifications.

JavaQuestion Bank - http://javaquestion.tripod.com/ Includes general and certification questions and other java resources.

SUN Certification Study Materials - http://www.xyzws.com Provides study guides & mock exams (needs registration) for SCJP 5.0 (CX-310-055) and SCDJWS (CX-311-220) tests.

JavaQueries - http://www.javaqueries.com/ SCEA Mock Exam, Solutions for JavaQueries.

SoftLearn Systems - http://www.softlearn-systems.com/ Provides simulators for SCBCD and SCJD exams. [Commercial]

Universal teacher - http://www.geocities.com/rameshchhabra2002/Java/certification.htm SCJP exam simulator containing 600 questions [Download].

SCJP Simulator - http://www.examsguide.com/scjp/freesimulator.html Offers an exam simulator with provision to add more questions.

Quick Java - http://home.worldonline.dk/qjava/ Contains a Java lookup reference and test-simulator based on a book.

Java Certification Guide - http://rohitgeorge.netfirms.com/scjp.html Contains tutorial on SCJP. Also contains a downloadable PDF version.

SCJP 1.4 certification primer - http://www-106.ibm.com/developerworks/java/library/j-scjp/ Outlines the new programmer certification exam with suggestions for preparation, sample questions and links to resources.

Abhilash's java quiz site - http://www.angelfire.com/or/abhilash/ Comprises of set of nine practice quizzes for SCJP exam with answers.

Oracle Certified Java Developer - http://otn.oracle.com/training/certification/jdeveloper_ocpds.html Starting point for Oracle Certified Java Developer OCP program.

Home Page of Koray Guclu - http://www.korayguclu.de/ Contains excerpts from an ongoing SCJP book, exam information, notes and links to Mock exams/resources. Also publications, resume, photography, banner art.

go4java- Java Certification Site - http://www.mycgiserver.com/~go4java/ Includes SCJP experiences, FAQs, mock exams, tutorials and links to other resources.

Java Programmer Certification - http://www.geocities.com/technofundo/tech/scjp/scjp.html SCJP Revision notes, links and other resources.

Java Certification Webring - http://www.webring.com/hub?ring=javacert Web-ring of sites involved with certification.

Sun Certified Programmer Examination Revision Book - http://home.worldonline.nl/~bmc88/java/javacert/revision.html SCJP Tutorial based on Sun's Objectives.

j-think
Contains SCJP notes.

Concentrated Guide to SCJP2 - A zip archive consisting of SCJP Notes (PDF) and Questions and Answers (Word document) compiled by Ashraf Fouad Ayoub and Ashraf Samir Helmy.

Passing the Java Programmer Certification Exam - Article discusses how to prepare for the Java Programmer certification. Includes suggestions on how to study for the exam.

Java certification forum - A discussion forum dedicated to Java certification exams.