O'Reilly logo

Harnessing Hibernate by James Elliott, Ryan Fowler, Timothy M. O'Brien

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Setting Up a Project Hierarchy

Although we’re going to start small in this walk-through, once we begin designing data structures and building Java classes and database tables that represent them, along with all the configuration and control files to glue them together and make useful things happen, we’re going to end up with a lot of files. So, we want to make certain we are very organized from the beginning. Between the tools we’ve downloaded and their supporting libraries, there are already a significant number of files to organize. Luckily for us, the Maven Ant Tasks download and manage all of our external dependencies.

Why do I care?

If you end up building something cool by extending the examples in this book, and want to turn it into a real application, you’ll be in good shape from the beginning. More to the point, if you set things up the way we describe here, the commands and instructions we give you throughout the examples will make sense and actually work; many examples build on one another throughout the book, so it’s important to get on the right track from the beginning.

If you want to skip ahead to a later example, or just avoid typing some of the longer sample code and configuration files, you can download “finished” versions of the chapter examples from the book’s web site. These downloads will all be organized as described here. We strongly recommend that you download the examples and use them as a reference while you read this book.

How do I do that?

Here’s how to set up an empty project hierarchy if you’re not downloading the “finished” examples:

  1. Pick a location on your hard drive where you want to work through these examples, and create a new folder, which we’ll refer to from now on as your project directory.

  2. Move into that directory, and create subdirectories called src and data. The hierarchy of Java source and related resources will be in the src directory. Our build process will compile it into a classes directory it creates, as well as copy any runtime resources there. The data directory is where we’ll put the HSQLDB database.

  3. The example classes we’re going to create are all going to live in the com.oreilly.hh (harnessing Hibernate) package, and we’ll have Hibernate generate our data beans in the com.oreilly.hh.data package to keep them separate from classes we write by hand, so create these directories under the src directory. On Linux and Mac OS X, you can use:

                        mkdir -p src/com/oreilly/hh/data
                  

    from within your project directory to accomplish this in one step.

At this point, your project directory should be structured as shown in Figure 1-5.

Note

This is so much simpler than it was in the first book that it’s almost not worth showing!

Initial project directory contents

Figure 1-5. Initial project directory contents

A quick test

Before we get into actually rousing Hibernate to do some useful work, it’s worth checking that the other supporting pieces are in place and ready to use. Let’s start the Ant configuration file we’ll be using throughout this project, tell Ant where we’ve put the files we’re using, and have it fire up the HSQLDB graphical database interface. This will prove that the Maven Ant Tasks are able to find and download the libraries on which the examples will rely, and the ability to access the interface will be useful later when we want to look at the actual data that Hibernate has been creating for us. For the moment this is primarily a sanity check that nothing is amiss and we’re ready to move forward.

Fire up your favorite text editor, and create a file named build.xml at the top level inside your project directory. Type the content of Example 1-1 into the file.

Example 1-1. Ant build file

<?xml version="1.0"?> 1
<project name="Harnessing Hibernate 3 (Developer's Notebook Second Edition)"
         default="db" basedir="."
         xmlns:artifact="antlib:org.apache.maven.artifact.ant"> 2

  <!-- Set up properties containing important project directories --> 3
  <property name="source.root" value="src"/>
  <property name="class.root" value="classes"/>
  <property name="data.dir" value="data"/>

  <artifact:dependencies pathId="dependency.classpath"> 4
    <dependency groupId="hsqldb" artifactId="hsqldb" version="1.8.0.7"/>
    <dependency groupId="org.hibernate" artifactId="hibernate"
                version="3.2.5.ga">
      <exclusion groupId="javax.transaction" artifactId="jta"/>
    </dependency>
    <dependency groupId="org.hibernate" artifactId="hibernate-tools"
                version="3.2.0.beta9a"/>
    <dependency groupId="org.apache.geronimo.specs"
                artifactId="geronimo-jta_1.1_spec" version="1.1"/>
    <dependency groupId="log4j" artifactId="log4j" version="1.2.14"/>
  </artifact:dependencies>

  <!-- Set up the class path for compilation and execution -->
  <path id="project.class.path"> 5
      <!-- Include our own classes, of course -->
      <pathelement location="${class.root}" /> 6
      <!-- Add the dependencies classpath -->
      <path refid="dependency.classpath"/> 7
  </path>

  <target name="db" description="Runs HSQLDB database management UI
against the database file--use when application is not running"> 8
      <java classname="org.hsqldb.util.DatabaseManager"
            fork="yes">
         <classpath refid="project.class.path"/>
         <arg value="-driver"/>
         <arg value="org.hsqldb.jdbcDriver"/>
         <arg value="-url"/>
         <arg value="jdbc:hsqldb:${data.dir}/music"/>
         <arg value="-user"/>
         <arg value="sa"/>
      </java>
  </target>
</project>

Tip

Take care with punctuation if you’re typing this, and pay special attention to self-closing XML tags (those which end in “/>” rather than just “>”). If you get it wrong, you’ll be rewarded with parse errors when you run Ant. Again, you can download all these files if you don’t need the typing practice. If you’re viewing this as a PDF on-screen, you can also cut and paste the code, but you will need to edit out the numbered callout bullets.

If you haven’t seen an Ant build file before, here’s a whirlwind introduction to help orient you. The documentation at http://ant.apache.org/manual/index.html is quite good if you want a bit more detail:

1

The first line is simply a declaration that the type of the file is XML. If you’ve worked with XML in other contexts, you’re used to seeing this. If not, you’ll see it again. (Ant doesn’t currently require this, but most XML parsers do, so it’s a good habit to develop.)

2

Ant’s build files always contain a single project definition. The default attribute tells Ant which target (defined later) to build if you don’t specify any on the command line. And the basedir attribute determines the directory relative to which all path calculations are done. We could have left this out since the default is to treat paths as being relative to the directory in which the build.xml is located, but it’s a good habit to be explicit about fundamental settings like this. An important thing to note in this project element is the xmlns:artifact namespace definition for the Maven Ant Tasks. This namespace definition makes the Maven Ant Tasks available within this build file using the artifact: prefix (as you’ll see used later).

3

The next bit defines three properties that we can use by name throughout the rest of the build file. Essentially, we’re defining symbolic names for the important directories used for different aspects of the project. This isn’t necessary (especially when the directories are named so simply), but it’s another good practice. For one thing, it means that if you need to change where one of these directories is located, you need to fix only one place in the build file, rather than conducting a tedious search and replace.

4

The artifact:dependencies element is from the Maven Ant Tasks, which you (and Ant) can tell by the artifact: prefix. In this element we are defining a set of dependencies which the project needs for compilation and execution. These dependencies correspond to JAR files (or artifacts) in the central Maven 2 Repository at http://repo1.maven.org/maven2. Each artifact is uniquely identified by a groupId, artifactId, and a version number. In this project, we’re depending on Hibernate, HSQLDB, Log4J, and the JTA API. When the Maven Ant Tasks encounter these dependency declarations, each artifact is downloaded from the central Maven 2 repository on an as-needed basis to your local Maven 2 repository (in ~/.m2/repository). Don’t worry if this section doesn’t make much sense just yet; we’re going to delve deeper into the details in a few pages.

This section is where you’d make changes to use a more recent version of one of these packages if you wanted to (since newer versions will likely become available after this book is printed), by changing the version values. But you can be confident the examples as printed in the book will continue to work, since the Maven repository guarantees the versions we tested against will continue to be available whenever you’re exploring the examples. This in itself was a big reason we decided to adopt the Maven Ant Tasks for this book.

5

The class-path section serves a clear purpose. This feature alone is why I almost never start Java projects anymore without setting up at least a simple Ant build for them. When you’re using a lot of third-party libraries, which you’re going to be doing for any serious project, there’s a whole lot that needs to go into your class path, and you have to be sure to set it equivalently at compile time and runtime. Ant makes this very easy. We define a path, which is kind of like a property, but it knows how to parse and collect files and directories. Our path contains the classes directory in which we’re going to be compiling our Java source (this directory doesn’t exist yet; we’ll add a step to the build process to create it in the next chapter), and it also contains all JAR files corresponding to the dependencies listed in the artifact:dependencies element. This is exactly what we need for compiling and running.

Tip

Ant’s understanding and manipulation of Java paths and class hierarchies is a big plus. It’s worth learning in some depth.

6

The syntax on this line looks like punctuation soup but can be broken down into pieces that make sense. Ant lets you use substitution to insert variable values into your rules. Where you see something like "${class.root}", this means “look up the value of the property named class.root and stick it here.” So, given the definition of the class.root property earlier, it’s as if we had typed: <pathelement location="classes"/>. So, why do this? It lets you share a value throughout the file, so if you ever need to change it, there’s only one place to worry about. In large, complex projects, this kind of organization and management is crucial.

7

The artifact:dependencies element we saw earlier assembled all of the declared dependencies into a single path named dependency.classpath using its pathId attribute. Here, we are appending the contents of dependency.classpath to the project.class.path so all our Maven-fetched dependencies are available at compilation and runtime.

8

Finally, with all this preamble out of the way, we can define our first target. A target is just a series of tasks that need to be executed in order to accomplish a project goal. Typical targets do things like compile code, run tests, package things up for distribution, and the like. Tasks are chosen from a rich set of capabilities built into Ant, and third-party tools like Hibernate can extend Ant to provide their own useful tasks, as we’ll see in the next chapter. Our first target, db, is going to run HSQLDB’s graphical interface so we can look at our example database. We can accomplish that using Ant’s built-in java task, which can run a Java virtual machine for us, with whatever starting class, arguments, and properties we’d like.

In this case, the class we want to invoke is org.hsqldb.util.DatabaseManager, found in the HSQLDB JAR that the Maven Ant Tasks will manage for us. Setting the fork attribute to yes tells Ant to use a separate virtual machine, which isn’t the default since it takes a little longer and isn’t usually necessary. In this case, it’s important since we want the database manager GUI to stay around until we dismiss it, and this doesn’t happen when it runs in Ant’s own VM.

Tip

If your database GUI pops up and vanishes, double-check the fork attribute of your java task.

You can see how we’re telling the java task about the class path we’ve set up; this will be a common feature of our targets. Then we supply a bunch of arguments to the database manager, telling it to use the normal HSQLDB JDBC driver, where to find the database, and what username to use. We’ve specified a database called music in the data directory. That directory is currently empty, so HSQLDB will create the database the first time we use it. The user sa is the default “system administrator” user for new databases, and it’s configured not to need a password initially. Obviously, if you plan to make this database available over the network (which HSQLDB is capable of doing), you’ll want to set a password. We aren’t doing any such fancy things, so we can leave that out for now.

OK, let’s try it! Save the file, and from a shell (command) prompt running in your top-level project directory (where you put build.xml), type the command:

            ant db
          

(Or, since we’ve made db the default target, you can just type ant.) Once Ant starts running, if all goes well, you’ll see output like this:

