Tuesday, January 19, 2010

Section 1.7. Setting Up a Project Hierarchy








1.7. 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.



1.7.1. 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.




1.7.2. 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!




Figure 1-5. Initial project directory contents










1.7.3. 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"?> 
<project name="Harnessing Hibernate 3 (Developer's Notebook Second Edition)"
default="db" basedir="."
xmlns:artifact="antlib:org.apache.maven.artifact.ant">

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

<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>

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

<target name="db" description="Runs HSQLDB database management UI
against the database file--use when application is not running">
<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>






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:



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.



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.





1.7.4. 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.




1.7.5. 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.




1.7.6. 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.










No comments: