Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: {noformat} -> {code} & other minor tweaks

...

First, we must update the POM to list a new set of dependencies, that includes Hibernate, the Tapestry/Hibernate integration library, and the HSQLDB JDBC driver:

Code Block
XML
XML
titlesrc/pom.xml (partial)

...

noformat
    <dependencies>
        <dependency>
            <groupId>org.apache.tapestry</groupId>
            <artifactId>tapestry-hibernate</artifactId>
            <version>${tapestry-release-version}</version>
        </dependency>

        <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.7</version>
        </dependency>

    </dependencies>

The tapestry-hibernate library includes, as transitive dependencies, Hibernate and tapestry-core. This means that you can simply replace "tapestry-core" with "tapestry-hibernate" inside the <artifactId> element.

...

Hibernate has a master configuration file used to store connection and other data.

Code Block
XML
XML
titlesrc/main/resources/hibernate.cfg.xml

...

noformat
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="hibernate.connection.url">jdbc:hsqldb:./target/work/t5_tutorial1;shutdown=true</property>
        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hbm2ddl.auto">update</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
    </session-factory>
</hibernate-configuration>

...

Below is the updated Address class, with the Hibernate annotations (as well as the Tapestry ones).

Code Block
titlesrc/main/java/org/apache/tapestry5/tutorial/entities/Address.java

...

noformat
package org.apache.tapestry5.tutorial.entities;

import org.apache.tapestry5.beaneditor.NonVisual;
import org.apache.tapestry5.beaneditor.Validate;
import org.apache.tapestry5.tutorial.data.Honorific;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Address
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @NonVisual
    private Long id;

    private Honorific honorific;

    @Validate("required")
    private String firstName;

    @Validate("required")
    private String lastName;

    private String street1;

    private String street2;

    @Validate("required")
    private String city;

    @Validate("required")
    private String state;

    @Validate("required,regexp")
    private String zip;

    private String email;

    private String phone;

    public Long getId()
    {
        return id;
    }

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

    public Honorific getHonorific()
    {
        return honorific;
    }

    public String getFirstName()
    {
        return firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public String getStreet1()
    {
        return street1;
    }

    public String getStreet2()
    {
        return street2;
    }

    public String getCity()
    {
        return city;
    }

    public String getState()
    {
        return state;
    }

    public String getZip()
    {
        return zip;
    }

    public String getEmail()
    {
        return email;
    }

    public String getPhone()
    {
        return phone;
    }

    public void setCity(String city)
    {
        this.city = city;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    public void setHonorific(Honorific honorific)
    {
        this.honorific = honorific;
    }

    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    public void setPhone(String phone)
    {
        this.phone = phone;
    }

    public void setState(String state)
    {
        this.state = state;
    }

    public void setStreet1(String street1)
    {
        this.street1 = street1;
    }

    public void setStreet2(String street2)
    {
        this.street2 = street2;
    }

    public void setZip(String zip)
    {
        this.zip = zip;
    }
}

The Tapestry annotations, @NonVisual and @Validate, may be placed on the setter or getter method or on the field (as we have done here). As with the Hibernate annotations, putting the annotation on the field requires that the field name match the corresponding property name.

  • @NonVisual

...

  • indicates a field, such as a primary key, that should not be made visible to the user.
  • @Validate

...

  • identifies the validations associated with a field.

...

Updating the Database

So we have a database up and running, and Hibernate is configured to connect to it. Let's make use of that to store our Address object in the database.

...

  • Use the Hibernate Session object to persist the new Address object.
  • Commit the transaction to force the data to be written to the database.
Code Block
titlesrc/main/java/org/apache/tapestry5/tutorial/pages/address/CreateAddress.java

...

noformat
package org.apache.tapestry5.tutorial.pages.address;

import org.apache.tapestry5.annotations.InjectPage;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.tutorial.entities.Address;
import org.apache.tapestry5.tutorial.pages.Index;
import org.hibernate.Session;

public class CreateAddress
{
    @Property
    private Address address;

    @Inject
    private Session session;

    @InjectPage
    private Index index;

    @CommitAfter
    Object onSuccess()
    {
        session.persist(address);

        return index;
    }
}

The Inject annotation tells Tapestry to inject a service into the annotated field; Tapestry includes a sophisticated Inversion of Control container (similar in many ways to Spring) that is very good at locating available services by type, rather than by a string id. In any case, the Hibernate Session object is exposed as a Tapestry IoC service, ready to be injected (this is one of the things provided by the tapestry-hibernate module).

...

As a little preview of what's next, let's display all the Addresses entered by the user on the Index page of the application. After you enter a few names, it will look something like:

Adding the Grid to the Index page

So pageSo, how is this implemented? Primarily, its accomplished by the Grid component.

...

src/main/webapp/Index.tml (partial):

noformat
Code Block
XML
XML
  <t:grid source="addresses"/>

And all we have to do is supply the addresses property in the Java code:

src/main/java/org/apache/tapestry5/tutorial/pages/Index.java (partial):

No Formatcode
    @Inject
    private Session session;

    public List<Address> getAddresses()
    {
        return session.createCriteria(Address.class).list();
    }

Here, we're using the Hibernate Session object to find all Address objects in the database. Any sorting that takes place will be done in memory. This is fine for now (with only a handful of Address objects in the database). Later we'll see how to optimize this for very large result sets.

...

... but Tapestry and this tutorial are a work in progress, so stay patient, and check out the other Tapestry tutorials and resources available on the Tapestry 5 home Documentation page.