Buildfile: build.xml
Downloading: hsqldb/hsqldb/1.8.0.7/hsqldb-1.8.0.7.pom
Transferring 0K
Downloading: org/hibernate/hibernate/3.2.5.ga/hibernate-3.2.5.ga.pom
Transferring 3K
Downloading: net/sf/ehcache/ehcache/1.2.3/ehcache-1.2.3.pom
Transferring 19K
Downloading: commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom
Transferring 5K
Downloading: commons-collections/commons-collections/2.1/commons-collections-2.1
.pom
Transferring 3K
Downloading: asm/asm-attrs/1.5.3/asm-attrs-1.5.3.pom
Transferring 0K
Downloading: dom4j/dom4j/1.6.1/dom4j-1.6.1.pom
Transferring 6K
Downloading: antlr/antlr/2.7.6/antlr-2.7.6.pom
Transferring 0K
Downloading: cglib/cglib/2.1_3/cglib-2.1_3.pom
Transferring 0K
Downloading: asm/asm/1.5.3/asm-1.5.3.pom
Transferring 0K
Downloading: commons-collections/commons-collections/2.1.1/commons-collections-2
.1.1.pom
Transferring 0K
Downloading: org/hibernate/hibernate-tools/3.2.0.beta9a/hibernate-tools-3.2.0.be
ta9a.pom
Transferring 1K
Downloading: org/hibernate/hibernate/3.2.0.cr5/hibernate-3.2.0.cr5.pom
Transferring 3K
Downloading: freemarker/freemarker/2.3.4/freemarker-2.3.4.pom
Transferring 0K
Downloading: org/hibernate/jtidy/r8-20060801/jtidy-r8-20060801.pom
Transferring 0K
Downloading: org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1/geronimo-jta_1.
1_spec-1.1.pom
Transferring 1K
Downloading: org/apache/geronimo/specs/specs/1.2/specs-1.2.pom
Transferring 2K
Downloading: org/apache/geronimo/genesis/config/project-config/1.1/project-confi
g-1.1.pom
Transferring 14K
Downloading: org/apache/geronimo/genesis/config/config/1.1/config-1.1.pom
Downloading: org/apache/geronimo/genesis/config/config/1.1/config-1.1.pom
Downloading: org/apache/geronimo/genesis/config/config/1.1/config-1.1.pom
Transferring 0K
Downloading: org/apache/geronimo/genesis/genesis/1.1/genesis-1.1.pom
Downloading: org/apache/geronimo/genesis/genesis/1.1/genesis-1.1.pom
Downloading: org/apache/geronimo/genesis/genesis/1.1/genesis-1.1.pom
Transferring 6K
Downloading: org/apache/apache/3/apache-3.pom
Downloading: org/apache/apache/3/apache-3.pom
Downloading: org/apache/apache/3/apache-3.pom
Transferring 3K
Downloading: log4j/log4j/1.2.14/log4j-1.2.14.pom
Transferring 2K
Downloading: org/hibernate/hibernate-tools/3.2.0.beta9a/hibernate-tools-3.2.0.be
ta9a.jar
Transferring 352K
Downloading: org/hibernate/jtidy/r8-20060801/jtidy-r8-20060801.jar
Transferring 243K
Downloading: commons-collections/commons-collections/2.1.1/commons-collections-2
.1.1.jar
Transferring 171K
Downloading: commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar
Transferring 37K
Downloading: antlr/antlr/2.7.6/antlr-2.7.6.jar
Transferring 433K
Downloading: org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1/geronimo-jta_1.
1_spec-1.1.jar
Transferring 15K
Downloading: net/sf/ehcache/ehcache/1.2.3/ehcache-1.2.3.jar
Transferring 203K
Downloading: asm/asm/1.5.3/asm-1.5.3.jar
Transferring 25K
Downloading: freemarker/freemarker/2.3.4/freemarker-2.3.4.jar
Transferring 770K
Downloading: dom4j/dom4j/1.6.1/dom4j-1.6.1.jar
Transferring 306K
Downloading: asm/asm-attrs/1.5.3/asm-attrs-1.5.3.jar
Transferring 16K
Downloading: cglib/cglib/2.1_3/cglib-2.1_3.jar
Transferring 275K
Downloading: hsqldb/hsqldb/1.8.0.7/hsqldb-1.8.0.7.jar
Transferring 628K
Downloading: log4j/log4j/1.2.14/log4j-1.2.14.jar
Transferring 358K
Downloading: org/hibernate/hibernate/3.2.5.ga/hibernate-3.2.5.ga.jar
Transferring 2202K

db:

This big list of downloads shows the Maven Ant Tasks doing their job of finding the pieces we told them we needed (including HSQLDB and Hibernate), along with all the libraries on which they, in turn, depend. This takes a little while to accomplish (depending on how fast your network connection is, and how loaded the servers are), but it will only need to happen once. The next time you fire up Ant, the Maven Ant Tasks will simply notice that your local repository already contains all these pieces, and will silently proceed with whatever else you wanted to accomplish.

