Getting started with Trails and Firebird

0. Preface


A Video of a trails tutorial is available on the Trails homepage, that show much more than this tutorial covers. Try this, and just do the firebird related stuff in Firebird settings

1. What is Trails?


Trails is a domain driven development framework that uses Hibernate, Spring and Tapestry. Hibernate is used as the data access layer and Tapestry is used to display data to the user. Spring ties Hibernate and Tapestry together.

Trails comes with nearly all required jar files - you just have to install the database drivers for firebird - available at firebirdsql.sf.net.

1.1 Hibernate


Hibernate is a so called O/RM tool. O/RM means: object relation modeling. O/RM lets you map your java objects to the underlying database. Hibernate uses XDoclet to specify informations needed to map information for storing complex objects in the database. XDoclet uses javadoc comments to tell hibernate, where to map the objects. For example:
/**
 * @hibernate.class table="PERSON"
 */

public class Person {
 :

tells Hibernate, to map a specific Object (in this case Person) to the table PERSON.

Hibernate can be found at www.hibernate.org.

1.2 Tapestry


Tapestry is (simply spoken) a Web framework. To be more precise, Tapestry is a component based web framework, that keeps a clean separation of the presentation from the logic.

In Tapestry, one page consists of a .html file, that is responsible for the look of a page, a java class, that is responsible for feeding the .html page with the data, and a .page or a .jwc (this depends, wether you have a real page, or a component) file, that is responsible for tying these layers together.

A Component is accessed via the ognl Language and could look like:
<a href="#" jwcid="@PageLink" page="myPage">Goto MyPage>/a<

The jwcid specifies the component to use - in this case a PageLink, which is a component of a tag in HTML representation. The page property specifies the name of the page, you want to link to.

Tapestry can be found at jakarta.apache.org/tapestry

2. Installing Trails.


Download Trails from trails.dev.java.net.

Current version is 0.5.1 and unzip the file (There is a cool demo of how-to write applications with trails on https://trails.dev.java.net - simply search for the link "with narration" and watch it :-).

Unzip trails, and enter the created folder. Change the build.properties file, to match your tomcat home folder and do the following:

Create the trail.jar by typing (I had to do this on my machine)
#> ant jar

3. Write a new application

3.1 Create a new trail application:

#> ant create-project


This will ask you, where to put the project root (I entered /Users/chris/Desktop/projects on MacOS X - Windows Users will have to enter something like c:\path\to\new\project

Enter the project name

After this, a new folder with all the required jars will be created.

3.2 Start eclipse.

3.3 Create a new "Java Project"


The newly created project will be imported to eclipse.

4. Settings

4.1 Change the tomcat home:

4.2 Change the database driver:

hibernate.dialect=net.sf.hibernate.dialect.FirebirdDialect

hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
hibernate.connection.driver_class=org.firebirdsql.jdbc.FBDriver
hibernate.connection.url=jdbc:firebirdsql:127.0.0.1:myapplication
hibernate.connection.username=sysdba
hibernate.connection.password=masterkey

4.3 Create a new database on the host (in this case 127.0.0.1)

#>isql -user sysdba -password masterkey
#>create database '127.0.0.1:/path/to/mydatabase.fdb';
#>commit;
#>exit;

and make an alias in FIREBIRD_HOME/aliases.conf which says:
myapplication = /path/to/mydatabase.fdb

In production systems, you should also change the username and password for the user to connect :-)

4.4 Install the firebird database driver


Download the firebird JCA-JDBC driver from firebird.sf.net unpack it and install the jars to CATALINE_HOME/common/lib/ (for details see JayBird FAQ).

5. Start coding

5.1 Create a Domain Object


Domain objects are simpley spoken POJOs (plain old java objects), which are used by hibernate to store data in the database.

A class is created and opened.

5.2 Tell hibernate about the table to use:


Add the table name as an XDoclet tag hibernate.classabove the class specification. XDoclet tasks start with the @ sign, followed by a namespace (in our case hibernate) and an action, of what to do (see hibernate.sf.net for details).

The XDoclet tag @hibernate.class table="PERSON" tells hibernate to store the data from this object in a table called PERSON.

The name of the table doesn't need to match the class name - you could also specify a MY_PERSON entry here :-).

5.3 Create the properties:

public class Person {
  private Integer PersonID;
  private String Name;
  private String SurName;
  private LSalutation Salutaion;

}

The getter and setter routines are created and a commend is created. Add the following to the comment:
     * @hibernate.id generator-class="sequence" column="PERSON_ID"
     * @hibernate.generator-param name="sequence" value="SQ_PERSON_ID" 

This tells hibernate to use the table column PERSON_ID to store the primary key of the table and create the value of this field by using a generator. The key will be generated by the generator SQ_PERSON_ID.

Mark the name in the outline and right click on it (choose source -> generate getters and setters, select Name and SurName and OK :-) )

This time, we don't need a primary key - we simply need a field to store the name. So we go and add the following javadoc comment:
    /**
     * @hibernate.property column="LAST_NAME" not-null="true"
     */
    public String getName() {
        return Name;
    }

and on the surname property
    /**
     * @return Liefert den surName zurueck.
     * @hibernate.property
     */
    public String getSurName() {
        return SurName;
    }
    /**
     * @param surName The surName to set.
     */
    public void setSurName(String surName) {
        SurName = surName;
    }

The column at the getter from the name property is needed, as we have to override the default behavior. Hibernate would assume a field named "NAME" - but as this is a keyword in firebird, we have to choose an other name.

Remerber: the hibernate tags must always be set at the getter routines - not at the setter routines.

If we want, we can set a null value by adding the not-null="true" property to the hibernate XDoclet tag - the default value is false.

5.4 Create the Lookup Tables


There's one error marked - with the LSalutation.

So put your cursor on the LSaltutaion and press ctrl and 1 (on Apple Macintosh you have to press Command + 1) and choose "create new class" from the popup list. This will show you the following dialog:



Enter the package name for the file to create, press "finish", and do the following steps:
package de.test.data;

/**
 * @author chris
 *
 * @hibernate.class table="SALUTATION"
 */
public class LSalutation {
    private Integer SalutaionID;  
    private String Salutation;
    /**
     * @return Liefert den salutaionID zurueck.
     * @hibernate.id generator-class="sequence" column="SALUTATION_ID"
     * @hibernate.generator-param name="sequence" value="SQ_SALUTATION_ID"
     */
    public Integer getSalutaionID() {
        return SalutaionID;
    }
    /**
     * @param salutaionID The salutaionID to set.
     */
    public void setSalutaionID(Integer salutaionID) {
        SalutaionID = salutaionID;
    }
    /**
     * @return Liefert den salutation zurueck.
     * @hibernate.property not-null="true"
     */
    public String getSalutation() {
        return Salutation;
    }
    /**
     * @param salutation The salutation to set.
     */
    public void setSalutation(String salutation) {
        Salutation = salutation;
    }
}


So, this is an other object, which could be mapped by hibernate. It should work for hibernate, but for trails, one thing is missing:

The toString() method is used to display the property correctly in the list view, while the equals method is used to identify the object. So simply add the following code to the LSalutation Class:
	public boolean equals(Object obj){
		return ((LSalutation)obj).getSalutationId().equals(getSalutationId());
	}

	public String toString(){
		return getSalutation();
	}

Go back to the Person.java class and create the getter and setter routines for the Saltuation property.

We don't have an other property here, since we will use another table for our salutations. So here we have a many-to-one relation ship. This means, we have to change the javadoc comment to:
    /**
     * @return Liefert den salutaion zurueck.
     * @hibernate.many-to-one column="SALUTATION_ID"
     */
    public LSalutation getSalutaion() {
        return Salutaion;
    }

Now Hibernate knows, how to reference the our salutation class.

This is all we have to code :-)

6. Build the application:


Open the build.xml file, right click the war target and choose ant -> build
.
This will ant to build the .war file (the tutorial from trail says, that doing the deploy target will deploy the app - this did not work on my machine). So I simply copied the project.war file to TOMCAT_HOME/webapps.

7. Accessing the application:


Open a browser and enter 127.0.0.1:8080/project_name

And have fun browsing and entering the data :-)

No warranty - Chris