Once all the downloading is accomplished, Ant prints db: to indicate that it’s starting to execute the target you requested. A moment later, you should see the HSQLDB graphical interface, which will look something like Figure 1-6. There’s nothing in our database yet, so there’s not much to see beyond whether the command worked at all. The tree view at the top left of the window is where the various tables and columns in our database can be explored. For now, just verify that the top reads jdbc:hsqldb:data/music.

HSQLDB database manager interface

Figure 1-6. HSQLDB database manager interface

You can explore the menus a bit if you like, but don’t make any changes to the database. Once you’re done, choose FileExit. The window will close, and Ant will report:

BUILD SUCCESSFUL
Total time: 56 seconds

The amount of time you spend playing may vary, of course. (Recall that Ant sticks around until the database shuts down because of the fork attribute we added to the java task.) At this point, if you look in the data directory, you’ll find that HSQLDB has created some files to hold the database:

% ls data
music.log        music.properties music.script

You can even look at the contents of these files. Unlike most database systems, HSQLDB stores its data in a human-readable format by default. The properties file contains some basic settings, and the data itself goes in the script file, in the form of SQL statements. The log file is used to reconstruct a consistent database state if the application crashes or otherwise exits without gracefully closing the database. Right now, all you’ll find in these files are the basic definitions that are entered by default, but as we start creating tables and adding data to them, you can view the file again and see the changes appear in it. This can be a useful debugging feature for basic sanity checks, and is even faster than firing up the graphical interface and running queries.

Note

The fact that you can read HSQLDB’s database files is weird but fun.

What just happened?

Now that we’ve successfully run the first example and set up our project’s build file, it is probably time to explain how Ant retrieved all of the necessary dependencies for this project. Let’s re-examine the artifact:dependencies element from the example’s build.xml file (see Example 1-2).

Example 1-2. Our artifact:dependencies element

<artifact:dependencies pathId="dependency.classpath"> 
  <dependency groupId="hsqldb" artifactId="hsqldb" version="1.8.0.7"/>        
  <dependency groupId="org.hibernate" artifactId="hibernate"                  
              version="3.2.5.ga">                                            
    <exclusion groupId="javax.transaction" artifactId="jta"/>                 
  </dependency>                                                               
  <dependency groupId="org.hibernate" artifactId="hibernate-tools"            
              version="3.2.0.beta9a"/>                                        
  <dependency groupId="org.apache.geronimo.specs"                             
              artifactId="geronimo-jta_1.1_spec" version="1.1"/>              
  <dependency groupId="log4j" artifactId="log4j" version="1.2.14"/>           
</artifact:dependencies>

If you’ve never used Maven before, this probably looks very confusing. Let’s start by defining some terminology. First there is an artifact. An artifact is a file that is produced by a project. An artifact can be any type—a WAR for a web application, an EAR for an enterprise application, or a JAR. For our purposes we are depending on JAR artifacts, and the default type if you don’t specify it in the dependency element is jar, conveniently enough.

A specific artifact is identified by four attributes: groupId, artifactId, version, and type. For example, we are depending on version 3.2.5.ga of the hibernate artifact in group org.hibernate and the implied type is jar. Maven will use these identifiers to locate the appropriate dependency in the central Maven 2 repository which is hosted at http://repo1.maven.org/maven2/. Using these values, Maven will attempt to locate the JAR for hibernate using the following pattern: <repositoryUrl>/<groupId>/<artifactId>/<version>/<artifactId>-<version>.<type>, where periods in the groupId are converted to path separators for the URLs that, using this pattern, would be used to locate the JARs for the Hibernate and HSQLDB dependencies. See Example 1-3.

Example 1-3. URLs for project dependencies

http://repo1.maven.org/org/hibernate/hibernate/3.2.5.ga/hibernate-3.2.5.ga.jar
http://repo1.maven.org/hsqldb/hsqldb/1.8.0.7/hsqldb-1.8.0.7.jar

In our build.xml file, we are excluding the JTA dependency from the Hibernate dependency declaration. This is necessary because the Hibernate library depends on a nonfree JAR artifact not available on the public Maven 2 repository. Instead of using the standard Sun-supplied JTA API JAR, this project depends on a version of the JTA API created by the Apache Geronimo project. geronimo-jta_1.1_spec is a free, open source implementation of the Java Transaction API. This substitution is accomplished using the exclusion element within the dependency for Hibernate 3.2.5.ga, combined with the explicit dependency on the Geronimo JTA spec 1.1 later on.

All right, so we have some insight into how the Maven Ant Tasks retrieve the dependencies from the Maven repository, but where do they go once they’ve been downloaded? The Maven Ant Tasks download all dependencies to a local Maven repository. Maven maintains a local repository with a structure that mirrors the remote repository. When it needs to check for an artifact, it checks the local repository first before it requests the artifact from the remote repository. This means that if twenty projects all reference the same version of Hibernate, it is only downloaded from the remote repository once, and all twenty projects will refer to a single copy stored in the local Maven repository. So where is this magical local Maven repository? The easiest way to answer this question is to add a target to our build.xml file. Add the following target to the end of the Ant build.xml from earlier in the chapter, as shown in Example 1-4.

Example 1-4. Printing the dependency class path

<target name="print-classpath" description="Show the dependency class path">
  <property name="class.path" refid="dependency.classpath"/>
  <echo>${class.path}</echo>
</target>

Running this target will produce the following output results:

% ant print-classpath
Buildfile: build.xml

print-classpath:
     [echo] ~\.m2\repository\commons-logging\commons-logging\1.0.4\commons-logging-
1.0.4.jar;\
~\.m2\repository\dom4j\dom4j\1.6.1\dom4j-1.6.1.jar;\
~\.m2\repository\cglib\cglib\2.1_3\cglib-2.1_3.jar;\...

Try running this target. The output will vary depending on which operating system you are using, but you’ll notice that the dependency class path refers to your local Maven repository. On a Windows XP machine this will likely be in C:\Documents and Settings\Username\.m2\repository; on Windows Vista this will likely be in C:\Users\Username\.m2\repository; and on Unix and Macintosh this will be the ~/.m2/repository directory.

You will also notice that there are more dependencies listed in the class path than were declared in the artifact:dependencies element in build.xml. These extra dependencies are called transitive dependencies, and they are dependencies of your explicitly declared dependencies. For example, Hibernate depends upon CGLib, EHCache, and Commons Collections, among other things. Although it is outside the scope of this book, I’ll give you a hint as to how the Maven Ant Tasks figure out the full set of dependencies for your project. If you explore your local repository after you’ve built one of the examples, you will notice that next to every JAR artifact sits a file with the extension .pom. Project Object Model files (or POMs) are the foundation of the Maven build system and repository. Each POM describes an artifact and that artifact’s dependencies. The Maven Ant Tasks use this metadata to construct a tree of transitive dependencies. In other words, the Maven Ant Tasks don’t just take care of downloading Hibernate, they download everything that Hibernate depends upon.

All you really need to know is that it works.

What’s next?

Thanks to the Maven Ant Tasks, you had far fewer hoops to jump through to find, download, expand, and organize software than did readers of the previous version of this book. You’re in a great position to start working with Hibernate and, as you’ll see in the next chapter, we’ll be moving very quickly. You’ll be able to see Java code written for you! Database schemas created out of thin air (or, at least, out of the same XML mapping table that produced the Java)! Real tables and data appearing in the HSQLDB manager interface! (Or, at least, genuine faux sample data….)

Sound exciting? Well, compared to what you’ve done so far anyway? Then let’s dig in to awakening the power of Hibernate.

Why didn’t it work?

If, on the other hand, you saw no database manager window appear, and instead were greeted by error messages, try to figure out if they’re due to problems in the build file, differences in the way you’ve set up Ant or your project hierarchy, difficulty accessing the Internet to download dependencies from the Maven repository, or something else. Double-check that all the pieces are arranged and installed as shown earlier, and consider downloading the sample code if you are having trouble with a version you typed in yourself.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required